Improving parsing and specs

This commit is contained in:
Martino Ferrari
2026-01-22 03:15:42 +01:00
parent b2e963fc04
commit a88f833f49
5 changed files with 59 additions and 9 deletions

View File

@@ -268,11 +268,13 @@ func handleDidOpen(params DidOpenTextDocumentParams) {
documents[params.TextDocument.URI] = params.TextDocument.Text documents[params.TextDocument.URI] = params.TextDocument.Text
p := parser.NewParser(params.TextDocument.Text) p := parser.NewParser(params.TextDocument.Text)
config, err := p.Parse() config, err := p.Parse()
if err == nil { if err != nil {
tree.AddFile(path, config) publishParserError(params.TextDocument.URI, err)
tree.ResolveReferences() return
runValidation(params.TextDocument.URI)
} }
tree.AddFile(path, config)
tree.ResolveReferences()
runValidation(params.TextDocument.URI)
} }
func handleDidChange(params DidChangeTextDocumentParams) { func handleDidChange(params DidChangeTextDocumentParams) {
@@ -284,11 +286,13 @@ func handleDidChange(params DidChangeTextDocumentParams) {
path := uriToPath(params.TextDocument.URI) path := uriToPath(params.TextDocument.URI)
p := parser.NewParser(text) p := parser.NewParser(text)
config, err := p.Parse() config, err := p.Parse()
if err == nil { if err != nil {
tree.AddFile(path, config) publishParserError(params.TextDocument.URI, err)
tree.ResolveReferences() return
runValidation(params.TextDocument.URI)
} }
tree.AddFile(path, config)
tree.ResolveReferences()
runValidation(params.TextDocument.URI)
} }
func handleFormatting(params DocumentFormattingParams) []TextEdit { 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) { func collectFiles(node *index.ProjectNode, files map[string]bool) {
for _, frag := range node.Fragments { for _, frag := range node.Fragments {
files[frag.File] = true files[frag.File] = true

View File

@@ -22,6 +22,7 @@ const (
TokenPragma TokenPragma
TokenComment TokenComment
TokenDocstring TokenDocstring
TokenComma
) )
type Token struct { type Token struct {
@@ -109,7 +110,7 @@ func (l *Lexer) NextToken() Token {
return l.emit(TokenEOF) return l.emit(TokenEOF)
} }
if unicode.IsSpace(r) || r == ',' { if unicode.IsSpace(r) {
l.ignore() l.ignore()
continue continue
} }
@@ -121,6 +122,8 @@ func (l *Lexer) NextToken() Token {
return l.emit(TokenLBrace) return l.emit(TokenLBrace)
case '}': case '}':
return l.emit(TokenRBrace) return l.emit(TokenRBrace)
case ',':
return l.emit(TokenComma)
case '"': case '"':
return l.lexString() return l.lexString()
case '/': case '/':

View File

@@ -235,6 +235,10 @@ func (p *Parser) parseValue() (Value, error) {
arr.EndPosition = endTok.Position arr.EndPosition = endTok.Position
break break
} }
if t.Type == TokenComma {
p.next()
continue
}
val, err := p.parseValue() val, err := p.parseValue()
if err != nil { if err != nil {
return nil, err return nil, err

BIN
mdt

Binary file not shown.

View File

@@ -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`). - `//!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. - `//!cast(DEF_TYPE, CUR_TYPE): REASON` - Suppress "Type Inconsistency" errors if types match.
- **Structure**: A configuration is composed by one or more definitions. - **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 ### Core MARTe Classes