From 8e717d2ea15398847b4b888d415f50722df42e79 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 2 Jul 2023 14:15:54 +0200 Subject: [PATCH] - transpiler now always returns an object - emit transpiler metadata from evaluate / afterEval - currently logging miniLocations from Repl.jsx --- packages/core/evaluate.mjs | 8 ++++++-- packages/core/repl.mjs | 5 ++--- packages/eval/shapeshifter.mjs | 4 ++-- packages/eval/test/shapeshifter.test.mjs | 8 +++++--- packages/transpiler/test/transpiler.test.mjs | 12 ++++++------ packages/transpiler/transpiler.mjs | 4 ++-- website/src/repl/Repl.jsx | 3 ++- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/core/evaluate.mjs b/packages/core/evaluate.mjs index 1d7be8e4..0dada761 100644 --- a/packages/core/evaluate.mjs +++ b/packages/core/evaluate.mjs @@ -37,8 +37,12 @@ function safeEval(str, options = {}) { } export const evaluate = async (code, transpiler) => { + let meta = {}; 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) const options = { wrapExpression: !!transpiler }; @@ -48,5 +52,5 @@ export const evaluate = async (code, transpiler) => { 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 }; + return { mode: 'javascript', pattern: evaluated, meta }; }; diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 93e86622..b6866b87 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -35,11 +35,10 @@ export function repl({ } try { await beforeEval?.({ code }); - let { pattern } = await _evaluate(code, transpiler); - + let { pattern, meta } = await _evaluate(code, transpiler); logger(`[eval] code updated`); setPattern(pattern, autostart); - afterEval?.({ code, pattern }); + afterEval?.({ code, pattern, meta }); return pattern; } catch (err) { // console.warn(`[repl] eval error: ${err.message}`); diff --git a/packages/eval/shapeshifter.mjs b/packages/eval/shapeshifter.mjs index f2edf604..19907341 100644 --- a/packages/eval/shapeshifter.mjs +++ b/packages/eval/shapeshifter.mjs @@ -129,8 +129,8 @@ export default (_code) => { if (shouldAddReturn) { addReturn(shifted); } - const generated = undisguiseImports(codegen(shifted)); - return generated; + const output = undisguiseImports(codegen(shifted)); + return { output }; }; // renames all import statements to "_mport" as Shift doesn't support dynamic import. diff --git a/packages/eval/test/shapeshifter.test.mjs b/packages/eval/test/shapeshifter.test.mjs index ae958326..a76c2aae 100644 --- a/packages/eval/test/shapeshifter.test.mjs +++ b/packages/eval/test/shapeshifter.test.mjs @@ -10,14 +10,16 @@ import shapeshifter, { wrappedAsync } from '../shapeshifter.mjs'; describe('shapeshifter', () => { it('Should shift simple double quote string', () => { 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 { - 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) { 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])', ); }); diff --git a/packages/transpiler/test/transpiler.test.mjs b/packages/transpiler/test/transpiler.test.mjs index ecfbe5a3..23b0e64f 100644 --- a/packages/transpiler/test/transpiler.test.mjs +++ b/packages/transpiler/test/transpiler.test.mjs @@ -11,22 +11,22 @@ const simple = { wrapAsync: false, addReturn: false, simpleLocs: true }; describe('transpiler', () => { it('wraps double quote string with mini and adds location', () => { - expect(transpiler('"c3"', simple)).toEqual("mini('c3').withMiniLocation(0, 4);"); - expect(transpiler('stack("c3","bd sd")', simple)).toEqual( + expect(transpiler('"c3"', simple).output).toEqual("mini('c3').withMiniLocation(0, 4);"); + expect(transpiler('stack("c3","bd sd")', simple).output).toEqual( "stack(mini('c3').withMiniLocation(6, 10), mini('bd sd').withMiniLocation(11, 18));", ); }); 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', () => { - 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', () => { - expect(transpiler('xxx`c3`', simple)).toEqual('xxx`c3`;'); + expect(transpiler('xxx`c3`', simple).output).toEqual('xxx`c3`;'); }); 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', () => { expect( diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 1bb3b85b..d2f9eed6 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -5,7 +5,7 @@ import { isNoteWithOctave } from '@strudel.cycles/core'; import { getLeafLocations } from '@strudel.cycles/mini'; 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, { ecmaVersion: 2022, @@ -62,7 +62,7 @@ export function transpiler(input, options = {}) { output = `(async ()=>{${output}})()`; } if (!emitMiniLocations) { - return output; + return { output }; } return { output, miniLocations }; } diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 02e14ca3..2030fad1 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -128,7 +128,8 @@ export function Repl({ embedded = false }) { cleanupUi(); cleanupDraw(); }, - afterEval: ({ code }) => { + afterEval: ({ code, meta }) => { + console.log('miniLocations', meta.miniLocations); setPending(false); setLatestCode(code); window.location.hash = '#' + encodeURIComponent(btoa(code));