2022-11-26 08:34:23 +11:00
|
|
|
import fs from 'node:fs'
|
2022-11-14 14:04:23 +11:00
|
|
|
|
2022-11-26 08:34:23 +11:00
|
|
|
import { abstractSyntaxTree } from './abstractSyntaxTree'
|
|
|
|
import { lexer } from './tokeniser'
|
2023-06-22 16:43:33 +10:00
|
|
|
import { ProgramMemory, Path, SketchGroup } from './executor'
|
2023-02-21 09:42:41 +11:00
|
|
|
import { initPromise } from './rust'
|
2023-07-10 15:15:07 +10:00
|
|
|
import { enginelessExecutor } from '../lib/testHelpers'
|
2023-08-08 10:50:27 +10:00
|
|
|
import { vi } from 'vitest'
|
2023-08-07 20:33:38 -05:00
|
|
|
import { KCLUndefinedValueError } from './errors'
|
2023-02-21 09:42:41 +11:00
|
|
|
|
|
|
|
beforeAll(() => initPromise)
|
2022-11-14 14:04:23 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
describe('test executor', () => {
|
|
|
|
it('test assigning two variables, the second summing with the first', async () => {
|
2022-11-14 14:04:23 +11:00
|
|
|
const code = `const myVar = 5
|
2022-11-26 08:34:23 +11:00
|
|
|
const newVar = myVar + 1`
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar.value).toBe(5)
|
|
|
|
expect(root.newVar.value).toBe(6)
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('test assigning a var with a string', async () => {
|
2022-11-26 08:34:23 +11:00
|
|
|
const code = `const myVar = "a str"`
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar.value).toBe('a str')
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('test assigning a var by cont concatenating two strings string execute', async () => {
|
2022-11-20 09:41:21 +11:00
|
|
|
const code = fs.readFileSync(
|
2022-11-26 08:34:23 +11:00
|
|
|
'./src/lang/testExamples/variableDeclaration.cado',
|
|
|
|
'utf-8'
|
|
|
|
)
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar.value).toBe('a str another str')
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('test with function call', async () => {
|
2022-11-14 14:04:23 +11:00
|
|
|
const code = `
|
|
|
|
const myVar = "hello"
|
2022-11-26 08:34:23 +11:00
|
|
|
log(5, myVar)`
|
2023-01-08 16:37:31 +11:00
|
|
|
const programMemoryOverride: ProgramMemory['root'] = {
|
|
|
|
log: {
|
|
|
|
type: 'userVal',
|
2023-08-08 10:50:27 +10:00
|
|
|
value: vi.fn(),
|
2023-01-08 16:37:31 +11:00
|
|
|
__meta: [
|
|
|
|
{
|
|
|
|
sourceRange: [0, 0],
|
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2022-11-26 08:34:23 +11:00
|
|
|
}
|
2023-07-10 15:15:07 +10:00
|
|
|
const { root } = await enginelessExecutor(abstractSyntaxTree(lexer(code)), {
|
2022-11-20 09:41:21 +11:00
|
|
|
root: programMemoryOverride,
|
2023-06-22 16:43:33 +10:00
|
|
|
pendingMemory: {},
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar.value).toBe('hello')
|
|
|
|
expect(programMemoryOverride.log.value).toHaveBeenCalledWith(5, 'hello')
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('fn funcN = () => {} execute', async () => {
|
|
|
|
const { root } = await exe(
|
2022-11-20 09:41:21 +11:00
|
|
|
[
|
2022-11-26 08:34:23 +11:00
|
|
|
'fn funcN = (a, b) => {',
|
|
|
|
' return a + b',
|
|
|
|
'}',
|
|
|
|
'const theVar = 60',
|
|
|
|
'const magicNum = funcN(9, theVar)',
|
|
|
|
].join('\n')
|
|
|
|
)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.theVar.value).toBe(60)
|
|
|
|
expect(root.magicNum.value).toBe(69)
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('sketch declaration', async () => {
|
2023-02-12 10:56:45 +11:00
|
|
|
let code = `const mySketch = startSketchAt([0,0])
|
|
|
|
|> lineTo({to: [0,2], tag: "myPath"}, %)
|
|
|
|
|> lineTo([2,3], %)
|
|
|
|
|> lineTo({ to: [5,-1], tag: "rightPath" }, %)
|
|
|
|
// |> close(%)
|
2022-11-21 09:16:24 +11:00
|
|
|
show(mySketch)
|
2022-11-26 08:34:23 +11:00
|
|
|
`
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root, return: _return } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
// geo is three js buffer geometry and is very bloated to have in tests
|
2023-07-10 15:15:07 +10:00
|
|
|
const minusGeo = root.mySketch.value
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(minusGeo).toEqual([
|
|
|
|
{
|
|
|
|
type: 'toPoint',
|
|
|
|
to: [0, 2],
|
2023-02-12 10:56:45 +11:00
|
|
|
from: [0, 0],
|
2023-01-08 16:37:31 +11:00
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [43, 80],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '37333036-3033-4432-b530-643030303837',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
name: 'myPath',
|
|
|
|
},
|
2022-11-23 21:28:38 +11:00
|
|
|
{
|
2023-01-08 16:37:31 +11:00
|
|
|
type: 'toPoint',
|
|
|
|
to: [2, 3],
|
|
|
|
from: [0, 2],
|
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [86, 102],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '32343136-3330-4134-a462-376437386365',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'toPoint',
|
|
|
|
to: [5, -1],
|
|
|
|
from: [2, 3],
|
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [108, 151],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '32306132-6130-4138-b832-636363326330',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
name: 'rightPath',
|
|
|
|
},
|
2022-11-26 08:34:23 +11:00
|
|
|
])
|
2022-12-30 14:09:07 +11:00
|
|
|
// expect(root.mySketch.sketch[0]).toEqual(root.mySketch.sketch[4].firstPath)
|
2022-11-21 09:16:24 +11:00
|
|
|
expect(_return).toEqual([
|
|
|
|
{
|
2022-11-26 08:34:23 +11:00
|
|
|
type: 'Identifier',
|
2023-02-12 10:56:45 +11:00
|
|
|
start: 174,
|
|
|
|
end: 182,
|
2022-11-26 08:34:23 +11:00
|
|
|
name: 'mySketch',
|
2022-11-21 09:16:24 +11:00
|
|
|
},
|
2022-11-26 08:34:23 +11:00
|
|
|
])
|
|
|
|
})
|
2022-12-03 22:50:46 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
it('pipe binary expression into call expression', async () => {
|
2022-12-03 22:50:46 +11:00
|
|
|
const code = [
|
|
|
|
'fn myFn = (a) => { return a + 1 }',
|
|
|
|
'const myVar = 5 + 1 |> myFn(%)',
|
|
|
|
].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar.value).toBe(7)
|
2022-12-03 22:50:46 +11:00
|
|
|
})
|
|
|
|
|
2023-07-10 15:15:07 +10:00
|
|
|
// Enable rotations #152
|
|
|
|
// it('rotated sketch', async () => {
|
|
|
|
// const code = [
|
|
|
|
// 'const mySk1 = startSketchAt([0,0])',
|
|
|
|
// ' |> lineTo([1,1], %)',
|
|
|
|
// ' |> lineTo({to: [0, 1], tag: "myPath"}, %)',
|
|
|
|
// ' |> lineTo([1, 1], %)',
|
|
|
|
// 'const rotated = rx(90, mySk1)',
|
|
|
|
// ].join('\n')
|
|
|
|
// const { root } = await exe(code)
|
|
|
|
// expect(root.mySk1.value).toHaveLength(3)
|
|
|
|
// expect(root?.rotated?.type).toBe('sketchGroup')
|
|
|
|
// if (
|
|
|
|
// root?.mySk1?.type !== 'sketchGroup' ||
|
|
|
|
// root?.rotated?.type !== 'sketchGroup'
|
|
|
|
// )
|
|
|
|
// throw new Error('not a sketch group')
|
|
|
|
// expect(root.mySk1.rotation).toEqual([0, 0, 0, 1])
|
|
|
|
// expect(root.rotated.rotation.map((a) => a.toFixed(4))).toEqual([
|
|
|
|
// '0.7071',
|
|
|
|
// '0.0000',
|
|
|
|
// '0.0000',
|
|
|
|
// '0.7071',
|
|
|
|
// ])
|
|
|
|
// })
|
2022-12-04 08:16:04 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
it('execute pipe sketch into call expression', async () => {
|
2023-07-10 15:15:07 +10:00
|
|
|
// Enable rotations #152
|
2022-12-04 08:16:04 +11:00
|
|
|
const code = [
|
2023-02-12 10:56:45 +11:00
|
|
|
'const mySk1 = startSketchAt([0,0])',
|
|
|
|
' |> lineTo([1,1], %)',
|
|
|
|
' |> lineTo({to: [0, 1], tag: "myPath"}, %)',
|
|
|
|
' |> lineTo([1,1], %)',
|
2023-07-10 15:15:07 +10:00
|
|
|
// ' |> rx(90, %)',
|
2022-12-04 08:16:04 +11:00
|
|
|
].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-07-10 15:15:07 +10:00
|
|
|
expect(root.mySk1).toEqual({
|
2023-01-08 16:37:31 +11:00
|
|
|
type: 'sketchGroup',
|
2023-03-17 08:27:40 +11:00
|
|
|
start: {
|
|
|
|
type: 'base',
|
|
|
|
to: [0, 0],
|
|
|
|
from: [0, 0],
|
|
|
|
__geoMeta: {
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '37663863-3664-4366-a637-623739336334',
|
2023-03-17 08:27:40 +11:00
|
|
|
sourceRange: [14, 34],
|
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
},
|
2023-01-08 16:37:31 +11:00
|
|
|
value: [
|
2022-12-04 08:16:04 +11:00
|
|
|
{
|
|
|
|
type: 'toPoint',
|
|
|
|
to: [1, 1],
|
2023-01-08 16:37:31 +11:00
|
|
|
from: [0, 0],
|
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [40, 56],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '34356231-3362-4363-b935-393033353034',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
2022-12-04 08:16:04 +11:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'toPoint',
|
|
|
|
to: [0, 1],
|
2023-01-08 16:37:31 +11:00
|
|
|
from: [1, 1],
|
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [62, 100],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '39623339-3538-4366-b633-356630326639',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
2022-12-04 08:16:04 +11:00
|
|
|
name: 'myPath',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'toPoint',
|
|
|
|
to: [1, 1],
|
2023-01-08 16:37:31 +11:00
|
|
|
from: [0, 1],
|
|
|
|
__geoMeta: {
|
2023-02-12 10:56:45 +11:00
|
|
|
sourceRange: [106, 122],
|
2023-06-22 16:43:33 +10:00
|
|
|
id: '30636135-6232-4335-b665-366562303161',
|
2023-01-08 16:37:31 +11:00
|
|
|
pathToNode: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
position: [0, 0, 0],
|
2023-07-10 15:15:07 +10:00
|
|
|
rotation: [0, 0, 0, 1],
|
|
|
|
id: '30376661-3039-4965-b532-653665313731',
|
|
|
|
__meta: [{ sourceRange: [14, 34], pathToNode: [] }],
|
2022-12-04 08:16:04 +11:00
|
|
|
})
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('execute array expression', async () => {
|
2022-12-30 21:53:50 +11:00
|
|
|
const code = ['const three = 3', "const yo = [1, '2', three, 4 + 5]"].join(
|
|
|
|
'\n'
|
|
|
|
)
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
// TODO path to node is probably wrong here, zero indexes are not correct
|
2022-12-30 21:53:50 +11:00
|
|
|
expect(root).toEqual({
|
2023-01-08 16:37:31 +11:00
|
|
|
three: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: 3,
|
|
|
|
__meta: [
|
|
|
|
{
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: [
|
|
|
|
['body', ''],
|
|
|
|
[0, 'index'],
|
|
|
|
['declarations', 'VariableDeclaration'],
|
|
|
|
[0, 'index'],
|
|
|
|
['init', 'VariableDeclaration'],
|
|
|
|
],
|
2023-01-08 16:37:31 +11:00
|
|
|
sourceRange: [14, 15],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
yo: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: [1, '2', 3, 9],
|
|
|
|
__meta: [
|
|
|
|
{
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: [
|
|
|
|
['body', ''],
|
|
|
|
[1, 'index'],
|
|
|
|
['declarations', 'VariableDeclaration'],
|
|
|
|
[0, 'index'],
|
|
|
|
['init', 'VariableDeclaration'],
|
|
|
|
],
|
2023-01-08 16:37:31 +11:00
|
|
|
sourceRange: [27, 49],
|
|
|
|
},
|
|
|
|
{
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: [
|
|
|
|
['body', ''],
|
|
|
|
[0, 'index'],
|
|
|
|
['declarations', 'VariableDeclaration'],
|
|
|
|
[0, 'index'],
|
|
|
|
['init', 'VariableDeclaration'],
|
|
|
|
],
|
2023-01-08 16:37:31 +11:00
|
|
|
sourceRange: [14, 15],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2022-12-30 21:53:50 +11:00
|
|
|
})
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('execute object expression', async () => {
|
2023-01-01 21:48:30 +11:00
|
|
|
const code = [
|
|
|
|
'const three = 3',
|
|
|
|
"const yo = {aStr: 'str', anum: 2, identifier: three, binExp: 4 + 5}",
|
|
|
|
].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.yo).toEqual({
|
|
|
|
type: 'userVal',
|
2023-04-01 16:47:00 +11:00
|
|
|
value: { aStr: 'str', anum: 2, identifier: 3, binExp: 9 },
|
2023-01-08 16:37:31 +11:00
|
|
|
__meta: [
|
|
|
|
{
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: [
|
|
|
|
['body', ''],
|
|
|
|
[1, 'index'],
|
|
|
|
['declarations', 'VariableDeclaration'],
|
|
|
|
[0, 'index'],
|
|
|
|
['init', 'VariableDeclaration'],
|
|
|
|
],
|
2023-01-08 16:37:31 +11:00
|
|
|
sourceRange: [27, 83],
|
|
|
|
},
|
|
|
|
],
|
2023-01-01 21:48:30 +11:00
|
|
|
})
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('execute memberExpression', async () => {
|
2023-01-03 19:41:27 +11:00
|
|
|
const code = ["const yo = {a: {b: '123'}}", "const myVar = yo.a['b']"].join(
|
|
|
|
'\n'
|
|
|
|
)
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-08 16:37:31 +11:00
|
|
|
expect(root.myVar).toEqual({
|
|
|
|
type: 'userVal',
|
|
|
|
value: '123',
|
|
|
|
__meta: [
|
|
|
|
{
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: [
|
|
|
|
['body', ''],
|
|
|
|
[1, 'index'],
|
|
|
|
['declarations', 'VariableDeclaration'],
|
|
|
|
[0, 'index'],
|
|
|
|
['init', 'VariableDeclaration'],
|
|
|
|
],
|
2023-01-08 16:37:31 +11:00
|
|
|
sourceRange: [41, 50],
|
|
|
|
},
|
|
|
|
],
|
2023-01-03 19:41:27 +11:00
|
|
|
})
|
|
|
|
})
|
2022-11-26 08:34:23 +11:00
|
|
|
})
|
2022-11-14 14:04:23 +11:00
|
|
|
|
2023-01-21 21:23:01 +11:00
|
|
|
describe('testing math operators', () => {
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can sum', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 + 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(3)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can subtract', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 - 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(-1)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can multiply', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 * 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(2)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can divide', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 / 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(0.5)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can modulus', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 5 % 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(1)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('can do multiple operations', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 + 2 * 3'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(7)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('big example with parans', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 1 + 2 * (3 - 4) / -5 + 6'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(7.4)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with identifier', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const yo = 6', 'const myVar = yo / 2'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(3)
|
|
|
|
})
|
2023-07-20 19:25:04 -04:00
|
|
|
it('with lots of testing', async () => {
|
2023-01-21 21:23:01 +11:00
|
|
|
const code = ['const myVar = 2 * ((2 + 3 ) / 4 + 5)'].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-01-21 21:23:01 +11:00
|
|
|
expect(root.myVar.value).toBe(12.5)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with callExpression at start', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = min(4, 100) + 2'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(6)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with callExpression at end', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = 2 + min(4, 100)'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(6)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with nested callExpression', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = 2 + min(100, legLen(5, 3))'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(6)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with unaryExpression', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = -min(100, 3)'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(-3)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with unaryExpression in callExpression', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = min(-legLen(5, 4), 5)'
|
|
|
|
const code2 = 'const myVar = min(5 , -legLen(5, 4))'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
|
|
|
const { root: root2 } = await exe(code2)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(-3)
|
|
|
|
expect(root.myVar.value).toBe(root2.myVar.value)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with unaryExpression in ArrayExpression', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = [1,-legLen(5, 4)]'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toEqual([1, -3])
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with unaryExpression in ArrayExpression in CallExpression, checking nothing funny happens when used in a sketch', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = [
|
|
|
|
'const part001 = startSketchAt([0, 0])',
|
|
|
|
'|> line([-2.21, -legLen(5, min(3, 999))], %)',
|
|
|
|
].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-07-10 15:15:07 +10:00
|
|
|
const sketch = root.part001
|
2023-03-02 21:19:11 +11:00
|
|
|
// result of `-legLen(5, min(3, 999))` should be -4
|
|
|
|
const yVal = sketch.value?.[0]?.to?.[1]
|
|
|
|
expect(yVal).toBe(-4)
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('test that % substitution feeds down CallExp->ArrExp->UnaryExp->CallExp', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = [
|
|
|
|
`const myVar = 3`,
|
|
|
|
`const part001 = startSketchAt([0, 0])`,
|
|
|
|
` |> line({ to: [3, 4], tag: 'seg01' }, %)`,
|
|
|
|
` |> line([`,
|
|
|
|
` min(segLen('seg01', %), myVar),`,
|
|
|
|
` -legLen(segLen('seg01', %), myVar)`,
|
|
|
|
`], %)`,
|
|
|
|
``,
|
|
|
|
`show(part001)`,
|
|
|
|
].join('\n')
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-07-10 15:15:07 +10:00
|
|
|
const sketch = root.part001
|
2023-03-02 21:19:11 +11:00
|
|
|
// expect -legLen(segLen('seg01', %), myVar) to equal -4 setting the y value back to 0
|
|
|
|
expect(sketch.value?.[1]?.from).toEqual([3, 4])
|
|
|
|
expect(sketch.value?.[1]?.to).toEqual([6, 0])
|
|
|
|
const removedUnaryExp = code.replace(
|
|
|
|
`-legLen(segLen('seg01', %), myVar)`,
|
|
|
|
`legLen(segLen('seg01', %), myVar)`
|
|
|
|
)
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root: removedUnaryExpRoot } = await exe(removedUnaryExp)
|
2023-07-10 15:15:07 +10:00
|
|
|
const removedUnaryExpRootSketch = removedUnaryExpRoot.part001
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
// without the minus sign, the y value should be 8
|
|
|
|
expect(removedUnaryExpRootSketch.value?.[1]?.to).toEqual([6, 8])
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
it('with nested callExpression and binaryExpression', async () => {
|
2023-03-02 21:19:11 +11:00
|
|
|
const code = 'const myVar = 2 + min(100, -1 + legLen(5, 3))'
|
2023-06-22 16:43:33 +10:00
|
|
|
const { root } = await exe(code)
|
2023-03-02 21:19:11 +11:00
|
|
|
expect(root.myVar.value).toBe(5)
|
|
|
|
})
|
2023-01-21 21:23:01 +11:00
|
|
|
})
|
|
|
|
|
2023-08-07 20:33:38 -05:00
|
|
|
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]])
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-11-14 14:04:23 +11:00
|
|
|
// helpers
|
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
async function exe(
|
2022-11-20 09:41:21 +11:00
|
|
|
code: string,
|
2023-06-22 16:43:33 +10:00
|
|
|
programMemory: ProgramMemory = { root: {}, pendingMemory: {} }
|
2022-11-20 09:41:21 +11:00
|
|
|
) {
|
2022-11-26 08:34:23 +11:00
|
|
|
const tokens = lexer(code)
|
|
|
|
const ast = abstractSyntaxTree(tokens)
|
2023-06-22 16:43:33 +10:00
|
|
|
|
2023-07-10 15:15:07 +10:00
|
|
|
const result = await enginelessExecutor(ast, programMemory)
|
2023-06-22 16:43:33 +10:00
|
|
|
return result
|
2022-11-20 09:41:21 +11:00
|
|
|
}
|