[Bootstrap] Update the call stack to container the caller and add a line index to the parser
This commit is contained in:
parent
66e9340005
commit
e895377811
|
@ -53,23 +53,65 @@ type Source struct {
|
|||
LineIndex *[]int
|
||||
}
|
||||
|
||||
func (s *Source) GetPos(start, end int) *string {
|
||||
if start < len(*s.Buffer) && start >= 0 && end < len(*s.Buffer) && end > 0 && start <= end {
|
||||
result := strings.Join((*s.Buffer)[start:end], "")
|
||||
return &result
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
func (s *Source) GetLine(linenum int) string {
|
||||
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
||||
return lines[linenum-1]
|
||||
if linenum > 0 && linenum < len(lines) {
|
||||
return lines[linenum-1]
|
||||
}
|
||||
return "!!!"
|
||||
}
|
||||
|
||||
func (s *Source) LineNumberFor(pos int) int {
|
||||
|
||||
// Some dirty print debugger code
|
||||
// for i, r := range *s.LineIndex {
|
||||
// empty := ""
|
||||
// var line *string
|
||||
// var num int
|
||||
// if i == 0 {
|
||||
// line = s.GetPos(0, r)
|
||||
// num = 0
|
||||
// } else {
|
||||
// line = s.GetPos((*s.LineIndex)[i-1], r)
|
||||
// num = (*s.LineIndex)[i-1]
|
||||
|
||||
// }
|
||||
|
||||
// if line == nil {
|
||||
// line = &empty
|
||||
// }
|
||||
|
||||
// fmt.Print(">>>> ", num, r, *line)
|
||||
// }
|
||||
|
||||
if pos < 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
return sort.Search(len(*s.LineIndex), func(i int) bool {
|
||||
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]
|
||||
}
|
||||
})
|
||||
|
||||
// We've found something
|
||||
if result > -1 {
|
||||
// Since line numbers start from 1 unlike arrays :))
|
||||
result += 1
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
type Location struct {
|
||||
|
|
|
@ -52,7 +52,7 @@ type Frame struct {
|
|||
Caller IExpr
|
||||
}
|
||||
|
||||
type TraceBack = []Frame
|
||||
type TraceBack = []*Frame
|
||||
|
||||
type CallStackItem struct {
|
||||
prev *CallStackItem
|
||||
|
@ -158,7 +158,7 @@ func (c *CallStack) ToTraceBack() *TraceBack {
|
|||
if item == nil {
|
||||
break
|
||||
}
|
||||
tr = append(tr, item.data)
|
||||
tr = append(tr, &item.data)
|
||||
item = item.prev
|
||||
}
|
||||
|
||||
|
@ -172,3 +172,11 @@ func MakeCallStack(debugMode bool) CallStack {
|
|||
debug: debugMode,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeFrame(caller IExpr, f IFn, count uint) *Frame {
|
||||
return &Frame{
|
||||
Count: count,
|
||||
Caller: caller,
|
||||
Fn: f,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/ast"
|
||||
"serene-lang.org/bootstrap/pkg/errors"
|
||||
)
|
||||
|
||||
// IError defines the necessary functionality of the internal errors.
|
||||
|
@ -49,6 +50,7 @@ type IError interface {
|
|||
IRepresentable
|
||||
IDebuggable
|
||||
|
||||
GetDescription() *string
|
||||
GetStackTrace() *TraceBack
|
||||
// To wrap Golan rrrrors
|
||||
WithError(err error) IError
|
||||
|
@ -61,6 +63,7 @@ type IError interface {
|
|||
|
||||
type Error struct {
|
||||
Node
|
||||
errno errors.Errno
|
||||
WrappedErr error
|
||||
msg string
|
||||
trace *TraceBack
|
||||
|
@ -95,6 +98,16 @@ func (e *Error) GetStackTrace() *TraceBack {
|
|||
return e.trace
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -104,7 +117,7 @@ func MakePlainError(msg string) IError {
|
|||
// 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 {
|
||||
trace := append(*rt.Stack.ToTraceBack(), Frame{0, rt.Stack.GetCurrentFn(), e})
|
||||
trace := append(*rt.Stack.ToTraceBack(), &Frame{0, rt.Stack.GetCurrentFn(), e})
|
||||
|
||||
return &Error{
|
||||
Node: MakeNodeFromExpr(e),
|
||||
|
@ -119,3 +132,18 @@ func MakeParsetimeErrorf(n Node, msg string, a ...interface{}) IError {
|
|||
msg: fmt.Sprintf(msg, a...),
|
||||
}
|
||||
}
|
||||
|
||||
func MakeSemanticError(rt *Runtime, e IExpr, errno errors.Errno, msg string) IError {
|
||||
currentFn := rt.Stack.GetCurrentFn()
|
||||
|
||||
frames := &[]*Frame{
|
||||
MakeFrame(e, currentFn, 1),
|
||||
}
|
||||
|
||||
return &Error{
|
||||
Node: MakeNodeFromExpr(e),
|
||||
errno: errno,
|
||||
msg: msg,
|
||||
trace: frames,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/ast"
|
||||
"serene-lang.org/bootstrap/pkg/errors"
|
||||
)
|
||||
|
||||
func restOfExprs(es []IExpr, i int) []IExpr {
|
||||
|
@ -623,7 +624,12 @@ func EvalNSBody(rt *Runtime, ns *Namespace) (*Namespace, IError) {
|
|||
exprs := body.ToSlice()
|
||||
|
||||
if len(exprs) == 0 {
|
||||
return nil, MakeError(rt, ns, fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()))
|
||||
return nil, MakeSemanticError(
|
||||
rt,
|
||||
ns,
|
||||
errors.E0001,
|
||||
fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()),
|
||||
)
|
||||
}
|
||||
|
||||
if exprs[0].GetType() == ast.List {
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/ast"
|
||||
"serene-lang.org/bootstrap/pkg/errors"
|
||||
"serene-lang.org/bootstrap/pkg/hash"
|
||||
)
|
||||
|
||||
|
@ -175,9 +176,12 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
|||
fmt.Printf("[DEBUG] Mismatch on bindings and values: Bindings: %s, Values: %s\n", bindings, values)
|
||||
}
|
||||
|
||||
fmt.Println("3333333", values.(IExpr).GetLocation(), bindings.(IExpr).GetLocation())
|
||||
return nil, MakeError(rt, values.(IExpr),
|
||||
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()))
|
||||
return nil, MakeSemanticError(
|
||||
rt,
|
||||
values.(IExpr),
|
||||
errors.E0002,
|
||||
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()),
|
||||
)
|
||||
}
|
||||
|
||||
for i := 0; i < len(binds); i += 1 {
|
||||
|
|
|
@ -66,26 +66,45 @@ type IParsable interface {
|
|||
// StringParser is an implementation of the IParsable that operates on strings.
|
||||
// To put it simply it parses input strings
|
||||
type StringParser struct {
|
||||
buffer []string
|
||||
pos int
|
||||
source string
|
||||
buffer []string
|
||||
pos int
|
||||
source string
|
||||
|
||||
// This slice holds the boundaries of lines in the buffer. Basically
|
||||
// each element determines the position which a line ends and the line
|
||||
// number directly maps to the position of it's boundary in the slice.
|
||||
lineIndex []int
|
||||
}
|
||||
|
||||
// Implementing IParsable for StringParser ---
|
||||
|
||||
// updateLineIndex reads the current character and if it is an end of line, then
|
||||
// it will update the line index to add the boundaries of the current line.
|
||||
func (sp *StringParser) updateLineIndex(pos int) {
|
||||
if pos < len(sp.buffer) {
|
||||
c := sp.buffer[pos]
|
||||
if c == "\n" {
|
||||
if len(sp.lineIndex) > 0 {
|
||||
if sp.lineIndex[len(sp.lineIndex)-1] != pos+1 {
|
||||
// Including the \n itself
|
||||
sp.lineIndex = append(sp.lineIndex, pos+1)
|
||||
}
|
||||
} else {
|
||||
sp.lineIndex = append(sp.lineIndex, pos+1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns the next character in the buffer
|
||||
func (sp *StringParser) next(skipWhitespace bool) *string {
|
||||
if sp.pos >= len(sp.buffer) {
|
||||
return nil
|
||||
}
|
||||
char := sp.buffer[sp.pos]
|
||||
|
||||
if char == "\n" {
|
||||
// Including the \n itself
|
||||
sp.lineIndex = append(sp.lineIndex, sp.pos+1)
|
||||
}
|
||||
|
||||
sp.updateLineIndex(sp.pos)
|
||||
sp.pos = sp.pos + 1
|
||||
|
||||
if skipWhitespace && isSeparator(&char) {
|
||||
|
@ -121,6 +140,7 @@ func (sp *StringParser) peek(skipWhitespace bool) *string {
|
|||
|
||||
c := sp.buffer[sp.pos]
|
||||
if isSeparator(&c) && skipWhitespace {
|
||||
sp.updateLineIndex(sp.pos)
|
||||
sp.pos = sp.pos + 1
|
||||
return sp.peek(skipWhitespace)
|
||||
}
|
||||
|
|
|
@ -67,29 +67,29 @@ func Println(rt *Runtime, ast ...IRepresentable) {
|
|||
func PrintError(rt *Runtime, err IError) {
|
||||
trace := err.GetStackTrace()
|
||||
|
||||
for i, f := range *trace {
|
||||
loc := f.Caller.GetLocation()
|
||||
fmt.Println("===============")
|
||||
fmt.Println(f.Fn.GetLocation())
|
||||
fmt.Println(loc)
|
||||
source := loc.GetSource()
|
||||
// if loc.GetSource().Buffer != nil {
|
||||
// fmt.Println(loc.GetSource().LineIndex)
|
||||
// source = *loc.GetSource().Buffer
|
||||
// }
|
||||
startline := source.LineNumberFor(loc.GetStart()) - 1
|
||||
endline := source.LineNumberFor(loc.GetEnd()) + 1
|
||||
for i, t := range *trace {
|
||||
caller := t.Caller
|
||||
callerLoc := caller.GetLocation()
|
||||
callerSource := callerLoc.GetSource()
|
||||
|
||||
startline := callerSource.LineNumberFor(callerLoc.GetStart())
|
||||
|
||||
if startline > 0 {
|
||||
startline -= 1
|
||||
}
|
||||
|
||||
endline := callerSource.LineNumberFor(callerLoc.GetEnd()) + 1
|
||||
|
||||
var lines string
|
||||
for i := startline; i <= endline; i++ {
|
||||
lines += fmt.Sprintf("%d:\t%s\n", i, source.GetLine(i))
|
||||
lines += fmt.Sprintf("%d:\t%s\n", i, t.Fn.GetLocation().GetSource().GetLine(i))
|
||||
}
|
||||
|
||||
color.Yellow.Printf(
|
||||
"%d: In function '%s' at '%s'\n",
|
||||
i,
|
||||
f.Fn.GetName(),
|
||||
loc.GetSource().Path,
|
||||
t.Fn.GetName(),
|
||||
callerLoc.GetSource().Path,
|
||||
)
|
||||
color.White.Printf("%s\n", lines)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue