From 4d7bf4468b44ce593e6c87886aa0443b11e60c3a Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Thu, 6 Mar 2025 19:50:09 +0000 Subject: [PATCH] ZOMG --- .../useConstructRunCode.ts | 29 +++-- .../generateAndRunTestSuite/execTest.ts | 6 +- app/javascript/components/execJS.ts | 100 ++++++++++++++++++ app/javascript/interpreter/frames.ts | 4 +- package.json | 5 +- yarn.lock | 22 ++++ 6 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 app/javascript/components/execJS.ts diff --git a/app/javascript/components/bootcamp/SolveExercisePage/hooks/useConstructRunCode/useConstructRunCode.ts b/app/javascript/components/bootcamp/SolveExercisePage/hooks/useConstructRunCode/useConstructRunCode.ts index a715d96c0f..b24a521bac 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/hooks/useConstructRunCode/useConstructRunCode.ts +++ b/app/javascript/components/bootcamp/SolveExercisePage/hooks/useConstructRunCode/useConstructRunCode.ts @@ -94,22 +94,19 @@ export function useConstructRunCode({ .querySelectorAll('.exercise-container') .forEach((e) => e.remove()) - // @ts-ignore - const compiled = compile(studentCode, { - languageFeatures: config.interpreterOptions, - customFunctions: Object.values(customFunctionsForInterpreter).map( - (cfn) => { - return { name: cfn.name, arity: cfn.arity, code: cfn.code } - } - ), - }) - - const error = compiled.error as CompilationError - - if (error) { - handleCompilationError(error, editorView) - return - } + // const compiled = compile(studentCode, { + // languageFeatures: config.interpreterOptions, + // customFunctions: customFunctionsForInterpreter.map((cfn) => { + // return { name: cfn.name, arity: cfn.arity, code: cfn.code } + // }), + // }) + + // const error = compiled.error as CompilationError + + // if (error) { + // handleCompilationError(error, editorView) + // return + // } let testResults diff --git a/app/javascript/components/bootcamp/SolveExercisePage/test-runner/generateAndRunTestSuite/execTest.ts b/app/javascript/components/bootcamp/SolveExercisePage/test-runner/generateAndRunTestSuite/execTest.ts index 2b563a51e8..ea4a24d16a 100644 --- a/app/javascript/components/bootcamp/SolveExercisePage/test-runner/generateAndRunTestSuite/execTest.ts +++ b/app/javascript/components/bootcamp/SolveExercisePage/test-runner/generateAndRunTestSuite/execTest.ts @@ -15,6 +15,7 @@ import { AnimationTimeline, } from '../../AnimationTimeline/AnimationTimeline' import { Frame } from '@/interpreter/frames' +import { execJS } from '../../../../execJS' /** This is of type TestCallback @@ -36,7 +37,8 @@ export function execTest( const args = testData.args ? parseArgs(testData.args) : [] - let evaluated + let evaluated = execJS(options.studentCode) + /*let evaluated if (testData.function) { evaluated = evaluateFunction( options.studentCode, @@ -52,7 +54,7 @@ export function execTest( ) } else { evaluated = interpret(options.studentCode, context) - } + }*/ const { value: actual, frames } = evaluated diff --git a/app/javascript/components/execJS.ts b/app/javascript/components/execJS.ts new file mode 100644 index 0000000000..fbcac18941 --- /dev/null +++ b/app/javascript/components/execJS.ts @@ -0,0 +1,100 @@ +import { generate } from 'astring' +import { parse } from 'acorn' +import { instrument } from 'aran' +import { Frame } from '@/interpreter/frames' + +export const execJS = (code: string) => { + return runCode(code) +} + +function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n) +} + +const runCode = (code: string) => { + const parsedCode = parse(code, { + sourceType: 'script', + locations: true, + ecmaVersion: 2024, + }) + + const extactLOCFromTag = (tag) => { + let node = parsedCode.body + tag + .replace('main#$.body.', '') + .split('.') + .forEach((elem) => { + if (isNumeric(elem)) { + node = node[parseInt(elem)] + } else { + node = node[elem] + } + }) + return node.loc + } + + const advice_global_variable = '_ARAN_ADVICE_' + const data_global_variable = '_DATA_' + + let data = { time: 0 } + const frames: Frame[] = [] + const describeFrame = (value) => { + if (typeof value === 'function') { + return String(value.name || 'anonynmous') + } else if (typeof value === 'object' && value !== null) { + return '#' + Object.prototype.toString.call(value).slice(8, -1) + } else if (typeof value === 'symbol') { + return '@' + String(value.description ?? 'unknown') + } else if (typeof value === 'string') { + return JSON.stringify(value) + } else { + return String(value) + } + } + const addFrame = ( + code: string, + status: 'SUCCESS' | 'ERROR', + callee: any, + location: any + ) => { + const time = globalThis._DATA_.time + const line = extactLOCFromTag(location).start.line + const frame: Frame = { + timelineTime: time * 100, + time: globalThis._DATA_.time, + line: line, + code: code, + status: status, + + description: () => { + return describeFrame(callee) + }, + } + frames.push(frame) + globalThis._DATA_.time += 0.01 + } + globalThis._ADD_FRAME_ = addFrame + + const advice = { + 'apply@around': (_state, callee, that, input, location) => { + // console.log(_state, callee, that, input, location) + const result = Reflect.apply(callee, that, input) + globalThis._ADD_FRAME_('', 'SUCCESS', callee, location) + return result + }, + } + + Reflect.defineProperty(globalThis, advice_global_variable, { value: advice }) + Reflect.defineProperty(globalThis, data_global_variable, { value: {} }) + + // Reset time + globalThis._DATA_.time = 0 + + const root2 = instrument( + { kind: 'eval', path: 'main', root: parsedCode }, + { mode: 'standalone', advice_global_variable, pointcut: ['apply@around'] } + ) + const res = globalThis.eval(generate(root2)) + console.log(res) + return { value: res, frames: frames } +} diff --git a/app/javascript/interpreter/frames.ts b/app/javascript/interpreter/frames.ts index 992f6fecef..b0553a86a0 100644 --- a/app/javascript/interpreter/frames.ts +++ b/app/javascript/interpreter/frames.ts @@ -48,8 +48,8 @@ export type Frame = { code: string status: FrameExecutionStatus error?: RuntimeError - priorVariables: Record - variables: Record + // priorVariables: Record + variables?: Record time: number timelineTime: number result?: EvaluationResult diff --git a/package.json b/package.json index d996ff5254..87f6226fa4 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@gleam-lang/highlight.js-gleam": "^1.0.0", "@hotwired/stimulus": "^3.2.2", "@hotwired/turbo-rails": "^7.3.0", + "@juliangarnierorg/anime-beta": "^4.0.0-rc.4", "@plutojl/lang-julia": "^0.12.1", "@popperjs/core": "^2.11.8", "@rails/actioncable": "^6.0.0", @@ -46,8 +47,10 @@ "@xstate/react": "^3.2.2", "abortcontroller-polyfill": "^1.7.3", "ace-builds": "^1.4.12", + "acorn": "^8.14.1", "actioncable": "^5.2.4-3", - "@juliangarnierorg/anime-beta": "^4.0.0-rc.4", + "aran": "^5.1.0", + "astring": "^1.9.0", "autoprefixer": "latest", "browserslist-to-esbuild": "^1.1.1", "canvas-confetti": "^1.9.3", diff --git a/yarn.lock b/yarn.lock index 2d7a31e1aa..e23f776270 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2631,6 +2631,11 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.14.1: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + acorn@^8.2.4: version "8.14.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" @@ -2798,6 +2803,13 @@ aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2: resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== +aran@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/aran/-/aran-5.1.0.tgz#e8583510d5b197c7df1cbbbb5553b41eefaa6b5c" + integrity sha512-km8oG8EMRtn1MPnBJ7upMS4ikLrmH3ja75+anzVod8qj2hCrYcdXl5l5VsAEMY5ZqoT0WrPrPntsG4QzH2vRvA== + dependencies: + estree-sentry "^0.4.1" + archy@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" @@ -2991,6 +3003,11 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +astring@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.9.0.tgz#cc73e6062a7eb03e7d19c22d8b0b3451fd9bfeef" + integrity sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -5023,6 +5040,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-sentry@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/estree-sentry/-/estree-sentry-0.4.1.tgz#7f258ae702d54c04f17712431bd8bb0d3f5e7f10" + integrity sha512-tTlF1mwCLlKf0dWMc9Xi9Ady3d6I1cq/hCTsMPZF6EmfJjr9gpewJqOPLKJEhxHYPY6dzzMPO2w3qS8mbmNVLQ== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"