package errors import ( "fmt" "os" "path/filepath" "git.akyoto.dev/cli/q/src/build/token" ) // Error is a compiler error at a given line and column. type Error struct { Path string Line int Column int Err error Stack string } // 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, path string, tokens []token.Token, cursor int) *Error { var ( lineCount = 1 lineStart = -1 ) for i := range cursor { if tokens[i].Kind == token.NewLine { lineCount++ lineStart = int(tokens[i].Position) } } var column int if cursor < len(tokens) { column = tokens[cursor].Position - lineStart } else { lastToken := tokens[len(tokens)-1] column = lastToken.Position - lineStart + len(lastToken.Text()) } return &Error{path, lineCount, column, err, Stack()} } // Error generates the string representation. func (e *Error) Error() string { path := e.Path cwd, err := os.Getwd() if err == nil { relativePath, err := filepath.Rel(cwd, e.Path) if err == nil { path = relativePath } } return fmt.Sprintf("%s:%d:%d: %s\n\n%s", path, e.Line, e.Column, e.Err, e.Stack) } // Unwrap returns the wrapped error. func (e *Error) Unwrap() error { return e.Err }