diff --git a/src/components/challengeView/SceneButtons/Execute.tsx b/src/components/challengeView/SceneButtons/Execute.tsx index 5a9e0f67..c5855771 100644 --- a/src/components/challengeView/SceneButtons/Execute.tsx +++ b/src/components/challengeView/SceneButtons/Execute.tsx @@ -1,10 +1,6 @@ import { Button } from "@mui/material" -import { workspaceToCode } from "../../blockly/blockly" -//@ts-ignore -import Interpreter from 'js-interpreter' -//@ts-ignore -import beautify from 'js-beautify' -import { scene } from "../Scene/scene" +import { scene } from "../scene" +import { interpreterFactory } from "./interpreter-factory" export const ExecuteButton = () => { @@ -21,12 +17,10 @@ export const ExecuteButton = () => { const executeInterpreter = (interpreter: any) => { try { moreToExecute = interpreter.run(); - console.log("Mas para ejecutar: ", moreToExecute) } catch (e) { console.log(e); reject(e); } - if (moreToExecute) { setTimeout(executeInterpreter, 10, interpreter) } else { @@ -41,74 +35,3 @@ export const ExecuteButton = () => { return } - -class InterpreterFactory { - createInterpreter(): any { ///TODO tipo - console.log(this.wrappedCode()) - return new Interpreter(this.wrappedCode(), (interpreter: any, scope: any) => { - return this.init(interpreter, scope); - }) - } - - init(interpreter: any, scope: any): any { - interpreter.setProperty(scope, 'out_hacer', interpreter.createAsyncFunction(this.do_wrapper)); - interpreter.setProperty(scope, 'highlightBlock', interpreter.createNativeFunction(this.highlightBlock)); - } - - - /** - * Generates the function "out_hacer", which will be called in the interpreter - * - * This method will chain two behaviours to simplify the use of async functions. It - * will add the behaviour that represents the action the user wants to do wih the actor, - * and then it will add another behaviour to indicate the async task finished. - * - * For example, if the code calls the function "hacer" this way: - * - * hacer("Saltar", {}); - * - * hacer("Caminar", {pasos: 20}); - * - * Internally, the function will make the actor first jump ("Saltar") and then walk - * ("caminar") 20 steps ("pasos"). - * - * @param behaviour - * @param params - * @param callback - */ - do_wrapper(behaviour: any, params: any, callback: any) { - const actor = scene.sceneActor() - params = params ? params.toString() : ''; - params = JSON.parse(params); - var behaviourClass = scene.behaviourClass(behaviour ? behaviour.toString() : '') - - if (typeof params.receptor === 'string') { - params.receptor = scene.sceneReceptor(params.receptor) - } - - actor.hacer_luego(behaviourClass, params); - actor.hacer_luego(scene.behaviourClass('LlamarCallback'), { callback }); - }; - - highlightBlock(id: string){ - console.log(id) - } - - wrappedCode(): string { - return beautify.js(` - var actor_id = 'demo'; // se asume el actor receptor de la escena. - - function hacer(id, comportamiento, params) { - out_hacer(comportamiento, JSON.stringify(params)); - } - - function main() { - ${workspaceToCode()} - } - - main(); - `); - } -} - -export const interpreterFactory = new InterpreterFactory() diff --git a/src/components/challengeView/SceneButtons/interpreter-factory.ts b/src/components/challengeView/SceneButtons/interpreter-factory.ts new file mode 100644 index 00000000..91caf2b6 --- /dev/null +++ b/src/components/challengeView/SceneButtons/interpreter-factory.ts @@ -0,0 +1,86 @@ +import { workspaceToCode } from "../../blockly/blockly" +//@ts-ignore +import Interpreter from 'js-interpreter' +//@ts-ignore +import beautify from 'js-beautify' +import { scene } from "../scene" + + +class InterpreterFactory { + createInterpreter(): any { ///TODO tipo + console.log(this.wrappedCode()) + return new Interpreter(this.wrappedCode(), (interpreter: any, scope: any) => { + return this.init(interpreter, scope); + }) + } + + init(interpreter: any, scope: any): any { + interpreter.setProperty(scope, 'out_hacer', interpreter.createAsyncFunction(this.doWrapper)) + interpreter.setProperty(scope, 'highlightBlock', interpreter.createNativeFunction(this.highlightBlock)) + interpreter.setProperty(scope, 'evaluar', interpreter.createNativeFunction(this.evaluateWrapper)) + } + + /** + * Generates the function "out_hacer", which will be called in the interpreter + * + * This method will chain two behaviours to simplify the use of async functions. It + * will add the behaviour that represents the action the user wants to do wih the actor, + * and then it will add another behaviour to indicate the async task finished. + * + * For example, if the code calls the function "hacer" this way: + * + * hacer("Saltar", {}); + * + * hacer("Caminar", {pasos: 20}); + * + * Internally, the function will make the actor first jump ("Saltar") and then walk + * ("caminar") 20 steps ("pasos"). + * + * @param behaviour + * @param params + * @param callback + */ + doWrapper(behaviour: any, params: any, callback: any) { + const actor = scene.sceneActor() + params = JSON.parse(params ? params.toString() : '') + var behaviourClass = scene.behaviourClass(behaviour ? behaviour.toString() : '') + + if (typeof params.receptor === 'string') { + params.receptor = scene.sceneReceptor(params.receptor) + } + + actor.hacer_luego(behaviourClass, params); + actor.hacer_luego(scene.behaviourClass('LlamarCallback'), { callback }); + }; + + highlightBlock(id: string) { + console.log(id) //TODO + } + + /** + * This is the code that executes with an expression (sensor, operation, etc) + * @param expression + * @returns + */ + evaluateWrapper(expression: any) { + return scene.evaluateExpression(expression ? expression.toString() : '') + } + + wrappedCode(): string { + return beautify.js(` + var actor_id = 'demo'; // se asume el actor receptor de la escena. + + function hacer(id, comportamiento, params) { + out_hacer(comportamiento, JSON.stringify(params)); + } + + function main() { + ${workspaceToCode()} + } + + main(); + `); + } +} + +export const interpreterFactory = new InterpreterFactory() \ No newline at end of file diff --git a/src/components/challengeView/SceneView.tsx b/src/components/challengeView/SceneView.tsx index a7c6243f..b2bcc80f 100644 --- a/src/components/challengeView/SceneView.tsx +++ b/src/components/challengeView/SceneView.tsx @@ -1,6 +1,6 @@ import { Challenge } from "../../staticData/challenges" import { PBCard } from "../PBCard" -import { scene } from "./Scene/scene" +import { scene } from "./scene" import { useMediaQuery } from "@mui/material" import { useThemeContext } from "../../theme/ThemeContext" import { useState } from "react" diff --git a/src/components/challengeView/Scene/scene.ts b/src/components/challengeView/scene.ts similarity index 89% rename from src/components/challengeView/Scene/scene.ts rename to src/components/challengeView/scene.ts index f82d5ceb..b4838f0c 100644 --- a/src/components/challengeView/Scene/scene.ts +++ b/src/components/challengeView/scene.ts @@ -1,5 +1,5 @@ -import { adaptURL } from "../../../scriptLoader"; -import { Challenge } from "../../../staticData/challenges"; +import { adaptURL } from "../../scriptLoader"; +import { Challenge } from "../../staticData/challenges"; class Scene { iframe(): HTMLIFrameElement { @@ -42,11 +42,11 @@ class Scene { }) } - listenToIframeMessages() { + listenToIframeMessages() { window.addEventListener("message", (event) => { // exercises post error messages in the form { tipo: "error", error: object } // where object can be any error or { name: "ActividadError", message: "description"} - if(event.data.tipo === "error") + if (event.data.tipo === "error") console.log(`Pilasweb execution ended with error: ${JSON.stringify(event.data.error)}`) }) } @@ -107,6 +107,17 @@ class Scene { comportamiento; `) } + + evaluateExpression(expression: string) { + return this.eval(` + try { + var value = pilas.escena_actual().automata.${expression} + } catch (e) { + pilas.escena_actual().errorHandler.handle(e); + } + + value`) + } } export const scene = new Scene() \ No newline at end of file