92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
import { TextDocument, Position } from 'vscode-languageserver-textdocument'
|
|
import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver/node'
|
|
import { Tree } from '@lezer/common'
|
|
import { Compiler } from '../../../src/compiler/compiler'
|
|
import { CompilerError } from '../../../src/compiler/compilerError'
|
|
|
|
export const buildDiagnostics = (textDocument: TextDocument, tree: Tree): Diagnostic[] => {
|
|
const text = textDocument.getText()
|
|
const diagnostics = getParseErrors(textDocument, tree)
|
|
|
|
if (diagnostics.length > 0) {
|
|
return diagnostics
|
|
}
|
|
const diagnostic = getCompilerError(text)
|
|
if (diagnostic) return [diagnostic]
|
|
|
|
return []
|
|
}
|
|
|
|
const getCompilerError = (text: string): Diagnostic | undefined => {
|
|
try {
|
|
new Compiler(text)
|
|
} catch (e) {
|
|
if (!(e instanceof CompilerError)) {
|
|
return unknownDiagnostic(getErrorMessage(e))
|
|
}
|
|
|
|
const lineInfo = e.lineAtPosition(text)!
|
|
const cause = e.cause ? ` Cause: ${e.cause}` : ''
|
|
const message = e.message
|
|
|
|
if (!lineInfo) {
|
|
return unknownDiagnostic(message + cause)
|
|
}
|
|
|
|
const diagnostic: Diagnostic = {
|
|
severity: DiagnosticSeverity.Error,
|
|
range: {
|
|
start: { line: lineInfo.lineNumber, character: lineInfo.columnStart },
|
|
end: { line: lineInfo.lineNumber, character: lineInfo.columnEnd },
|
|
},
|
|
message: `Compiler error: ${message}${cause}`,
|
|
source: 'shrimp',
|
|
}
|
|
return diagnostic
|
|
}
|
|
}
|
|
|
|
const unknownDiagnostic = (message: string): Diagnostic => {
|
|
const diagnostic: Diagnostic = {
|
|
severity: DiagnosticSeverity.Error,
|
|
range: {
|
|
start: { line: 0, character: 0 },
|
|
end: { line: -1, character: -1 },
|
|
},
|
|
message,
|
|
source: 'shrimp',
|
|
}
|
|
return diagnostic
|
|
}
|
|
|
|
const getParseErrors = (textDocument: TextDocument, tree: Tree): Diagnostic[] => {
|
|
const ranges: { start: Position; end: Position }[] = []
|
|
tree.iterate({
|
|
enter(n) {
|
|
if (n.type.isError) {
|
|
ranges.push({
|
|
start: textDocument.positionAt(n.from),
|
|
end: textDocument.positionAt(n.to),
|
|
})
|
|
return false
|
|
}
|
|
},
|
|
})
|
|
|
|
return ranges.map((range) => {
|
|
return {
|
|
range,
|
|
severity: DiagnosticSeverity.Error,
|
|
message: 'Parse error: Invalid syntax',
|
|
source: 'shrimp',
|
|
}
|
|
})
|
|
}
|
|
|
|
const getErrorMessage = (error: unknown): string => {
|
|
if (error instanceof Error) {
|
|
return error.message
|
|
}
|
|
return String(error)
|
|
}
|