- transpiler now always returns an object

- emit transpiler metadata from evaluate / afterEval
- currently logging miniLocations from Repl.jsx
This commit is contained in:
Felix Roos 2023-07-02 14:15:54 +02:00
parent 5f271ed127
commit 8e717d2ea1
7 changed files with 25 additions and 19 deletions

View File

@ -37,8 +37,12 @@ function safeEval(str, options = {}) {
} }
export const evaluate = async (code, transpiler) => { export const evaluate = async (code, transpiler) => {
let meta = {};
if (transpiler) { if (transpiler) {
code = transpiler(code); // transform syntactically correct js code to semantically usable code // transform syntactically correct js code to semantically usable code
const transpiled = transpiler(code);
code = transpiled.output;
meta = transpiled;
} }
// if no transpiler is given, we expect a single instruction (!wrapExpression) // if no transpiler is given, we expect a single instruction (!wrapExpression)
const options = { wrapExpression: !!transpiler }; const options = { wrapExpression: !!transpiler };
@ -48,5 +52,5 @@ export const evaluate = async (code, transpiler) => {
const message = `got "${typeof evaluated}" instead of pattern`; const message = `got "${typeof evaluated}" instead of pattern`;
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.')); throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
} }
return { mode: 'javascript', pattern: evaluated }; return { mode: 'javascript', pattern: evaluated, meta };
}; };

View File

@ -35,11 +35,10 @@ export function repl({
} }
try { try {
await beforeEval?.({ code }); await beforeEval?.({ code });
let { pattern } = await _evaluate(code, transpiler); let { pattern, meta } = await _evaluate(code, transpiler);
logger(`[eval] code updated`); logger(`[eval] code updated`);
setPattern(pattern, autostart); setPattern(pattern, autostart);
afterEval?.({ code, pattern }); afterEval?.({ code, pattern, meta });
return pattern; return pattern;
} catch (err) { } catch (err) {
// console.warn(`[repl] eval error: ${err.message}`); // console.warn(`[repl] eval error: ${err.message}`);

View File

@ -129,8 +129,8 @@ export default (_code) => {
if (shouldAddReturn) { if (shouldAddReturn) {
addReturn(shifted); addReturn(shifted);
} }
const generated = undisguiseImports(codegen(shifted)); const output = undisguiseImports(codegen(shifted));
return generated; return { output };
}; };
// renames all import statements to "_mport" as Shift doesn't support dynamic import. // renames all import statements to "_mport" as Shift doesn't support dynamic import.

View File

@ -10,14 +10,16 @@ import shapeshifter, { wrappedAsync } from '../shapeshifter.mjs';
describe('shapeshifter', () => { describe('shapeshifter', () => {
it('Should shift simple double quote string', () => { it('Should shift simple double quote string', () => {
if (wrappedAsync) { if (wrappedAsync) {
expect(shapeshifter('"c3"')).toEqual('(async()=>{return mini("c3").withMiniLocation([1,0,15],[1,4,19])})()'); expect(shapeshifter('"c3"').output).toEqual(
'(async()=>{return mini("c3").withMiniLocation([1,0,15],[1,4,19])})()',
);
} else { } else {
expect(shapeshifter('"c3"')).toEqual('return mini("c3").withMiniLocation([1,0,0],[1,4,4])'); expect(shapeshifter('"c3"').output).toEqual('return mini("c3").withMiniLocation([1,0,0],[1,4,4])');
} }
}); });
if (wrappedAsync) { if (wrappedAsync) {
it('Should handle dynamic imports', () => { it('Should handle dynamic imports', () => {
expect(shapeshifter('const { default: foo } = await import(\'https://bar.com/foo.js\');"c3"')).toEqual( expect(shapeshifter('const { default: foo } = await import(\'https://bar.com/foo.js\');"c3"').output).toEqual(
'const{default:foo}=await import("https://bar.com/foo.js");return mini("c3").withMiniLocation([1,64,79],[1,68,83])', 'const{default:foo}=await import("https://bar.com/foo.js");return mini("c3").withMiniLocation([1,64,79],[1,68,83])',
); );
}); });

View File

@ -11,22 +11,22 @@ const simple = { wrapAsync: false, addReturn: false, simpleLocs: true };
describe('transpiler', () => { describe('transpiler', () => {
it('wraps double quote string with mini and adds location', () => { it('wraps double quote string with mini and adds location', () => {
expect(transpiler('"c3"', simple)).toEqual("mini('c3').withMiniLocation(0, 4);"); expect(transpiler('"c3"', simple).output).toEqual("mini('c3').withMiniLocation(0, 4);");
expect(transpiler('stack("c3","bd sd")', simple)).toEqual( expect(transpiler('stack("c3","bd sd")', simple).output).toEqual(
"stack(mini('c3').withMiniLocation(6, 10), mini('bd sd').withMiniLocation(11, 18));", "stack(mini('c3').withMiniLocation(6, 10), mini('bd sd').withMiniLocation(11, 18));",
); );
}); });
it('wraps backtick string with mini and adds location', () => { it('wraps backtick string with mini and adds location', () => {
expect(transpiler('`c3`', simple)).toEqual("mini('c3').withMiniLocation(0, 4);"); expect(transpiler('`c3`', simple).output).toEqual("mini('c3').withMiniLocation(0, 4);");
}); });
it('replaces note variables with note strings', () => { it('replaces note variables with note strings', () => {
expect(transpiler('seq(c3, d3)', simple)).toEqual("seq('c3', 'd3');"); expect(transpiler('seq(c3, d3)', simple).output).toEqual("seq('c3', 'd3');");
}); });
it('keeps tagged template literal as is', () => { it('keeps tagged template literal as is', () => {
expect(transpiler('xxx`c3`', simple)).toEqual('xxx`c3`;'); expect(transpiler('xxx`c3`', simple).output).toEqual('xxx`c3`;');
}); });
it('supports top level await', () => { it('supports top level await', () => {
expect(transpiler("await samples('xxx');", simple)).toEqual("await samples('xxx');"); expect(transpiler("await samples('xxx');", simple).output).toEqual("await samples('xxx');");
}); });
/* it('parses dynamic imports', () => { /* it('parses dynamic imports', () => {
expect( expect(

View File

@ -5,7 +5,7 @@ import { isNoteWithOctave } from '@strudel.cycles/core';
import { getLeafLocations } from '@strudel.cycles/mini'; import { getLeafLocations } from '@strudel.cycles/mini';
export function transpiler(input, options = {}) { export function transpiler(input, options = {}) {
const { wrapAsync = false, addReturn = true, simpleLocs = false, emitMiniLocations = false } = options; const { wrapAsync = false, addReturn = true, simpleLocs = false, emitMiniLocations = true } = options;
let ast = parse(input, { let ast = parse(input, {
ecmaVersion: 2022, ecmaVersion: 2022,
@ -62,7 +62,7 @@ export function transpiler(input, options = {}) {
output = `(async ()=>{${output}})()`; output = `(async ()=>{${output}})()`;
} }
if (!emitMiniLocations) { if (!emitMiniLocations) {
return output; return { output };
} }
return { output, miniLocations }; return { output, miniLocations };
} }

View File

@ -128,7 +128,8 @@ export function Repl({ embedded = false }) {
cleanupUi(); cleanupUi();
cleanupDraw(); cleanupDraw();
}, },
afterEval: ({ code }) => { afterEval: ({ code, meta }) => {
console.log('miniLocations', meta.miniLocations);
setPending(false); setPending(false);
setLatestCode(code); setLatestCode(code);
window.location.hash = '#' + encodeURIComponent(btoa(code)); window.location.hash = '#' + encodeURIComponent(btoa(code));