Surface warnings to frontend and LSP (#4603)

* Send multiple errors and warnings to the frontend and LSP

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactor the parser to use CompilationError for parsing errors rather than KclError

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactoring: move CompilationError, etc.

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Integrate compilation errors with the frontend and CodeMirror

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fix tests

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Review comments

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fix module id/source range stuff

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* More test fixups

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2024-12-06 13:57:31 +13:00
committed by GitHub
parent 513c76ecc8
commit eb96d6539c
76 changed files with 1461 additions and 3139 deletions

View File

@ -1,4 +1,4 @@
import { parse, recast, initPromise, Identifier } from './wasm'
import { assertParse, recast, initPromise, Identifier } from './wasm'
import {
createLiteral,
createIdentifier,
@ -146,10 +146,13 @@ function giveSketchFnCallTagTestHelper(
// giveSketchFnCallTag inputs and outputs an ast, which is very verbose for testing
// 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
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const start = code.indexOf(searchStr)
const range: [number, number] = [start, start + searchStr.length]
const range: [number, number, boolean] = [
start,
start + searchStr.length,
true,
]
const sketchRes = giveSketchFnCallTag(ast, range)
if (err(sketchRes)) throw sketchRes
const { modifiedAst, tag, isTagExisting } = sketchRes
@ -221,14 +224,13 @@ part001 = startSketchOn('XY')
|> angledLine([jkl(yo) + 2, 3.09], %)
yo2 = hmm([identifierGuy + 5])`
it('should move a binary expression into a new variable', async () => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const startIndex = code.indexOf('100 + 100') + 1
const { modifiedAst } = moveValueIntoNewVariable(
ast,
execState.memory,
[startIndex, startIndex],
[startIndex, startIndex, true],
'newVar'
)
const newCode = recast(modifiedAst)
@ -236,14 +238,13 @@ yo2 = hmm([identifierGuy + 5])`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
})
it('should move a value into a new variable', async () => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const startIndex = code.indexOf('2.8') + 1
const { modifiedAst } = moveValueIntoNewVariable(
ast,
execState.memory,
[startIndex, startIndex],
[startIndex, startIndex, true],
'newVar'
)
const newCode = recast(modifiedAst)
@ -251,14 +252,13 @@ yo2 = hmm([identifierGuy + 5])`
expect(newCode).toContain(`line([newVar, 0], %)`)
})
it('should move a callExpression into a new variable', async () => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const startIndex = code.indexOf('def(')
const { modifiedAst } = moveValueIntoNewVariable(
ast,
execState.memory,
[startIndex, startIndex],
[startIndex, startIndex, true],
'newVar'
)
const newCode = recast(modifiedAst)
@ -266,14 +266,13 @@ yo2 = hmm([identifierGuy + 5])`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
})
it('should move a binary expression with call expression into a new variable', async () => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const startIndex = code.indexOf('jkl(') + 1
const { modifiedAst } = moveValueIntoNewVariable(
ast,
execState.memory,
[startIndex, startIndex],
[startIndex, startIndex, true],
'newVar'
)
const newCode = recast(modifiedAst)
@ -281,14 +280,13 @@ yo2 = hmm([identifierGuy + 5])`
expect(newCode).toContain(`angledLine([newVar, 3.09], %)`)
})
it('should move a identifier into a new variable', async () => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const startIndex = code.indexOf('identifierGuy +') + 1
const { modifiedAst } = moveValueIntoNewVariable(
ast,
execState.memory,
[startIndex, startIndex],
[startIndex, startIndex, true],
'newVar'
)
const newCode = recast(modifiedAst)
@ -305,19 +303,20 @@ describe('testing sketchOnExtrudedFace', () => {
|> line([8.62, -9.57], %)
|> close(%)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const segmentSnippet = `line([9.7, 9.19], %)`
const segmentRange: [number, number] = [
const segmentRange: [number, number, boolean] = [
code.indexOf(segmentSnippet),
code.indexOf(segmentSnippet) + segmentSnippet.length,
true,
]
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
const extrudeSnippet = `extrude(5 + 7, %)`
const extrudeRange: [number, number] = [
const extrudeRange: [number, number, boolean] = [
code.indexOf(extrudeSnippet),
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
true,
]
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
@ -345,18 +344,19 @@ sketch001 = startSketchOn(part001, seg01)`)
|> line([8.62, -9.57], %)
|> close(%)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const segmentSnippet = `close(%)`
const segmentRange: [number, number] = [
const segmentRange: [number, number, boolean] = [
code.indexOf(segmentSnippet),
code.indexOf(segmentSnippet) + segmentSnippet.length,
true,
]
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
const extrudeSnippet = `extrude(5 + 7, %)`
const extrudeRange: [number, number] = [
const extrudeRange: [number, number, boolean] = [
code.indexOf(extrudeSnippet),
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
true,
]
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
@ -384,18 +384,19 @@ sketch001 = startSketchOn(part001, seg01)`)
|> line([8.62, -9.57], %)
|> close(%)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
const sketchRange: [number, number] = [
const sketchRange: [number, number, boolean] = [
code.indexOf(sketchSnippet),
code.indexOf(sketchSnippet) + sketchSnippet.length,
true,
]
const sketchPathToNode = getNodePathFromSourceRange(ast, sketchRange)
const extrudeSnippet = `extrude(5 + 7, %)`
const extrudeRange: [number, number] = [
const extrudeRange: [number, number, boolean] = [
code.indexOf(extrudeSnippet),
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
true,
]
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
@ -432,18 +433,19 @@ sketch001 = startSketchOn(part001, 'END')`)
|> line([-17.67, 0.85], %)
|> close(%)
part001 = extrude(5 + 7, sketch001)`
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const segmentSnippet = `line([4.99, -0.46], %)`
const segmentRange: [number, number] = [
const segmentRange: [number, number, boolean] = [
code.indexOf(segmentSnippet),
code.indexOf(segmentSnippet) + segmentSnippet.length,
true,
]
const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange)
const extrudeSnippet = `extrude(5 + 7, sketch001)`
const extrudeRange: [number, number] = [
const extrudeRange: [number, number, boolean] = [
code.indexOf(extrudeSnippet),
code.indexOf(extrudeSnippet) + extrudeSnippet.length,
true,
]
const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange)
@ -466,13 +468,13 @@ describe('Testing deleteSegmentFromPipeExpression', () => {
|> line([306.21, 198.82], %)
|> line([306.21, 198.85], %, $a)
|> line([306.21, 198.87], %)`
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const lineOfInterest = 'line([306.21, 198.85], %, $a)'
const range: [number, number] = [
const range: [number, number, boolean] = [
code.indexOf(lineOfInterest),
code.indexOf(lineOfInterest) + lineOfInterest.length,
true,
]
const pathToNode = getNodePathFromSourceRange(ast, range)
const modifiedAst = deleteSegmentFromPipeExpression(
@ -544,13 +546,13 @@ ${!replace1 ? ` |> ${line}\n` : ''} |> angledLine([-65, ${
],
])(`%s`, async (_, line, [replace1, replace2]) => {
const code = makeCode(line)
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const lineOfInterest = line
const range: [number, number] = [
const range: [number, number, boolean] = [
code.indexOf(lineOfInterest),
code.indexOf(lineOfInterest) + lineOfInterest.length,
true,
]
const pathToNode = getNodePathFromSourceRange(ast, range)
const dependentSegments = findUsesOfTagInPipe(ast, pathToNode)
@ -632,14 +634,14 @@ describe('Testing removeSingleConstraintInfo', () => {
],
['tangentialArcTo([3.14 + 0, 13.14], %)', 'arrayIndex', 1],
] as const)('stdlib fn: %s', async (expectedFinish, key, value) => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const lineOfInterest = expectedFinish.split('(')[0] + '('
const range: [number, number] = [
const range: [number, number, boolean] = [
code.indexOf(lineOfInterest) + 1,
code.indexOf(lineOfInterest) + lineOfInterest.length,
true,
]
const pathToNode = getNodePathFromSourceRange(ast, range)
let argPosition: SimplifiedArgDetails
@ -686,14 +688,14 @@ describe('Testing removeSingleConstraintInfo', () => {
['angledLineToX([12.14 + 0, 12], %)', 'arrayIndex', 1],
['angledLineToY([30, 10.14 + 0], %)', 'arrayIndex', 0],
])('stdlib fn: %s', async (expectedFinish, key, value) => {
const ast = parse(code)
if (err(ast)) throw ast
const ast = assertParse(code)
const execState = await enginelessExecutor(ast)
const lineOfInterest = expectedFinish.split('(')[0] + '('
const range: [number, number] = [
const range: [number, number, boolean] = [
code.indexOf(lineOfInterest) + 1,
code.indexOf(lineOfInterest) + lineOfInterest.length,
true,
]
let argPosition: SimplifiedArgDetails
if (key === 'arrayIndex' && typeof value === 'number') {
@ -883,14 +885,14 @@ sketch002 = startSketchOn({
'%s',
async (name, { codeBefore, codeAfter, lineOfInterest, type }) => {
// const lineOfInterest = 'line([-2.94, 2.7], %)'
const ast = parse(codeBefore)
if (err(ast)) throw ast
const ast = assertParse(codeBefore)
const execState = await enginelessExecutor(ast)
// deleteFromSelection
const range: [number, number] = [
const range: [number, number, boolean] = [
codeBefore.indexOf(lineOfInterest),
codeBefore.indexOf(lineOfInterest) + lineOfInterest.length,
true,
]
const artifact = { type } as Artifact
const newAst = await deleteFromSelection(