mirror of
https://github.com/bearlanguageorg/bear.git
synced 2026-08-26 14:57:18 +00:00
Code split
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
// opcodes.v — bytecode opcodes for the VuurRaaf VM.
|
||||
//
|
||||
// Keep in sync with the compiler and assembler.
|
||||
module vm
|
||||
|
||||
const op_halt = u8(0)
|
||||
const op_push_i = u8(1)
|
||||
const op_push_s = u8(2)
|
||||
const op_load = u8(3)
|
||||
const op_store = u8(4)
|
||||
const op_pop = u8(5)
|
||||
const op_dup = u8(6)
|
||||
const op_add = u8(7)
|
||||
const op_sub = u8(8)
|
||||
const op_mul = u8(9)
|
||||
const op_div = u8(10)
|
||||
const op_mod = u8(11)
|
||||
const op_neg = u8(12)
|
||||
const op_eq = u8(13)
|
||||
const op_ne = u8(14)
|
||||
const op_lt = u8(15)
|
||||
const op_le = u8(16)
|
||||
const op_gt = u8(17)
|
||||
const op_ge = u8(18)
|
||||
const op_and = u8(19)
|
||||
const op_or = u8(20)
|
||||
const op_not = u8(21)
|
||||
const op_jmp = u8(22)
|
||||
const op_jz = u8(23)
|
||||
const op_jnz = u8(24)
|
||||
const op_call = u8(25)
|
||||
const op_ret = u8(26)
|
||||
const op_retv = u8(27)
|
||||
const op_print = u8(28)
|
||||
const op_println = u8(29)
|
||||
const op_assert = u8(30)
|
||||
const op_enter = u8(31)
|
||||
const op_mkarray = u8(32)
|
||||
const op_aget = u8(33)
|
||||
const op_aset = u8(34)
|
||||
const op_alen = u8(35)
|
||||
const op_apush = u8(36)
|
||||
const op_mkstruct = u8(37)
|
||||
const op_sget = u8(38)
|
||||
const op_sset = u8(39)
|
||||
const op_shas = u8(40) // has(map, "key") -> 1 if key exists, 0 otherwise
|
||||
const op_sdel = u8(41) // delete(map, "key") -> removes the key
|
||||
const op_slen = u8(42) // slen(struct) -> number of fields
|
||||
const op_skeys = u8(43) // skeys(struct) -> array of field name strings
|
||||
@@ -0,0 +1,111 @@
|
||||
// ops.v — arithmetic, comparison, and string operations for the VuurRaaf VM.
|
||||
module vm
|
||||
|
||||
fn (mut v Vm) add(a i64, b i64) !i64 {
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
return error('cannot add arrays with +')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
return error('cannot add structs with +')
|
||||
}
|
||||
if v.is_str(a) && v.is_str(b) {
|
||||
return v.alloc_str(v.strings[v.hand(a)] + v.strings[v.hand(b)])
|
||||
}
|
||||
if v.is_str(a) {
|
||||
return v.alloc_str(v.strings[v.hand(a)] + v.num_str(b))
|
||||
}
|
||||
if v.is_str(b) {
|
||||
return v.alloc_str(v.num_str(a) + v.strings[v.hand(b)])
|
||||
}
|
||||
return v.enc_int(v.dec_int(a) + v.dec_int(b))
|
||||
}
|
||||
|
||||
fn (mut v Vm) alloc_str(s string) i64 {
|
||||
v.strings << s
|
||||
return v.mkstr(v.strings.len - 1)
|
||||
}
|
||||
|
||||
fn (mut v Vm) num_str(x i64) string {
|
||||
return v.dec_int(x).str()
|
||||
}
|
||||
|
||||
fn (mut v Vm) arith(a i64, b i64, op string) !i64 {
|
||||
if v.is_str(a) || v.is_str(b) {
|
||||
return error('cannot use strings with "${op}"')
|
||||
}
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
return error('cannot use arrays with "${op}"')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
return error('cannot use structs with "${op}"')
|
||||
}
|
||||
x := v.dec_int(a)
|
||||
y := v.dec_int(b)
|
||||
match op {
|
||||
'-' {
|
||||
return v.enc_int(x - y)
|
||||
}
|
||||
'*' {
|
||||
return v.enc_int(x * y)
|
||||
}
|
||||
'/' {
|
||||
if y == 0 {
|
||||
return error('division by zero')
|
||||
}
|
||||
return v.enc_int(x / y)
|
||||
}
|
||||
'%' {
|
||||
if y == 0 {
|
||||
return error('division by zero')
|
||||
}
|
||||
return v.enc_int(x % y)
|
||||
}
|
||||
else {
|
||||
return error('internal: bad arith op "${op}"')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut v Vm) cmp(a i64, b i64, op string) !i64 {
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
// arrays compare by identity (handle equality) with ==/!=
|
||||
if op == '==' || op == '!=' {
|
||||
return bool_i64(if op == '==' { a == b } else { a != b })
|
||||
}
|
||||
return error('cannot order arrays')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
// structs compare by identity (handle equality) with ==/!=
|
||||
if op == '==' || op == '!=' {
|
||||
return bool_i64(if op == '==' { a == b } else { a != b })
|
||||
}
|
||||
return error('cannot order structs')
|
||||
}
|
||||
if v.is_str(a) && v.is_str(b) {
|
||||
sa := v.strings[v.hand(a)]
|
||||
sb := v.strings[v.hand(b)]
|
||||
return bool_i64(match op {
|
||||
'==' { sa == sb }
|
||||
'!=' { sa != sb }
|
||||
'<' { sa < sb }
|
||||
'<=' { sa <= sb }
|
||||
'>' { sa > sb }
|
||||
'>=' { sa >= sb }
|
||||
else { return error('internal: bad cmp op "${op}"') }
|
||||
})
|
||||
}
|
||||
if v.is_str(a) || v.is_str(b) {
|
||||
return error('cannot compare a string and a number')
|
||||
}
|
||||
x := v.dec_int(a)
|
||||
y := v.dec_int(b)
|
||||
return bool_i64(match op {
|
||||
'==' { x == y }
|
||||
'!=' { x != y }
|
||||
'<' { x < y }
|
||||
'<=' { x <= y }
|
||||
'>' { x > y }
|
||||
'>=' { x >= y }
|
||||
else { return error('internal: bad cmp op "${op}"') }
|
||||
})
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// print.v — value rendering and instruction tracing for the VuurRaaf VM.
|
||||
module vm
|
||||
|
||||
fn (mut v Vm) print_val(x i64) {
|
||||
print(v.val_str(x, 0))
|
||||
}
|
||||
|
||||
// val_str renders a value: strings as-is, arrays as [a, b, ...] (with a depth
|
||||
// guard so self-referential arrays cannot hang the printer), numbers as ints.
|
||||
fn (mut v Vm) val_str(x i64, depth int) string {
|
||||
if depth > 16 {
|
||||
return '...'
|
||||
}
|
||||
if v.is_str(x) && v.valid_handle(x) {
|
||||
return v.strings[v.hand(x)]
|
||||
}
|
||||
if v.is_arr(x) && v.valid_arr_handle(x) {
|
||||
a := v.arrays[v.hand(x)]
|
||||
mut s := '['
|
||||
limit := if a.len > 20 { 20 } else { a.len }
|
||||
for i in 0..limit {
|
||||
if i > 0 {
|
||||
s += ', '
|
||||
}
|
||||
s += v.val_str(a[i], depth + 1)
|
||||
}
|
||||
if a.len > limit {
|
||||
s += ', ...'
|
||||
}
|
||||
return s + ']'
|
||||
}
|
||||
if v.is_struct(x) && v.valid_struct_handle(x) {
|
||||
s := v.structs[v.hand(x)]
|
||||
mut out := '{'
|
||||
limit := if s.fields.len > 20 { 20 } else { s.fields.len }
|
||||
for i in 0..limit {
|
||||
if i > 0 {
|
||||
out += ', '
|
||||
}
|
||||
out += s.fields[i].name + ': ' + v.val_str(s.fields[i].val, depth + 1)
|
||||
}
|
||||
if s.fields.len > limit {
|
||||
out += ', ...'
|
||||
}
|
||||
return out + '}'
|
||||
}
|
||||
return v.dec_int(x).str()
|
||||
}
|
||||
|
||||
fn (mut v Vm) trace_op(op u8) {
|
||||
name := match op {
|
||||
op_halt { 'halt' }
|
||||
op_push_i { 'push_int' }
|
||||
op_push_s { 'push_str' }
|
||||
op_load { 'load' }
|
||||
op_store { 'store' }
|
||||
op_pop { 'pop' }
|
||||
op_dup { 'dup' }
|
||||
op_add { 'add' }
|
||||
op_sub { 'sub' }
|
||||
op_mul { 'mul' }
|
||||
op_div { 'div' }
|
||||
op_mod { 'mod' }
|
||||
op_neg { 'neg' }
|
||||
op_eq { 'eq' }
|
||||
op_ne { 'ne' }
|
||||
op_lt { 'lt' }
|
||||
op_le { 'le' }
|
||||
op_gt { 'gt' }
|
||||
op_ge { 'ge' }
|
||||
op_and { 'and' }
|
||||
op_or { 'or' }
|
||||
op_not { 'not' }
|
||||
op_jmp { 'jmp' }
|
||||
op_jz { 'jz' }
|
||||
op_jnz { 'jnz' }
|
||||
op_call { 'call' }
|
||||
op_ret { 'ret' }
|
||||
op_retv { 'retv' }
|
||||
op_print { 'print' }
|
||||
op_println { 'println' }
|
||||
op_assert { 'assert' }
|
||||
op_enter { 'enter' }
|
||||
op_mkarray { 'mkarray' }
|
||||
op_aget { 'aget' }
|
||||
op_aset { 'aset' }
|
||||
op_alen { 'alen' }
|
||||
op_apush { 'apush' }
|
||||
op_mkstruct { 'mkstruct' }
|
||||
op_sget { 'sget' }
|
||||
op_sset { 'sset' }
|
||||
op_shas { 'shas' }
|
||||
op_sdel { 'sdel' }
|
||||
op_slen { 'slen' }
|
||||
op_skeys { 'skeys' }
|
||||
else { '??' }
|
||||
}
|
||||
mut s := ''
|
||||
for i in 0..v.sp {
|
||||
if i > 0 {
|
||||
s += ' '
|
||||
}
|
||||
if v.is_str(v.stack[i]) && v.valid_handle(v.stack[i]) {
|
||||
s += '"${v.strings[v.hand(v.stack[i])]}"'
|
||||
} else {
|
||||
s += v.val_str(v.stack[i], 0)
|
||||
}
|
||||
}
|
||||
println(' [ip=${v.ip:4}] ${name:-9} stack: [${s}]')
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// types.v — core types and constants for the VuurRaaf VM.
|
||||
module vm
|
||||
|
||||
const stack_cap = 65536
|
||||
|
||||
// Field is one `name: value` entry of a struct value.
|
||||
struct Field {
|
||||
mut:
|
||||
name string
|
||||
val i64
|
||||
}
|
||||
|
||||
struct StructVal {
|
||||
mut:
|
||||
fields []Field
|
||||
}
|
||||
|
||||
struct Vm {
|
||||
mut:
|
||||
code []u8
|
||||
strings []string
|
||||
arrays [][]i64
|
||||
structs []StructVal
|
||||
stack []i64
|
||||
sp int
|
||||
bp int
|
||||
ip int
|
||||
trace bool
|
||||
halted bool
|
||||
}
|
||||
|
||||
fn bool_i64(b bool) i64 {
|
||||
return if b { i64(1) } else { i64(0) }
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// value.v — tagged value encoding and helpers for the VuurRaaf VM.
|
||||
//
|
||||
// Stack values are 64-bit tagged integers with two tag bits:
|
||||
// low bits 00 -> encoded number (value = raw << 2)
|
||||
// low bits 01 -> string handle (handle = value >> 2, into v.strings)
|
||||
// low bits 10 -> struct handle (handle = value >> 2, into v.structs)
|
||||
// low bits 11 -> array handle (handle = value >> 2, into v.arrays)
|
||||
module vm
|
||||
|
||||
fn (mut v Vm) is_str(x i64) bool {
|
||||
return x & 3 == 1
|
||||
}
|
||||
|
||||
fn (mut v Vm) is_arr(x i64) bool {
|
||||
return x & 3 == 3
|
||||
}
|
||||
|
||||
fn (mut v Vm) is_struct(x i64) bool {
|
||||
return x & 3 == 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) enc_int(x i64) i64 {
|
||||
return u64(x) << 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) dec_int(x i64) i64 {
|
||||
return x >> 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) hand(x i64) int {
|
||||
return int(x >> 2)
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkstr(idx int) i64 {
|
||||
return (u64(idx) << 2) | 1
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkarr(idx int) i64 {
|
||||
return (u64(idx) << 2) | 3
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkstruct_handle(idx int) i64 {
|
||||
return (u64(idx) << 2) | 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) truthy(x i64) bool {
|
||||
return x != 0
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.strings.len
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_arr_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.arrays.len
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_struct_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.structs.len
|
||||
}
|
||||
@@ -1,13 +1,5 @@
|
||||
// vm.v — the VuurRaaf runtime: a small stack-based virtual machine.
|
||||
//
|
||||
// Stack values are 64-bit tagged integers with two tag bits:
|
||||
// low bits 00 -> encoded number (value = raw << 2)
|
||||
// low bits 01 -> string handle (handle = value >> 2, into v.strings)
|
||||
// low bits 10 -> struct handle (handle = value >> 2, into v.structs)
|
||||
// low bits 11 -> array handle (handle = value >> 2, into v.arrays)
|
||||
// Encoding numbers with a constant shift means no integer ever collides with
|
||||
// a string, struct, or array handle.
|
||||
//
|
||||
// Call convention: CALL pushes a frame (retaddr, old bp, argc) and copies the
|
||||
// arguments into the callee's local slots; the callee reserves extra locals
|
||||
// with `enter n` and cleans up with `ret`/`retv`.
|
||||
@@ -15,80 +7,6 @@ module vm
|
||||
|
||||
import obj
|
||||
|
||||
// opcodes — keep in sync with the compiler, assembler, and this interpreter
|
||||
const op_halt = u8(0)
|
||||
const op_push_i = u8(1)
|
||||
const op_push_s = u8(2)
|
||||
const op_load = u8(3)
|
||||
const op_store = u8(4)
|
||||
const op_pop = u8(5)
|
||||
const op_dup = u8(6)
|
||||
const op_add = u8(7)
|
||||
const op_sub = u8(8)
|
||||
const op_mul = u8(9)
|
||||
const op_div = u8(10)
|
||||
const op_mod = u8(11)
|
||||
const op_neg = u8(12)
|
||||
const op_eq = u8(13)
|
||||
const op_ne = u8(14)
|
||||
const op_lt = u8(15)
|
||||
const op_le = u8(16)
|
||||
const op_gt = u8(17)
|
||||
const op_ge = u8(18)
|
||||
const op_and = u8(19)
|
||||
const op_or = u8(20)
|
||||
const op_not = u8(21)
|
||||
const op_jmp = u8(22)
|
||||
const op_jz = u8(23)
|
||||
const op_jnz = u8(24)
|
||||
const op_call = u8(25)
|
||||
const op_ret = u8(26)
|
||||
const op_retv = u8(27)
|
||||
const op_print = u8(28)
|
||||
const op_println = u8(29)
|
||||
const op_assert = u8(30)
|
||||
const op_enter = u8(31)
|
||||
const op_mkarray = u8(32)
|
||||
const op_aget = u8(33)
|
||||
const op_aset = u8(34)
|
||||
const op_alen = u8(35)
|
||||
const op_apush = u8(36)
|
||||
const op_mkstruct = u8(37)
|
||||
const op_sget = u8(38)
|
||||
const op_sset = u8(39)
|
||||
const op_shas = u8(40) // has(map, "key") -> 1 if key exists, 0 otherwise
|
||||
const op_sdel = u8(41) // delete(map, "key") -> removes the key
|
||||
const op_slen = u8(42) // slen(struct) -> number of fields
|
||||
const op_skeys = u8(43) // skeys(struct) -> array of field name strings
|
||||
|
||||
const stack_cap = 65536
|
||||
|
||||
// Field is one `name: value` entry of a struct value.
|
||||
struct Field {
|
||||
mut:
|
||||
name string
|
||||
val i64
|
||||
}
|
||||
|
||||
struct StructVal {
|
||||
mut:
|
||||
fields []Field
|
||||
}
|
||||
|
||||
struct Vm {
|
||||
mut:
|
||||
code []u8
|
||||
strings []string
|
||||
arrays [][]i64
|
||||
structs []StructVal
|
||||
stack []i64
|
||||
sp int
|
||||
bp int
|
||||
ip int
|
||||
trace bool
|
||||
halted bool
|
||||
}
|
||||
|
||||
// run executes the function named `entry` from the executable `bin` and
|
||||
// returns its return value (0 if it never returns one).
|
||||
pub fn run(bin obj.Bin, entry string, trace bool) !i64 {
|
||||
@@ -595,279 +513,3 @@ fn (mut v Vm) ret(with_val bool) ! {
|
||||
v.ip = ip
|
||||
v.push(retval)!
|
||||
}
|
||||
|
||||
fn (mut v Vm) is_str(x i64) bool {
|
||||
return x & 3 == 1
|
||||
}
|
||||
|
||||
fn (mut v Vm) is_arr(x i64) bool {
|
||||
return x & 3 == 3
|
||||
}
|
||||
|
||||
fn (mut v Vm) is_struct(x i64) bool {
|
||||
return x & 3 == 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) enc_int(x i64) i64 {
|
||||
return u64(x) << 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) dec_int(x i64) i64 {
|
||||
return x >> 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) hand(x i64) int {
|
||||
return int(x >> 2)
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkstr(idx int) i64 {
|
||||
return (u64(idx) << 2) | 1
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkarr(idx int) i64 {
|
||||
return (u64(idx) << 2) | 3
|
||||
}
|
||||
|
||||
fn (mut v Vm) mkstruct_handle(idx int) i64 {
|
||||
return (u64(idx) << 2) | 2
|
||||
}
|
||||
|
||||
fn (mut v Vm) truthy(x i64) bool {
|
||||
return x != 0
|
||||
}
|
||||
|
||||
fn bool_i64(b bool) i64 {
|
||||
return if b { i64(1) } else { i64(0) }
|
||||
}
|
||||
|
||||
fn (mut v Vm) add(a i64, b i64) !i64 {
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
return error('cannot add arrays with +')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
return error('cannot add structs with +')
|
||||
}
|
||||
if v.is_str(a) && v.is_str(b) {
|
||||
return v.alloc_str(v.strings[v.hand(a)] + v.strings[v.hand(b)])
|
||||
}
|
||||
if v.is_str(a) {
|
||||
return v.alloc_str(v.strings[v.hand(a)] + v.num_str(b))
|
||||
}
|
||||
if v.is_str(b) {
|
||||
return v.alloc_str(v.num_str(a) + v.strings[v.hand(b)])
|
||||
}
|
||||
return v.enc_int(v.dec_int(a) + v.dec_int(b))
|
||||
}
|
||||
|
||||
fn (mut v Vm) alloc_str(s string) i64 {
|
||||
v.strings << s
|
||||
return v.mkstr(v.strings.len - 1)
|
||||
}
|
||||
|
||||
fn (mut v Vm) num_str(x i64) string {
|
||||
return v.dec_int(x).str()
|
||||
}
|
||||
|
||||
fn (mut v Vm) arith(a i64, b i64, op string) !i64 {
|
||||
if v.is_str(a) || v.is_str(b) {
|
||||
return error('cannot use strings with "${op}"')
|
||||
}
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
return error('cannot use arrays with "${op}"')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
return error('cannot use structs with "${op}"')
|
||||
}
|
||||
x := v.dec_int(a)
|
||||
y := v.dec_int(b)
|
||||
match op {
|
||||
'-' {
|
||||
return v.enc_int(x - y)
|
||||
}
|
||||
'*' {
|
||||
return v.enc_int(x * y)
|
||||
}
|
||||
'/' {
|
||||
if y == 0 {
|
||||
return error('division by zero')
|
||||
}
|
||||
return v.enc_int(x / y)
|
||||
}
|
||||
'%' {
|
||||
if y == 0 {
|
||||
return error('division by zero')
|
||||
}
|
||||
return v.enc_int(x % y)
|
||||
}
|
||||
else {
|
||||
return error('internal: bad arith op "${op}"')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut v Vm) cmp(a i64, b i64, op string) !i64 {
|
||||
if v.is_arr(a) || v.is_arr(b) {
|
||||
// arrays compare by identity (handle equality) with ==/!=
|
||||
if op == '==' || op == '!=' {
|
||||
return bool_i64(if op == '==' { a == b } else { a != b })
|
||||
}
|
||||
return error('cannot order arrays')
|
||||
}
|
||||
if v.is_struct(a) || v.is_struct(b) {
|
||||
// structs compare by identity (handle equality) with ==/!=
|
||||
if op == '==' || op == '!=' {
|
||||
return bool_i64(if op == '==' { a == b } else { a != b })
|
||||
}
|
||||
return error('cannot order structs')
|
||||
}
|
||||
if v.is_str(a) && v.is_str(b) {
|
||||
sa := v.strings[v.hand(a)]
|
||||
sb := v.strings[v.hand(b)]
|
||||
return bool_i64(match op {
|
||||
'==' { sa == sb }
|
||||
'!=' { sa != sb }
|
||||
'<' { sa < sb }
|
||||
'<=' { sa <= sb }
|
||||
'>' { sa > sb }
|
||||
'>=' { sa >= sb }
|
||||
else { return error('internal: bad cmp op "${op}"') }
|
||||
})
|
||||
}
|
||||
if v.is_str(a) || v.is_str(b) {
|
||||
return error('cannot compare a string and a number')
|
||||
}
|
||||
x := v.dec_int(a)
|
||||
y := v.dec_int(b)
|
||||
return bool_i64(match op {
|
||||
'==' { x == y }
|
||||
'!=' { x != y }
|
||||
'<' { x < y }
|
||||
'<=' { x <= y }
|
||||
'>' { x > y }
|
||||
'>=' { x >= y }
|
||||
else { return error('internal: bad cmp op "${op}"') }
|
||||
})
|
||||
}
|
||||
|
||||
fn (mut v Vm) print_val(x i64) {
|
||||
print(v.val_str(x, 0))
|
||||
}
|
||||
|
||||
// val_str renders a value: strings as-is, arrays as [a, b, ...] (with a depth
|
||||
// guard so self-referential arrays cannot hang the printer), numbers as ints.
|
||||
fn (mut v Vm) val_str(x i64, depth int) string {
|
||||
if depth > 16 {
|
||||
return '...'
|
||||
}
|
||||
if v.is_str(x) && v.valid_handle(x) {
|
||||
return v.strings[v.hand(x)]
|
||||
}
|
||||
if v.is_arr(x) && v.valid_arr_handle(x) {
|
||||
a := v.arrays[v.hand(x)]
|
||||
mut s := '['
|
||||
limit := if a.len > 20 { 20 } else { a.len }
|
||||
for i in 0..limit {
|
||||
if i > 0 {
|
||||
s += ', '
|
||||
}
|
||||
s += v.val_str(a[i], depth + 1)
|
||||
}
|
||||
if a.len > limit {
|
||||
s += ', ...'
|
||||
}
|
||||
return s + ']'
|
||||
}
|
||||
if v.is_struct(x) && v.valid_struct_handle(x) {
|
||||
s := v.structs[v.hand(x)]
|
||||
mut out := '{'
|
||||
limit := if s.fields.len > 20 { 20 } else { s.fields.len }
|
||||
for i in 0..limit {
|
||||
if i > 0 {
|
||||
out += ', '
|
||||
}
|
||||
out += s.fields[i].name + ': ' + v.val_str(s.fields[i].val, depth + 1)
|
||||
}
|
||||
if s.fields.len > limit {
|
||||
out += ', ...'
|
||||
}
|
||||
return out + '}'
|
||||
}
|
||||
return v.dec_int(x).str()
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.strings.len
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_arr_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.arrays.len
|
||||
}
|
||||
|
||||
fn (mut v Vm) valid_struct_handle(x i64) bool {
|
||||
h := v.hand(x)
|
||||
return h >= 0 && h < v.structs.len
|
||||
}
|
||||
|
||||
fn (mut v Vm) trace_op(op u8) {
|
||||
name := match op {
|
||||
op_halt { 'halt' }
|
||||
op_push_i { 'push_int' }
|
||||
op_push_s { 'push_str' }
|
||||
op_load { 'load' }
|
||||
op_store { 'store' }
|
||||
op_pop { 'pop' }
|
||||
op_dup { 'dup' }
|
||||
op_add { 'add' }
|
||||
op_sub { 'sub' }
|
||||
op_mul { 'mul' }
|
||||
op_div { 'div' }
|
||||
op_mod { 'mod' }
|
||||
op_neg { 'neg' }
|
||||
op_eq { 'eq' }
|
||||
op_ne { 'ne' }
|
||||
op_lt { 'lt' }
|
||||
op_le { 'le' }
|
||||
op_gt { 'gt' }
|
||||
op_ge { 'ge' }
|
||||
op_and { 'and' }
|
||||
op_or { 'or' }
|
||||
op_not { 'not' }
|
||||
op_jmp { 'jmp' }
|
||||
op_jz { 'jz' }
|
||||
op_jnz { 'jnz' }
|
||||
op_call { 'call' }
|
||||
op_ret { 'ret' }
|
||||
op_retv { 'retv' }
|
||||
op_print { 'print' }
|
||||
op_println { 'println' }
|
||||
op_assert { 'assert' }
|
||||
op_enter { 'enter' }
|
||||
op_mkarray { 'mkarray' }
|
||||
op_aget { 'aget' }
|
||||
op_aset { 'aset' }
|
||||
op_alen { 'alen' }
|
||||
op_apush { 'apush' }
|
||||
op_mkstruct { 'mkstruct' }
|
||||
op_sget { 'sget' }
|
||||
op_sset { 'sset' }
|
||||
op_shas { 'shas' }
|
||||
op_sdel { 'sdel' }
|
||||
op_slen { 'slen' }
|
||||
op_skeys { 'skeys' }
|
||||
else { '??' }
|
||||
}
|
||||
mut s := ''
|
||||
for i in 0..v.sp {
|
||||
if i > 0 {
|
||||
s += ' '
|
||||
}
|
||||
if v.is_str(v.stack[i]) && v.valid_handle(v.stack[i]) {
|
||||
s += '"${v.strings[v.hand(v.stack[i])]}"'
|
||||
} else {
|
||||
s += v.val_str(v.stack[i], 0)
|
||||
}
|
||||
}
|
||||
println(' [ip=${v.ip:4}] ${name:-9} stack: [${s}]')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user