Skip to content

Commit

Permalink
Track both start and end positions of every object, report start posi…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
candid82 committed Dec 23, 2016
1 parent 81cab0b commit 3e2036d
Show file tree
Hide file tree
Showing 5 changed files with 384 additions and 350 deletions.
14 changes: 7 additions & 7 deletions core/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ func (rt *Runtime) stacktrace() string {
name := "global"
for _, f := range rt.callstack.frames {
pos := f.traceable.Pos()
b.WriteString(fmt.Sprintf(" %s %s:%d:%d\n", name, pos.Filename(), pos.line, pos.column))
b.WriteString(fmt.Sprintf(" %s %s:%d:%d\n", name, pos.Filename(), pos.startLine, pos.startColumn))
name = f.traceable.Name()
if strings.HasPrefix(name, "#'") {
name = name[2:]
}
}
b.WriteString(fmt.Sprintf(" %s %s:%d:%d", name, pos.Filename(), pos.line, pos.column))
b.WriteString(fmt.Sprintf(" %s %s:%d:%d", name, pos.Filename(), pos.startLine, pos.startColumn))
return b.String()
}

Expand Down Expand Up @@ -125,7 +125,7 @@ func (s *Callstack) String() string {
var b bytes.Buffer
for _, f := range s.frames {
pos := f.traceable.Pos()
b.WriteString(fmt.Sprintf("%s %s:%d:%d\n", f.traceable.Name(), pos.Filename(), pos.line, pos.column))
b.WriteString(fmt.Sprintf("%s %s:%d:%d\n", f.traceable.Name(), pos.Filename(), pos.startLine, pos.startColumn))
}
if b.Len() > 0 {
b.Truncate(b.Len() - 1)
Expand Down Expand Up @@ -159,9 +159,9 @@ func (err *EvalError) WithInfo(info *ObjectInfo) Object {

func (err *EvalError) Error() string {
if len(err.rt.callstack.frames) > 0 {
return fmt.Sprintf("%s:%d:%d: Eval error: %s\nStacktrace:\n%s", err.pos.Filename(), err.pos.line, err.pos.column, err.msg, err.rt.stacktrace())
return fmt.Sprintf("%s:%d:%d: Eval error: %s\nStacktrace:\n%s", err.pos.Filename(), err.pos.startLine, err.pos.startColumn, err.msg, err.rt.stacktrace())
} else {
return fmt.Sprintf("%s:%d:%d: Eval error: %s", err.pos.Filename(), err.pos.line, err.pos.column, err.msg)
return fmt.Sprintf("%s:%d:%d: Eval error: %s", err.pos.Filename(), err.pos.startLine, err.pos.startColumn, err.msg)
}
}

Expand Down Expand Up @@ -227,8 +227,8 @@ func (expr *DefExpr) Eval(env *LocalEnv) Object {
expr.vr.Value = Eval(expr.value, env)
}
meta := EmptyArrayMap()
meta.Add(MakeKeyword("line"), Int{I: expr.line})
meta.Add(MakeKeyword("column"), Int{I: expr.column})
meta.Add(MakeKeyword("line"), Int{I: expr.startLine})
meta.Add(MakeKeyword("column"), Int{I: expr.startColumn})
meta.Add(MakeKeyword("file"), String{S: *expr.filename})
expr.vr.meta = meta
if expr.meta != nil {
Expand Down
12 changes: 7 additions & 5 deletions core/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import (

type (
Position struct {
line int
column int
filename *string
endLine int
endColumn int
startLine int
startColumn int
filename *string
}
Equality interface {
Equals(interface{}) bool
Expand Down Expand Up @@ -556,9 +558,9 @@ func (exInfo *ExInfo) Error() string {
}
}
if len(exInfo.rt.callstack.frames) > 0 {
return fmt.Sprintf("%s:%d:%d: Exception: %s\nStacktrace:\n%s", pos.Filename(), pos.line, pos.column, exInfo.msg.S, exInfo.rt.stacktrace())
return fmt.Sprintf("%s:%d:%d: Exception: %s\nStacktrace:\n%s", pos.Filename(), pos.startLine, pos.startColumn, exInfo.msg.S, exInfo.rt.stacktrace())
} else {
return fmt.Sprintf("%s:%d:%d: Exception: %s", pos.Filename(), pos.line, pos.column, exInfo.msg.S)
return fmt.Sprintf("%s:%d:%d: Exception: %s", pos.Filename(), pos.startLine, pos.startColumn, exInfo.msg.S)
}
}

Expand Down
8 changes: 4 additions & 4 deletions core/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (err ParseError) Error() string {
line, column, filename := 0, 0, "<file>"
info := err.obj.GetInfo()
if info != nil {
line, column, filename = info.line, info.column, info.Filename()
line, column, filename = info.startLine, info.startColumn, info.Filename()
}
return fmt.Sprintf("%s:%d:%d: Parse error: %s", filename, line, column, err.msg)
}
Expand Down Expand Up @@ -679,7 +679,7 @@ func parseLetLoop(obj Object, isLoop bool, ctx *ParseContext) *LetExpr {
res.body = parseBody(obj.(Seq).Rest().Rest(), ctx)
if len(res.body) == 0 {
pos := GetPosition(obj)
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: %s form with empty body\n", pos.Filename(), pos.line, pos.column, formName)
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: %s form with empty body\n", pos.Filename(), pos.startLine, pos.startColumn, formName)
}
default:
panic(&ParseError{obj: obj, msg: formName + " requires a vector for its bindings"})
Expand Down Expand Up @@ -784,7 +784,7 @@ func macroexpand1(seq Seq, ctx *ParseContext) Object {
}

func reportNotAFunction(pos Position, name string) {
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: %s is not a function\n", pos.Filename(), pos.line, pos.column, name)
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: %s is not a function\n", pos.Filename(), pos.startLine, pos.startColumn, name)
}

func reportWrongArity(expr *FnExpr, isMacro bool, call *CallExpr, pos Position) {
Expand All @@ -801,7 +801,7 @@ func reportWrongArity(expr *FnExpr, isMacro bool, call *CallExpr, pos Position)
if v != nil && passedArgsCount >= len(v.args)-1 {
return
}
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: Wrong number of args (%d) passed to %s\n", pos.Filename(), pos.line, pos.column, len(call.args), call.name)
fmt.Fprintf(os.Stderr, "%s:%d:%d: Parse warning: Wrong number of args (%d) passed to %s\n", pos.Filename(), pos.startLine, pos.startColumn, len(call.args), call.name)
}

func parseSetMacro(obj Object, ctx *ParseContext) Expr {
Expand Down
34 changes: 33 additions & 1 deletion core/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ type (
msg string
}
ReadFunc func(reader *Reader) Object
pos struct {
line int
column int
}
)

const EOF = -1
Expand All @@ -37,6 +41,17 @@ func readStub(reader *Reader) Object {

var DATA_READERS = map[*string]ReadFunc{}
var NIL = Nil{}
var posStack = make([]pos, 0, 8)

func pushPos(reader *Reader) {
posStack = append(posStack, pos{line: reader.line, column: reader.column})
}

func popPos() pos {
p := posStack[len(posStack)-1]
posStack = posStack[:len(posStack)-1]
return p
}

func init() {
DATA_READERS[MakeSymbol("inst").name] = readStub
Expand Down Expand Up @@ -99,7 +114,14 @@ func MakeReadError(reader *Reader, msg string) ReadError {
}

func MakeReadObject(reader *Reader, obj Object) Object {
return obj.WithInfo(&ObjectInfo{Position: Position{line: reader.line, column: reader.column, filename: reader.filename}})
p := popPos()
return obj.WithInfo(&ObjectInfo{Position: Position{
startColumn: p.column,
startLine: p.line,
endLine: reader.line,
endColumn: reader.column,
filename: reader.filename,
}})
}

func DeriveReadObject(base Object, obj Object) Object {
Expand Down Expand Up @@ -748,20 +770,24 @@ func readDispatch(reader *Reader) Object {
case '"':
return readString(reader, true)
case '\'':
popPos()
nextObj := Read(reader)
return DeriveReadObject(nextObj, NewListFrom(DeriveReadObject(nextObj, MakeSymbol("var")), nextObj))
case '^':
popPos()
return readWithMeta(reader)
case '{':
return readSet(reader)
case '(':
popPos()
reader.Unget()
ARGS = make(map[int]Symbol)
fn := Read(reader)
res := makeFnForm(ARGS, fn)
ARGS = nil
return res
}
popPos()
reader.Unget()
return readTagged(reader)
}
Expand All @@ -780,6 +806,7 @@ func readWithMeta(reader *Reader) Object {
func Read(reader *Reader) Object {
eatWhitespace(reader)
r := reader.Get()
pushPos(reader)
switch {
case r == '\\':
return readCharacter(reader)
Expand Down Expand Up @@ -807,12 +834,15 @@ func Read(reader *Reader) Object {
case r == '/' && isDelimiter(reader.Peek()):
return MakeReadObject(reader, MakeSymbol("/"))
case r == '\'':
popPos()
nextObj := Read(reader)
return makeQuote(nextObj, MakeSymbol("quote"))
case r == '@':
popPos()
nextObj := Read(reader)
return DeriveReadObject(nextObj, NewListFrom(DeriveReadObject(nextObj, MakeSymbol("deref")), nextObj))
case r == '~':
popPos()
if reader.Peek() == '@' {
reader.Get()
nextObj := Read(reader)
Expand All @@ -821,9 +851,11 @@ func Read(reader *Reader) Object {
nextObj := Read(reader)
return makeQuote(nextObj, MakeSymbol("unquote"))
case r == '`':
popPos()
nextObj := Read(reader)
return makeSyntaxQuote(nextObj, make(map[*string]Symbol), reader)
case r == '^':
popPos()
return readWithMeta(reader)
case r == '#':
return readDispatch(reader)
Expand Down
Loading

0 comments on commit 3e2036d

Please sign in to comment.