package errors import ( "fmt" "os" "path/filepath" "git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/token" ) // Error is a compiler error at a given line and column. type Error struct { Err error File *fs.File Stack string Position int } // New generates an error message at the current token position. // The error message is clickable in popular editors and leads you // directly to the faulty file at the given line and position. func New(err error, file *fs.File, position int) *Error { return &Error{ Err: err, File: file, Position: position, Stack: Stack(), } } // Error generates the string representation. func (e *Error) Error() string { path := e.File.Path cwd, err := os.Getwd() if err == nil { relativePath, err := filepath.Rel(cwd, e.File.Path) if err == nil { path = relativePath } } line := 1 column := 1 lineStart := -1 for _, t := range e.File.Tokens { if t.Position >= e.Position { column = e.Position - lineStart break } if t.Kind == token.NewLine { lineStart = t.Position line++ } } return fmt.Sprintf("%s:%d:%d: %s\n\n%s", path, line, column, e.Err, e.Stack) } // Unwrap returns the wrapped error. func (e *Error) Unwrap() error { return e.Err }