/* Serene --- Yet an other Lisp Copyright (c) 2020 Sameer Rahmani This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package core // Error implementations: // * `IError` is the main interface to represent errors. // * `Error` struct is an expression itself. // * `IError` and any implementation of it has to implement `ILocatable` // so we can point to the exact location of the error. // * We have to use `IError` everywhere and avoid using Golangs errors // since IError is an expression itself. // // TODOs: // * Make errors stackable, so different pieces of code can stack related // errors on top of each other so user can track them through the code // * Errors should contain a help message as well to give some hints to the // user about how to fix the problem. Something similar to Rust's error // messages // * Integrate the call stack with IError import ( "fmt" "serene-lang.org/bootstrap/pkg/ast" "serene-lang.org/bootstrap/pkg/errors" ) type ErrType uint8 const ( SyntaxError ErrType = iota SemanticError RuntimeError ) func (e ErrType) String() string { return [...]string{"Syntax Error", "Semantic Error", "Runtime Error"}[e] } // IError defines the necessary functionality of the internal errors. type IError interface { // In order to point to a specific point in the input ast.ILocatable // We want errors to be printable by the `print` family IRepresentable IDebuggable GetErrType() ErrType GetErrno() errors.Errno GetDescription() *string GetStackTrace() *TraceBack // To wrap Golan rrrrors WithError(err error) IError // Some errors might doesn't have any node available to them // at the creation time. SetNode allows us to the the appropriate // node later in time. SetNode(n *Node) } type Error struct { Node errtype ErrType errno errors.Errno WrappedErr error msg string trace *TraceBack } func (e *Error) String() string { return e.msg } func (e *Error) ToDebugStr() string { _, isInternalErr := e.WrappedErr.(*Error) if isInternalErr { return fmt.Sprintf("%s:\n\t%s", e.msg, e.WrappedErr.(*Error).ToDebugStr()) } return fmt.Sprintf("%s:\n\t%s", e.msg, e.WrappedErr.Error()) } func (e *Error) GetErrType() ErrType { return e.errtype } func (e *Error) WithError(err error) IError { e.WrappedErr = err return e } func (e *Error) SetNode(n *Node) { e.Node = *n } func (e *Error) Error() string { return e.msg } func (e *Error) GetStackTrace() *TraceBack { return e.trace } func (e *Error) GetErrno() errors.Errno { return e.errno } func (e *Error) GetDescription() *string { desc, ok := errors.ErrorsDescription[e.errno] if ok { return &desc } desc = errors.ErrorsDescription[0] return &desc } func MakePlainError(msg string) IError { return &Error{ msg: msg, } } // MakeError creates an Error which points to the given IExpr `e` as // the root of the error. func MakeError(rt *Runtime, e IExpr, msg string) IError { rt.Stack.Push(e, rt.Stack.GetCurrentFn()) return &Error{ Node: MakeNodeFromExpr(e), errtype: RuntimeError, msg: msg, trace: rt.Stack.ToTraceBack(), } } func MakeRuntimeError(rt *Runtime, e IExpr, errno errors.Errno, msg string) IError { rt.Stack.Push(e, rt.Stack.GetCurrentFn()) return &Error{ Node: MakeNodeFromExpr(e), errtype: RuntimeError, msg: msg, errno: errno, trace: rt.Stack.ToTraceBack(), } } func MakeSyntaxErrorf(n Node, msg string, a ...interface{}) IError { return &Error{ Node: n, errtype: SyntaxError, msg: fmt.Sprintf(msg, a...), } } func MakeSemanticError(rt *Runtime, e IExpr, errno errors.Errno, msg string) IError { rt.Stack.Push(e, rt.Stack.GetCurrentFn()) frames := &[]*Frame{ rt.Stack.Pop(), } return &Error{ Node: MakeNodeFromExpr(e), errtype: SemanticError, errno: errno, msg: msg, trace: frames, } }