[Bootstrap] Add a basic PrintError function to print error messages with the traceback

This commit is contained in:
Sameer Rahmani 2021-01-03 23:42:49 +00:00
parent 9be27c124a
commit e4001e3802
6 changed files with 87 additions and 29 deletions

View File

@ -5,14 +5,24 @@
(fn (name)
(println "hello" name)))
(def a1
(fn (x y)
x))
(defmacro defn
(name args &body)
(list 'def name (cons 'fn (cons args body))))
(list 'do
(list 'def name (cons 'fn (cons args body)))
(list 'a1 ~args)))
(defn pp (x y)
(println x))
(def main
(fn (&args)
(pp "sam")
(pp "sam" 2)
(hello-world "world")))

View File

@ -66,7 +66,7 @@ func (s *Source) GetLine(linenum int) string {
if linenum > 0 && linenum < len(lines) {
return lines[linenum-1]
}
return "!!!"
return "----"
}
func (s *Source) LineNumberFor(pos int) int {
@ -96,13 +96,7 @@ func (s *Source) LineNumberFor(pos int) int {
return -1
}
result := sort.Search(len(*s.LineIndex), func(i int) bool {
if i == 0 {
return pos < (*s.LineIndex)[i]
} else {
return (*s.LineIndex)[i-1] < pos && pos < (*s.LineIndex)[i]
}
})
result := sort.SearchInts(*s.LineIndex, pos)
// We've found something
if result > -1 {
@ -111,7 +105,6 @@ func (s *Source) LineNumberFor(pos int) int {
}
return result
}
type Location struct {

View File

@ -118,7 +118,7 @@ func Run(flags map[string]bool, args []string) {
}
rt := MakeRuntime([]string{cwd}, flags)
rt.CreateNS("user", "REPL", true)
rt.CreateNS("user", "RUN", true)
if len(args) == 0 {
@ -137,12 +137,8 @@ func Run(flags map[string]bool, args []string) {
}
tmpl, e := template.New("run").Parse(
`(def run-main
(fn ()
(require '({{.NS}} n))
(n/main {{.Args}})))
(run-main)`,
`(require '({{.NS}} n))
(n/main {{.Args}})`,
)
if e != nil {
@ -160,7 +156,7 @@ func Run(flags map[string]bool, args []string) {
fmt.Println(buf.String())
}
ast, err := ReadString("*RUN*", buf.String())
ast, err := ReadString("*INTERNAL*", buf.String())
if err != nil {
PrintError(rt, err)

View File

@ -49,6 +49,10 @@ const (
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

View File

@ -29,6 +29,15 @@ package core
// * Add the support for strings
// * Add the support for kewords
// * Add a shortcut for the `deref` function like `@x` => `(deref x)`
// * A line of comment at the end of a list definition causes a synxtax error.
// We need to fix it. For example:
// (asdb xyz
// ;; problematic comment line
// )
// Will fails. The reason being we call `readExpr` in `readList` and in the
// `readExpr` when we read a line of comment we jump to a label and try to
// read another expr which in our case it would read the end of list and throw
// and error
import (
"strings"
@ -325,6 +334,8 @@ func readNumber(parser IParsable, neg bool) (IExpr, IError) {
r := rune(char[0])
if unicode.IsDigit(r) {
result = result + *c
} else if isValidForSymbol(char) {
return nil, makeErrorAtPoint(parser, "Illegal token while scanning for a number.")
} else {
parser.back()
break

View File

@ -64,12 +64,43 @@ func Println(rt *Runtime, ast ...IRepresentable) {
fmt.Println(toPrintableString(ast...))
}
func PrintError(rt *Runtime, err IError) {
func printError(rt *Runtime, err IError, stage int) {
loc := err.GetLocation()
source := loc.GetSource()
startline := source.LineNumberFor(loc.GetStart())
if startline > 0 {
startline -= 1
}
endline := source.LineNumberFor(loc.GetEnd()) + 1
var lines string
for i := startline; i <= endline; i++ {
line := source.GetLine(i)
if line != "----" {
lines += fmt.Sprintf("%d:\t%s\n", i, line)
}
}
color.Yellow.Printf(
"%d: At '%s'\n",
stage,
source.Path,
)
color.White.Printf("%s\n", lines)
errTag := color.Red.Sprint(err.GetErrType().String())
fmt.Printf("%s: %s\nAt: %d to %d\n", errTag, err.String(), loc.GetStart(), loc.GetEnd())
}
func printErrorWithTraceBack(rt *Runtime, err IError) {
trace := err.GetStackTrace()
fmt.Println(err)
for i, t := range *trace {
fmt.Println(*t)
caller := t.Caller
callerLoc := caller.GetLocation()
callerSource := callerLoc.GetSource()
@ -84,23 +115,36 @@ func PrintError(rt *Runtime, err IError) {
var lines string
for i := startline; i <= endline; i++ {
fmt.Println(">>>>>>>>>> ", err)
fLoc := t.Fn.GetLocation()
fmt.Println(">>>>>>>>>> ", fLoc, fLoc.GetSource())
lines += fmt.Sprintf("%d:\t%s\n", i, fLoc.GetSource().GetLine(i))
line := fLoc.GetSource().GetLine(i)
if line != "----" {
lines += fmt.Sprintf("%d:\t%s\n", i, line)
}
}
color.Yellow.Printf(
"%d: In function '%s' at '%s'\n",
"%d: In function '%s' at '%s':%d\n",
i,
t.Fn.GetName(),
callerLoc.GetSource().Path,
callerSource.LineNumberFor(callerLoc.GetStart()),
)
color.White.Printf("%s\n", lines)
}
loc := err.GetLocation()
errTag := color.Red.Sprint("ERROR")
errTag := color.Red.Sprint(err.GetErrType().String())
fmt.Printf("%s: %s\nAt: %d to %d\n", errTag, err.String(), loc.GetStart(), loc.GetEnd())
}
func PrintError(rt *Runtime, err IError) {
switch err.GetErrType() {
case SyntaxError, SemanticError:
printError(rt, err, 0)
return
case RuntimeError:
printErrorWithTraceBack(rt, err)
return
default:
panic(fmt.Sprintf("Don't know about error type '%d'", err.GetErrType()))
}
}