Ensure exceptions in the executor are handled properly (#239)

Right now, if the executor throws a KCLError (e.g. for "variable name is not defined" errors), they aren't being caught by the .catch or the try/catch block in asyncWrap. This PR fixes it.

Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
This commit is contained in:
Adam Chalmers
2023-08-07 20:33:38 -05:00
committed by GitHub
parent 7a537eea8e
commit a986f76e70
3 changed files with 49 additions and 36 deletions

View File

@ -9,7 +9,12 @@ import { DebugPanel } from './components/DebugPanel'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { asyncLexer } from './lang/tokeniser' import { asyncLexer } from './lang/tokeniser'
import { abstractSyntaxTree } from './lang/abstractSyntaxTree' import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
import { _executor, ExtrudeGroup, SketchGroup } from './lang/executor' import {
_executor,
ProgramMemory,
ExtrudeGroup,
SketchGroup,
} from './lang/executor'
import CodeMirror from '@uiw/react-codemirror' import CodeMirror from '@uiw/react-codemirror'
import { langs } from '@uiw/codemirror-extensions-langs' import { langs } from '@uiw/codemirror-extensions-langs'
import { linter, lintGutter } from '@codemirror/lint' import { linter, lintGutter } from '@codemirror/lint'
@ -234,7 +239,7 @@ export function App() {
} }
engineCommandManager.startNewSession() engineCommandManager.startNewSession()
setEngineCommandManager(engineCommandManager) setEngineCommandManager(engineCommandManager)
_executor( const programMemory = await _executor(
_ast, _ast,
{ {
root: { root: {
@ -276,7 +281,8 @@ export function App() {
engineCommandManager, engineCommandManager,
{ bodyType: 'root' }, { bodyType: 'root' },
[] []
).then(async (programMemory) => { )
const { artifactMap, sourceRangeMap } = const { artifactMap, sourceRangeMap } =
await engineCommandManager.waitForAllCommands() await engineCommandManager.waitForAllCommands()
@ -292,23 +298,11 @@ export function App() {
engineCommandManager.onClick(({ id, type }) => { engineCommandManager.onClick(({ id, type }) => {
setCursor2({ range: sourceRangeMap[id], type }) setCursor2({ range: sourceRangeMap[id], type })
}) })
if (programMemory !== undefined) {
setProgramMemory(programMemory) setProgramMemory(programMemory)
const geos = programMemory?.return
?.map(({ name }: { name: string }) => {
const artifact = programMemory?.root?.[name]
if (
artifact.type === 'extrudeGroup' ||
artifact.type === 'sketchGroup'
) {
return artifact
} }
return null
})
.filter((a) => a) as (ExtrudeGroup | SketchGroup)[]
// console.log(programMemory)
setError() setError()
})
} catch (e: any) { } catch (e: any) {
if (e instanceof KCLError) { if (e instanceof KCLError) {
addKCLError(e) addKCLError(e)

View File

@ -6,6 +6,7 @@ import { ProgramMemory, Path, SketchGroup } from './executor'
import { initPromise } from './rust' import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
import { vi } from 'vitest' import { vi } from 'vitest'
import { KCLUndefinedValueError } from './errors'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -440,6 +441,22 @@ describe('testing math operators', () => {
}) })
}) })
describe('Testing Errors', () => {
it('should throw an error when a variable is not defined', async () => {
const code = `const myVar = 5
const theExtrude = startSketchAt([0, 0])
|> line([-2.4, 5], %)
|> line([-0.76], myVarZ, %)
|> line([5,5], %)
|> close(%)
|> extrude(4, %)
show(theExtrude)`
await expect(exe(code)).rejects.toEqual(
new KCLUndefinedValueError('Memory item myVarZ not found', [[100, 106]])
)
})
})
// helpers // helpers
async function exe( async function exe(

View File

@ -222,9 +222,11 @@ export const _executor = async (
} }
const { body } = node const { body } = node
const proms: Promise<any>[] = [] const proms: Promise<any>[] = []
body.forEach(async (statement, bodyIndex) => { for (let bodyIndex = 0; bodyIndex < body.length; bodyIndex++) {
const statement = body[bodyIndex]
if (statement.type === 'VariableDeclaration') { if (statement.type === 'VariableDeclaration') {
statement.declarations.forEach(async (declaration, index) => { for (let index = 0; index < statement.declarations.length; index++) {
const declaration = statement.declarations[index]
const variableName = declaration.id.name const variableName = declaration.id.name
const pathToNode: PathToNode = [ const pathToNode: PathToNode = [
...previousPathToNode, ...previousPathToNode,
@ -520,7 +522,7 @@ export const _executor = async (
[[declaration.start, declaration.end]] [[declaration.start, declaration.end]]
) )
} }
}) }
} else if (statement.type === 'ExpressionStatement') { } else if (statement.type === 'ExpressionStatement') {
const expression = statement.expression const expression = statement.expression
if (expression.type === 'CallExpression') { if (expression.type === 'CallExpression') {
@ -560,7 +562,7 @@ export const _executor = async (
_programMemory.return = await prom _programMemory.return = await prom
} }
} }
}) }
await Promise.all(proms) await Promise.all(proms)
return _programMemory return _programMemory
} }