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) }