This commit is contained in:
allexanderbergmns
2026-08-25 18:03:03 +02:00
parent 3e1e9bd08a
commit 68b3a3673c
15 changed files with 402 additions and 8 deletions
+83
View File
@@ -118,6 +118,15 @@ fn (mut v Vm) native(id int, _argc int) ! {
x := v.pop()!
v.push(v.alloc_str(v.type_name(x)))!
}
native_type_info {
x := v.pop()!
v.push(v.type_info_value(x))!
}
native_range {
b := v.pop()!
a := v.pop()!
v.push(v.range_value(a, b))!
}
native_split {
delim := v.pop_str()!
s := v.pop_str()!
@@ -1239,6 +1248,12 @@ fn (mut v Vm) type_name(x i64) string {
if v.is_float(x) {
return 'float'
}
if v.is_none(x) {
return 'none'
}
if v.is_closure(x) {
return 'closure'
}
if v.is_arr(x) {
return 'array'
}
@@ -1248,6 +1263,74 @@ fn (mut v Vm) type_name(x i64) string {
return 'int'
}
// type_info_value reflects a value into a struct for generic/duck-typed code:
// { kind, is_number, is_int, is_float, is_string, is_array, is_struct,
// is_none, is_closure, len, fields } where `fields` is the array of field
// names (structs) and `len` is the element/character count for arrays/strings.
fn (mut v Vm) type_info_value(x i64) i64 {
kind := v.type_name(x)
is_int := v.is_int(x)
is_float := v.is_float(x)
is_string := v.is_str(x) && v.valid_handle(x)
is_array := v.is_arr(x) && v.valid_arr_handle(x)
is_struct := v.is_struct(x) && v.valid_struct_handle(x)
is_none := v.is_none(x)
is_closure := v.is_closure(x) && v.valid_closure_handle(x)
is_number := is_int || is_float
// len: array -> element count; string -> character count; struct -> field count
mut length := 0
if is_array {
length = v.arrays[v.hand(x)].len
} else if is_string {
length = v.strings[v.hand(x)].runes().len
} else if is_struct {
length = v.structs[v.hand(x)].fields.len
}
// fields: array of struct field names (empty otherwise)
mut names := []i64{}
if is_struct {
for f in v.structs[v.hand(x)].fields {
v.strings << f.name
names << v.mkstr(v.strings.len - 1)
}
}
v.arrays << names
field_h := v.mkarr(v.arrays.len - 1)
mut fields := []Field{}
fields << Field{ name: 'kind', val: v.alloc_str(kind) }
fields << Field{ name: 'is_number', val: v.enc_int(if is_number { 1 } else { 0 }) }
fields << Field{ name: 'is_int', val: v.enc_int(if is_int { 1 } else { 0 }) }
fields << Field{ name: 'is_float', val: v.enc_int(if is_float { 1 } else { 0 }) }
fields << Field{ name: 'is_string', val: v.enc_int(if is_string { 1 } else { 0 }) }
fields << Field{ name: 'is_array', val: v.enc_int(if is_array { 1 } else { 0 }) }
fields << Field{ name: 'is_struct', val: v.enc_int(if is_struct { 1 } else { 0 }) }
fields << Field{ name: 'is_none', val: v.enc_int(if is_none { 1 } else { 0 }) }
fields << Field{ name: 'is_closure', val: v.enc_int(if is_closure { 1 } else { 0 }) }
fields << Field{ name: 'len', val: v.enc_int(i64(length)) }
fields << Field{ name: 'fields', val: field_h }
fields << Field{ name: 'contents', val: x }
v.structs << StructVal{ fields: fields, by_name: v.index_fields(fields) }
return v.mkstruct_handle(v.structs.len - 1)
}
// range_value builds the array [a, a+1, ..., b) as ints.
fn (mut v Vm) range_value(a i64, b i64) i64 {
start := v.dec_int(a)
end := v.dec_int(b)
mut arr := []i64{}
if start <= end {
for i := start; i < end; i++ {
arr << v.enc_int(i)
}
} else {
for i := start; i > end; i-- {
arr << v.enc_int(i)
}
}
v.arrays << arr
return v.mkarr(v.arrays.len - 1)
}
// str_method dispatches a string method call. The receiver was pushed before
// the arguments, so it is the first argument from the native builtin's point
// of view; delegating keeps the behavior identical to the free-function forms.
+5
View File
@@ -66,6 +66,7 @@ const op_load_dyn = u8(59) // pop idx, push stack[bp + idx]
const op_varargs = u8(60) // <named:i64> <dst:i64> — collect args[named..argc-1] into array at local dst
const op_str_method = u8(61) // <name:str> <argc:i64> — call a string method (s.len(), s.contains(x), ...)
const op_push_none = u8(62) // push the `none` sentinel
const op_in = u8(63) // membership: x in col -> 0 or 1
// native builtin ids (the operand to op_native)
const native_abs = 100
@@ -190,3 +191,7 @@ const native_input = 196
const native_flag_val = 197
const native_flag_has = 198
const native_flag_positional = 199
// structured reflection + sequence helper
const native_type_info = 200
const native_range = 201
+1
View File
@@ -121,6 +121,7 @@ fn (mut v Vm) trace_op(op u8) {
op_varargs { 'varargs' }
op_str_method { 'str_method' }
op_push_none { 'push_none' }
op_in { 'in' }
else { '??' }
}
mut s := ''
+40
View File
@@ -632,6 +632,27 @@ fn (mut v Vm) exec() ! {
op_slice {
v.op_slice()!
}
op_in {
v.ip++
col := v.pop()!
needle := v.pop()!
// map/struct: string key membership
if v.is_struct(col) && v.valid_struct_handle(col) {
if v.is_str(needle) && v.valid_handle(needle) {
key := v.strings[v.hand(needle)]
v.push(v.enc_int(if key in v.structs[v.hand(col)].by_name { 1 } else { 0 }))!
} else {
v.push(v.enc_int(0))!
}
} else if v.is_arr(col) && v.valid_arr_handle(col) {
found := v.arr_contains(v.arrays[v.hand(col)], needle)
v.push(v.enc_int(if found { 1 } else { 0 }))!
} else if v.is_str(col) && v.valid_handle(col) && v.is_str(needle) && v.valid_handle(needle) {
v.push(v.enc_int(if v.strings[v.hand(col)].contains(v.strings[v.hand(needle)]) { 1 } else { 0 }))!
} else {
v.push(v.enc_int(0))!
}
}
op_native {
v.ip++
id := int(v.read_i64())
@@ -1005,6 +1026,25 @@ fn (mut v Vm) call(target int, argc int) {
v.ip = target
}
// arr_contains reports whether an array holds a value equal to needle
// (comparing ints/floats numerically and strings by content).
fn (mut v Vm) arr_contains(a []i64, needle i64) bool {
for el in a {
if v.vals_eq(el, needle) {
return true
}
}
return false
}
// vals_eq compares two values for equality, treating int/float numerically.
fn (mut v Vm) vals_eq(x i64, y i64) bool {
if (v.is_float(x) || v.is_float(y)) && !v.is_closure(x) && !v.is_closure(y) && !v.is_str(x) && !v.is_str(y) && !v.is_arr(x) && !v.is_arr(y) && !v.is_struct(x) && !v.is_struct(y) {
return v.to_f64(x) == v.to_f64(y)
}
return x == y
}
fn (mut v Vm) ret(with_val bool) ! {
retval := if with_val { v.pop()! } else { v.enc_int(0) }
v.sp = v.bp - 1