[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) (fn (name)
(println "hello" name))) (println "hello" name)))
(def a1
(fn (x y)
x))
(defmacro defn (defmacro defn
(name args &body) (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) (defn pp (x y)
(println x)) (println x))
(def main (def main
(fn (&args) (fn (&args)
(pp "sam") (pp "sam" 2)
(hello-world "world"))) (hello-world "world")))

View File

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

View File

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

View File

@ -49,6 +49,10 @@ const (
RuntimeError RuntimeError
) )
func (e ErrType) String() string {
return [...]string{"Syntax Error", "Semantic Error", "Runtime Error"}[e]
}
// IError defines the necessary functionality of the internal errors. // IError defines the necessary functionality of the internal errors.
type IError interface { type IError interface {
// In order to point to a specific point in the input // 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 strings
// * Add the support for kewords // * Add the support for kewords
// * Add a shortcut for the `deref` function like `@x` => `(deref x)` // * 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 ( import (
"strings" "strings"
@ -325,6 +334,8 @@ func readNumber(parser IParsable, neg bool) (IExpr, IError) {
r := rune(char[0]) r := rune(char[0])
if unicode.IsDigit(r) { if unicode.IsDigit(r) {
result = result + *c result = result + *c
} else if isValidForSymbol(char) {
return nil, makeErrorAtPoint(parser, "Illegal token while scanning for a number.")
} else { } else {
parser.back() parser.back()
break break

View File

@ -64,12 +64,43 @@ func Println(rt *Runtime, ast ...IRepresentable) {
fmt.Println(toPrintableString(ast...)) 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() trace := err.GetStackTrace()
fmt.Println(err)
for i, t := range *trace { for i, t := range *trace {
fmt.Println(*t)
caller := t.Caller caller := t.Caller
callerLoc := caller.GetLocation() callerLoc := caller.GetLocation()
callerSource := callerLoc.GetSource() callerSource := callerLoc.GetSource()
@ -84,23 +115,36 @@ func PrintError(rt *Runtime, err IError) {
var lines string var lines string
for i := startline; i <= endline; i++ { for i := startline; i <= endline; i++ {
fmt.Println(">>>>>>>>>> ", err)
fLoc := t.Fn.GetLocation() fLoc := t.Fn.GetLocation()
fmt.Println(">>>>>>>>>> ", fLoc, fLoc.GetSource()) line := fLoc.GetSource().GetLine(i)
if line != "----" {
lines += fmt.Sprintf("%d:\t%s\n", i, fLoc.GetSource().GetLine(i)) lines += fmt.Sprintf("%d:\t%s\n", i, line)
}
} }
color.Yellow.Printf( color.Yellow.Printf(
"%d: In function '%s' at '%s'\n", "%d: In function '%s' at '%s':%d\n",
i, i,
t.Fn.GetName(), t.Fn.GetName(),
callerLoc.GetSource().Path, callerLoc.GetSource().Path,
callerSource.LineNumberFor(callerLoc.GetStart()),
) )
color.White.Printf("%s\n", lines) color.White.Printf("%s\n", lines)
} }
loc := err.GetLocation() loc := err.GetLocation()
errTag := color.Red.Sprint(err.GetErrType().String())
errTag := color.Red.Sprint("ERROR")
fmt.Printf("%s: %s\nAt: %d to %d\n", errTag, err.String(), loc.GetStart(), loc.GetEnd()) 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()))
}
}