[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
|
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 {
|
func (s *Source) GetLine(linenum int) string {
|
||||||
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
||||||
|
if linenum > 0 && linenum < len(lines) {
|
||||||
return lines[linenum-1]
|
return lines[linenum-1]
|
||||||
}
|
}
|
||||||
|
return "!!!"
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Source) LineNumberFor(pos int) int {
|
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 {
|
if pos < 0 {
|
||||||
return -1
|
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 {
|
if i == 0 {
|
||||||
return pos < (*s.LineIndex)[i]
|
return pos < (*s.LineIndex)[i]
|
||||||
} else {
|
} else {
|
||||||
return (*s.LineIndex)[i-1] < pos && pos < (*s.LineIndex)[i]
|
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 {
|
type Location struct {
|
||||||
|
|
|
@ -52,7 +52,7 @@ type Frame struct {
|
||||||
Caller IExpr
|
Caller IExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
type TraceBack = []Frame
|
type TraceBack = []*Frame
|
||||||
|
|
||||||
type CallStackItem struct {
|
type CallStackItem struct {
|
||||||
prev *CallStackItem
|
prev *CallStackItem
|
||||||
|
@ -158,7 +158,7 @@ func (c *CallStack) ToTraceBack() *TraceBack {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
tr = append(tr, item.data)
|
tr = append(tr, &item.data)
|
||||||
item = item.prev
|
item = item.prev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,3 +172,11 @@ func MakeCallStack(debugMode bool) CallStack {
|
||||||
debug: debugMode,
|
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"
|
"fmt"
|
||||||
|
|
||||||
"serene-lang.org/bootstrap/pkg/ast"
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
|
"serene-lang.org/bootstrap/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IError defines the necessary functionality of the internal errors.
|
// IError defines the necessary functionality of the internal errors.
|
||||||
|
@ -49,6 +50,7 @@ type IError interface {
|
||||||
IRepresentable
|
IRepresentable
|
||||||
IDebuggable
|
IDebuggable
|
||||||
|
|
||||||
|
GetDescription() *string
|
||||||
GetStackTrace() *TraceBack
|
GetStackTrace() *TraceBack
|
||||||
// To wrap Golan rrrrors
|
// To wrap Golan rrrrors
|
||||||
WithError(err error) IError
|
WithError(err error) IError
|
||||||
|
@ -61,6 +63,7 @@ type IError interface {
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Node
|
Node
|
||||||
|
errno errors.Errno
|
||||||
WrappedErr error
|
WrappedErr error
|
||||||
msg string
|
msg string
|
||||||
trace *TraceBack
|
trace *TraceBack
|
||||||
|
@ -95,6 +98,16 @@ func (e *Error) GetStackTrace() *TraceBack {
|
||||||
return e.trace
|
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 {
|
func MakePlainError(msg string) IError {
|
||||||
return &Error{
|
return &Error{
|
||||||
msg: msg,
|
msg: msg,
|
||||||
|
@ -104,7 +117,7 @@ func MakePlainError(msg string) IError {
|
||||||
// MakeError creates an Error which points to the given IExpr `e` as
|
// MakeError creates an Error which points to the given IExpr `e` as
|
||||||
// the root of the error.
|
// the root of the error.
|
||||||
func MakeError(rt *Runtime, e IExpr, msg string) IError {
|
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{
|
return &Error{
|
||||||
Node: MakeNodeFromExpr(e),
|
Node: MakeNodeFromExpr(e),
|
||||||
|
@ -119,3 +132,18 @@ func MakeParsetimeErrorf(n Node, msg string, a ...interface{}) IError {
|
||||||
msg: fmt.Sprintf(msg, a...),
|
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"
|
"fmt"
|
||||||
|
|
||||||
"serene-lang.org/bootstrap/pkg/ast"
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
|
"serene-lang.org/bootstrap/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func restOfExprs(es []IExpr, i int) []IExpr {
|
func restOfExprs(es []IExpr, i int) []IExpr {
|
||||||
|
@ -623,7 +624,12 @@ func EvalNSBody(rt *Runtime, ns *Namespace) (*Namespace, IError) {
|
||||||
exprs := body.ToSlice()
|
exprs := body.ToSlice()
|
||||||
|
|
||||||
if len(exprs) == 0 {
|
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 {
|
if exprs[0].GetType() == ast.List {
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"serene-lang.org/bootstrap/pkg/ast"
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
|
"serene-lang.org/bootstrap/pkg/errors"
|
||||||
"serene-lang.org/bootstrap/pkg/hash"
|
"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.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, MakeSemanticError(
|
||||||
return nil, MakeError(rt, values.(IExpr),
|
rt,
|
||||||
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()))
|
values.(IExpr),
|
||||||
|
errors.E0002,
|
||||||
|
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(binds); i += 1 {
|
for i := 0; i < len(binds); i += 1 {
|
||||||
|
|
|
@ -69,23 +69,42 @@ type StringParser struct {
|
||||||
buffer []string
|
buffer []string
|
||||||
pos int
|
pos int
|
||||||
source string
|
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
|
lineIndex []int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing IParsable for StringParser ---
|
// 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
|
// Returns the next character in the buffer
|
||||||
func (sp *StringParser) next(skipWhitespace bool) *string {
|
func (sp *StringParser) next(skipWhitespace bool) *string {
|
||||||
if sp.pos >= len(sp.buffer) {
|
if sp.pos >= len(sp.buffer) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
char := sp.buffer[sp.pos]
|
char := sp.buffer[sp.pos]
|
||||||
|
sp.updateLineIndex(sp.pos)
|
||||||
if char == "\n" {
|
|
||||||
// Including the \n itself
|
|
||||||
sp.lineIndex = append(sp.lineIndex, sp.pos+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
sp.pos = sp.pos + 1
|
sp.pos = sp.pos + 1
|
||||||
|
|
||||||
if skipWhitespace && isSeparator(&char) {
|
if skipWhitespace && isSeparator(&char) {
|
||||||
|
@ -121,6 +140,7 @@ func (sp *StringParser) peek(skipWhitespace bool) *string {
|
||||||
|
|
||||||
c := sp.buffer[sp.pos]
|
c := sp.buffer[sp.pos]
|
||||||
if isSeparator(&c) && skipWhitespace {
|
if isSeparator(&c) && skipWhitespace {
|
||||||
|
sp.updateLineIndex(sp.pos)
|
||||||
sp.pos = sp.pos + 1
|
sp.pos = sp.pos + 1
|
||||||
return sp.peek(skipWhitespace)
|
return sp.peek(skipWhitespace)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,29 +67,29 @@ func Println(rt *Runtime, ast ...IRepresentable) {
|
||||||
func PrintError(rt *Runtime, err IError) {
|
func PrintError(rt *Runtime, err IError) {
|
||||||
trace := err.GetStackTrace()
|
trace := err.GetStackTrace()
|
||||||
|
|
||||||
for i, f := range *trace {
|
for i, t := range *trace {
|
||||||
loc := f.Caller.GetLocation()
|
caller := t.Caller
|
||||||
fmt.Println("===============")
|
callerLoc := caller.GetLocation()
|
||||||
fmt.Println(f.Fn.GetLocation())
|
callerSource := callerLoc.GetSource()
|
||||||
fmt.Println(loc)
|
|
||||||
source := loc.GetSource()
|
startline := callerSource.LineNumberFor(callerLoc.GetStart())
|
||||||
// if loc.GetSource().Buffer != nil {
|
|
||||||
// fmt.Println(loc.GetSource().LineIndex)
|
if startline > 0 {
|
||||||
// source = *loc.GetSource().Buffer
|
startline -= 1
|
||||||
// }
|
}
|
||||||
startline := source.LineNumberFor(loc.GetStart()) - 1
|
|
||||||
endline := source.LineNumberFor(loc.GetEnd()) + 1
|
endline := callerSource.LineNumberFor(callerLoc.GetEnd()) + 1
|
||||||
|
|
||||||
var lines string
|
var lines string
|
||||||
for i := startline; i <= endline; i++ {
|
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(
|
color.Yellow.Printf(
|
||||||
"%d: In function '%s' at '%s'\n",
|
"%d: In function '%s' at '%s'\n",
|
||||||
i,
|
i,
|
||||||
f.Fn.GetName(),
|
t.Fn.GetName(),
|
||||||
loc.GetSource().Path,
|
callerLoc.GetSource().Path,
|
||||||
)
|
)
|
||||||
color.White.Printf("%s\n", lines)
|
color.White.Printf("%s\n", lines)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue