refactor a bit before more rust port (#739)

* partially there

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanup

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-29 11:11:01 -07:00
committed by GitHub
parent 416fe0f644
commit 61943055e5
49 changed files with 476 additions and 434 deletions

View File

@ -1,7 +1,5 @@
import { useEffect, useState, useRef } from 'react' import { useEffect, useState, useRef } from 'react'
import { parser_wasm } from '../lang/abstractSyntaxTree' import { parse, BinaryPart, Value, executor } from '../lang/wasm'
import { BinaryPart, Value } from '../lang/abstractSyntaxTreeTypes'
import { executor } from '../lang/executor'
import { import {
createIdentifier, createIdentifier,
createLiteral, createLiteral,
@ -140,7 +138,7 @@ export function useCalc({
useEffect(() => { useEffect(() => {
try { try {
const code = `const __result__ = ${value}\nshow(__result__)` const code = `const __result__ = ${value}\nshow(__result__)`
const ast = parser_wasm(code) const ast = parse(code)
const _programMem: any = { root: {}, return: null } const _programMem: any = { root: {}, return: null }
availableVarInfo.variables.forEach(({ key, value }) => { availableVarInfo.variables.forEach(({ key, value }) => {
_programMem.root[key] = { type: 'userVal', value, __meta: [] } _programMem.root[key] = { type: 'userVal', value, __meta: [] }

View File

@ -1,7 +1,6 @@
import { processMemory } from './MemoryPanel' import { processMemory } from './MemoryPanel'
import { parser_wasm } from '../lang/abstractSyntaxTree'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
import { initPromise } from '../lang/rust' import { initPromise, parse } from '../lang/wasm'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -26,7 +25,7 @@ describe('processMemory', () => {
|> lineTo([2.15, 4.32], %) |> lineTo([2.15, 4.32], %)
// |> rx(90, %) // |> rx(90, %)
show(theExtrude, theSketch)` show(theExtrude, theSketch)`
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast, { const programMemory = await enginelessExecutor(ast, {
root: {}, root: {},
return: null, return: null,

View File

@ -2,7 +2,7 @@ import ReactJson from 'react-json-view'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel' import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { useMemo } from 'react' import { useMemo } from 'react'
import { ProgramMemory, Path, ExtrudeSurface } from '../lang/executor' import { ProgramMemory, Path, ExtrudeSurface } from '../lang/wasm'
import { Themes } from '../lib/theme' import { Themes } from '../lib/theme'
interface MemoryPanelProps extends CollapsiblePanelProps { interface MemoryPanelProps extends CollapsiblePanelProps {

View File

@ -1,6 +1,6 @@
import { Dialog, Transition } from '@headlessui/react' import { Dialog, Transition } from '@headlessui/react'
import { Fragment, useState } from 'react' import { Fragment, useState } from 'react'
import { Value } from '../lang/abstractSyntaxTreeTypes' import { Value } from '../lang/wasm'
import { import {
AvailableVars, AvailableVars,
addToInputHelper, addToInputHelper,

View File

@ -1,6 +1,6 @@
import { Dialog, Transition } from '@headlessui/react' import { Dialog, Transition } from '@headlessui/react'
import { Fragment, useState } from 'react' import { Fragment, useState } from 'react'
import { Value } from '../lang/abstractSyntaxTreeTypes' import { Value } from '../lang/wasm'
import { import {
AvailableVars, AvailableVars,
addToInputHelper, addToInputHelper,

View File

@ -20,11 +20,14 @@ import {
compareVec2Epsilon, compareVec2Epsilon,
} from 'lang/std/sketch' } from 'lang/std/sketch'
import { getNodeFromPath } from 'lang/queryAst' import { getNodeFromPath } from 'lang/queryAst'
import { Program, VariableDeclarator } from 'lang/abstractSyntaxTreeTypes' import {
import { modify_ast_for_sketch } from '../wasm-lib/pkg/wasm_lib' Program,
VariableDeclarator,
rangeTypeFix,
modifyAstForSketch,
} from 'lang/wasm'
import { KCLError } from 'lang/errors' import { KCLError } from 'lang/errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { rangeTypeFix } from 'lang/abstractSyntaxTree'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
export const Stream = ({ className = '' }) => { export const Stream = ({ className = '' }) => {
@ -249,26 +252,14 @@ export const Stream = ({ className = '' }) => {
let engineId = guiMode.pathId let engineId = guiMode.pathId
try { const updatedAst: Program = await modifyAstForSketch(
const updatedAst: Program = await modify_ast_for_sketch( engineCommandManager,
engineCommandManager, ast,
JSON.stringify(ast), variableName,
variableName, engineId
engineId )
)
updateAst(updatedAst, false) updateAst(updatedAst, false)
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
return return
} }

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value, VariableDeclarator } from '../../lang/abstractSyntaxTreeTypes' import { Value, VariableDeclarator } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value, VariableDeclarator } from '../../lang/abstractSyntaxTreeTypes' import { Value, VariableDeclarator } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value } from '../../lang/abstractSyntaxTreeTypes' import { Value } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,11 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise' import { create } from 'react-modal-promise'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { import { BinaryPart, Value, VariableDeclarator } from '../../lang/wasm'
BinaryPart,
Value,
VariableDeclarator,
} from '../../lang/abstractSyntaxTreeTypes'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value } from '../../lang/abstractSyntaxTreeTypes' import { Value } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,7 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise' import { create } from 'react-modal-promise'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value } from '../../lang/abstractSyntaxTreeTypes' import { Value } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,11 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise' import { create } from 'react-modal-promise'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { import { BinaryPart, Value, VariableDeclarator } from '../../lang/wasm'
BinaryPart,
Value,
VariableDeclarator,
} from '../../lang/abstractSyntaxTreeTypes'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,11 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise' import { create } from 'react-modal-promise'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { import { BinaryPart, Value, VariableDeclarator } from '../../lang/wasm'
BinaryPart,
Value,
VariableDeclarator,
} from '../../lang/abstractSyntaxTreeTypes'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,
@ -21,8 +17,6 @@ import { GetInfoModal } from '../SetHorVertDistanceModal'
import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst' import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { updateCursors } from '../../lang/util' import { updateCursors } from '../../lang/util'
import { ActionIcon } from 'components/ActionIcon'
import { sketchButtonClassnames } from 'Toolbar'
const getModalInfo = create(GetInfoModal as any) const getModalInfo = create(GetInfoModal as any)

View File

@ -1,7 +1,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise' import { create } from 'react-modal-promise'
import { toolTips, useStore } from '../../useStore' import { toolTips, useStore } from '../../useStore'
import { Value } from '../../lang/abstractSyntaxTreeTypes' import { Value } from '../../lang/wasm'
import { import {
getNodePathFromSourceRange, getNodePathFromSourceRange,
getNodeFromPath, getNodeFromPath,

View File

@ -1,5 +1,5 @@
import { useLayoutEffect, useEffect, useRef } from 'react' import { useLayoutEffect, useEffect, useRef } from 'react'
import { _executor } from '../lang/executor' import { _executor } from '../lang/wasm'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { deferExecution } from 'lib/utils' import { deferExecution } from 'lib/utils'

View File

@ -1,12 +1,11 @@
import { parser_wasm } from './abstractSyntaxTree'
import { KCLError } from './errors' import { KCLError } from './errors'
import { initPromise } from './rust' import { initPromise, parse } from './wasm'
beforeAll(() => initPromise) beforeAll(() => initPromise)
describe('testing AST', () => { describe('testing AST', () => {
test('5 + 6', () => { test('5 + 6', () => {
const result = parser_wasm('5 +6') const result = parse('5 +6')
delete (result as any).nonCodeMeta delete (result as any).nonCodeMeta
expect(result.body).toEqual([ expect(result.body).toEqual([
{ {
@ -37,7 +36,7 @@ describe('testing AST', () => {
]) ])
}) })
test('const myVar = 5', () => { test('const myVar = 5', () => {
const { body } = parser_wasm('const myVar = 5') const { body } = parse('const myVar = 5')
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -71,7 +70,7 @@ describe('testing AST', () => {
const code = `const myVar = 5 const code = `const myVar = 5
const newVar = myVar + 1 const newVar = myVar + 1
` `
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -143,7 +142,7 @@ const newVar = myVar + 1
describe('testing function declaration', () => { describe('testing function declaration', () => {
test('fn funcN = () => {}', () => { test('fn funcN = () => {}', () => {
const { body } = parser_wasm('fn funcN = () => {}') const { body } = parse('fn funcN = () => {}')
delete (body[0] as any).declarations[0].init.body.nonCodeMeta delete (body[0] as any).declarations[0].init.body.nonCodeMeta
expect(body).toEqual([ expect(body).toEqual([
{ {
@ -179,7 +178,7 @@ describe('testing function declaration', () => {
]) ])
}) })
test('fn funcN = (a, b) => {return a + b}', () => { test('fn funcN = (a, b) => {return a + b}', () => {
const { body } = parser_wasm( const { body } = parse(
['fn funcN = (a, b) => {', ' return a + b', '}'].join('\n') ['fn funcN = (a, b) => {', ' return a + b', '}'].join('\n')
) )
delete (body[0] as any).declarations[0].init.body.nonCodeMeta delete (body[0] as any).declarations[0].init.body.nonCodeMeta
@ -256,7 +255,7 @@ describe('testing function declaration', () => {
test('call expression assignment', () => { test('call expression assignment', () => {
const code = `fn funcN = (a, b) => { return a + b } const code = `fn funcN = (a, b) => { return a + b }
const myVar = funcN(1, 2)` const myVar = funcN(1, 2)`
const { body } = parser_wasm(code) const { body } = parse(code)
delete (body[0] as any).declarations[0].init.body.nonCodeMeta delete (body[0] as any).declarations[0].init.body.nonCodeMeta
expect(body).toEqual([ expect(body).toEqual([
{ {
@ -388,7 +387,7 @@ describe('testing pipe operator special', () => {
|> lineTo([1, 1], %) |> lineTo([1, 1], %)
|> rx(45, %) |> rx(45, %)
` `
const { body } = parser_wasm(code) const { body } = parse(code)
delete (body[0] as any).declarations[0].init.nonCodeMeta delete (body[0] as any).declarations[0].init.nonCodeMeta
expect(body).toEqual([ expect(body).toEqual([
{ {
@ -624,7 +623,7 @@ describe('testing pipe operator special', () => {
}) })
test('pipe operator with binary expression', () => { test('pipe operator with binary expression', () => {
let code = `const myVar = 5 + 6 |> myFunc(45, %)` let code = `const myVar = 5 + 6 |> myFunc(45, %)`
const { body } = parser_wasm(code) const { body } = parse(code)
delete (body as any)[0].declarations[0].init.nonCodeMeta delete (body as any)[0].declarations[0].init.nonCodeMeta
expect(body).toEqual([ expect(body).toEqual([
{ {
@ -706,7 +705,7 @@ describe('testing pipe operator special', () => {
}) })
test('array expression', () => { test('array expression', () => {
let code = `const yo = [1, '2', three, 4 + 5]` let code = `const yo = [1, '2', three, 4 + 5]`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -781,7 +780,7 @@ describe('testing pipe operator special', () => {
'const three = 3', 'const three = 3',
"const yo = {aStr: 'str', anum: 2, identifier: three, binExp: 4 + 5}", "const yo = {aStr: 'str', anum: 2, identifier: three, binExp: 4 + 5}",
].join('\n') ].join('\n')
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -925,7 +924,7 @@ describe('testing pipe operator special', () => {
const code = `const yo = {key: { const code = `const yo = {key: {
key2: 'value' key2: 'value'
}}` }}`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -993,7 +992,7 @@ describe('testing pipe operator special', () => {
}) })
test('object expression with array ast', () => { test('object expression with array ast', () => {
const code = `const yo = {key: [1, '2']}` const code = `const yo = {key: [1, '2']}`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -1057,7 +1056,7 @@ describe('testing pipe operator special', () => {
}) })
test('object memberExpression simple', () => { test('object memberExpression simple', () => {
const code = `const prop = yo.one.two` const code = `const prop = yo.one.two`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -1112,7 +1111,7 @@ describe('testing pipe operator special', () => {
}) })
test('object memberExpression with square braces', () => { test('object memberExpression with square braces', () => {
const code = `const prop = yo.one["two"]` const code = `const prop = yo.one["two"]`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -1168,7 +1167,7 @@ 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', () => {
const code = `const prop = yo["one"][two]` const code = `const prop = yo["one"][two]`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body).toEqual([ expect(body).toEqual([
{ {
type: 'VariableDeclaration', type: 'VariableDeclaration',
@ -1227,7 +1226,7 @@ describe('testing pipe operator special', () => {
describe('nests binary expressions correctly', () => { describe('nests binary expressions correctly', () => {
it('works with the simple case', () => { it('works with the simple case', () => {
const code = `const yo = 1 + 2` const code = `const yo = 1 + 2`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body[0]).toEqual({ expect(body[0]).toEqual({
type: 'VariableDeclaration', type: 'VariableDeclaration',
start: 0, start: 0,
@ -1271,7 +1270,7 @@ describe('nests binary expressions correctly', () => {
it('should nest according to precedence with multiply first', () => { it('should nest according to precedence with multiply first', () => {
// should be binExp { binExp { lit-1 * lit-2 } + lit} // should be binExp { binExp { lit-1 * lit-2 } + lit}
const code = `const yo = 1 * 2 + 3` const code = `const yo = 1 * 2 + 3`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body[0]).toEqual({ expect(body[0]).toEqual({
type: 'VariableDeclaration', type: 'VariableDeclaration',
start: 0, start: 0,
@ -1328,7 +1327,7 @@ describe('nests binary expressions correctly', () => {
it('should nest according to precedence with sum first', () => { it('should nest according to precedence with sum first', () => {
// should be binExp { lit-1 + binExp { lit-2 * lit-3 } } // should be binExp { lit-1 + binExp { lit-2 * lit-3 } }
const code = `const yo = 1 + 2 * 3` const code = `const yo = 1 + 2 * 3`
const { body } = parser_wasm(code) const { body } = parse(code)
expect(body[0]).toEqual({ expect(body[0]).toEqual({
type: 'VariableDeclaration', type: 'VariableDeclaration',
start: 0, start: 0,
@ -1384,7 +1383,7 @@ describe('nests binary expressions correctly', () => {
}) })
it('should nest properly with two opperators of equal precedence', () => { it('should nest properly with two opperators of equal precedence', () => {
const code = `const yo = 1 + 2 - 3` const code = `const yo = 1 + 2 - 3`
const { body } = parser_wasm(code) const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({ expect((body[0] as any).declarations[0].init).toEqual({
type: 'BinaryExpression', type: 'BinaryExpression',
start: 11, start: 11,
@ -1421,7 +1420,7 @@ describe('nests binary expressions correctly', () => {
}) })
it('should nest properly with two opperators of equal (but higher) precedence', () => { it('should nest properly with two opperators of equal (but higher) precedence', () => {
const code = `const yo = 1 * 2 / 3` const code = `const yo = 1 * 2 / 3`
const { body } = parser_wasm(code) const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({ expect((body[0] as any).declarations[0].init).toEqual({
type: 'BinaryExpression', type: 'BinaryExpression',
start: 11, start: 11,
@ -1458,7 +1457,7 @@ describe('nests binary expressions correctly', () => {
}) })
it('should nest properly with longer example', () => { it('should nest properly with longer example', () => {
const code = `const yo = 1 + 2 * (3 - 4) / 5 + 6` const code = `const yo = 1 + 2 * (3 - 4) / 5 + 6`
const { body } = parser_wasm(code) const { body } = parse(code)
const init = (body[0] as any).declarations[0].init const init = (body[0] as any).declarations[0].init
expect(init).toEqual({ expect(init).toEqual({
type: 'BinaryExpression', type: 'BinaryExpression',
@ -1520,14 +1519,12 @@ const key = 'c'`
value: 'this is a comment', value: 'this is a comment',
}, },
} }
const { nonCodeMeta } = parser_wasm(code) const { nonCodeMeta } = parse(code)
expect(nonCodeMeta.nonCodeNodes[0]).toEqual(nonCodeMetaInstance) expect(nonCodeMeta.nonCodeNodes[0]).toEqual(nonCodeMetaInstance)
// extra whitespace won't change it's position (0) or value (NB the start end would have changed though) // 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 codeWithExtraStartWhitespace = '\n\n\n' + code
const { nonCodeMeta: nonCodeMeta2 } = parser_wasm( const { nonCodeMeta: nonCodeMeta2 } = parse(codeWithExtraStartWhitespace)
codeWithExtraStartWhitespace
)
expect(nonCodeMeta2.nonCodeNodes[0].value).toStrictEqual( expect(nonCodeMeta2.nonCodeNodes[0].value).toStrictEqual(
nonCodeMetaInstance.value nonCodeMetaInstance.value
) )
@ -1545,7 +1542,7 @@ const key = 'c'`
|> close(%) |> close(%)
` `
const { body } = parser_wasm(code) const { body } = parse(code)
const indexOfSecondLineToExpression = 2 const indexOfSecondLineToExpression = 2
const sketchNonCodeMeta = (body as any)[0].declarations[0].init.nonCodeMeta const sketchNonCodeMeta = (body as any)[0].declarations[0].init.nonCodeMeta
.nonCodeNodes .nonCodeNodes
@ -1569,7 +1566,7 @@ const key = 'c'`
' |> rx(90, %)', ' |> rx(90, %)',
].join('\n') ].join('\n')
const { body } = parser_wasm(code) const { body } = parse(code)
const sketchNonCodeMeta = (body[0] as any).declarations[0].init.nonCodeMeta const sketchNonCodeMeta = (body[0] as any).declarations[0].init.nonCodeMeta
.nonCodeNodes .nonCodeNodes
expect(sketchNonCodeMeta[3]).toEqual({ expect(sketchNonCodeMeta[3]).toEqual({
@ -1587,7 +1584,7 @@ const key = 'c'`
describe('test UnaryExpression', () => { 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', () => {
const code = `const myVar = -min(4, 100)` const code = `const myVar = -min(4, 100)`
const { body } = parser_wasm(code) const { body } = parse(code)
const myVarInit = (body?.[0] as any).declarations[0]?.init const myVarInit = (body?.[0] as any).declarations[0]?.init
expect(myVarInit).toEqual({ expect(myVarInit).toEqual({
type: 'UnaryExpression', type: 'UnaryExpression',
@ -1613,7 +1610,7 @@ describe('test UnaryExpression', () => {
describe('testing nested call expressions', () => { describe('testing nested call expressions', () => {
it('callExp in a binExp in a callExp', () => { it('callExp in a binExp in a callExp', () => {
const code = 'const myVar = min(100, 1 + legLen(5, 3))' const code = 'const myVar = min(100, 1 + legLen(5, 3))'
const { body } = parser_wasm(code) const { body } = parse(code)
const myVarInit = (body?.[0] as any).declarations[0]?.init const myVarInit = (body?.[0] as any).declarations[0]?.init
expect(myVarInit).toEqual({ expect(myVarInit).toEqual({
type: 'CallExpression', type: 'CallExpression',
@ -1651,7 +1648,7 @@ describe('testing nested call expressions', () => {
describe('should recognise callExpresions in binaryExpressions', () => { describe('should recognise callExpresions in binaryExpressions', () => {
const code = "xLineTo(segEndX('seg02', %) + 1, %)" const code = "xLineTo(segEndX('seg02', %) + 1, %)"
it('should recognise the callExp', () => { it('should recognise the callExp', () => {
const { body } = parser_wasm(code) const { body } = parse(code)
const callExpArgs = (body?.[0] as any).expression?.arguments const callExpArgs = (body?.[0] as any).expression?.arguments
expect(callExpArgs).toEqual([ expect(callExpArgs).toEqual([
{ {
@ -1690,7 +1687,7 @@ describe('parsing errors', () => {
let _theError let _theError
try { try {
const result = expect(parser_wasm(code)) const result = expect(parse(code))
} catch (e) { } catch (e) {
_theError = e _theError = e
} }

View File

@ -1,48 +0,0 @@
import { Program } from './abstractSyntaxTreeTypes'
import { parse_js } from '../wasm-lib/pkg/wasm_lib'
import { initPromise } from './rust'
import { Token } from './tokeniser'
import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
export const rangeTypeFix = (ranges: number[][]): [number, number][] =>
ranges.map(([start, end]) => [start, end])
export const parser_wasm = (code: string): Program => {
try {
const program: Program = parse_js(code)
return program
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}
export async function asyncParser(code: string): Promise<Program> {
await initPromise
try {
const program: Program = parse_js(code)
return program
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}
export function rangeOfToken(token: Token | undefined): [number, number][] {
return token === undefined ? [] : [[token.start, token.end]]
}

View File

@ -1,37 +0,0 @@
export type { Program } from '../wasm-lib/kcl/bindings/Program'
export type { Value } from '../wasm-lib/kcl/bindings/Value'
export type { ObjectExpression } from '../wasm-lib/kcl/bindings/ObjectExpression'
export type { MemberExpression } from '../wasm-lib/kcl/bindings/MemberExpression'
export type { PipeExpression } from '../wasm-lib/kcl/bindings/PipeExpression'
export type { VariableDeclaration } from '../wasm-lib/kcl/bindings/VariableDeclaration'
export type { PipeSubstitution } from '../wasm-lib/kcl/bindings/PipeSubstitution'
export type { Identifier } from '../wasm-lib/kcl/bindings/Identifier'
export type { UnaryExpression } from '../wasm-lib/kcl/bindings/UnaryExpression'
export type { BinaryExpression } from '../wasm-lib/kcl/bindings/BinaryExpression'
export type { ReturnStatement } from '../wasm-lib/kcl/bindings/ReturnStatement'
export type { ExpressionStatement } from '../wasm-lib/kcl/bindings/ExpressionStatement'
export type { CallExpression } from '../wasm-lib/kcl/bindings/CallExpression'
export type { VariableDeclarator } from '../wasm-lib/kcl/bindings/VariableDeclarator'
export type { BinaryPart } from '../wasm-lib/kcl/bindings/BinaryPart'
export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
export type SyntaxType =
| 'Program'
| 'ExpressionStatement'
| 'BinaryExpression'
| 'CallExpression'
| 'Identifier'
| 'ReturnStatement'
| 'VariableDeclaration'
| 'VariableDeclarator'
| 'MemberExpression'
| 'ArrayExpression'
| 'ObjectExpression'
| 'ObjectProperty'
| 'FunctionExpression'
| 'PipeExpression'
| 'PipeSubstitution'
| 'Literal'
| 'NonCodeNode'
| 'UnaryExpression'

View File

@ -1,5 +1,4 @@
import { parser_wasm } from './abstractSyntaxTree' import { parse, initPromise } from './wasm'
import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -13,7 +12,7 @@ const mySketch001 = startSketchAt([0, 0])
|> lineTo([0.46, -5.82], %) |> lineTo([0.46, -5.82], %)
// |> rx(45, %) // |> rx(45, %)
show(mySketch001)` show(mySketch001)`
const programMemory = await enginelessExecutor(parser_wasm(code)) const programMemory = await enginelessExecutor(parse(code))
// @ts-ignore // @ts-ignore
const shown = programMemory?.return?.map( const shown = programMemory?.return?.map(
// @ts-ignore // @ts-ignore
@ -69,7 +68,7 @@ const mySketch001 = startSketchAt([0, 0])
// |> rx(45, %) // |> rx(45, %)
|> extrude(2, %) |> extrude(2, %)
show(mySketch001)` show(mySketch001)`
const programMemory = await enginelessExecutor(parser_wasm(code)) const programMemory = await enginelessExecutor(parse(code))
// @ts-ignore // @ts-ignore
const shown = programMemory?.return?.map( const shown = programMemory?.return?.map(
// @ts-ignore // @ts-ignore
@ -109,7 +108,7 @@ const sk2 = startSketchAt([0, 0])
show(theExtrude, sk2)` show(theExtrude, sk2)`
const programMemory = await enginelessExecutor(parser_wasm(code)) const programMemory = await enginelessExecutor(parse(code))
// @ts-ignore // @ts-ignore
const geos = programMemory?.return?.map( const geos = programMemory?.return?.map(
// @ts-ignore // @ts-ignore

View File

@ -1,10 +1,7 @@
import fs from 'node:fs' import fs from 'node:fs'
import { parser_wasm } from './abstractSyntaxTree' import { parse, ProgramMemory, SketchGroup, initPromise } from './wasm'
import { ProgramMemory, SketchGroup } from './executor'
import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
import { vi } from 'vitest'
import { KCLError } from './errors' import { KCLError } from './errors'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -403,7 +400,7 @@ async function exe(
code: string, code: string,
programMemory: ProgramMemory = { root: {}, return: null } programMemory: ProgramMemory = { root: {}, return: null }
) { ) {
const ast = parser_wasm(code) const ast = parse(code)
const result = await enginelessExecutor(ast, programMemory) const result = await enginelessExecutor(ast, programMemory)
return result return result

View File

@ -1,81 +0,0 @@
import { Program } from './abstractSyntaxTreeTypes'
import {
EngineCommandManager,
ArtifactMap,
SourceRangeMap,
} from './std/engineConnection'
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
import { execute_wasm } from '../wasm-lib/pkg/wasm_lib'
import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { rangeTypeFix } from './abstractSyntaxTree'
export type { SourceRange } from '../wasm-lib/kcl/bindings/SourceRange'
export type { Position } from '../wasm-lib/kcl/bindings/Position'
export type { Rotation } from '../wasm-lib/kcl/bindings/Rotation'
export type { Path } from '../wasm-lib/kcl/bindings/Path'
export type { SketchGroup } from '../wasm-lib/kcl/bindings/SketchGroup'
export type { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
export type { ExtrudeSurface } from '../wasm-lib/kcl/bindings/ExtrudeSurface'
export type PathToNode = [string | number, string][]
interface Memory {
[key: string]: MemoryItem
}
export interface ProgramMemory {
root: Memory
return: ProgramReturn | null
}
export const executor = async (
node: Program,
programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager,
// work around while the gemotry is still be stored on the frontend
// will be removed when the stream UI is added.
tempMapCallback: (a: {
artifactMap: ArtifactMap
sourceRangeMap: SourceRangeMap
}) => void = () => {}
): Promise<ProgramMemory> => {
engineCommandManager.startNewSession()
const _programMemory = await _executor(
node,
programMemory,
engineCommandManager
)
const { artifactMap, sourceRangeMap } =
await engineCommandManager.waitForAllCommands(node, _programMemory)
tempMapCallback({ artifactMap, sourceRangeMap })
engineCommandManager.endSession()
return _programMemory
}
export const _executor = async (
node: Program,
programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager
): Promise<ProgramMemory> => {
try {
const memory: ProgramMemory = await execute_wasm(
JSON.stringify(node),
JSON.stringify(programMemory),
engineCommandManager
)
return memory
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}

View File

@ -1,7 +1,5 @@
import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst' import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst'
import { parser_wasm } from './abstractSyntaxTree' import { Identifier, parse, initPromise } from './wasm'
import { initPromise } from './rust'
import { Identifier } from './abstractSyntaxTreeTypes'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -21,7 +19,7 @@ const sk3 = startSketchAt([0, 0])
lineToSubstringIndex + subStr.length, lineToSubstringIndex + subStr.length,
] ]
const ast = parser_wasm(code) const ast = parse(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange) const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const { node } = getNodeFromPath<any>(ast, nodePath) const { node } = getNodeFromPath<any>(ast, nodePath)
@ -46,7 +44,7 @@ const b1 = cube([0,0], 10)`
subStrIndex + 'pos'.length, subStrIndex + 'pos'.length,
] ]
const ast = parser_wasm(code) const ast = parse(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange) const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const node = getNodeFromPath<Identifier>(ast, nodePath).node const node = getNodeFromPath<Identifier>(ast, nodePath).node
@ -80,7 +78,7 @@ const b1 = cube([0,0], 10)`
subStrIndex + 'scale'.length, subStrIndex + 'scale'.length,
] ]
const ast = parser_wasm(code) const ast = parse(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange) const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const node = getNodeFromPath<Identifier>(ast, nodePath).node const node = getNodeFromPath<Identifier>(ast, nodePath).node
expect(nodePath).toEqual([ expect(nodePath).toEqual([

View File

@ -1,4 +1,4 @@
import { parser_wasm } from './abstractSyntaxTree' import { parse, recast, initPromise } from './wasm'
import { import {
createLiteral, createLiteral,
createIdentifier, createIdentifier,
@ -13,8 +13,6 @@ import {
giveSketchFnCallTag, giveSketchFnCallTag,
moveValueIntoNewVariable, moveValueIntoNewVariable,
} from './modifyAst' } from './modifyAst'
import { recast } from './recast'
import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -126,7 +124,7 @@ function giveSketchFnCallTagTestHelper(
// giveSketchFnCallTag inputs and outputs an ast, which is very verbose for testing // giveSketchFnCallTag inputs and outputs an ast, which is very verbose for testing
// this wrapper changes the input and output to code // this wrapper changes the input and output to code
// making it more of an integration test, but easier to read the test intention is the goal // making it more of an integration test, but easier to read the test intention is the goal
const ast = parser_wasm(code) const ast = parse(code)
const start = code.indexOf(searchStr) const start = code.indexOf(searchStr)
const range: [number, number] = [start, start + searchStr.length] const range: [number, number] = [start, start + searchStr.length]
const { modifiedAst, tag, isTagExisting } = giveSketchFnCallTag(ast, range) const { modifiedAst, tag, isTagExisting } = giveSketchFnCallTag(ast, range)
@ -197,7 +195,7 @@ const part001 = startSketchAt([-1.2, 4.83])
const yo2 = hmm([identifierGuy + 5]) const yo2 = hmm([identifierGuy + 5])
show(part001)` show(part001)`
it('should move a binary expression into a new variable', async () => { it('should move a binary expression into a new variable', async () => {
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const startIndex = code.indexOf('100 + 100') + 1 const startIndex = code.indexOf('100 + 100') + 1
const { modifiedAst } = moveValueIntoNewVariable( const { modifiedAst } = moveValueIntoNewVariable(
@ -211,7 +209,7 @@ show(part001)`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`) expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
}) })
it('should move a value into a new variable', async () => { it('should move a value into a new variable', async () => {
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const startIndex = code.indexOf('2.8') + 1 const startIndex = code.indexOf('2.8') + 1
const { modifiedAst } = moveValueIntoNewVariable( const { modifiedAst } = moveValueIntoNewVariable(
@ -225,7 +223,7 @@ show(part001)`
expect(newCode).toContain(`line([newVar, 0], %)`) expect(newCode).toContain(`line([newVar, 0], %)`)
}) })
it('should move a callExpression into a new variable', async () => { it('should move a callExpression into a new variable', async () => {
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const startIndex = code.indexOf('def(') const startIndex = code.indexOf('def(')
const { modifiedAst } = moveValueIntoNewVariable( const { modifiedAst } = moveValueIntoNewVariable(
@ -239,7 +237,7 @@ show(part001)`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`) expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
}) })
it('should move a binary expression with call expression into a new variable', async () => { it('should move a binary expression with call expression into a new variable', async () => {
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const startIndex = code.indexOf('jkl(') + 1 const startIndex = code.indexOf('jkl(') + 1
const { modifiedAst } = moveValueIntoNewVariable( const { modifiedAst } = moveValueIntoNewVariable(
@ -253,7 +251,7 @@ show(part001)`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`) expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
}) })
it('should move a identifier into a new variable', async () => { it('should move a identifier into a new variable', async () => {
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const startIndex = code.indexOf('identifierGuy +') + 1 const startIndex = code.indexOf('identifierGuy +') + 1
const { modifiedAst } = moveValueIntoNewVariable( const { modifiedAst } = moveValueIntoNewVariable(

View File

@ -14,14 +14,15 @@ import {
ObjectExpression, ObjectExpression,
UnaryExpression, UnaryExpression,
BinaryExpression, BinaryExpression,
} from './abstractSyntaxTreeTypes' PathToNode,
ProgramMemory,
} from './wasm'
import { import {
findAllPreviousVariables, findAllPreviousVariables,
getNodeFromPath, getNodeFromPath,
getNodePathFromSourceRange, getNodePathFromSourceRange,
isNodeSafeToReplace, isNodeSafeToReplace,
} from './queryAst' } from './queryAst'
import { PathToNode, ProgramMemory } from './executor'
import { import {
addTagForSketchOnFace, addTagForSketchOnFace,
getFirstArg, getFirstArg,

View File

@ -1,11 +1,10 @@
import { parser_wasm } from './abstractSyntaxTree' import { parse, recast, initPromise } from './wasm'
import { import {
findAllPreviousVariables, findAllPreviousVariables,
isNodeSafeToReplace, isNodeSafeToReplace,
isTypeInValue, isTypeInValue,
getNodePathFromSourceRange, getNodePathFromSourceRange,
} from './queryAst' } from './queryAst'
import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
import { import {
createArrayExpression, createArrayExpression,
@ -13,7 +12,6 @@ import {
createLiteral, createLiteral,
createPipeSubstitution, createPipeSubstitution,
} from './modifyAst' } from './modifyAst'
import { recast } from './recast'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -36,7 +34,7 @@ const variableBelowShouldNotBeIncluded = 3
show(part001)` show(part001)`
const rangeStart = code.indexOf('// selection-range-7ish-before-this') - 7 const rangeStart = code.indexOf('// selection-range-7ish-before-this') - 7
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const { variables, bodyPath, insertIndex } = findAllPreviousVariables( const { variables, bodyPath, insertIndex } = findAllPreviousVariables(
@ -70,7 +68,7 @@ const yo = 5 + 6
const yo2 = hmm([identifierGuy + 5]) const yo2 = hmm([identifierGuy + 5])
show(part001)` show(part001)`
it('find a safe binaryExpression', () => { it('find a safe binaryExpression', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('100 + 100') + 2 const rangeStart = code.indexOf('100 + 100') + 2
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -84,7 +82,7 @@ show(part001)`
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`) expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
}) })
it('find a safe Identifier', () => { it('find a safe Identifier', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('abc') const rangeStart = code.indexOf('abc')
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -92,7 +90,7 @@ show(part001)`
expect(code.slice(result.value.start, result.value.end)).toBe('abc') expect(code.slice(result.value.start, result.value.end)).toBe('abc')
}) })
it('find a safe CallExpression', () => { it('find a safe CallExpression', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('def') const rangeStart = code.indexOf('def')
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -106,7 +104,7 @@ show(part001)`
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`) expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
}) })
it('find an UNsafe CallExpression, as it has a PipeSubstitution', () => { it('find an UNsafe CallExpression, as it has a PipeSubstitution', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('ghi') const rangeStart = code.indexOf('ghi')
const range: [number, number] = [rangeStart, rangeStart] const range: [number, number] = [rangeStart, rangeStart]
const result = isNodeSafeToReplace(ast, range) const result = isNodeSafeToReplace(ast, range)
@ -115,7 +113,7 @@ show(part001)`
expect(code.slice(result.value.start, result.value.end)).toBe('ghi(%)') expect(code.slice(result.value.start, result.value.end)).toBe('ghi(%)')
}) })
it('find an UNsafe Identifier, as it is a callee', () => { it('find an UNsafe Identifier, as it is a callee', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('ine([2.8,') const rangeStart = code.indexOf('ine([2.8,')
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(false) expect(result.isSafe).toBe(false)
@ -125,7 +123,7 @@ show(part001)`
) )
}) })
it("find a safe BinaryExpression that's assigned to a variable", () => { it("find a safe BinaryExpression that's assigned to a variable", () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('5 + 6') + 1 const rangeStart = code.indexOf('5 + 6') + 1
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -139,7 +137,7 @@ show(part001)`
expect(outCode).toContain(`const yo = replaceName`) expect(outCode).toContain(`const yo = replaceName`)
}) })
it('find a safe BinaryExpression that has a CallExpression within', () => { it('find a safe BinaryExpression that has a CallExpression within', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('jkl') + 1 const rangeStart = code.indexOf('jkl') + 1
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -155,7 +153,7 @@ show(part001)`
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`) expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
}) })
it('find a safe BinaryExpression within a CallExpression', () => { it('find a safe BinaryExpression within a CallExpression', () => {
const ast = parser_wasm(code) const ast = parse(code)
const rangeStart = code.indexOf('identifierGuy') + 1 const rangeStart = code.indexOf('identifierGuy') + 1
const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart]) const result = isNodeSafeToReplace(ast, [rangeStart, rangeStart])
expect(result.isSafe).toBe(true) expect(result.isSafe).toBe(true)
@ -203,7 +201,7 @@ show(part001)`
it('finds the second line when cursor is put at the end', () => { it('finds the second line when cursor is put at the end', () => {
const searchLn = `line([0.94, 2.61], %)` const searchLn = `line([0.94, 2.61], %)`
const sourceIndex = code.indexOf(searchLn) + searchLn.length const sourceIndex = code.indexOf(searchLn) + searchLn.length
const ast = parser_wasm(code) const ast = parse(code)
const result = getNodePathFromSourceRange(ast, [sourceIndex, sourceIndex]) const result = getNodePathFromSourceRange(ast, [sourceIndex, sourceIndex])
expect(result).toEqual([ expect(result).toEqual([
['body', ''], ['body', ''],
@ -218,7 +216,7 @@ show(part001)`
it('finds the last line when cursor is put at the end', () => { it('finds the last line when cursor is put at the end', () => {
const searchLn = `line([-0.21, -1.4], %)` const searchLn = `line([-0.21, -1.4], %)`
const sourceIndex = code.indexOf(searchLn) + searchLn.length const sourceIndex = code.indexOf(searchLn) + searchLn.length
const ast = parser_wasm(code) const ast = parse(code)
const result = getNodePathFromSourceRange(ast, [sourceIndex, sourceIndex]) const result = getNodePathFromSourceRange(ast, [sourceIndex, sourceIndex])
const expected = [ const expected = [
['body', ''], ['body', ''],

View File

@ -1,4 +1,3 @@
import { PathToNode, ProgramMemory, SketchGroup, SourceRange } from './executor'
import { Selection, ToolTip } from '../useStore' import { Selection, ToolTip } from '../useStore'
import { import {
BinaryExpression, BinaryExpression,
@ -10,7 +9,11 @@ import {
VariableDeclaration, VariableDeclaration,
ReturnStatement, ReturnStatement,
ArrayExpression, ArrayExpression,
} from './abstractSyntaxTreeTypes' PathToNode,
ProgramMemory,
SketchGroup,
SourceRange,
} from './wasm'
import { createIdentifier, splitPathAtLastIndex } from './modifyAst' import { createIdentifier, splitPathAtLastIndex } from './modifyAst'
import { getSketchSegmentFromSourceRange } from './std/sketchConstraints' import { getSketchSegmentFromSourceRange } from './std/sketchConstraints'
import { getAngle } from '../lib/utils' import { getAngle } from '../lib/utils'

View File

@ -1,8 +1,5 @@
import { recast } from './recast' import { parse, Program, recast, initPromise } from './wasm'
import { parser_wasm } from './abstractSyntaxTree'
import { Program } from './abstractSyntaxTreeTypes'
import fs from 'node:fs' import fs from 'node:fs'
import { initPromise } from './rust'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -366,6 +363,6 @@ describe('it recasts binary expression using brackets where needed', () => {
// helpers // helpers
function code2ast(code: string): { ast: Program } { function code2ast(code: string): { ast: Program } {
const ast = parser_wasm(code) const ast = parse(code)
return { ast } return { ast }
} }

View File

@ -1,13 +0,0 @@
import { Program } from './abstractSyntaxTreeTypes'
import { recast_wasm } from '../wasm-lib/pkg/wasm_lib'
export const recast = (ast: Program): string => {
try {
const s: string = recast_wasm(JSON.stringify(ast))
return s
} catch (e) {
// TODO: do something real with the error.
console.log('recast error', e)
throw e
}
}

View File

@ -1,20 +0,0 @@
import init from '../wasm-lib/pkg/wasm_lib'
const initialise = async () => {
const baseUrl =
typeof window === 'undefined'
? 'http://127.0.0.1:3000'
: window.location.origin.includes('tauri://localhost')
? 'tauri://localhost'
: window.location.origin.includes('localhost')
? 'http://localhost:3000'
: window.location.origin && window.location.origin !== 'null'
? window.location.origin
: 'http://localhost:3000'
const fullUrl = baseUrl + '/wasm_lib_bg.wasm'
const input = await fetch(fullUrl)
const buffer = await input.arrayBuffer()
return init(buffer)
}
export const initPromise = initialise()

View File

@ -1,4 +1,9 @@
import { ProgramMemory, SourceRange } from 'lang/executor' import {
ProgramMemory,
SourceRange,
Program,
VariableDeclarator,
} from 'lang/wasm'
import { Selections } from 'useStore' import { Selections } from 'useStore'
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env' import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
@ -6,7 +11,6 @@ import { exportSave } from 'lib/exportSave'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import * as Sentry from '@sentry/react' import * as Sentry from '@sentry/react'
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
import { Program, VariableDeclarator } from 'lang/abstractSyntaxTreeTypes'
let lastMessage = '' let lastMessage = ''

View File

@ -6,13 +6,9 @@ import {
getXComponent, getXComponent,
addCloseToPipe, addCloseToPipe,
} from './sketch' } from './sketch'
import { parser_wasm } from '../abstractSyntaxTree' import { parse, recast, initPromise } from '../wasm'
import { getNodePathFromSourceRange } from '../queryAst' import { getNodePathFromSourceRange } from '../queryAst'
import { recast } from '../recast'
import { enginelessExecutor } from '../../lib/testHelpers' import { enginelessExecutor } from '../../lib/testHelpers'
import { initPromise } from '../rust'
beforeAll(() => initPromise)
const eachQuad: [number, [number, number]][] = [ const eachQuad: [number, [number, number]][] = [
[-315, [1, 1]], [-315, [1, 1]],
@ -29,6 +25,8 @@ const eachQuad: [number, [number, number]][] = [
[675, [1, -1]], [675, [1, -1]],
] ]
beforeAll(() => initPromise)
describe('testing getYComponent', () => { describe('testing getYComponent', () => {
it('should return the vertical component of a vector correctly when given angles in each quadrant (and with angles < 0, or > 360)', () => { it('should return the vertical component of a vector correctly when given angles in each quadrant (and with angles < 0, or > 360)', () => {
const expected: [number, number][] = [] const expected: [number, number][] = []
@ -106,7 +104,7 @@ show(mySketch001)
` `
const code = genCode(lineToChange) const code = genCode(lineToChange)
const expectedCode = genCode(lineAfterChange) const expectedCode = genCode(lineAfterChange)
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const sourceStart = code.indexOf(lineToChange) const sourceStart = code.indexOf(lineToChange)
const { modifiedAst } = changeSketchArguments( const { modifiedAst } = changeSketchArguments(
@ -144,7 +142,7 @@ const mySketch001 = startSketchAt([0, 0])
|> lineTo([-1.59, -1.54], %) |> lineTo([-1.59, -1.54], %)
|> lineTo([0.46, -5.82], %) |> lineTo([0.46, -5.82], %)
show(mySketch001)` show(mySketch001)`
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const sourceStart = code.indexOf(lineToChange) const sourceStart = code.indexOf(lineToChange)
expect(sourceStart).toBe(66) expect(sourceStart).toBe(66)
@ -205,7 +203,7 @@ describe('testing addTagForSketchOnFace', () => {
show(mySketch001) show(mySketch001)
` `
const code = genCode(originalLine) const code = genCode(originalLine)
const ast = parser_wasm(code) const ast = parse(code)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const sourceStart = code.indexOf(originalLine) const sourceStart = code.indexOf(originalLine)
const sourceRange: [number, number] = [ const sourceRange: [number, number] = [

View File

@ -4,9 +4,6 @@ import {
SketchGroup, SketchGroup,
SourceRange, SourceRange,
PathToNode, PathToNode,
MemoryItem,
} from '../executor'
import {
Program, Program,
PipeExpression, PipeExpression,
CallExpression, CallExpression,
@ -14,7 +11,7 @@ import {
Value, Value,
Literal, Literal,
VariableDeclaration, VariableDeclaration,
} from '../abstractSyntaxTreeTypes' } from '../wasm'
import { import {
getNodeFromPath, getNodeFromPath,
getNodeFromPathCurry, getNodeFromPathCurry,
@ -38,7 +35,6 @@ import {
findUniqueName, findUniqueName,
} from '../modifyAst' } from '../modifyAst'
import { roundOff, getLength, getAngle } from '../../lib/utils' import { roundOff, getLength, getAngle } from '../../lib/utils'
import { getSketchSegmentFromSourceRange } from './sketchConstraints'
import { perpendicularDistance } from 'sketch-helpers' import { perpendicularDistance } from 'sketch-helpers'
export type Coords2d = [number, number] export type Coords2d = [number, number]

View File

@ -1,12 +1,9 @@
import { parser_wasm } from '../abstractSyntaxTree' import { parse, SketchGroup, recast, initPromise } from '../wasm'
import { SketchGroup } from '../executor'
import { import {
ConstraintType, ConstraintType,
getTransformInfos, getTransformInfos,
transformAstSketchLines, transformAstSketchLines,
} from './sketchcombos' } from './sketchcombos'
import { recast } from '../recast'
import { initPromise } from '../rust'
import { getSketchSegmentFromSourceRange } from './sketchConstraints' import { getSketchSegmentFromSourceRange } from './sketchConstraints'
import { Selection } from '../../useStore' import { Selection } from '../../useStore'
import { enginelessExecutor } from '../../lib/testHelpers' import { enginelessExecutor } from '../../lib/testHelpers'
@ -31,7 +28,7 @@ async function testingSwapSketchFnCall({
type: 'default', type: 'default',
range: [startIndex, startIndex + callToSwap.length], range: [startIndex, startIndex + callToSwap.length],
} }
const ast = parser_wasm(inputCode) const ast = parse(inputCode)
const programMemory = await enginelessExecutor(ast) const programMemory = await enginelessExecutor(ast)
const selections = { const selections = {
codeBasedSelections: [range], codeBasedSelections: [range],
@ -381,7 +378,7 @@ const part001 = startSketchAt([0, 0.04]) // segment-in-start
|> xLine(3.54, %) |> xLine(3.54, %)
show(part001)` show(part001)`
it('normal case works', async () => { it('normal case works', async () => {
const programMemory = await enginelessExecutor(parser_wasm(code)) const programMemory = await enginelessExecutor(parse(code))
const index = code.indexOf('// normal-segment') - 7 const index = code.indexOf('// normal-segment') - 7
const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange( const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange(
programMemory.root['part001'] as SketchGroup, programMemory.root['part001'] as SketchGroup,
@ -395,7 +392,7 @@ show(part001)`
}) })
}) })
it('verify it works when the segment is in the `start` property', async () => { it('verify it works when the segment is in the `start` property', async () => {
const programMemory = await enginelessExecutor(parser_wasm(code)) const programMemory = await enginelessExecutor(parse(code))
const index = code.indexOf('// segment-in-start') - 7 const index = code.indexOf('// segment-in-start') - 7
const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange( const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange(
programMemory.root['part001'] as SketchGroup, programMemory.root['part001'] as SketchGroup,

View File

@ -3,8 +3,10 @@ import {
Program, Program,
VariableDeclarator, VariableDeclarator,
CallExpression, CallExpression,
} from '../abstractSyntaxTreeTypes' SketchGroup,
import { SketchGroup, SourceRange, Path } from '../executor' SourceRange,
Path,
} from '../wasm'
export function getSketchSegmentFromSourceRange( export function getSketchSegmentFromSourceRange(
sketchGroup: SketchGroup, sketchGroup: SketchGroup,

View File

@ -1,5 +1,4 @@
import { parser_wasm } from '../abstractSyntaxTree' import { parse, Value, recast, initPromise } from '../wasm'
import { Value } from '../abstractSyntaxTreeTypes'
import { import {
getConstraintType, getConstraintType,
getTransformInfos, getTransformInfos,
@ -8,10 +7,8 @@ import {
ConstraintType, ConstraintType,
getConstraintLevelFromSourceRange, getConstraintLevelFromSourceRange,
} from './sketchcombos' } from './sketchcombos'
import { initPromise } from '../rust'
import { Selections, ToolTip } from '../../useStore' import { Selections, ToolTip } from '../../useStore'
import { enginelessExecutor } from '../../lib/testHelpers' import { enginelessExecutor } from '../../lib/testHelpers'
import { recast } from '../../lang/recast'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -63,7 +60,7 @@ describe('testing getConstraintType', () => {
function getConstraintTypeFromSourceHelper( function getConstraintTypeFromSourceHelper(
code: string code: string
): ReturnType<typeof getConstraintType> { ): ReturnType<typeof getConstraintType> {
const ast = parser_wasm(code) const ast = parse(code)
const args = (ast.body[0] as any).expression.arguments[0].elements as [ const args = (ast.body[0] as any).expression.arguments[0].elements as [
Value, Value,
Value Value
@ -74,7 +71,7 @@ function getConstraintTypeFromSourceHelper(
function getConstraintTypeFromSourceHelper2( function getConstraintTypeFromSourceHelper2(
code: string code: string
): ReturnType<typeof getConstraintType> { ): ReturnType<typeof getConstraintType> {
const ast = parser_wasm(code) const ast = parse(code)
const arg = (ast.body[0] as any).expression.arguments[0] as Value const arg = (ast.body[0] as any).expression.arguments[0] as Value
const fnName = (ast.body[0] as any).expression.callee.name as ToolTip const fnName = (ast.body[0] as any).expression.callee.name as ToolTip
return getConstraintType(arg, fnName) return getConstraintType(arg, fnName)
@ -199,7 +196,7 @@ const part001 = startSketchAt([0, 0])
show(part001) show(part001)
` `
it('should transform the ast', async () => { it('should transform the ast', async () => {
const ast = parser_wasm(inputScript) const ast = parse(inputScript)
const selectionRanges: Selections['codeBasedSelections'] = inputScript const selectionRanges: Selections['codeBasedSelections'] = inputScript
.split('\n') .split('\n')
.filter((ln) => ln.includes('//')) .filter((ln) => ln.includes('//'))
@ -286,7 +283,7 @@ const part001 = startSketchAt([0, 0])
|> angledLineToY([301, myVar], %) // select for vertical constraint 10 |> angledLineToY([301, myVar], %) // select for vertical constraint 10
show(part001) show(part001)
` `
const ast = parser_wasm(inputScript) const ast = parse(inputScript)
const selectionRanges: Selections['codeBasedSelections'] = inputScript const selectionRanges: Selections['codeBasedSelections'] = inputScript
.split('\n') .split('\n')
.filter((ln) => ln.includes('// select for horizontal constraint')) .filter((ln) => ln.includes('// select for horizontal constraint'))
@ -344,7 +341,7 @@ const part001 = startSketchAt([0, 0])
|> yLineTo(myVar, %) // select for vertical constraint 10 |> yLineTo(myVar, %) // select for vertical constraint 10
show(part001) show(part001)
` `
const ast = parser_wasm(inputScript) const ast = parse(inputScript)
const selectionRanges: Selections['codeBasedSelections'] = inputScript const selectionRanges: Selections['codeBasedSelections'] = inputScript
.split('\n') .split('\n')
.filter((ln) => ln.includes('// select for vertical constraint')) .filter((ln) => ln.includes('// select for vertical constraint'))
@ -435,7 +432,7 @@ async function helperThing(
linesOfInterest: string[], linesOfInterest: string[],
constraint: ConstraintType constraint: ConstraintType
): Promise<string> { ): Promise<string> {
const ast = parser_wasm(inputScript) const ast = parse(inputScript)
const selectionRanges: Selections['codeBasedSelections'] = inputScript const selectionRanges: Selections['codeBasedSelections'] = inputScript
.split('\n') .split('\n')
.filter((ln) => .filter((ln) =>
@ -498,7 +495,7 @@ const part001 = startSketchAt([-0.01, -0.05])
|> xLine(-3.43 + 0, %) // full |> xLine(-3.43 + 0, %) // full
|> angledLineOfXLength([243 + 0, 1.2 + 0], %) // full |> angledLineOfXLength([243 + 0, 1.2 + 0], %) // full
show(part001)` show(part001)`
const ast = parser_wasm(code) const ast = parse(code)
const constraintLevels: ReturnType< const constraintLevels: ReturnType<
typeof getConstraintLevelFromSourceRange typeof getConstraintLevelFromSourceRange
>[] = ['full', 'partial', 'free'] >[] = ['full', 'partial', 'free']

View File

@ -6,7 +6,9 @@ import {
Value, Value,
BinaryPart, BinaryPart,
VariableDeclarator, VariableDeclarator,
} from '../abstractSyntaxTreeTypes' PathToNode,
ProgramMemory,
} from '../wasm'
import { import {
getNodeFromPath, getNodeFromPath,
getNodeFromPathCurry, getNodeFromPathCurry,
@ -25,10 +27,8 @@ import {
giveSketchFnCallTag, giveSketchFnCallTag,
} from '../modifyAst' } from '../modifyAst'
import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch' import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
import { PathToNode, ProgramMemory } from '../executor'
import { getSketchSegmentFromSourceRange } from './sketchConstraints' import { getSketchSegmentFromSourceRange } from './sketchConstraints'
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils' import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
import { MemoryItem } from 'wasm-lib/kcl/bindings/MemoryItem'
type LineInputsType = type LineInputsType =
| 'xAbsolute' | 'xAbsolute'

View File

@ -1,6 +1,5 @@
import { parser_wasm } from '../abstractSyntaxTree' import { parse, initPromise } from '../wasm'
import { enginelessExecutor } from '../../lib/testHelpers' import { enginelessExecutor } from '../../lib/testHelpers'
import { initPromise } from '../rust'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -17,9 +16,9 @@ describe('testing angledLineThatIntersects', () => {
}, %) }, %)
const intersect = segEndX('yo2', part001) const intersect = segEndX('yo2', part001)
show(part001)` show(part001)`
const { root } = await enginelessExecutor(parser_wasm(code('-1'))) const { root } = await enginelessExecutor(parse(code('-1')))
expect(root.intersect.value).toBe(1 + Math.sqrt(2)) expect(root.intersect.value).toBe(1 + Math.sqrt(2))
const { root: noOffset } = await enginelessExecutor(parser_wasm(code('0'))) const { root: noOffset } = await enginelessExecutor(parse(code('0')))
expect(noOffset.intersect.value).toBeCloseTo(1) expect(noOffset.intersect.value).toBeCloseTo(1)
}) })
}) })

View File

@ -1,7 +1,12 @@
import { ProgramMemory, Path, SourceRange } from '../executor' import {
import { Program, Value } from '../abstractSyntaxTreeTypes' ProgramMemory,
Path,
SourceRange,
Program,
Value,
PathToNode,
} from '../wasm'
import { ToolTip } from '../../useStore' import { ToolTip } from '../../useStore'
import { PathToNode } from '../executor'
import { EngineCommandManager } from './engineConnection' import { EngineCommandManager } from './engineConnection'
export interface InternalFirstArg { export interface InternalFirstArg {

View File

@ -1,5 +1,4 @@
import { lexer, asyncLexer } from './tokeniser' import { lexer, initPromise } from './wasm'
import { initPromise } from './rust'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -10,9 +9,9 @@ describe('testing lexer', () => {
const code3 = `const yo = 45 /* this is a comment const code3 = `const yo = 45 /* this is a comment
const ya = 6 */ const ya = 6 */
const yi=45` const yi=45`
expect(await asyncLexer(code)).toEqual(lexer(code)) expect(lexer(code)).toEqual(lexer(code))
expect(await asyncLexer(code2)).toEqual(lexer(code2)) expect(lexer(code2)).toEqual(lexer(code2))
expect(await asyncLexer(code3)).toEqual(lexer(code3)) expect(lexer(code3)).toEqual(lexer(code3))
}) })
it('test lexer', () => { it('test lexer', () => {
expect(stringSummaryLexer('1 + 2')).toEqual([ expect(stringSummaryLexer('1 + 2')).toEqual([

View File

@ -1,28 +0,0 @@
import { lexer_js } from '../wasm-lib/pkg/wasm_lib'
import { initPromise } from './rust'
import { Token } from '../wasm-lib/kcl/bindings/Token'
export type { Token } from '../wasm-lib/kcl/bindings/Token'
export async function asyncLexer(str: string): Promise<Token[]> {
await initPromise
try {
const tokens: Token[] = lexer_js(str)
return tokens
} catch (e) {
// TODO: do something real with the error.
console.log('lexer error', e)
throw e
}
}
export function lexer(str: string): Token[] {
try {
const tokens: Token[] = lexer_js(str)
return tokens
} catch (e) {
// TODO: do something real with the error.
console.log('lexer error', e)
throw e
}
}

View File

@ -1,6 +1,5 @@
import { Selections, StoreState } from '../useStore' import { Selections, StoreState } from '../useStore'
import { Program } from './abstractSyntaxTreeTypes' import { Program, PathToNode } from './wasm'
import { PathToNode } from './executor'
import { getNodeFromPath } from './queryAst' import { getNodeFromPath } from './queryAst'
export function updateCursors( export function updateCursors(

215
src/lang/wasm.ts Normal file
View File

@ -0,0 +1,215 @@
import init, {
parse_wasm,
recast_wasm,
execute_wasm,
lexer_wasm,
modify_ast_for_sketch_wasm,
} from '../wasm-lib/pkg/wasm_lib'
import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import {
EngineCommandManager,
ArtifactMap,
SourceRangeMap,
} from './std/engineConnection'
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
import type { Program } from '../wasm-lib/kcl/bindings/Program'
import type { Token } from '../wasm-lib/kcl/bindings/Token'
export type { Program } from '../wasm-lib/kcl/bindings/Program'
export type { Value } from '../wasm-lib/kcl/bindings/Value'
export type { ObjectExpression } from '../wasm-lib/kcl/bindings/ObjectExpression'
export type { MemberExpression } from '../wasm-lib/kcl/bindings/MemberExpression'
export type { PipeExpression } from '../wasm-lib/kcl/bindings/PipeExpression'
export type { VariableDeclaration } from '../wasm-lib/kcl/bindings/VariableDeclaration'
export type { PipeSubstitution } from '../wasm-lib/kcl/bindings/PipeSubstitution'
export type { Identifier } from '../wasm-lib/kcl/bindings/Identifier'
export type { UnaryExpression } from '../wasm-lib/kcl/bindings/UnaryExpression'
export type { BinaryExpression } from '../wasm-lib/kcl/bindings/BinaryExpression'
export type { ReturnStatement } from '../wasm-lib/kcl/bindings/ReturnStatement'
export type { ExpressionStatement } from '../wasm-lib/kcl/bindings/ExpressionStatement'
export type { CallExpression } from '../wasm-lib/kcl/bindings/CallExpression'
export type { VariableDeclarator } from '../wasm-lib/kcl/bindings/VariableDeclarator'
export type { BinaryPart } from '../wasm-lib/kcl/bindings/BinaryPart'
export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
export type SyntaxType =
| 'Program'
| 'ExpressionStatement'
| 'BinaryExpression'
| 'CallExpression'
| 'Identifier'
| 'ReturnStatement'
| 'VariableDeclaration'
| 'VariableDeclarator'
| 'MemberExpression'
| 'ArrayExpression'
| 'ObjectExpression'
| 'ObjectProperty'
| 'FunctionExpression'
| 'PipeExpression'
| 'PipeSubstitution'
| 'Literal'
| 'NonCodeNode'
| 'UnaryExpression'
export type { SourceRange } from '../wasm-lib/kcl/bindings/SourceRange'
export type { Position } from '../wasm-lib/kcl/bindings/Position'
export type { Rotation } from '../wasm-lib/kcl/bindings/Rotation'
export type { Path } from '../wasm-lib/kcl/bindings/Path'
export type { SketchGroup } from '../wasm-lib/kcl/bindings/SketchGroup'
export type { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
export type { ExtrudeSurface } from '../wasm-lib/kcl/bindings/ExtrudeSurface'
// Initialise the wasm module.
const initialise = async () => {
const baseUrl =
typeof window === 'undefined'
? 'http://127.0.0.1:3000'
: window.location.origin.includes('tauri://localhost')
? 'tauri://localhost'
: window.location.origin.includes('localhost')
? 'http://localhost:3000'
: window.location.origin && window.location.origin !== 'null'
? window.location.origin
: 'http://localhost:3000'
const fullUrl = baseUrl + '/wasm_lib_bg.wasm'
const input = await fetch(fullUrl)
const buffer = await input.arrayBuffer()
return init(buffer)
}
export const initPromise = initialise()
export const rangeTypeFix = (ranges: number[][]): [number, number][] =>
ranges.map(([start, end]) => [start, end])
export const parse = (code: string): Program => {
try {
const program: Program = parse_wasm(code)
return program
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}
export type PathToNode = [string | number, string][]
interface Memory {
[key: string]: MemoryItem
}
export interface ProgramMemory {
root: Memory
return: ProgramReturn | null
}
export const executor = async (
node: Program,
programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager,
// work around while the gemotry is still be stored on the frontend
// will be removed when the stream UI is added.
tempMapCallback: (a: {
artifactMap: ArtifactMap
sourceRangeMap: SourceRangeMap
}) => void = () => {}
): Promise<ProgramMemory> => {
engineCommandManager.startNewSession()
const _programMemory = await _executor(
node,
programMemory,
engineCommandManager
)
const { artifactMap, sourceRangeMap } =
await engineCommandManager.waitForAllCommands(node, _programMemory)
tempMapCallback({ artifactMap, sourceRangeMap })
engineCommandManager.endSession()
return _programMemory
}
export const _executor = async (
node: Program,
programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager
): Promise<ProgramMemory> => {
try {
const memory: ProgramMemory = await execute_wasm(
JSON.stringify(node),
JSON.stringify(programMemory),
engineCommandManager
)
return memory
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}
export const recast = (ast: Program): string => {
try {
const s: string = recast_wasm(JSON.stringify(ast))
return s
} catch (e) {
// TODO: do something real with the error.
console.log('recast error', e)
throw e
}
}
export function lexer(str: string): Token[] {
try {
const tokens: Token[] = lexer_wasm(str)
return tokens
} catch (e) {
// TODO: do something real with the error.
console.log('lexer error', e)
throw e
}
}
export const modifyAstForSketch = async (
engineCommandManager: EngineCommandManager,
ast: Program,
variableName: string,
engineId: string
): Promise<Program> => {
try {
const updatedAst: Program = await modify_ast_for_sketch_wasm(
engineCommandManager,
JSON.stringify(ast),
variableName,
engineId
)
return updatedAst
} catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString())
const kclError = new KCLError(
parsed.kind,
parsed.msg,
rangeTypeFix(parsed.sourceRanges)
)
console.log(kclError)
throw kclError
}
}

View File

@ -1,10 +1,8 @@
import { Program } from '../lang/abstractSyntaxTreeTypes' import { Program, ProgramMemory, _executor, SourceRange } from '../lang/wasm'
import { ProgramMemory, _executor } from '../lang/executor'
import { import {
EngineCommandManager, EngineCommandManager,
EngineCommand, EngineCommand,
} from '../lang/std/engineConnection' } from '../lang/std/engineConnection'
import { SourceRange } from 'lang/executor'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
type WebSocketResponse = Models['OkWebSocketResponseData_type'] type WebSocketResponse = Models['OkWebSocketResponseData_type']

View File

@ -1,5 +1,5 @@
import { isOverlap, roundOff } from './utils' import { isOverlap, roundOff } from './utils'
import { SourceRange } from '../lang/executor' import { SourceRange } from '../lang/wasm'
describe('testing isOverlapping', () => { describe('testing isOverlapping', () => {
testBothOrders([0, 3], [3, 10]) testBothOrders([0, 3], [3, 10])

View File

@ -1,4 +1,4 @@
import { SourceRange } from '../lang/executor' import { SourceRange } from '../lang/wasm'
export function isOverlap(a: SourceRange, b: SourceRange) { export function isOverlap(a: SourceRange, b: SourceRange) {
const [startingRange, secondRange] = a[0] < b[0] ? [a, b] : [b, a] const [startingRange, secondRange] = a[0] < b[0] ? [a, b] : [b, a]

View File

@ -1,23 +1,23 @@
import { create } from 'zustand' import { create } from 'zustand'
import { persist } from 'zustand/middleware' import { persist } from 'zustand/middleware'
import { addLineHighlight, EditorView } from './editor/highlightextension' import { addLineHighlight, EditorView } from './editor/highlightextension'
import { parser_wasm } from './lang/abstractSyntaxTree'
import { Program } from './lang/abstractSyntaxTreeTypes'
import { getNodeFromPath } from './lang/queryAst'
import { enginelessExecutor } from './lib/testHelpers'
import { import {
parse,
Program,
_executor,
recast,
ProgramMemory, ProgramMemory,
Position, Position,
PathToNode, PathToNode,
Rotation, Rotation,
SourceRange, SourceRange,
} from './lang/executor' } from './lang/wasm'
import { recast } from './lang/recast' import { getNodeFromPath } from './lang/queryAst'
import { enginelessExecutor } from './lib/testHelpers'
import { EditorSelection } from '@codemirror/state' import { EditorSelection } from '@codemirror/state'
import { EngineCommandManager } from './lang/std/engineConnection' import { EngineCommandManager } from './lang/std/engineConnection'
import { KCLError } from './lang/errors' import { KCLError } from './lang/errors'
import { deferExecution } from 'lib/utils' import { deferExecution } from 'lib/utils'
import { _executor } from './lang/executor'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { engineCommandManager } from './lang/std/engineConnection' import { engineCommandManager } from './lang/std/engineConnection'
@ -366,7 +366,7 @@ export const useStore = create<StoreState>()(
{ focusPath, callBack = () => {} } = {} { focusPath, callBack = () => {} } = {}
) => { ) => {
const newCode = recast(ast) const newCode = recast(ast)
const astWithUpdatedSource = parser_wasm(newCode) const astWithUpdatedSource = parse(newCode)
callBack(astWithUpdatedSource) callBack(astWithUpdatedSource)
set({ set({
@ -422,7 +422,7 @@ export const useStore = create<StoreState>()(
}, },
formatCode: async () => { formatCode: async () => {
const code = get().code const code = get().code
const ast = parser_wasm(code) const ast = parse(code)
const newCode = recast(ast) const newCode = recast(ast)
set({ code: newCode, ast }) set({ code: newCode, ast })
}, },
@ -527,7 +527,7 @@ async function executeCode({
> { > {
let ast: Program let ast: Program
try { try {
ast = parser_wasm(code) ast = parse(code)
} catch (e) { } catch (e) {
let errors: KCLError[] = [] let errors: KCLError[] = []
let logs: string[] = [JSON.stringify(e)] let logs: string[] = [JSON.stringify(e)]

View File

@ -258,6 +258,23 @@ impl Program {
} }
} }
/// Replace a value with the new value, use the source range for matching the exact value.
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for item in &mut self.body {
match item {
BodyItem::ExpressionStatement(ref mut expression_statement) => expression_statement
.expression
.replace_value(source_range, new_value.clone()),
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
variable_declaration.replace_value(source_range, new_value.clone())
}
BodyItem::ReturnStatement(ref mut return_statement) => {
return_statement.argument.replace_value(source_range, new_value.clone())
}
}
}
}
/// Get the variable declaration with the given name. /// Get the variable declaration with the given name.
pub fn get_variable(&self, name: &str) -> Option<&VariableDeclarator> { pub fn get_variable(&self, name: &str) -> Option<&VariableDeclarator> {
for item in &self.body { for item in &self.body {
@ -393,6 +410,27 @@ impl Value {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
if source_range == self.clone().into() {
*self = new_value;
return;
}
match self {
Value::BinaryExpression(ref mut bin_exp) => bin_exp.replace_value(source_range, new_value),
Value::ArrayExpression(ref mut array_exp) => array_exp.replace_value(source_range, new_value),
Value::ObjectExpression(ref mut obj_exp) => obj_exp.replace_value(source_range, new_value),
Value::MemberExpression(_) => {}
Value::Literal(_) => {}
Value::FunctionExpression(ref mut func_exp) => func_exp.replace_value(source_range, new_value),
Value::CallExpression(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
Value::Identifier(_) => {}
Value::PipeExpression(ref mut pipe_exp) => pipe_exp.replace_value(source_range, new_value),
Value::UnaryExpression(ref mut unary_exp) => unary_exp.replace_value(source_range, new_value),
Value::PipeSubstitution(_) => {}
}
}
pub fn start(&self) -> usize { pub fn start(&self) -> usize {
match self { match self {
Value::Literal(literal) => literal.start(), Value::Literal(literal) => literal.start(),
@ -538,6 +576,23 @@ impl BinaryPart {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
match self {
BinaryPart::Literal(_) => {}
BinaryPart::Identifier(_) => {}
BinaryPart::BinaryExpression(ref mut binary_expression) => {
binary_expression.replace_value(source_range, new_value)
}
BinaryPart::CallExpression(ref mut call_expression) => {
call_expression.replace_value(source_range, new_value)
}
BinaryPart::UnaryExpression(ref mut unary_expression) => {
unary_expression.replace_value(source_range, new_value)
}
BinaryPart::MemberExpression(_) => {}
}
}
fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String { fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
match &self { match &self {
BinaryPart::Literal(literal) => literal.recast(), BinaryPart::Literal(literal) => literal.recast(),
@ -801,6 +856,12 @@ impl CallExpression {
}) })
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for arg in &mut self.arguments {
arg.replace_value(source_range, new_value.clone());
}
}
fn recast(&self, options: &FormatOptions, indentation_level: usize, is_in_pipe: bool) -> String { fn recast(&self, options: &FormatOptions, indentation_level: usize, is_in_pipe: bool) -> String {
format!( format!(
"{}({})", "{}({})",
@ -1014,6 +1075,12 @@ impl VariableDeclaration {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for declaration in &mut self.declarations {
declaration.init.replace_value(source_range, new_value.clone());
}
}
/// Returns a value that includes the given character position. /// Returns a value that includes the given character position.
pub fn get_value_for_position(&self, pos: usize) -> Option<&Value> { pub fn get_value_for_position(&self, pos: usize) -> Option<&Value> {
for declaration in &self.declarations { for declaration in &self.declarations {
@ -1367,6 +1434,12 @@ impl ArrayExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for element in &mut self.elements {
element.replace_value(source_range, new_value.clone());
}
}
pub fn get_constraint_level(&self) -> ConstraintLevel { pub fn get_constraint_level(&self) -> ConstraintLevel {
if self.elements.is_empty() { if self.elements.is_empty() {
return ConstraintLevel::Ignore { return ConstraintLevel::Ignore {
@ -1517,6 +1590,12 @@ impl ObjectExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for property in &mut self.properties {
property.value.replace_value(source_range, new_value.clone());
}
}
pub fn get_constraint_level(&self) -> ConstraintLevel { pub fn get_constraint_level(&self) -> ConstraintLevel {
if self.properties.is_empty() { if self.properties.is_empty() {
return ConstraintLevel::Ignore { return ConstraintLevel::Ignore {
@ -1961,6 +2040,11 @@ impl BinaryExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
self.left.replace_value(source_range, new_value.clone());
self.right.replace_value(source_range, new_value);
}
pub fn get_constraint_level(&self) -> ConstraintLevel { pub fn get_constraint_level(&self) -> ConstraintLevel {
let left_constraint_level = self.left.get_constraint_level(); let left_constraint_level = self.left.get_constraint_level();
let right_constraint_level = self.right.get_constraint_level(); let right_constraint_level = self.right.get_constraint_level();
@ -2183,6 +2267,10 @@ impl UnaryExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
self.argument.replace_value(source_range, new_value);
}
pub fn get_constraint_level(&self) -> ConstraintLevel { pub fn get_constraint_level(&self) -> ConstraintLevel {
self.argument.get_constraint_level() self.argument.get_constraint_level()
} }
@ -2278,6 +2366,12 @@ impl PipeExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
for value in &mut self.body {
value.replace_value(source_range, new_value.clone());
}
}
pub fn get_constraint_level(&self) -> ConstraintLevel { pub fn get_constraint_level(&self) -> ConstraintLevel {
if self.body.is_empty() { if self.body.is_empty() {
return ConstraintLevel::Ignore { return ConstraintLevel::Ignore {
@ -2420,6 +2514,10 @@ impl FunctionExpression {
} }
} }
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Value) {
self.body.replace_value(source_range, new_value);
}
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String { pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
// We don't want to end with a new line inside nested functions. // We don't want to end with a new line inside nested functions.
let mut new_options = options.clone(); let mut new_options = options.clone();

View File

@ -36,7 +36,7 @@ pub async fn execute_wasm(
// wasm_bindgen wrapper for execute // wasm_bindgen wrapper for execute
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[wasm_bindgen] #[wasm_bindgen]
pub async fn modify_ast_for_sketch( pub async fn modify_ast_for_sketch_wasm(
manager: kcl_lib::engine::conn_wasm::EngineCommandManager, manager: kcl_lib::engine::conn_wasm::EngineCommandManager,
program_str: &str, program_str: &str,
sketch_name: &str, sketch_name: &str,
@ -83,13 +83,13 @@ pub fn deserialize_files(data: &[u8]) -> Result<JsValue, JsError> {
// wasm_bindgen wrapper for lexer // wasm_bindgen wrapper for lexer
// test for this function and by extension lexer are done in javascript land src/lang/tokeniser.test.ts // test for this function and by extension lexer are done in javascript land src/lang/tokeniser.test.ts
#[wasm_bindgen] #[wasm_bindgen]
pub fn lexer_js(js: &str) -> Result<JsValue, JsError> { pub fn lexer_wasm(js: &str) -> Result<JsValue, JsError> {
let tokens = kcl_lib::token::lexer(js); let tokens = kcl_lib::token::lexer(js);
Ok(JsValue::from_serde(&tokens)?) Ok(JsValue::from_serde(&tokens)?)
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn parse_js(js: &str) -> Result<JsValue, String> { pub fn parse_wasm(js: &str) -> Result<JsValue, String> {
let tokens = kcl_lib::token::lexer(js); let tokens = kcl_lib::token::lexer(js);
let parser = kcl_lib::parser::Parser::new(tokens); let parser = kcl_lib::parser::Parser::new(tokens);
let program = parser.ast().map_err(String::from)?; let program = parser.ast().map_err(String::from)?;