diff --git a/e2e/playwright/snapshot-tests.spec.ts b/e2e/playwright/snapshot-tests.spec.ts index 5e85eb869..7976fd173 100644 --- a/e2e/playwright/snapshot-tests.spec.ts +++ b/e2e/playwright/snapshot-tests.spec.ts @@ -143,11 +143,11 @@ const part001 = startSketchOn('-XZ') |> xLineTo({ to: totalLen, tag: 'seg03' }, %) |> yLine({ length: -armThick, tag: 'seg01' }, %) |> angledLineThatIntersects({ - angle: _180, + angle: HALF_TURN, offset: -armThick, intersectTag: 'seg04' }, %) - |> angledLineToY([segAng('seg04', %) + 180, _0], %) + |> angledLineToY([segAng('seg04', %) + 180, ZERO], %) |> angledLineToY({ angle: -bottomAng, to: -totalHeightHalf - armThick, @@ -156,12 +156,12 @@ const part001 = startSketchOn('-XZ') |> xLineTo(segEndX('seg03', %) + 0, %) |> yLine(-segLen('seg01', %), %) |> angledLineThatIntersects({ - angle: _180, + angle: HALF_TURN, offset: -armThick, intersectTag: 'seg02' }, %) |> angledLineToY([segAng('seg02', %) + 180, -baseHeight], %) - |> xLineTo(_0, %) + |> xLineTo(ZERO, %) |> close(%) |> extrude(4, %)` ) diff --git a/src/clientSideScene/clientSideScene.ts b/src/clientSideScene/clientSideScene.ts index 5ffe17e2e..f82189f6c 100644 --- a/src/clientSideScene/clientSideScene.ts +++ b/src/clientSideScene/clientSideScene.ts @@ -42,6 +42,7 @@ import { PipeExpression, Program, ProgramMemory, + programMemoryInit, recast, SketchGroup, VariableDeclaration, @@ -49,7 +50,7 @@ import { } from 'lang/wasm' import { kclManager } from 'lang/KclSingleton' import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' -import { defaultProgramMemory, executeAst } from 'useStore' +import { executeAst } from 'useStore' import { engineCommandManager } from 'lang/std/engineConnection' import { createArcGeometry, @@ -869,10 +870,7 @@ function prepareTruncatedMemoryAndAst( ..._ast, body: [JSON.parse(JSON.stringify(_ast.body[bodyIndex]))], } - const programMemoryOverride: ProgramMemory = { - root: defaultProgramMemory(), - return: null, - } + const programMemoryOverride: ProgramMemory = programMemoryInit() for (let i = 0; i < bodyIndex; i++) { const node = _ast.body[i] if (node.type !== 'VariableDeclaration') { diff --git a/src/components/Toolbar/SetAbsDistance.tsx b/src/components/Toolbar/SetAbsDistance.tsx index 2a0d44dce..f1997aa0b 100644 --- a/src/components/Toolbar/SetAbsDistance.tsx +++ b/src/components/Toolbar/SetAbsDistance.tsx @@ -139,7 +139,7 @@ export function applyConstraintAxisAlign({ constraint, }).transforms - let finalValue = createIdentifier('_0') + let finalValue = createIdentifier('ZERO') return transformAstSketchLines({ ast: JSON.parse(JSON.stringify(kclManager.ast)), diff --git a/src/components/Toolbar/setAngleLength.tsx b/src/components/Toolbar/setAngleLength.tsx index 88499c39a..0f70073a9 100644 --- a/src/components/Toolbar/setAngleLength.tsx +++ b/src/components/Toolbar/setAngleLength.tsx @@ -89,12 +89,16 @@ export async function applyConstraintAngleLength({ isReferencingXAxis && angleOrLength === 'setAngle' let forceVal = valueUsedInTransform || 0 - let calcIdentifier = createIdentifier('_0') + let calcIdentifier = createIdentifier('ZERO') if (isReferencingYAxisAngle) { - calcIdentifier = createIdentifier(forceVal < 0 ? '_270' : '_90') + calcIdentifier = createIdentifier( + forceVal < 0 ? 'THREE_QUARTER_TURN' : 'QUARTER_TURN' + ) forceVal = normaliseAngle(forceVal + (forceVal < 0 ? 90 : -90)) } else if (isReferencingXAxisAngle) { - calcIdentifier = createIdentifier(Math.abs(forceVal) > 90 ? '_180' : '_0') + calcIdentifier = createIdentifier( + Math.abs(forceVal) > 90 ? 'HALF_TURN' : 'ZERO' + ) forceVal = Math.abs(forceVal) > 90 ? normaliseAngle(forceVal - 180) : forceVal } @@ -112,7 +116,7 @@ export async function applyConstraintAngleLength({ ) if ( isReferencingYAxisAngle || - (isReferencingXAxisAngle && calcIdentifier.name !== '_0') + (isReferencingXAxisAngle && calcIdentifier.name !== 'ZERO') ) { finalValue = createBinaryExpressionWithUnary([calcIdentifier, finalValue]) } diff --git a/src/lang/std/sketchcombos.ts b/src/lang/std/sketchcombos.ts index 5f212424d..efa2727fb 100644 --- a/src/lang/std/sketchcombos.ts +++ b/src/lang/std/sketchcombos.ts @@ -405,8 +405,14 @@ const setAngledIntersectLineForLines: TransformInfo['createNode'] = 2 ) const angle = args[0].type === 'Literal' ? Number(args[0].value) : 0 + const varNamMap: { [key: number]: string } = { + 0: 'ZERO', + 90: 'QUARTER_TURN', + 180: 'HALF_TURN', + 270: 'THREE_QUARTER_TURN', + } const angleVal = [0, 90, 180, 270].includes(angle) - ? createIdentifier(`_${angle}`) + ? createIdentifier(varNamMap[angle]) : createLiteral(angle) return intersectCallWrapper({ fnName: 'angledLineThatIntersects', @@ -455,7 +461,7 @@ const setAngleBetweenCreateNode = firstHalfValue = createBinaryExpression([ firstHalfValue, '+', - createIdentifier('_180'), + createIdentifier('HALF_TURN'), ]) valueUsedInTransform = normaliseAngle(valueUsedInTransform - 180) } diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index 353599689..5493450a9 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -6,6 +6,7 @@ import init, { modify_ast_for_sketch_wasm, is_points_ccw, get_tangential_arc_to_info, + program_memory_init, } from '../wasm-lib/pkg/wasm_lib' import { KCLError } from './errors' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' @@ -252,3 +253,21 @@ export function getTangentialArcToInfo({ ccw: result.ccw > 0, } } + +export function programMemoryInit(): ProgramMemory { + try { + const memory: ProgramMemory = program_memory_init() + return memory + } catch (e: any) { + console.log(e) + const parsed: RustKclError = JSON.parse(e.toString()) + const kclError = new KCLError( + parsed.kind, + parsed.msg, + rangeTypeFix(parsed.sourceRanges) + ) + + console.log(kclError) + throw kclError + } +} diff --git a/src/useStore.ts b/src/useStore.ts index eec90a99f..0508b80be 100644 --- a/src/useStore.ts +++ b/src/useStore.ts @@ -1,7 +1,13 @@ import { create } from 'zustand' import { persist } from 'zustand/middleware' import { addLineHighlight, EditorView } from './editor/highlightextension' -import { parse, Program, _executor, ProgramMemory } from './lang/wasm' +import { + parse, + Program, + _executor, + ProgramMemory, + programMemoryInit, +} from './lang/wasm' import { Selection } from 'lib/selections' import { enginelessExecutor } from './lib/testHelpers' import { EngineCommandManager } from './lang/std/engineConnection' @@ -156,34 +162,6 @@ export const useStore = create()( ) ) -export const defaultProgramMemory: () => ProgramMemory['root'] = () => ({ - _0: { - type: 'UserVal', - value: 0, - __meta: [], - }, - _90: { - type: 'UserVal', - value: 90, - __meta: [], - }, - _180: { - type: 'UserVal', - value: 180, - __meta: [], - }, - _270: { - type: 'UserVal', - value: 270, - __meta: [], - }, - PI: { - type: 'UserVal', - value: Math.PI, - __meta: [], - }, -}) - export async function executeCode({ engineCommandManager, code, @@ -273,21 +251,8 @@ export async function executeAst({ engineCommandManager.startNewSession() } const programMemory = await (useFakeExecutor - ? enginelessExecutor( - ast, - programMemoryOverride || { - root: defaultProgramMemory(), - return: null, - } - ) - : _executor( - ast, - { - root: defaultProgramMemory(), - return: null, - }, - engineCommandManager - )) + ? enginelessExecutor(ast, programMemoryOverride || programMemoryInit()) + : _executor(ast, programMemoryInit(), engineCommandManager)) await engineCommandManager.waitForAllCommands() return { diff --git a/src/wasm-lib/kcl/src/executor.rs b/src/wasm-lib/kcl/src/executor.rs index 6286103e2..9d9a1a92e 100644 --- a/src/wasm-lib/kcl/src/executor.rs +++ b/src/wasm-lib/kcl/src/executor.rs @@ -30,7 +30,36 @@ pub struct ProgramMemory { impl ProgramMemory { pub fn new() -> Self { Self { - root: HashMap::new(), + root: HashMap::from([ + ( + "ZERO".to_string(), + MemoryItem::UserVal(UserVal { + value: serde_json::Value::Number(serde_json::value::Number::from(0)), + meta: Default::default(), + }), + ), + ( + "QUARTER_TURN".to_string(), + MemoryItem::UserVal(UserVal { + value: serde_json::Value::Number(serde_json::value::Number::from(90)), + meta: Default::default(), + }), + ), + ( + "HALF_TURN".to_string(), + MemoryItem::UserVal(UserVal { + value: serde_json::Value::Number(serde_json::value::Number::from(180)), + meta: Default::default(), + }), + ), + ( + "THREE_QUARTER_TURN".to_string(), + MemoryItem::UserVal(UserVal { + value: serde_json::Value::Number(serde_json::value::Number::from(270)), + meta: Default::default(), + }), + ), + ]), return_: None, } } @@ -1664,6 +1693,13 @@ show(bracket) optional: false, } } + fn additional_program_memory(items: &[(String, MemoryItem)]) -> ProgramMemory { + let mut program_memory = ProgramMemory::new(); + for (name, item) in items { + program_memory.root.insert(name.to_string(), item.clone()); + } + program_memory + } // Declare the test cases. for (test_name, params, args, expected) in [ ("empty", Vec::new(), Vec::new(), Ok(ProgramMemory::new())), @@ -1671,10 +1707,7 @@ show(bracket) "all params required, and all given, should be OK", vec![req_param("x")], vec![mem(1)], - Ok(ProgramMemory { - return_: None, - root: HashMap::from([("x".to_owned(), mem(1))]), - }), + Ok(additional_program_memory(&[("x".to_owned(), mem(1))])), ), ( "all params required, none given, should error", @@ -1689,10 +1722,10 @@ show(bracket) "all params optional, none given, should be OK", vec![opt_param("x")], vec![], - Ok(ProgramMemory { - return_: None, - root: HashMap::from([("x".to_owned(), MemoryItem::from(&KclNone::default()))]), - }), + Ok(additional_program_memory(&[( + "x".to_owned(), + MemoryItem::from(&KclNone::default()), + )])), ), ( "mixed params, too few given", @@ -1707,22 +1740,19 @@ show(bracket) "mixed params, minimum given, should be OK", vec![req_param("x"), opt_param("y")], vec![mem(1)], - Ok(ProgramMemory { - return_: None, - root: HashMap::from([ - ("x".to_owned(), mem(1)), - ("y".to_owned(), MemoryItem::from(&KclNone::default())), - ]), - }), + Ok(additional_program_memory(&[ + ("x".to_owned(), mem(1)), + ("y".to_owned(), MemoryItem::from(&KclNone::default())), + ])), ), ( "mixed params, maximum given, should be OK", vec![req_param("x"), opt_param("y")], vec![mem(1), mem(2)], - Ok(ProgramMemory { - return_: None, - root: HashMap::from([("x".to_owned(), mem(1)), ("y".to_owned(), mem(2))]), - }), + Ok(additional_program_memory(&[ + ("x".to_owned(), mem(1)), + ("y".to_owned(), mem(2)), + ])), ), ( "mixed params, too many given", diff --git a/src/wasm-lib/src/lib.rs b/src/wasm-lib/src/lib.rs index bccafb84e..b5e4bd48b 100644 --- a/src/wasm-lib/src/lib.rs +++ b/src/wasm-lib/src/lib.rs @@ -251,3 +251,14 @@ pub fn get_tangential_arc_to_info( ccw: result.ccw, } } + +/// Create the default program memory. +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +pub fn program_memory_init() -> Result { + let memory = kcl_lib::executor::ProgramMemory::default(); + + // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the + // gloo-serialize crate instead. + JsValue::from_serde(&memory).map_err(|e| e.to_string()) +}