aboutsummaryrefslogtreecommitdiff
path: root/pkg/lang
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-08-22 23:41:49 +0000
committerMel <einebeere@gmail.com>2022-08-22 23:41:49 +0000
commite22df631c4428f8dea4d5784a8a7840d2f84c6be (patch)
tree084c233741374cdabde8d70b49988b3dca686719 /pkg/lang
parent24183cd5363b96d83292df17d44fa79d8b47a89f (diff)
downloadjinx-e22df631c4428f8dea4d5784a8a7840d2f84c6be.tar.zst
jinx-e22df631c4428f8dea4d5784a8a7840d2f84c6be.zip
Generate runtime debug info with source locations
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/compiler/compiler.go46
-rw-r--r--pkg/lang/vm/code/builder.go6
-rw-r--r--pkg/lang/vm/code/debug.go29
-rw-r--r--pkg/lang/vm/vm.go8
4 files changed, 67 insertions, 22 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go
index b08a215..b1d4dfb 100644
--- a/pkg/lang/compiler/compiler.go
+++ b/pkg/lang/compiler/compiler.go
@@ -70,6 +70,8 @@ func (comp *Compiler) Compile() (modules.Module, error) {
}
func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error {
+ startPc := t.Len()
+
var err error
switch stmt.Kind {
case ast.StmtKindEmpty:
@@ -119,15 +121,24 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error {
}
// Wrap errors in a compiler error, if it's not already one.
- if err != nil && !isCompilerError(err) {
- err = Error{
- Module: comp.name,
- Loc: stmt.At,
- Err: err,
+ if err != nil {
+ if !isCompilerError(err) {
+ err = Error{
+ Module: comp.name,
+ Loc: stmt.At,
+ Err: err,
+ }
}
+ return err
}
- return err
+ // Add debug info if needed.
+ endPc := t.Len()
+ if startPc != endPc {
+ t.AddDebugInfo(startPc, endPc-1, stmt.At)
+ }
+
+ return nil
}
func (comp *Compiler) compileUseStmt(t *code.Builder, stmt ast.StmtUse) error {
@@ -645,6 +656,8 @@ func (comp *Compiler) compileExprStmt(t *code.Builder, exprStmt ast.StmtExpr) er
}
func (comp *Compiler) compileExpr(t *code.Builder, expr ast.Expr) error {
+ startPc := t.Len()
+
var err error
switch expr.Kind {
case ast.ExprKindBinary:
@@ -683,15 +696,24 @@ func (comp *Compiler) compileExpr(t *code.Builder, expr ast.Expr) error {
}
// If the error was not a compiler error, we need to wrap it in one.
- if err != nil && !isCompilerError(err) {
- err = Error{
- Module: comp.name,
- Loc: expr.At,
- Err: err,
+ if err != nil {
+ if !isCompilerError(err) {
+ err = Error{
+ Module: comp.name,
+ Loc: expr.At,
+ Err: err,
+ }
}
+
+ return err
}
- return err
+ endPc := t.Len()
+ if startPc != endPc {
+ t.AddDebugInfo(startPc, endPc-1, expr.At)
+ }
+
+ return nil
}
func (comp *Compiler) compileBinaryExpr(t *code.Builder, expr ast.ExprBinary) error {
diff --git a/pkg/lang/vm/code/builder.go b/pkg/lang/vm/code/builder.go
index f413ba1..618608a 100644
--- a/pkg/lang/vm/code/builder.go
+++ b/pkg/lang/vm/code/builder.go
@@ -2,6 +2,7 @@ package code
import (
"encoding/binary"
+ "jinx/pkg/libs/source"
"math"
)
@@ -76,6 +77,7 @@ func (b *Builder) AppendBuilder(other Builder) error {
}
b.AppendRaw(other.code)
+ b.debugInfo.AppendOther(other.debugInfo)
return nil
}
@@ -114,6 +116,10 @@ func (b *Builder) EndLine() {
b.debugInfo.AppendLine(b.Len()-1, b.currentLine)
}
+func (b *Builder) AddDebugInfo(fromPc, toPc int, loc source.Loc) {
+ b.debugInfo.FillInfo(fromPc, toPc, loc)
+}
+
func (b *Builder) SetInt(at int, x int64) {
binary.LittleEndian.PutUint64(b.code[at:], uint64(x))
}
diff --git a/pkg/lang/vm/code/debug.go b/pkg/lang/vm/code/debug.go
index ebf0ea1..efb788c 100644
--- a/pkg/lang/vm/code/debug.go
+++ b/pkg/lang/vm/code/debug.go
@@ -1,16 +1,19 @@
package code
-import "jinx/pkg/libs/rangemap"
+import (
+ "jinx/pkg/libs/rangemap"
+ "jinx/pkg/libs/source"
+)
type DebugInfo struct {
file string
- pcToLine rangemap.RangeMap[int]
+ pcToLine rangemap.RangeMap[source.Loc]
}
func NewDebugInfo(file string) DebugInfo {
return DebugInfo{
file: file,
- pcToLine: rangemap.New[int](),
+ pcToLine: rangemap.New[source.Loc](),
}
}
@@ -18,14 +21,22 @@ func (di *DebugInfo) File() string {
return di.file
}
-func (di *DebugInfo) PCToLine(pc int) int {
- line := di.pcToLine.Get(pc)
- if line == nil {
- return -1
+func (di *DebugInfo) PCToLoc(pc int) (source.Loc, bool) {
+ loc := di.pcToLine.Get(pc)
+ if loc == nil {
+ return source.Loc{}, false
}
- return *line
+ return *loc, true
}
func (di *DebugInfo) AppendLine(uptoPc, line int) {
- di.pcToLine.AppendToLast(uptoPc, line)
+ di.pcToLine.AppendToLast(uptoPc, source.Loc{Row: line, Col: 0})
+}
+
+func (di *DebugInfo) FillInfo(from, to int, loc source.Loc) {
+ di.pcToLine.Fill(from, to, loc)
+}
+
+func (di *DebugInfo) AppendOther(other DebugInfo) {
+ di.pcToLine.AppendRanges(other.pcToLine)
}
diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go
index 4d4d5ca..b18e7cb 100644
--- a/pkg/lang/vm/vm.go
+++ b/pkg/lang/vm/vm.go
@@ -121,10 +121,16 @@ func (vm *VM) executeModule(moduleID int) error {
vm.advancePC(advance)
if decision, err := vm.step(code, op); err != nil {
+ loc, ok := code.Debug().PCToLoc(vm.pc())
+ line := loc.Row
+ if !ok {
+ line = -1
+ }
+
return Error{
Pos: vm.pos,
Module: module.Name(),
- Line: code.Debug().PCToLine(vm.pc()),
+ Line: line,
Err: err,
}
} else if decision == stepDecisionHalt {