about summary refs log tree commit diff
path: root/pkg/lang/vm/code
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-07-05 22:15:29 +0200
committerMel <einebeere@gmail.com>2022-07-05 22:15:29 +0200
commitb09fce67753e199d4ae0fe6138f909b5e3413208 (patch)
treee2010cc61b2614b43556a738eae38053ef8be345 /pkg/lang/vm/code
parente29ee3e310044ddb2356513808554a46de957659 (diff)
downloadjinx-b09fce67753e199d4ae0fe6138f909b5e3413208.tar.zst
jinx-b09fce67753e199d4ae0fe6138f909b5e3413208.zip
Fix nested if block compiling
Diffstat (limited to 'pkg/lang/vm/code')
-rw-r--r--pkg/lang/vm/code/builder.go77
1 files changed, 67 insertions, 10 deletions
diff --git a/pkg/lang/vm/code/builder.go b/pkg/lang/vm/code/builder.go
index 4a5ef70..f027c49 100644
--- a/pkg/lang/vm/code/builder.go
+++ b/pkg/lang/vm/code/builder.go
@@ -2,12 +2,14 @@ package code
 
 import (
 	"encoding/binary"
+	"fmt"
 	"math"
 )
 
 type Builder struct {
-	code      []byte
-	debugInfo DebugInfo
+	code           []byte
+	debugInfo      DebugInfo
+	relativePcRefs map[int][]int
 
 	currentLine int
 	lineStart   int
@@ -15,10 +17,11 @@ type Builder struct {
 
 func NewBuilder() Builder {
 	return Builder{
-		code:        make([]byte, 0, 64),
-		debugInfo:   NewDebugInfo("unknown file"),
-		lineStart:   -1,
-		currentLine: -1,
+		code:           make([]byte, 0, 64),
+		debugInfo:      NewDebugInfo("unknown file"),
+		relativePcRefs: make(map[int][]int),
+		lineStart:      -1,
+		currentLine:    -1,
 	}
 }
 
@@ -40,17 +43,59 @@ func (b *Builder) AppendString(s string) {
 	b.code = append(b.code, 0)
 }
 
+func (b *Builder) AppendReferenceToPc(pc int64) {
+	b.addPcRef(int(pc), b.Len())
+	b.AppendInt(pc)
+}
+
 func (b *Builder) AppendRaw(raw Raw) {
 	b.code = append(b.code, raw...)
 }
 
+func (b *Builder) AppendBuilder(other Builder) {
+	code := other.code
+	for pc, refsToPc := range other.relativePcRefs {
+		newPc := b.Len() + pc
+		for _, ref := range refsToPc {
+			valueAtRef := binary.LittleEndian.Uint64(code[ref : ref+8])
+			if int(valueAtRef) != pc {
+				panic(fmt.Errorf("reference to pc in builder does not actually reference pc. (pc: %d, value at reference: %d)", pc, valueAtRef))
+			}
+
+			binary.LittleEndian.PutUint64(code[ref:], uint64(newPc))
+			b.addPcRef(newPc, ref+b.Len())
+		}
+	}
+
+	b.code = append(b.code, code...)
+
+	if other.debugInfo.pcToLine.Len() != 0 || other.currentLine != -1 || other.lineStart != -1 {
+		panic("appending debug infos not implemented yet")
+	}
+}
+
+func (b *Builder) AppendBuilderWithoutAdjustingReferences(other Builder) {
+	code := other.code
+	for pc, refsToPc := range other.relativePcRefs {
+		for _, ref := range refsToPc {
+			b.addPcRef(pc, ref+b.Len())
+		}
+	}
+
+	b.code = append(b.code, code...)
+
+	if other.debugInfo.pcToLine.Len() != 0 || other.currentLine != -1 || other.lineStart != -1 {
+		panic("appending debug infos not implemented yet")
+	}
+}
+
 func (b *Builder) StartLine(line int) {
 	if b.lineStart != -1 {
 		panic("line already started")
 	}
 
 	b.currentLine = line
-	b.lineStart = len(b.code)
+	b.lineStart = b.Len()
 }
 
 func (b *Builder) EndLine() {
@@ -63,11 +108,11 @@ func (b *Builder) EndLine() {
 		panic("line not started")
 	}
 
-	if b.lineStart == len(b.code) {
+	if b.lineStart == b.Len() {
 		return
 	}
-	
-	b.debugInfo.AppendLine(len(b.code)-1, b.currentLine)
+
+	b.debugInfo.AppendLine(b.Len()-1, b.currentLine)
 }
 
 func (b *Builder) SetInt(at int, x int64) {
@@ -85,3 +130,15 @@ func (b *Builder) Len() int {
 func (b *Builder) Build() Code {
 	return New(b.code, b.debugInfo)
 }
+
+func (b *Builder) addPcRef(pc int, at int) {
+	refs, ok := b.relativePcRefs[pc]
+	if ok {
+		refs = append(refs, at)
+	} else {
+		refs = make([]int, 1)
+		refs[0] = at
+	}
+
+	b.relativePcRefs[pc] = refs
+}