diff --git a/src/components/AvailableVarsHelpers.tsx b/src/components/AvailableVarsHelpers.tsx index a2559928c..8cee1b445 100644 --- a/src/components/AvailableVarsHelpers.tsx +++ b/src/components/AvailableVarsHelpers.tsx @@ -137,33 +137,34 @@ export function useCalc({ setAvailableVarInfo(varInfo) }, [kclManager.ast, kclManager.programMemory, selectionRange]) - useEffect(() => { + useEffect(async () => { try { const code = `const __result__ = ${value}` - const ast = parse(code) - const _programMem: any = { root: {}, return: null } - availableVarInfo.variables.forEach(({ key, value }) => { - _programMem.root[key] = { type: 'userVal', value, __meta: [] } - }) - executeAst({ - ast, - engineCommandManager, - useFakeExecutor: true, - programMemoryOverride: JSON.parse( - JSON.stringify(kclManager.programMemory) - ), - }).then(({ programMemory }) => { - const resultDeclaration = ast.body.find( - (a) => - a.type === 'VariableDeclaration' && - a.declarations?.[0]?.id?.name === '__result__' - ) - const init = - resultDeclaration?.type === 'VariableDeclaration' && - resultDeclaration?.declarations?.[0]?.init - const result = programMemory?.root?.__result__?.value - setCalcResult(typeof result === 'number' ? String(result) : 'NAN') - init && setValueNode(init) + parse(code).then((ast) => { + const _programMem: any = { root: {}, return: null } + availableVarInfo.variables.forEach(({ key, value }) => { + _programMem.root[key] = { type: 'userVal', value, __meta: [] } + }) + executeAst({ + ast, + engineCommandManager, + useFakeExecutor: true, + programMemoryOverride: JSON.parse( + JSON.stringify(kclManager.programMemory) + ), + }).then(({ programMemory }) => { + const resultDeclaration = ast.body.find( + (a) => + a.type === 'VariableDeclaration' && + a.declarations?.[0]?.id?.name === '__result__' + ) + const init = + resultDeclaration?.type === 'VariableDeclaration' && + resultDeclaration?.declarations?.[0]?.init + const result = programMemory?.root?.__result__?.value + setCalcResult(typeof result === 'number' ? String(result) : 'NAN') + init && setValueNode(init) + }) }) } catch (e) { setCalcResult('NAN') diff --git a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx index 82babdf2b..440c27463 100644 --- a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx +++ b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx @@ -26,7 +26,7 @@ describe('processMemory', () => { |> lineTo([0.98, 5.16], %) |> lineTo([2.15, 4.32], %) // |> rx(90, %)` - const ast = parse(code) + const ast = await parse(code) const programMemory = await enginelessExecutor(ast, { root: {}, return: null, diff --git a/src/lang/KclSingleton.ts b/src/lang/KclSingleton.ts index abcabb522..9d8e6cb85 100644 --- a/src/lang/KclSingleton.ts +++ b/src/lang/KclSingleton.ts @@ -43,14 +43,16 @@ export class KclManager { const ast = this.safeParse(code) if (!ast) return try { + parse(recast(ast)).then((newAst) => { const fmtAndStringify = (ast: Program) => - JSON.stringify(parse(recast(ast))) + JSON.stringify(newAst) const isAstTheSame = fmtAndStringify(ast) === fmtAndStringify(this._ast) if (isAstTheSame) return + this.executeAst(ast) + }) } catch (e) { console.error(e) } - this.executeAst(ast) }, 600) private _isExecutingCallback: (arg: boolean) => void = () => {} @@ -143,9 +145,9 @@ export class KclManager { this._executeCallback = callback } - safeParse(code: string): Program | null { + async safeParse(code: string): Promise { try { - const ast = parse(code) + const ast = await parse(code) this.kclErrors = [] return ast } catch (e) { diff --git a/src/lang/abstractSyntaxTree.test.ts b/src/lang/abstractSyntaxTree.test.ts index 996bc4e98..878ea7edc 100644 --- a/src/lang/abstractSyntaxTree.test.ts +++ b/src/lang/abstractSyntaxTree.test.ts @@ -4,8 +4,8 @@ import { initPromise, parse } from './wasm' beforeAll(() => initPromise) describe('testing AST', () => { - test('5 + 6', () => { - const result = parse('5 +6') + test('5 + 6', async () => { + const result = await parse('5 +6') delete (result as any).nonCodeMeta expect(result.body).toEqual([ { @@ -35,8 +35,8 @@ describe('testing AST', () => { }, ]) }) - test('const myVar = 5', () => { - const { body } = parse('const myVar = 5') + test('const myVar = 5', async () => { + const { body } = await parse('const myVar = 5') expect(body).toEqual([ { type: 'VariableDeclaration', @@ -66,11 +66,11 @@ describe('testing AST', () => { }, ]) }) - test('multi-line', () => { + test('multi-line', async () => { const code = `const myVar = 5 const newVar = myVar + 1 ` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -141,8 +141,8 @@ const newVar = myVar + 1 }) describe('testing function declaration', () => { - test('fn funcN = (a, b) => {return a + b}', () => { - const { body } = parse( + test('fn funcN = (a, b) => {return a + b}', async () => { + const { body } = await parse( ['fn funcN = (a, b) => {', ' return a + b', '}'].join('\n') ) delete (body[0] as any).declarations[0].init.body.nonCodeMeta @@ -224,10 +224,10 @@ describe('testing function declaration', () => { }, ]) }) - test('call expression assignment', () => { + test('call expression assignment', async () => { const code = `fn funcN = (a, b) => { return a + b } const myVar = funcN(1, 2)` - const { body } = parse(code) + const { body } = await parse(code) delete (body[0] as any).declarations[0].init.body.nonCodeMeta expect(body).toEqual([ { @@ -357,14 +357,14 @@ const myVar = funcN(1, 2)` }) describe('testing pipe operator special', () => { - test('pipe operator with sketch', () => { + test('pipe operator with sketch', async () => { let code = `const mySketch = startSketchAt([0, 0]) |> lineTo([2, 3], %) |> lineTo([0, 1], %, "myPath") |> lineTo([1, 1], %) |> rx(45, %) ` - const { body } = parse(code) + const { body } = await parse(code) delete (body[0] as any).declarations[0].init.nonCodeMeta expect(body).toEqual([ { @@ -562,9 +562,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('pipe operator with binary expression', () => { + test('pipe operator with binary expression', async () => { let code = `const myVar = 5 + 6 |> myFunc(45, %)` - const { body } = parse(code) + const { body } = await parse(code) delete (body as any)[0].declarations[0].init.nonCodeMeta expect(body).toEqual([ { @@ -641,9 +641,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('array expression', () => { + test('array expression', async () => { let code = `const yo = [1, '2', three, 4 + 5]` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -713,12 +713,12 @@ describe('testing pipe operator special', () => { }, ]) }) - test('object expression ast', () => { + test('object expression ast', async () => { const code = [ 'const three = 3', "const yo = {aStr: 'str', anum: 2, identifier: three, binExp: 4 + 5}", ].join('\n') - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -858,11 +858,11 @@ describe('testing pipe operator special', () => { }, ]) }) - test('nested object expression ast', () => { + test('nested object expression ast', async () => { const code = `const yo = {key: { key2: 'value' }}` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -928,9 +928,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('object expression with array ast', () => { + test('object expression with array ast', async () => { const code = `const yo = {key: [1, '2']}` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -992,9 +992,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('object memberExpression simple', () => { + test('object memberExpression simple', async () => { const code = `const prop = yo.one.two` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -1047,9 +1047,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('object memberExpression with square braces', () => { + test('object memberExpression with square braces', async () => { const code = `const prop = yo.one["two"]` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -1103,9 +1103,9 @@ describe('testing pipe operator special', () => { }, ]) }) - test('object memberExpression with two square braces literal and identifier', () => { + test('object memberExpression with two square braces literal and identifier', async () => { const code = `const prop = yo["one"][two]` - const { body } = parse(code) + const { body } = await parse(code) expect(body).toEqual([ { type: 'VariableDeclaration', @@ -1162,9 +1162,9 @@ describe('testing pipe operator special', () => { }) describe('nests binary expressions correctly', () => { - it('works with the simple case', () => { + it('works with the simple case', async () => { const code = `const yo = 1 + 2` - const { body } = parse(code) + const { body } = await parse(code) expect(body[0]).toEqual({ type: 'VariableDeclaration', start: 0, @@ -1205,10 +1205,10 @@ describe('nests binary expressions correctly', () => { ], }) }) - it('should nest according to precedence with multiply first', () => { + it('should nest according to precedence with multiply first', async () => { // should be binExp { binExp { lit-1 * lit-2 } + lit} const code = `const yo = 1 * 2 + 3` - const { body } = parse(code) + const { body } = await parse(code) expect(body[0]).toEqual({ type: 'VariableDeclaration', start: 0, @@ -1262,10 +1262,10 @@ describe('nests binary expressions correctly', () => { ], }) }) - it('should nest according to precedence with sum first', () => { + it('should nest according to precedence with sum first', async () => { // should be binExp { lit-1 + binExp { lit-2 * lit-3 } } const code = `const yo = 1 + 2 * 3` - const { body } = parse(code) + const { body } = await parse(code) expect(body[0]).toEqual({ type: 'VariableDeclaration', start: 0, @@ -1319,9 +1319,9 @@ describe('nests binary expressions correctly', () => { ], }) }) - it('should nest properly with two operators of equal precedence', () => { + it('should nest properly with two operators of equal precedence', async () => { const code = `const yo = 1 + 2 - 3` - const { body } = parse(code) + const { body } = await parse(code) expect((body[0] as any).declarations[0].init).toEqual({ type: 'BinaryExpression', start: 11, @@ -1356,9 +1356,9 @@ describe('nests binary expressions correctly', () => { }, }) }) - it('should nest properly with two operators of equal (but higher) precedence', () => { + it('should nest properly with two operators of equal (but higher) precedence', async () => { const code = `const yo = 1 * 2 / 3` - const { body } = parse(code) + const { body } = await parse(code) expect((body[0] as any).declarations[0].init).toEqual({ type: 'BinaryExpression', start: 11, @@ -1393,9 +1393,9 @@ describe('nests binary expressions correctly', () => { }, }) }) - it('should nest properly with longer example', () => { + it('should nest properly with longer example', async () => { const code = `const yo = 1 + 2 * (3 - 4) / 5 + 6` - const { body } = parse(code) + const { body } = await parse(code) const init = (body[0] as any).declarations[0].init expect(init).toEqual({ type: 'BinaryExpression', @@ -1443,7 +1443,7 @@ describe('nests binary expressions correctly', () => { }) describe('check nonCodeMeta data is attached to the AST correctly', () => { - it('comments between expressions', () => { + it('comments between expressions', async () => { const code = ` const yo = { a: { b: { c: '123' } } } // this is a comment @@ -1458,12 +1458,14 @@ const key = 'c'` value: 'this is a comment', }, } - const { nonCodeMeta } = parse(code) + const { nonCodeMeta } = await parse(code) expect(nonCodeMeta.nonCodeNodes[0][0]).toEqual(nonCodeMetaInstance) // extra whitespace won't change it's position (0) or value (NB the start end would have changed though) const codeWithExtraStartWhitespace = '\n\n\n' + code - const { nonCodeMeta: nonCodeMeta2 } = parse(codeWithExtraStartWhitespace) + const { nonCodeMeta: nonCodeMeta2 } = await parse( + codeWithExtraStartWhitespace + ) expect(nonCodeMeta2.nonCodeNodes[0][0].value).toStrictEqual( nonCodeMetaInstance.value ) @@ -1471,7 +1473,7 @@ const key = 'c'` nonCodeMetaInstance.start ) }) - it('comments nested within a block statement', () => { + it('comments nested within a block statement', async () => { const code = `const mySketch = startSketchAt([0,0]) |> lineTo([0, 1], %, 'myPath') |> lineTo([1, 1], %) /* this is @@ -1481,7 +1483,7 @@ const key = 'c'` |> close(%) ` - const { body } = parse(code) + const { body } = await parse(code) const indexOfSecondLineToExpression = 2 const sketchNonCodeMeta = (body as any)[0].declarations[0].init.nonCodeMeta .nonCodeNodes @@ -1496,7 +1498,7 @@ const key = 'c'` }, }) }) - it('comments in a pipe expression', () => { + it('comments in a pipe expression', async () => { const code = [ 'const mySk1 = startSketchAt([0, 0])', ' |> lineTo([1, 1], %)', @@ -1506,7 +1508,7 @@ const key = 'c'` ' |> rx(90, %)', ].join('\n') - const { body } = parse(code) + const { body } = await parse(code) const sketchNonCodeMeta = (body[0] as any).declarations[0].init.nonCodeMeta .nonCodeNodes[3][0] expect(sketchNonCodeMeta).toEqual({ @@ -1523,9 +1525,9 @@ const key = 'c'` }) describe('test UnaryExpression', () => { - it('should parse a unary expression in simple var dec situation', () => { + it('should parse a unary expression in simple var dec situation', async () => { const code = `const myVar = -min(4, 100)` - const { body } = parse(code) + const { body } = await parse(code) const myVarInit = (body?.[0] as any).declarations[0]?.init expect(myVarInit).toEqual({ type: 'UnaryExpression', @@ -1548,9 +1550,9 @@ describe('test UnaryExpression', () => { }) describe('testing nested call expressions', () => { - it('callExp in a binExp in a callExp', () => { + it('callExp in a binExp in a callExp', async () => { const code = 'const myVar = min(100, 1 + legLen(5, 3))' - const { body } = parse(code) + const { body } = await parse(code) const myVarInit = (body?.[0] as any).declarations[0]?.init expect(myVarInit).toEqual({ type: 'CallExpression', @@ -1585,8 +1587,8 @@ describe('testing nested call expressions', () => { describe('should recognise callExpresions in binaryExpressions', () => { const code = "xLineTo(segEndX('seg02', %) + 1, %)" - it('should recognise the callExp', () => { - const { body } = parse(code) + it('should recognise the callExp', async () => { + const { body } = await parse(code) const callExpArgs = (body?.[0] as any).expression?.arguments expect(callExpArgs).toEqual([ { diff --git a/src/lang/artifact.test.ts b/src/lang/artifact.test.ts index f4fbe2937..ec1b1217c 100644 --- a/src/lang/artifact.test.ts +++ b/src/lang/artifact.test.ts @@ -12,7 +12,7 @@ const mySketch001 = startSketchOn('XY') |> lineTo([-1.59, -1.54], %) |> lineTo([0.46, -5.82], %) // |> rx(45, %)` - const programMemory = await enginelessExecutor(parse(code)) + const programMemory = await enginelessExecutor(await parse(code)) // @ts-ignore const sketch001 = programMemory?.root?.mySketch001 expect(sketch001).toEqual({ @@ -68,7 +68,7 @@ const mySketch001 = startSketchOn('XY') |> lineTo([0.46, -5.82], %) // |> rx(45, %) |> extrude(2, %)` - const programMemory = await enginelessExecutor(parse(code)) + const programMemory = await enginelessExecutor(await parse(code)) // @ts-ignore const sketch001 = programMemory?.root?.mySketch001 expect(sketch001).toEqual({ @@ -150,7 +150,7 @@ const sk2 = startSketchOn('XY') |> extrude(2, %) ` - const programMemory = await enginelessExecutor(parse(code)) + const programMemory = await enginelessExecutor(await parse(code)) // @ts-ignore const geos = [programMemory?.root?.theExtrude, programMemory?.root?.sk2] expect(geos).toEqual([ diff --git a/src/lang/executor.test.ts b/src/lang/executor.test.ts index 3da86f5d2..7e5bf039f 100644 --- a/src/lang/executor.test.ts +++ b/src/lang/executor.test.ts @@ -398,7 +398,7 @@ async function exe( code: string, programMemory: ProgramMemory = { root: {}, return: null } ) { - const ast = parse(code) + const ast = await parse(code) const result = await enginelessExecutor(ast, programMemory) return result diff --git a/src/lang/getNodePathFromSourceRange.test.ts b/src/lang/getNodePathFromSourceRange.test.ts index 4c0ac56cf..380d6481b 100644 --- a/src/lang/getNodePathFromSourceRange.test.ts +++ b/src/lang/getNodePathFromSourceRange.test.ts @@ -4,7 +4,7 @@ import { Identifier, parse, initPromise, Parameter } from './wasm' beforeAll(() => initPromise) describe('testing getNodePathFromSourceRange', () => { - it('test it gets the right path for a `lineTo` CallExpression within a SketchExpression', () => { + it('test it gets the right path for a `lineTo` CallExpression within a SketchExpression', async () => { const code = ` const myVar = 5 const sk3 = startSketchAt([0, 0]) @@ -19,14 +19,14 @@ const sk3 = startSketchAt([0, 0]) lineToSubstringIndex + subStr.length, ] - const ast = parse(code) + const ast = await parse(code) const nodePath = getNodePathFromSourceRange(ast, sourceRange) const { node } = getNodeFromPath(ast, nodePath) expect([node.start, node.end]).toEqual(sourceRange) expect(node.type).toBe('CallExpression') }) - it('gets path right for function definition params', () => { + it('gets path right for function definition params', async () => { const code = `fn cube = (pos, scale) => { const sg = startSketchAt(pos) |> line([0, scale], %) @@ -44,7 +44,7 @@ const b1 = cube([0,0], 10)` subStrIndex + 'pos'.length, ] - const ast = parse(code) + const ast = await parse(code) const nodePath = getNodePathFromSourceRange(ast, sourceRange) const node = getNodeFromPath(ast, nodePath).node @@ -60,7 +60,7 @@ const b1 = cube([0,0], 10)` expect(node.type).toBe('Parameter') expect(node.identifier.name).toBe('pos') }) - it('gets path right for deep within function definition body', () => { + it('gets path right for deep within function definition body', async () => { const code = `fn cube = (pos, scale) => { const sg = startSketchAt(pos) |> line([0, scale], %) @@ -78,7 +78,7 @@ const b1 = cube([0,0], 10)` subStrIndex + 'scale'.length, ] - const ast = parse(code) + const ast = await parse(code) const nodePath = getNodePathFromSourceRange(ast, sourceRange) const node = getNodeFromPath(ast, nodePath).node expect(nodePath).toEqual([ diff --git a/src/lang/recast.test.ts b/src/lang/recast.test.ts index 7985d41b2..09f765093 100644 --- a/src/lang/recast.test.ts +++ b/src/lang/recast.test.ts @@ -4,53 +4,53 @@ import fs from 'node:fs' beforeAll(() => initPromise) describe('recast', () => { - it('recasts a simple program', () => { + it('recasts a simple program', async () => { const code = '1 + 2' - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('variable declaration', () => { + it('variable declaration', async () => { const code = 'const myVar = 5' - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it("variable declaration that's binary with string", () => { + it("variable declaration that's binary with string", async () => { const code = "const myVar = 5 + 'yo'" - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) const codeWithOtherQuotes = 'const myVar = 5 + "yo"' - const { ast: ast2 } = code2ast(codeWithOtherQuotes) + const { ast: ast2 } = await code2ast(codeWithOtherQuotes) expect(recast(ast2).trim()).toBe(codeWithOtherQuotes) }) - it('test assigning two variables, the second summing with the first', () => { + it('test assigning two variables, the second summing with the first', async () => { const code = `const myVar = 5 const newVar = myVar + 1 ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('test assigning a var by cont concatenating two strings string', () => { + it('test assigning a var by cont concatenating two strings string', async () => { const code = fs.readFileSync( './src/lang/testExamples/variableDeclaration.cado', 'utf-8' ) - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('test with function call', () => { + it('test with function call', async () => { const code = `const myVar = "hello" log(5, myVar) ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('function declaration with call', () => { + it('function declaration with call', async () => { const code = [ 'fn funcN = (a, b) => {', ' return a + b', @@ -58,22 +58,22 @@ log(5, myVar) 'const theVar = 60', 'const magicNum = funcN(9, theVar)', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('recast sketch declaration', () => { + it('recast sketch declaration', async () => { let code = `const mySketch = startSketchAt([0, 0]) |> lineTo([0, 1], %, "myPath") |> lineTo([1, 1], %) |> lineTo([1, 0], %, "rightPath") |> close(%) ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('sketch piped into callExpression', () => { + it('sketch piped into callExpression', async () => { const code = [ 'const mySk1 = startSketchAt([0, 0])', ' |> lineTo([1, 1], %)', @@ -81,11 +81,11 @@ log(5, myVar) ' |> lineTo([1, 1], %)', ' |> rx(90, %)', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('recast BinaryExpression piped into CallExpression', () => { + it('recast BinaryExpression piped into CallExpression', async () => { const code = [ 'fn myFn = (a) => {', ' return a + 1', @@ -93,49 +93,49 @@ log(5, myVar) 'const myVar = 5 + 1', ' |> myFn(%)', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('recast nested binary expression', () => { + it('recast nested binary expression', async () => { const code = ['const myVar = 1 + 2 * 5'].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('recast nested binary expression with parans', () => { + it('recast nested binary expression with parans', async () => { const code = ['const myVar = 1 + (1 + 2) * 5'].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('unnecessary paran wrap will be remove', () => { + it('unnecessary paran wrap will be remove', async () => { const code = ['const myVar = 1 + (2 * 5)'].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.replace('(', '').replace(')', '')) }) - it('complex nested binary expression', () => { + it('complex nested binary expression', async () => { const code = ['1 * ((2 + 3) / 4 + 5)'].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('multiplied paren expressions', () => { + it('multiplied paren expressions', async () => { const code = ['3 + (1 + 2) * (3 + 4)'].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('recast array declaration', () => { + it('recast array declaration', async () => { const code = ['const three = 3', "const yo = [1, '2', three, 4 + 5]"].join( '\n' ) - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('recast long array declaration', () => { + it('recast long array declaration', async () => { const code = [ 'const three = 3', 'const yo = [', @@ -146,11 +146,11 @@ log(5, myVar) " 'hey oooooo really long long long'", ']', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code.trim()) }) - it('recast long object execution', () => { + it('recast long object execution', async () => { const code = `const three = 3 const yo = { aStr: 'str', @@ -159,43 +159,43 @@ const yo = { binExp: 4 + 5 } ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('recast short object execution', () => { + it('recast short object execution', async () => { const code = `const yo = { key: 'val' } ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('recast object execution with member expression', () => { + it('recast object execution with member expression', async () => { const code = `const yo = { a: { b: { c: '123' } } } const key = 'c' const myVar = yo.a['b'][key] const key2 = 'b' const myVar2 = yo['a'][key2].c ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) }) describe('testing recasting with comments and whitespace', () => { - it('code with comments', () => { + it('code with comments', async () => { const code = `const yo = { a: { b: { c: '123' } } } // this is a comment const key = 'c' ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('code with comment and extra lines', () => { + it('code with comment and extra lines', async () => { const code = `const yo = 'c' /* this is @@ -203,23 +203,23 @@ a comment */ const yo = 'bing' ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('comments at the start and end', () => { + it('comments at the start and end', async () => { const code = `// this is a comment const yo = { a: { b: { c: '123' } } } const key = 'c' // this is also a comment ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('comments in a fn block', () => { - const code = `fn myFn = () => { + it('comments in a fn block', async () => { + const code = `fn myFn = async () => { // this is a comment const yo = { a: { b: { c: '123' } } } @@ -229,11 +229,11 @@ const key = 'c' // this is also a comment } ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('comments in a pipe expression', () => { + it('comments in a pipe expression', async () => { const code = [ 'const mySk1 = startSketchAt([0, 0])', ' |> lineTo([1, 1], %)', @@ -242,11 +242,11 @@ const key = 'c' ' // a comment', ' |> rx(90, %)', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('comments sprinkled in all over the place', () => { + it('comments sprinkled in all over the place', async () => { const code = ` /* comment at start */ @@ -268,7 +268,7 @@ const mySk1 = startSketchAt([0, 0]) one more for good measure */ ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(`/* comment at start */ @@ -289,37 +289,37 @@ const mySk1 = startSketchAt([0, 0]) }) describe('testing call Expressions in BinaryExpressions and UnaryExpressions', () => { - it('nested callExpression in binaryExpression', () => { + it('nested callExpression in binaryExpression', async () => { const code = 'const myVar = 2 + min(100, legLen(5, 3))' - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('nested callExpression in unaryExpression', () => { + it('nested callExpression in unaryExpression', async () => { const code = 'const myVar = -min(100, legLen(5, 3))' - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('with unaryExpression in callExpression', () => { + it('with unaryExpression in callExpression', async () => { const code = 'const myVar = min(5, -legLen(5, 4))' - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) - it('with unaryExpression in sketch situation', () => { + it('with unaryExpression in sketch situation', async () => { const code = [ 'const part001 = startSketchAt([0, 0])', ' |> line([-2.21, -legLen(5, min(3, 999))], %)', ].join('\n') - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted.trim()).toBe(code) }) }) describe('it recasts wrapped object expressions in pipe bodies with correct indentation', () => { - it('with a single line', () => { + it('with a single line', async () => { const code = `const part001 = startSketchAt([-0.01, -0.08]) |> line([0.62, 4.15], %, 'seg01') |> line([2.77, -1.24], %) @@ -330,35 +330,35 @@ describe('it recasts wrapped object expressions in pipe bodies with correct inde }, %) |> line([-0.42, -1.72], %) ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) - it('recasts wrapped object expressions NOT in pipe body correctly', () => { + it('recasts wrapped object expressions NOT in pipe body correctly', async () => { const code = `angledLineThatIntersects({ angle: 201, offset: -1.35, intersectTag: 'seg01' }, %) ` - const { ast } = code2ast(code) + const { ast } = await code2ast(code) const recasted = recast(ast) expect(recasted).toBe(code) }) }) describe('it recasts binary expression using brackets where needed', () => { - it('when there are two minus in a row', () => { + it('when there are two minus in a row', async () => { const code = `const part001 = 1 - (def - abc) ` - const recasted = recast(code2ast(code).ast) + const recasted = recast((await code2ast(code)).ast) expect(recasted).toBe(code) }) }) // helpers -function code2ast(code: string): { ast: Program } { - const ast = parse(code) +async function code2ast(code: string): Promise<{ ast: Program }> { + const ast = await parse(code) return { ast } } diff --git a/src/lang/std/sketch.test.ts b/src/lang/std/sketch.test.ts index dbee9375d..1c944de5a 100644 --- a/src/lang/std/sketch.test.ts +++ b/src/lang/std/sketch.test.ts @@ -104,7 +104,7 @@ describe('testing changeSketchArguments', () => { ` const code = genCode(lineToChange) const expectedCode = genCode(lineAfterChange) - const ast = parse(code) + const ast = await parse(code) const programMemory = await enginelessExecutor(ast) const sourceStart = code.indexOf(lineToChange) const { modifiedAst } = changeSketchArguments( @@ -128,7 +128,7 @@ const mySketch001 = startSketchOn('XY') // |> rx(45, %) |> lineTo([-1.59, -1.54], %) |> lineTo([0.46, -5.82], %)` - const ast = parse(code) + const ast = await parse(code) const programMemory = await enginelessExecutor(ast) const sourceStart = code.indexOf(lineToChange) expect(sourceStart).toBe(95) @@ -190,7 +190,7 @@ describe('testing addTagForSketchOnFace', () => { |> lineTo([0.46, -5.82], %) ` const code = genCode(originalLine) - const ast = parse(code) + const ast = await parse(code) const programMemory = await enginelessExecutor(ast) const sourceStart = code.indexOf(originalLine) const sourceRange: [number, number] = [ diff --git a/src/lang/std/sketchConstraints.test.ts b/src/lang/std/sketchConstraints.test.ts index b5eb8a09b..2038fe5b7 100644 --- a/src/lang/std/sketchConstraints.test.ts +++ b/src/lang/std/sketchConstraints.test.ts @@ -28,7 +28,7 @@ async function testingSwapSketchFnCall({ type: 'default', range: [startIndex, startIndex + callToSwap.length], } - const ast = parse(inputCode) + const ast = await parse(inputCode) const programMemory = await enginelessExecutor(ast) const selections = { codeBasedSelections: [range], @@ -351,7 +351,7 @@ const part001 = startSketchOn('XY') |> line([2.14, 1.35], %) // normal-segment |> xLine(3.54, %)` it('normal case works', async () => { - const programMemory = await enginelessExecutor(parse(code)) + const programMemory = await enginelessExecutor(await parse(code)) const index = code.indexOf('// normal-segment') - 7 const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange( programMemory.root['part001'] as SketchGroup, @@ -365,7 +365,7 @@ const part001 = startSketchOn('XY') }) }) it('verify it works when the segment is in the `start` property', async () => { - const programMemory = await enginelessExecutor(parse(code)) + const programMemory = await enginelessExecutor(await parse(code)) const index = code.indexOf('// segment-in-start') - 7 const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange( programMemory.root['part001'] as SketchGroup, diff --git a/src/lang/std/sketchcombos.test.ts b/src/lang/std/sketchcombos.test.ts index 71d9acee8..400c2d422 100644 --- a/src/lang/std/sketchcombos.test.ts +++ b/src/lang/std/sketchcombos.test.ts @@ -15,53 +15,53 @@ beforeAll(() => initPromise) describe('testing getConstraintType', () => { const helper = getConstraintTypeFromSourceHelper - it('testing line', () => { - expect(helper(`line([5, myVar], %)`)).toBe('yRelative') - expect(helper(`line([myVar, 5], %)`)).toBe('xRelative') + it('testing line', async () => { + expect(await helper(`line([5, myVar], %)`)).toBe('yRelative') + expect(await helper(`line([myVar, 5], %)`)).toBe('xRelative') }) - it('testing lineTo', () => { - expect(helper(`lineTo([5, myVar], %)`)).toBe('yAbsolute') - expect(helper(`lineTo([myVar, 5], %)`)).toBe('xAbsolute') + it('testing lineTo', async () => { + expect(await helper(`lineTo([5, myVar], %)`)).toBe('yAbsolute') + expect(await helper(`lineTo([myVar, 5], %)`)).toBe('xAbsolute') }) - it('testing angledLine', () => { - expect(helper(`angledLine([5, myVar], %)`)).toBe('length') - expect(helper(`angledLine([myVar, 5], %)`)).toBe('angle') + it('testing angledLine', async () => { + expect(await helper(`angledLine([5, myVar], %)`)).toBe('length') + expect(await helper(`angledLine([myVar, 5], %)`)).toBe('angle') }) - it('testing angledLineOfXLength', () => { - expect(helper(`angledLineOfXLength([5, myVar], %)`)).toBe('xRelative') - expect(helper(`angledLineOfXLength([myVar, 5], %)`)).toBe('angle') + it('testing angledLineOfXLength', async () => { + expect(await helper(`angledLineOfXLength([5, myVar], %)`)).toBe('xRelative') + expect(await helper(`angledLineOfXLength([myVar, 5], %)`)).toBe('angle') }) - it('testing angledLineToX', () => { - expect(helper(`angledLineToX([5, myVar], %)`)).toBe('xAbsolute') - expect(helper(`angledLineToX([myVar, 5], %)`)).toBe('angle') + it('testing angledLineToX', async () => { + expect(await helper(`angledLineToX([5, myVar], %)`)).toBe('xAbsolute') + expect(await helper(`angledLineToX([myVar, 5], %)`)).toBe('angle') }) - it('testing angledLineOfYLength', () => { - expect(helper(`angledLineOfYLength([5, myVar], %)`)).toBe('yRelative') - expect(helper(`angledLineOfYLength([myVar, 5], %)`)).toBe('angle') + it('testing angledLineOfYLength', async () => { + expect(await helper(`angledLineOfYLength([5, myVar], %)`)).toBe('yRelative') + expect(await helper(`angledLineOfYLength([myVar, 5], %)`)).toBe('angle') }) - it('testing angledLineToY', () => { - expect(helper(`angledLineToY([5, myVar], %)`)).toBe('yAbsolute') - expect(helper(`angledLineToY([myVar, 5], %)`)).toBe('angle') + it('testing angledLineToY', async () => { + expect(await helper(`angledLineToY([5, myVar], %)`)).toBe('yAbsolute') + expect(await helper(`angledLineToY([myVar, 5], %)`)).toBe('angle') }) const helper2 = getConstraintTypeFromSourceHelper2 - it('testing xLine', () => { - expect(helper2(`xLine(5, %)`)).toBe('yRelative') + it('testing xLine', async () => { + expect(await helper2(`xLine(5, %)`)).toBe('yRelative') }) - it('testing yLine', () => { - expect(helper2(`yLine(5, %)`)).toBe('xRelative') + it('testing yLine', async () => { + expect(await helper2(`yLine(5, %)`)).toBe('xRelative') }) - it('testing xLineTo', () => { - expect(helper2(`xLineTo(5, %)`)).toBe('yAbsolute') + it('testing xLineTo', async () => { + expect(await helper2(`xLineTo(5, %)`)).toBe('yAbsolute') }) - it('testing yLineTo', () => { - expect(helper2(`yLineTo(5, %)`)).toBe('xAbsolute') + it('testing yLineTo', async () => { + expect(await helper2(`yLineTo(5, %)`)).toBe('xAbsolute') }) }) -function getConstraintTypeFromSourceHelper( +async function getConstraintTypeFromSourceHelper( code: string -): ReturnType { - const ast = parse(code) +): Promise> { + const ast = await parse(code) const args = (ast.body[0] as any).expression.arguments[0].elements as [ Value, Value @@ -69,10 +69,10 @@ function getConstraintTypeFromSourceHelper( const fnName = (ast.body[0] as any).expression.callee.name as ToolTip return getConstraintType(args, fnName) } -function getConstraintTypeFromSourceHelper2( +async function getConstraintTypeFromSourceHelper2( code: string -): ReturnType { - const ast = parse(code) +): Promise> { + const ast = await parse(code) const arg = (ast.body[0] as any).expression.arguments[0] as Value const fnName = (ast.body[0] as any).expression.callee.name as ToolTip return getConstraintType(arg, fnName) @@ -197,7 +197,7 @@ const part001 = startSketchOn('XY') |> yLine(segLen('seg01', %), %) // ln-yLineTo-free should convert to yLine ` it('should transform the ast', async () => { - const ast = parse(inputScript) + const ast = await parse(inputScript) const selectionRanges: Selections['codeBasedSelections'] = inputScript .split('\n') .filter((ln) => ln.includes('//')) @@ -284,7 +284,7 @@ const part001 = startSketchOn('XY') |> xLineTo(myVar3, %) // select for horizontal constraint 10 |> angledLineToY([301, myVar], %) // select for vertical constraint 10 ` - const ast = parse(inputScript) + const ast = await parse(inputScript) const selectionRanges: Selections['codeBasedSelections'] = inputScript .split('\n') .filter((ln) => ln.includes('// select for horizontal constraint')) @@ -342,7 +342,7 @@ const part001 = startSketchOn('XY') |> angledLineToX([333, myVar3], %) // select for horizontal constraint 10 |> yLineTo(myVar, %) // select for vertical constraint 10 ` - const ast = parse(inputScript) + const ast = await parse(inputScript) const selectionRanges: Selections['codeBasedSelections'] = inputScript .split('\n') .filter((ln) => ln.includes('// select for vertical constraint')) @@ -433,7 +433,7 @@ async function helperThing( linesOfInterest: string[], constraint: ConstraintType ): Promise { - const ast = parse(inputScript) + const ast = await parse(inputScript) const selectionRanges: Selections['codeBasedSelections'] = inputScript .split('\n') .filter((ln) => @@ -465,7 +465,7 @@ async function helperThing( } describe('testing getConstraintLevelFromSourceRange', () => { - it('should divide up lines into free, partial and fully contrained', () => { + it('should divide up lines into free, partial and fully contrained', async () => { const code = `const baseLength = 3 const baseThick = 1 const armThick = 0.5 @@ -495,7 +495,7 @@ const part001 = startSketchOn('XY') |> line([-1.49, 1.06], %) // free |> xLine(-3.43 + 0, %) // full |> angledLineOfXLength([243 + 0, 1.2 + 0], %) // full` - const ast = parse(code) + const ast = await parse(code) const constraintLevels: ReturnType< typeof getConstraintLevelFromSourceRange >['level'][] = ['full', 'partial', 'free'] diff --git a/src/lang/std/std.test.ts b/src/lang/std/std.test.ts index fcc337d83..b7bea20d4 100644 --- a/src/lang/std/std.test.ts +++ b/src/lang/std/std.test.ts @@ -15,9 +15,9 @@ describe('testing angledLineThatIntersects', () => { offset: ${offset}, }, %, "yo2") const intersect = segEndX('yo2', part001)` - const { root } = await enginelessExecutor(parse(code('-1'))) + const { root } = await enginelessExecutor(await parse(code('-1'))) expect(root.intersect.value).toBe(1 + Math.sqrt(2)) - const { root: noOffset } = await enginelessExecutor(parse(code('0'))) + const { root: noOffset } = await enginelessExecutor(await parse(code('0'))) expect(noOffset.intersect.value).toBeCloseTo(1) }) }) diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index e9289cb1e..00c01bf09 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -26,6 +26,7 @@ import { CoreDumpManager } from 'lib/coredump' import openWindow from 'lib/openWindow' import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' import { rangeTypeFix } from './workers/types' +import { parser } from 'lib/singletons' export type { Program } from '../wasm-lib/kcl/bindings/Program' export type { Value } from '../wasm-lib/kcl/bindings/Value' @@ -115,7 +116,7 @@ export interface ProgramMemory { return: ProgramReturn | null } -export const parse = (code: string): Program => { +/*export const parse = (code: string): Program => { try { const program: Program = parse_wasm(code) return program @@ -130,12 +131,12 @@ export const parse = (code: string): Program => { console.log(kclError) throw kclError } -} - -/*export const parse = async (code: string): Promise => { - return parser.parse(code) }*/ +export const parse = async (code: string): Promise => { + return parser.parse(code) +} + export const executor = async ( node: Program, programMemory: ProgramMemory = { root: {}, return: null }, diff --git a/src/lib/selections.ts b/src/lib/selections.ts index 0f7db5d53..d20673f63 100644 --- a/src/lib/selections.ts +++ b/src/lib/selections.ts @@ -119,9 +119,9 @@ export async function getEventForSelectWithPoint( } } -export function getEventForSegmentSelection( +export async function getEventForSegmentSelection( obj: Object3D -): ModelingMachineEvent | null { +): Promise { const group = getParentGroup(obj, [ STRAIGHT_SEGMENT, TANGENTIAL_ARC_TO_SEGMENT, @@ -143,7 +143,7 @@ export function getEventForSegmentSelection( // previous drags don't update ast for efficiency reasons // So we want to make sure we have and updated ast with // accurate source ranges - const updatedAst = parse(codeManager.code) + const updatedAst = await parse(codeManager.code) const node = getNodeFromPath( updatedAst, pathToNode, @@ -254,10 +254,10 @@ export function processCodeMirrorRanges({ } } -function updateSceneObjectColors(codeBasedSelections: Selection[]) { +async function updateSceneObjectColors(codeBasedSelections: Selection[]) { let updated: Program try { - updated = parse(recast(kclManager.ast)) + updated = await parse(recast(kclManager.ast)) } catch (e) { console.error('error parsing code in processCodeMirrorRanges', e) return diff --git a/src/lib/useCalculateKclExpression.ts b/src/lib/useCalculateKclExpression.ts index 42590e002..40c818d9d 100644 --- a/src/lib/useCalculateKclExpression.ts +++ b/src/lib/useCalculateKclExpression.ts @@ -82,7 +82,7 @@ export function useCalculateKclExpression({ useEffect(() => { const execAstAndSetResult = async () => { const code = `const __result__ = ${value}` - const ast = parse(code) + const ast = await parse(code) const _programMem: any = { root: {}, return: null } availableVarInfo.variables.forEach(({ key, value }) => { _programMem.root[key] = { type: 'userVal', value, __meta: [] }