Made error messages display the source and some context.
This commit is contained in:
parent
27a5b51a02
commit
275f4782c8
1 changed files with 74 additions and 5 deletions
|
|
@ -2,6 +2,7 @@ package compiler
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"c65gm/internal/preproc"
|
||||
|
|
@ -37,7 +38,7 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
|||
var lastKind = preproc.Source
|
||||
var scriptBuffer []string
|
||||
|
||||
for _, line := range lines {
|
||||
for i, line := range lines {
|
||||
// Detect kind transitions and emit markers
|
||||
if line.Kind != lastKind {
|
||||
// Execute and close previous Script block
|
||||
|
|
@ -78,7 +79,8 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
|||
}
|
||||
end := strings.IndexByte(text[start+1:], '|')
|
||||
if end == -1 {
|
||||
return nil, fmt.Errorf("%s:%d: unclosed | in assembler line", line.Filename, line.LineNo)
|
||||
c.printErrorWithContext(lines, i, fmt.Errorf("unclosed | in assembler line"))
|
||||
return nil, fmt.Errorf("compilation failed")
|
||||
}
|
||||
end += start + 1
|
||||
|
||||
|
|
@ -102,18 +104,21 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
|||
// Find handler for this line
|
||||
cmd, found := c.registry.FindHandler(line)
|
||||
if !found {
|
||||
return nil, &UnhandledLineError{Line: line}
|
||||
c.printErrorWithContext(lines, i, fmt.Errorf("unhandled line (no matching command)"))
|
||||
return nil, fmt.Errorf("compilation failed")
|
||||
}
|
||||
|
||||
// Interpret the line
|
||||
if err := cmd.Interpret(line, c.ctx); err != nil {
|
||||
return nil, fmt.Errorf("%s:%d: %w", line.Filename, line.LineNo, err)
|
||||
c.printErrorWithContext(lines, i, err)
|
||||
return nil, fmt.Errorf("compilation failed")
|
||||
}
|
||||
|
||||
// Generate assembly
|
||||
asmLines, err := cmd.Generate(c.ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s:%d: %w", line.Filename, line.LineNo, err)
|
||||
c.printErrorWithContext(lines, i, err)
|
||||
return nil, fmt.Errorf("compilation failed")
|
||||
}
|
||||
|
||||
codeOutput = append(codeOutput, fmt.Sprintf("; %s", line.Text))
|
||||
|
|
@ -136,6 +141,70 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
|||
return c.assembleOutput(codeOutput), nil
|
||||
}
|
||||
|
||||
// printErrorWithContext prints an error with source code context to stderr
|
||||
func (c *Compiler) printErrorWithContext(lines []preproc.Line, lineIndex int, err error) {
|
||||
if lineIndex < 0 || lineIndex >= len(lines) {
|
||||
// Shouldn't happen, but be safe
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
line := lines[lineIndex]
|
||||
const contextLines = 3
|
||||
|
||||
// Print error header
|
||||
_, _ = fmt.Fprintf(os.Stderr, "\nError: %v\n", err)
|
||||
_, _ = fmt.Fprintf(os.Stderr, " --> %s:%d\n\n", line.Filename, line.LineNo)
|
||||
|
||||
// Find all lines from the same file for context
|
||||
// Group consecutive lines from the same file
|
||||
fileLines := make(map[string][]int)
|
||||
for i, l := range lines {
|
||||
if l.Filename == line.Filename {
|
||||
fileLines[l.Filename] = append(fileLines[l.Filename], i)
|
||||
}
|
||||
}
|
||||
|
||||
// Get context range (lineIndex within our lines array)
|
||||
startIdx := lineIndex - contextLines
|
||||
if startIdx < 0 {
|
||||
startIdx = 0
|
||||
}
|
||||
endIdx := lineIndex + contextLines
|
||||
if endIdx >= len(lines) {
|
||||
endIdx = len(lines) - 1
|
||||
}
|
||||
|
||||
// Calculate width for line numbers based on actual source line numbers
|
||||
maxLineNo := 0
|
||||
for i := startIdx; i <= endIdx; i++ {
|
||||
if lines[i].LineNo > maxLineNo {
|
||||
maxLineNo = lines[i].LineNo
|
||||
}
|
||||
}
|
||||
maxLineNumWidth := len(fmt.Sprintf("%d", maxLineNo))
|
||||
|
||||
// Print context
|
||||
for i := startIdx; i <= endIdx; i++ {
|
||||
l := lines[i]
|
||||
|
||||
// Skip lines from different files
|
||||
if l.Filename != line.Filename {
|
||||
continue
|
||||
}
|
||||
|
||||
if i == lineIndex {
|
||||
// Error line - highlight it
|
||||
_, _ = fmt.Fprintf(os.Stderr, ">> %*d | %s\n", maxLineNumWidth, l.LineNo, l.Text)
|
||||
} else {
|
||||
// Context line
|
||||
_, _ = fmt.Fprintf(os.Stderr, " %*d | %s\n", maxLineNumWidth, l.LineNo, l.Text)
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
// checkAbsoluteOverlaps analyzes and warns about overlapping absolute addresses
|
||||
func (c *Compiler) checkAbsoluteOverlaps() {
|
||||
c.ctx.FunctionHandler.ReportAbsoluteOverlaps()
|
||||
|
|
|
|||
Loading…
Reference in a new issue