move evaluate logic without transpiler to core

+ breaking change: evalScope is now imported from core
+ breaking change: deprecated extend is now removed
+ add repl.mjs
This commit is contained in:
Felix Roos 2022-11-06 12:12:43 +01:00
parent 0485632e22
commit 371af755df
14 changed files with 107 additions and 85 deletions

View file

@ -0,0 +1,45 @@
/*
evaluate.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/eval/evaluate.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import * as strudel from '@strudel.cycles/core';
const { isPattern, Pattern } = strudel;
let scoped = false;
export const evalScope = async (...args) => {
if (scoped) {
console.warn('evalScope was called more than once.');
}
scoped = true;
const results = await Promise.allSettled(args);
const modules = results.filter((result) => result.status === 'fulfilled').map((r) => r.value);
results.forEach((result, i) => {
if (result.status === 'rejected') {
console.warn(`evalScope: module with index ${i} could not be loaded:`, result.reason);
}
});
Object.assign(globalThis, ...modules, Pattern.prototype.bootstrap());
};
function safeEval(str) {
return Function('"use strict";return (' + str + ')')();
}
export const evaluate = async (code, transpiler) => {
if (!scoped) {
await evalScope(); // at least scope Pattern.prototype.boostrap
}
if (transpiler) {
code = transpiler(code); // transform syntactically correct js code to semantically usable code
}
let evaluated = await safeEval(code);
if (!isPattern(evaluated)) {
console.log('evaluated', evaluated);
const message = `got "${typeof evaluated}" instead of pattern`;
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
}
return { mode: 'javascript', pattern: evaluated };
};

View file

@ -17,6 +17,7 @@ export * from './util.mjs';
export * from './speak.mjs';
export * from './clockworker.mjs';
export * from './scheduler.mjs';
export * from './evaluate.mjs';
export { default as drawLine } from './drawLine.mjs';
export { default as gist } from './gist.js';
// below won't work with runtime.mjs (json import fails)

23
packages/core/repl.mjs Normal file
View file

@ -0,0 +1,23 @@
import { Cyclist } from './cyclist.mjs';
import { evaluate as _evaluate } from './evaluate.mjs';
export function repl({ interval, defaultOutput, onSchedulerError, onEvalError, onEval, getTime, transpiler }) {
const scheduler = new Cyclist({ interval, onTrigger: defaultOutput, onError: onSchedulerError, getTime });
const evaluate = async (code) => {
if (!code) {
throw new Error('no code to evaluate');
}
try {
const { pattern } = await _evaluate(code, transpiler);
scheduler.setPattern(pattern);
onEval({
pattern,
code,
});
} catch (err) {
onEvalError?.(err);
console.warn('eval error', err);
}
};
return { scheduler, evaluate };
}