Skip to content

Commit 4877400

Browse files
committed
feat: enhance parser error messages with precise file, line, and column numbers and structured agent outputs
1 parent bd6340e commit 4877400

2 files changed

Lines changed: 45 additions & 10 deletions

File tree

cli/ship/main.go

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"os"
1010
"os/exec"
1111
"path/filepath"
12+
"strconv"
13+
"strings"
1214

1315
"github.com/nathfavour/ship/compiler/emitter/elf"
1416
"github.com/nathfavour/ship/compiler/ir"
@@ -258,12 +260,44 @@ func fatalError(msg string, agent bool) {
258260

259261
func reportAgentErrors(phase string, errors []string) {
260262
for _, msg := range errors {
261-
out, _ := json.Marshal(map[string]interface{}{
262-
"status": "error",
263-
"phase": phase,
264-
"error": msg,
265-
})
266-
fmt.Fprintln(os.Stderr, string(out))
263+
file := ""
264+
line := 0
265+
col := 0
266+
errMsg := msg
267+
268+
parts := strings.SplitN(msg, ":", 4)
269+
if len(parts) >= 4 {
270+
l, err1 := strconv.Atoi(parts[1])
271+
c, err2 := strconv.Atoi(parts[2])
272+
if err1 == nil && err2 == nil {
273+
file = parts[0]
274+
line = l
275+
col = c
276+
errMsg = strings.TrimSpace(parts[3])
277+
}
278+
}
279+
280+
if line > 0 {
281+
out, _ := json.Marshal(map[string]interface{}{
282+
"status": "error",
283+
"phase": phase,
284+
"error": errMsg,
285+
"target": map[string]interface{}{
286+
"file": file,
287+
"function": "",
288+
"line": line,
289+
"char": col,
290+
},
291+
})
292+
fmt.Fprintln(os.Stderr, string(out))
293+
} else {
294+
out, _ := json.Marshal(map[string]interface{}{
295+
"status": "error",
296+
"phase": phase,
297+
"error": msg,
298+
})
299+
fmt.Fprintln(os.Stderr, string(out))
300+
}
267301
}
268302
}
269303

compiler/parser/parser.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ func (p *Parser) parseIntegerLiteral() ast.Expression {
338338

339339
value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
340340
if err != nil {
341-
msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal)
341+
msg := fmt.Sprintf("%s:%d:%d: could not parse %q as integer", p.curToken.File, p.curToken.Line, p.curToken.Col, p.curToken.Literal)
342342
p.errors = append(p.errors, msg)
343343
return nil
344344
}
@@ -492,8 +492,8 @@ func (p *Parser) expectPeek(t token.Type) bool {
492492
}
493493

494494
func (p *Parser) peekError(t token.Type) {
495-
msg := fmt.Sprintf("expected next token to be %s, got %s instead",
496-
t, p.peekToken.Type)
495+
msg := fmt.Sprintf("%s:%d:%d: expected next token to be %s, got %s instead",
496+
p.peekToken.File, p.peekToken.Line, p.peekToken.Col, t, p.peekToken.Type)
497497
p.errors = append(p.errors, msg)
498498
}
499499

@@ -506,7 +506,8 @@ func (p *Parser) registerInfix(tokenType token.Type, fn infixParseFn) {
506506
}
507507

508508
func (p *Parser) noPrefixParseFnError(t token.Type) {
509-
msg := fmt.Sprintf("no prefix parse function for %s found", t)
509+
msg := fmt.Sprintf("%s:%d:%d: no prefix parse function for %s found",
510+
p.curToken.File, p.curToken.Line, p.curToken.Col, t)
510511
p.errors = append(p.errors, msg)
511512
}
512513

0 commit comments

Comments
 (0)