diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 0642ddd..522425a 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -268,11 +268,13 @@ func handleDidOpen(params DidOpenTextDocumentParams) { documents[params.TextDocument.URI] = params.TextDocument.Text p := parser.NewParser(params.TextDocument.Text) config, err := p.Parse() - if err == nil { - tree.AddFile(path, config) - tree.ResolveReferences() - runValidation(params.TextDocument.URI) + if err != nil { + publishParserError(params.TextDocument.URI, err) + return } + tree.AddFile(path, config) + tree.ResolveReferences() + runValidation(params.TextDocument.URI) } func handleDidChange(params DidChangeTextDocumentParams) { @@ -284,11 +286,13 @@ func handleDidChange(params DidChangeTextDocumentParams) { path := uriToPath(params.TextDocument.URI) p := parser.NewParser(text) config, err := p.Parse() - if err == nil { - tree.AddFile(path, config) - tree.ResolveReferences() - runValidation(params.TextDocument.URI) + if err != nil { + publishParserError(params.TextDocument.URI, err) + return } + tree.AddFile(path, config) + tree.ResolveReferences() + runValidation(params.TextDocument.URI) } func handleFormatting(params DocumentFormattingParams) []TextEdit { @@ -378,6 +382,44 @@ func runValidation(uri string) { } } +func publishParserError(uri string, err error) { + var line, col int + var msg string + // Try parsing "line:col: message" + n, _ := fmt.Sscanf(err.Error(), "%d:%d: ", &line, &col) + if n == 2 { + parts := strings.SplitN(err.Error(), ": ", 2) + if len(parts) == 2 { + msg = parts[1] + } + } else { + // Fallback + line = 1 + col = 1 + msg = err.Error() + } + + diag := LSPDiagnostic{ + Range: Range{ + Start: Position{Line: line - 1, Character: col - 1}, + End: Position{Line: line - 1, Character: col}, + }, + Severity: 1, // Error + Message: msg, + Source: "mdt-parser", + } + + notification := JsonRpcMessage{ + Jsonrpc: "2.0", + Method: "textDocument/publishDiagnostics", + Params: mustMarshal(PublishDiagnosticsParams{ + URI: uri, + Diagnostics: []LSPDiagnostic{diag}, + }), + } + send(notification) +} + func collectFiles(node *index.ProjectNode, files map[string]bool) { for _, frag := range node.Fragments { files[frag.File] = true diff --git a/internal/parser/lexer.go b/internal/parser/lexer.go index 84bb052..c8afc3f 100644 --- a/internal/parser/lexer.go +++ b/internal/parser/lexer.go @@ -22,6 +22,7 @@ const ( TokenPragma TokenComment TokenDocstring + TokenComma ) type Token struct { @@ -109,7 +110,7 @@ func (l *Lexer) NextToken() Token { return l.emit(TokenEOF) } - if unicode.IsSpace(r) || r == ',' { + if unicode.IsSpace(r) { l.ignore() continue } @@ -121,6 +122,8 @@ func (l *Lexer) NextToken() Token { return l.emit(TokenLBrace) case '}': return l.emit(TokenRBrace) + case ',': + return l.emit(TokenComma) case '"': return l.lexString() case '/': diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 2a11217..a097098 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -235,6 +235,10 @@ func (p *Parser) parseValue() (Value, error) { arr.EndPosition = endTok.Position break } + if t.Type == TokenComma { + p.next() + continue + } val, err := p.parseValue() if err != nil { return nil, err diff --git a/mdt b/mdt index 652da78..11ff859 100755 Binary files a/mdt and b/mdt differ diff --git a/specification.md b/specification.md index 2c86e3a..2e52149 100644 --- a/specification.md +++ b/specification.md @@ -90,6 +90,7 @@ The LSP server should provide the following capabilities: - `//!allow(WARNING_TYPE): REASON` - Global suppression for a specific warning type across the whole project (supported: `unused`, `implicit`). - `//!cast(DEF_TYPE, CUR_TYPE): REASON` - Suppress "Type Inconsistency" errors if types match. - **Structure**: A configuration is composed by one or more definitions. +- **Strictness**: Any content that is not a valid comment (or pragma/docstring) or a valid definition (Field, Node, or Object) is **not allowed** and must generate a parsing error. ### Core MARTe Classes