diff --git a/bootstrap/examples/hello-world.srn b/bootstrap/examples/hello-world.srn index f206f87..28483ec 100644 --- a/bootstrap/examples/hello-world.srn +++ b/bootstrap/examples/hello-world.srn @@ -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"))) diff --git a/bootstrap/pkg/ast/ast.go b/bootstrap/pkg/ast/ast.go index 415bc38..8092694 100644 --- a/bootstrap/pkg/ast/ast.go +++ b/bootstrap/pkg/ast/ast.go @@ -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 { diff --git a/bootstrap/pkg/core/core.go b/bootstrap/pkg/core/core.go index 84b914c..e007c47 100644 --- a/bootstrap/pkg/core/core.go +++ b/bootstrap/pkg/core/core.go @@ -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) diff --git a/bootstrap/pkg/core/errors.go b/bootstrap/pkg/core/errors.go index 04f91c9..473e143 100644 --- a/bootstrap/pkg/core/errors.go +++ b/bootstrap/pkg/core/errors.go @@ -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 diff --git a/bootstrap/pkg/core/parser.go b/bootstrap/pkg/core/parser.go index 8f03748..8fc50d3 100644 --- a/bootstrap/pkg/core/parser.go +++ b/bootstrap/pkg/core/parser.go @@ -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 diff --git a/bootstrap/pkg/core/printer.go b/bootstrap/pkg/core/printer.go index 7974aa9..8c0bb2f 100644 --- a/bootstrap/pkg/core/printer.go +++ b/bootstrap/pkg/core/printer.go @@ -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())) + } +}