From e075a5585c3c9fd4e1a4941bd55fbe422853185c Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 11:15:05 +0700 Subject: [PATCH 01/17] switch to 32-bit ints --- build.rs | 1 + src/ast.rs | 13 ++- src/hanayo/array.rs | 12 +- src/hanayo/file.rs | 12 +- src/hanayo/int.rs | 4 +- src/hanayo/proc.rs | 2 +- src/hanayo/string.rs | 12 +- src/hanayo/time.rs | 8 +- src/vm/value.c | 2 +- src/vm/value.h | 4 +- src/vm/vm.c | 209 ++++++++++++++++++----------------- src/vmbindings/cnativeval.rs | 8 +- src/vmbindings/foreignc.rs | 2 + src/vmbindings/value.rs | 8 +- tests/vm.rs | 4 +- 15 files changed, 157 insertions(+), 144 deletions(-) diff --git a/build.rs b/build.rs index f67b687..b4f9321 100644 --- a/build.rs +++ b/build.rs @@ -31,6 +31,7 @@ fn main() { build .flag("-Wall") .flag("-Wno-unused-parameter") + .flag("-Wconversion") .flag("-std=c11") .shared_flag(true) .static_flag(true) diff --git a/src/ast.rs b/src/ast.rs index 7420502..818ac47 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -140,8 +140,9 @@ pub mod ast { c.cpush32(n as u32); } _ => { - c.cpushop(VmOpcode::OP_PUSH64); - c.cpush64(n); + unimplemented!() + //c.cpushop(VmOpcode::OP_PUSH64); + //c.cpush64(n); } } emit_end!(c, _smap_begin); @@ -191,8 +192,8 @@ pub mod ast { c.cpushop(VmOpcode::OP_PUSH8); c.cpush8(self.exprs.len() as u8); } else { - c.cpushop(VmOpcode::OP_PUSH64); - c.cpush64(self.exprs.len() as u64); + c.cpushop(VmOpcode::OP_PUSH32); + c.cpush32(self.exprs.len() as u32); } c.cpushop(VmOpcode::OP_ARRAY_LOAD); emit_end!(c, _smap_begin); @@ -315,8 +316,8 @@ pub mod ast { c.cpushop(VmOpcode::OP_PUSH8); c.cpush8(self.stmts.len() as u8); } else { - c.cpushop(VmOpcode::OP_PUSH64); - c.cpush64(self.stmts.len() as u64); + c.cpushop(VmOpcode::OP_PUSH32); + c.cpush32(self.stmts.len() as u32); } c.cpushop(VmOpcode::OP_DICT_LOAD); emit_end!(c, _smap_begin); diff --git a/src/hanayo/array.rs b/src/hanayo/array.rs index 6fdd771..83bd129 100644 --- a/src/hanayo/array.rs +++ b/src/hanayo/array.rs @@ -25,19 +25,21 @@ pub extern "C" fn constructor(cvm: *mut Vm, nargs: u16) { #[hana_function()] fn length(array: Value::Array) -> Value { - Value::Int(array.as_ref().len() as i64) + Value::Int(array.as_ref().len() as i32) } #[hana_function()] fn insert_(array: Value::Array, pos: Value::Int, elem: Value::Any) -> Value { array.as_mut().insert(pos as usize, elem.wrap()); - Value::Int(array.as_ref().len() as i64) + Value::Int(array.as_ref().len() as i32) } #[hana_function()] fn delete_(array: Value::Array, from_pos: Value::Int, nelems: Value::Int) -> Value { - array.as_mut().delete(from_pos as usize, nelems as usize); - Value::Int(array.as_ref().len() as i64) + array + .as_mut() + .drain((from_pos as usize)..((nelems as usize) + 1)); + Value::Int(array.as_ref().len() as i32) } // stack manipulation @@ -166,7 +168,7 @@ fn index(array: Value::Array, elem: Value::Any) -> Value { value_eq(&mut val, array[i], elem.wrap()); } if val.data == 1 { - return Value::Int(i as i64); + return Value::Int(i as i32); } } Value::Int(-1) diff --git a/src/hanayo/file.rs b/src/hanayo/file.rs index 9285cc8..c00bcfe 100644 --- a/src/hanayo/file.rs +++ b/src/hanayo/file.rs @@ -88,7 +88,7 @@ fn write(file: Value::Record, buf: Value::Str) -> Value { let file = file.as_mut(); if let Some(field) = file.native_field.as_mut() { let file = field.downcast_mut::().unwrap(); - Value::Int(file.write_all(buf.as_ref().as_bytes()).is_ok() as i64) + Value::Int(file.write_all(buf.as_ref().as_bytes()).is_ok() as i32) } else { Value::Int(0) } @@ -100,8 +100,8 @@ fn seek(file: Value::Record, pos: Value::Int) -> Value { let file = file.as_mut(); if let Some(field) = file.native_field.as_mut() { let file = field.downcast_mut::().unwrap(); - if let Ok(result) = file.seek(SeekFrom::Current(pos)) { - Value::Int(result as i64) + if let Ok(result) = file.seek(SeekFrom::Current(pos as i64)) { + Value::Int(result as i32) } else { Value::Int(-1) } @@ -116,7 +116,7 @@ fn seek_from_start(file: Value::Record, pos: Value::Int) -> Value { if let Some(field) = file.native_field.as_mut() { let file = field.downcast_mut::().unwrap(); if let Ok(result) = file.seek(SeekFrom::Start(pos as u64)) { - Value::Int(result as i64) + Value::Int(result as i32) } else { Value::Int(-1) } @@ -130,8 +130,8 @@ fn seek_from_end(file: Value::Record, pos: Value::Int) -> Value { let file = file.as_mut(); if let Some(field) = file.native_field.as_mut() { let file = field.downcast_mut::().unwrap(); - if let Ok(result) = file.seek(SeekFrom::End(pos)) { - Value::Int(result as i64) + if let Ok(result) = file.seek(SeekFrom::End(pos as i64)) { + Value::Int(result as i32) } else { Value::Int(-1) } diff --git a/src/hanayo/int.rs b/src/hanayo/int.rs index 1277473..d3136d0 100644 --- a/src/hanayo/int.rs +++ b/src/hanayo/int.rs @@ -9,8 +9,8 @@ use std::str::FromStr; fn constructor(val: Value::Any) -> Value { match val { Value::Int(n) => Value::Int(n), - Value::Float(n) => Value::Int(n as i64), - Value::Str(s) => match i64::from_str(s.as_ref()) { + Value::Float(n) => Value::Int(n as i32), + Value::Str(s) => match i32::from_str(s.as_ref()) { Ok(n) => Value::Int(n), Err(_) => { hana_raise!(vm, { diff --git a/src/hanayo/proc.rs b/src/hanayo/proc.rs index 6c42eca..fbb6679 100644 --- a/src/hanayo/proc.rs +++ b/src/hanayo/proc.rs @@ -106,7 +106,7 @@ fn wait(process: Value::Record) -> Value { match p.wait() { Ok(e) => { if let Some(code) = e.code() { - Value::Int(code as i64) + Value::Int(code as i32) } else { Value::Int(0) } diff --git a/src/hanayo/string.rs b/src/hanayo/string.rs index 8925ae7..4e94424 100644 --- a/src/hanayo/string.rs +++ b/src/hanayo/string.rs @@ -26,21 +26,21 @@ pub extern "C" fn constructor(cvm: *mut Vm, nargs: u16) { // length #[hana_function()] fn length(s: Value::Str) -> Value { - Value::Int(s.as_ref().graphemes(true).count() as i64) + Value::Int(s.as_ref().graphemes(true).count() as i32) } #[hana_function()] fn bytesize(s: Value::Str) -> Value { - Value::Int(s.as_ref().len() as i64) + Value::Int(s.as_ref().len() as i32) } // check #[hana_function()] fn startswith(s: Value::Str, left: Value::Str) -> Value { - Value::Int(s.as_ref().starts_with(left.as_ref()) as i64) + Value::Int(s.as_ref().starts_with(left.as_ref()) as i32) } #[hana_function()] fn endswith(s: Value::Str, left: Value::Str) -> Value { - Value::Int(s.as_ref().ends_with(left.as_ref()) as i64) + Value::Int(s.as_ref().ends_with(left.as_ref()) as i32) } // basic manip @@ -143,7 +143,7 @@ fn index(s: Value::Str, needle: Value::Str) -> Value { }) .next() { - (idx_grapheme - 1) as i64 + (idx_grapheme - 1) as i32 } else { -1 } @@ -166,7 +166,7 @@ fn chars(s: Value::Str) -> Value { fn ord(s: Value::Str) -> Value { let s = s.as_ref(); if let Some(ch) = s.chars().next() { - Value::Int(ch as i64) + Value::Int(ch as i32) } else { Value::Int(0) } diff --git a/src/hanayo/time.rs b/src/hanayo/time.rs index d3dd351..67cfd3b 100644 --- a/src/hanayo/time.rs +++ b/src/hanayo/time.rs @@ -42,25 +42,25 @@ fn since(left: Value::Record, right: Value::Record) -> Value { fn secs(time: Value::Record) -> Value { let tref = time.as_ref().native_field.as_ref().unwrap(); let time = tref.downcast_ref::().unwrap(); - Value::Int(time.as_secs() as i64) + Value::Int(time.as_secs() as i32) } #[hana_function()] fn millis(time: Value::Record) -> Value { let tref = time.as_ref().native_field.as_ref().unwrap(); let time = tref.downcast_ref::().unwrap(); - Value::Int(time.as_millis() as i64) + Value::Int(time.as_millis() as i32) } #[hana_function()] fn micros(time: Value::Record) -> Value { let tref = time.as_ref().native_field.as_ref().unwrap(); let time = tref.downcast_ref::().unwrap(); - Value::Int(time.as_micros() as i64) + Value::Int(time.as_micros() as i32) } #[hana_function()] fn nanos(time: Value::Record) -> Value { let tref = time.as_ref().native_field.as_ref().unwrap(); let time = tref.downcast_ref::().unwrap(); - Value::Int(time.as_nanos() as i64) + Value::Int(time.as_nanos() as i32) } // other diff --git a/src/vm/value.c b/src/vm/value.c index 0b4739d..72bf8fc 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -7,7 +7,7 @@ #include "array_obj.h" #include "function.h" -void value_int(struct value *val, int64_t data) { +void value_int(struct value *val, int32_t data) { val->type = TYPE_INT; val->as.integer = data; } diff --git a/src/vm/value.h b/src/vm/value.h index 51972cd..6daf6de 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -26,7 +26,7 @@ struct string; typedef void (*value_fn)(struct vm *vm, uint16_t nargs); struct __attribute__((packed)) value { union { - int64_t integer; + int32_t integer; double floatp; struct string *str; value_fn fn; @@ -37,7 +37,7 @@ struct __attribute__((packed)) value { uint8_t type; }; -void value_int(struct value*, int64_t); +void value_int(struct value*, int32_t); void value_float(struct value*, double); void value_str(struct value*, const char*, const struct vm*); struct env; diff --git a/src/vm/vm.c b/src/vm/vm.c index 5573297..bbe297a 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -23,8 +23,19 @@ #define FATAL(...) fprintf(stderr, __VA_ARGS__) void vm_execute(struct vm *vm) { -#define ERROR(code, unwind) do { vm->error = code; vm->ip -= unwind; return; } while(0) -#define ERROR_EXPECT(code, unwind, expect) do { vm->error = code; vm->ip -= unwind; vm->error_expected = expect; return; } while(0) +#define ERROR(code, unwind) \ + do { \ + vm->error = code; \ + vm->ip -= (uint32_t)(unwind); \ + return; \ + } while (0) +#define ERROR_EXPECT(code, unwind, expect) \ + do { \ + vm->error = code; \ + vm->ip -= (uint32_t)(unwind); \ + vm->error_expected = (uint32_t)expect; \ + return; \ + } while (0) #define doop(op) do_ ## op #define X(op) [op] = && doop(op) #ifdef NOLOG @@ -95,37 +106,32 @@ void vm_execute(struct vm *vm) { // stack manip // push uint family on to the stack -#define push_int_op(optype, _type, _data) \ - doop(optype): { \ - vm->ip++; \ - const _type data = _data; \ - vm->ip += sizeof(_type); \ +#define push_int_op(optype, _type, _data) \ + doop(optype) : { \ + vm->ip++; \ + const _type data = _data; \ + vm->ip += (uint32_t)sizeof(_type); \ LOG(sizeof(_type) == 8 ? "PUSH %ld\n" : "PUSH %d\n", data); \ -\ - struct value val = { \ - .type = TYPE_INT,\ - .as.integer = data }; \ - array_push(vm->stack, val); \ - dispatch(); \ + \ + struct value val = { \ + .type = TYPE_INT, \ + .as.integer = (int32_t)data}; \ + array_push(vm->stack, val); \ + dispatch(); \ } push_int_op(OP_PUSH8, uint8_t, vm->code.data[vm->ip+0]) - push_int_op(OP_PUSH16, uint16_t, (uint16_t)vm->code.data[vm->ip+0] << 8 | - (uint16_t)vm->code.data[vm->ip+1]) + push_int_op(OP_PUSH16, uint16_t, (uint16_t)(vm->code.data[vm->ip+0] << 8 | + vm->code.data[vm->ip+1])) - push_int_op(OP_PUSH32, uint32_t, (uint32_t)vm->code.data[vm->ip+0] << 24 | - (uint32_t)vm->code.data[vm->ip+1] << 16 | - (uint32_t)vm->code.data[vm->ip+2] << 8 | - (uint32_t)vm->code.data[vm->ip+3]) + push_int_op(OP_PUSH32, uint32_t, (uint32_t)(vm->code.data[vm->ip+0] << 24 | + vm->code.data[vm->ip+1] << 16 | + vm->code.data[vm->ip+2] << 8 | + vm->code.data[vm->ip+3])) - push_int_op(OP_PUSH64, uint64_t, (uint64_t)vm->code.data[vm->ip+0] << 56 | - (uint64_t)vm->code.data[vm->ip+1] << 48 | - (uint64_t)vm->code.data[vm->ip+2] << 40 | - (uint64_t)vm->code.data[vm->ip+3] << 32 | - (uint64_t)vm->code.data[vm->ip+4] << 24 | - (uint64_t)vm->code.data[vm->ip+5] << 16 | - (uint64_t)vm->code.data[vm->ip+6] << 8 | - (uint64_t)vm->code.data[vm->ip+7]) + doop(OP_PUSH64): { + assert(0); + } // push 32/64-bit float on to the stack doop(OP_PUSHF64): { @@ -142,7 +148,7 @@ void vm_execute(struct vm *vm) { u.u[5] = vm->code.data[vm->ip + 5]; u.u[6] = vm->code.data[vm->ip + 6]; u.u[7] = vm->code.data[vm->ip + 7]; - vm->ip += sizeof(u); + vm->ip += (uint32_t)sizeof(u); LOG("PUSH_F64 %f\n", u.d); array_push(vm->stack, (struct value){0}); value_float(&array_top(vm->stack), u.d); @@ -153,7 +159,7 @@ void vm_execute(struct vm *vm) { doop(OP_PUSHSTR): { vm->ip++; char *str = (char *)&vm->code.data[vm->ip]; // must be null terminated - vm->ip += strlen(str)+1; + vm->ip += (uint32_t)strlen(str) + 1; LOG("PUSH %s\n", str); array_push(vm->stack, (struct value){0}); value_str(&array_top(vm->stack), str, vm); @@ -302,9 +308,9 @@ void vm_execute(struct vm *vm) { // the environment is initialized with a copy of the current environment's variables doop(OP_ENV_NEW): { vm->ip++; - const uint16_t n = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(n); + const uint16_t n = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(n); LOG("RESERVE %d\n", n); env_init(vm->localenv, n, vm); dispatch(); @@ -314,47 +320,47 @@ void vm_execute(struct vm *vm) { // sets the value of current environment's slot to the top of the stack doop(OP_SET_LOCAL): { vm->ip++; - const uint16_t key = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(key); - LOG("SET LOCAL %d\n", key); - env_set(vm->localenv, key, array_top(vm->stack)); + const uint16_t n = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(n); + LOG("SET LOCAL %d\n", n); + env_set(vm->localenv, n, array_top(vm->stack)); dispatch(); } // this is for recursive function doop(OP_SET_LOCAL_FUNCTION_DEF): { vm->ip++; - const uint16_t key = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(key); + const uint16_t n = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(n); struct value val = array_top(vm->stack); - env_set(vm->localenv, key, val); - function_set_bound_var(val.as.ifn, key, val); + env_set(vm->localenv, n, val); + function_set_bound_var(val.as.ifn, n, val); dispatch(); } // pushes a copy of the value of current environment's slot doop(OP_GET_LOCAL): { vm->ip++; - const uint16_t key = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(key); - LOG("GET LOCAL %d\n", key); + const uint16_t n = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(n); + LOG("GET LOCAL %d\n", n); array_push(vm->stack, (struct value){0}); - array_top(vm->stack) = env_get(vm->localenv, key); + array_top(vm->stack) = env_get(vm->localenv, n); dispatch(); } doop(OP_GET_LOCAL_UP): { vm->ip++; - const uint16_t key = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(key); - uint16_t relascope = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(relascope); - LOG("GET LOCAL UP %d %d\n", key, relascope); + const uint16_t n = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(n); + const uint16_t relascope = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(relascope); + LOG("GET LOCAL UP %d %d\n", n, relascope); array_push(vm->stack, (struct value){0}); - array_top(vm->stack) = env_get_up(vm->localenv, relascope, key); + array_top(vm->stack) = env_get_up(vm->localenv, relascope, n); dispatch(); } @@ -362,7 +368,7 @@ void vm_execute(struct vm *vm) { doop(OP_SET_GLOBAL): { vm->ip++; char *key = (char *)&vm->code.data[vm->ip]; // must be null terminated - vm->ip += strlen(key)+1; + vm->ip += (uint32_t)strlen(key) + 1; LOG("SET GLOBAL %s %p\n", key, vm->globalenv); hmap_set(vm->globalenv, key, array_top(vm->stack)); dispatch(); @@ -371,7 +377,7 @@ void vm_execute(struct vm *vm) { doop(OP_GET_GLOBAL): { vm->ip++; char *key = (char *)&vm->code.data[vm->ip]; // must be null terminated - vm->ip += strlen(key)+1; + vm->ip += (uint32_t)strlen(key) + 1; LOG("GET GLOBAL %s\n", key); const struct value *val = hmap_get(vm->globalenv, key); if(val == NULL) { @@ -387,14 +393,14 @@ void vm_execute(struct vm *vm) { doop(OP_DEF_FUNCTION_PUSH): { // [opcode][end address] vm->ip++; - const uint16_t nargs = (uint16_t)vm->code.data[vm->ip + 0] << 8 | - (uint16_t)vm->code.data[vm->ip + 1]; - vm->ip += sizeof(nargs); - const uint16_t pos = (uint16_t)vm->code.data[vm->ip + 0] << 8 | - (uint16_t)vm->code.data[vm->ip + 1]; + const uint16_t nargs = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); + vm->ip += (uint32_t)sizeof(nargs); + const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); LOG("DEF_FUNCTION_PUSH %d %d\n", pos, nargs); array_push(vm->stack, (struct value){0}); - value_function(&array_top(vm->stack), vm->ip + sizeof(pos), nargs, vm->localenv, vm); + value_function(&array_top(vm->stack), vm->ip + (uint32_t)sizeof(pos), nargs, vm->localenv, vm); vm->ip += pos; dispatch(); } @@ -402,18 +408,18 @@ void vm_execute(struct vm *vm) { // flow control doop(OP_JMP): { // jmp [32-bit position] vm->ip++; - const int16_t pos = (uint16_t)vm->code.data[vm->ip + 0] << 8 | - (uint16_t)vm->code.data[vm->ip + 1]; + const int16_t pos = (int16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); vm->ip += pos; LOG("JMP %d\n", pos); dispatch(); } doop(OP_JMP_LONG): { // jmp [32-bit position] vm->ip++; - const uint32_t pos = (uint32_t)vm->code.data[vm->ip + 0] << 24 | - (uint32_t)vm->code.data[vm->ip + 1] << 16 | - (uint32_t)vm->code.data[vm->ip + 2] << 8 | - (uint32_t)vm->code.data[vm->ip + 3]; + const uint32_t pos = (uint32_t)(vm->code.data[vm->ip + 0] << 24 | + vm->code.data[vm->ip + 1] << 16 | + vm->code.data[vm->ip + 2] << 8 | + vm->code.data[vm->ip + 3]); vm->ip = pos; LOG("JMP LONG %d\n", pos); dispatch(); @@ -421,25 +427,25 @@ void vm_execute(struct vm *vm) { doop(OP_JCOND): doop(OP_JCOND_NO_POP): { // jmp if not true [32-bit position] const enum vm_opcode op = vm->code.data[vm->ip++]; - const int16_t pos = (uint16_t)vm->code.data[vm->ip+0] << 8 | - (uint16_t)vm->code.data[vm->ip+1]; + const int16_t pos = (int16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); struct value val = array_top(vm->stack); if(op == OP_JCOND) array_pop(vm->stack); LOG(op == OP_JCOND ? "JCOND %d\n" : "JCOND_NO_POP %d\n", pos); if(value_is_true(val)) vm->ip += pos; - else vm->ip += sizeof(pos); + else vm->ip += (uint32_t)sizeof(pos); dispatch(); } doop(OP_JNCOND): doop(OP_JNCOND_NO_POP): { // jump if true [32-bit position] const enum vm_opcode op = vm->code.data[vm->ip++]; - const int16_t pos = (uint16_t)vm->code.data[vm->ip+0] << 8 | - (uint16_t)vm->code.data[vm->ip+1]; + const int16_t pos = (int16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); struct value val = array_top(vm->stack); if(op == OP_JNCOND) array_pop(vm->stack); LOG(op == OP_JNCOND ? "JNCOND %d\n" : "JNCOND_NO_POP %d\n", pos); if(!value_is_true(val)) vm->ip += pos; - else vm->ip += sizeof(pos); + else vm->ip += (uint32_t)sizeof(pos); dispatch(); } // pops a function/record constructor on top of the stack, @@ -492,9 +498,9 @@ void vm_execute(struct vm *vm) { // argument: [arg2][arg1] vm->ip++; struct value val = array_top(vm->stack); - const uint16_t nargs = vm->code.data[vm->ip+0] << 8 | - vm->code.data[vm->ip+1]; - vm->ip += sizeof(nargs); + const uint16_t nargs = (uint16_t)(vm->code.data[vm->ip+0] << 8 | + vm->code.data[vm->ip+1]); + vm->ip += (uint32_t)sizeof(nargs); debug_assert(vm->stack.length >= nargs); LOG("call %d\n", nargs); switch(val.type) { @@ -549,7 +555,7 @@ void vm_execute(struct vm *vm) { const enum vm_opcode op = vm->code.data[vm->ip]; vm->ip++; const char *key = (const char *)&vm->code.data[vm->ip]; // must be null terminated - vm->ip += strlen(key)+1; + vm->ip += (uint32_t)strlen(key) + 1; LOG(op == OP_MEMBER_GET ? "MEMBER_GET %s\n" : "MEMBER_GET_NO_POP %s\n", key); struct value val = array_top(vm->stack); @@ -585,7 +591,7 @@ void vm_execute(struct vm *vm) { // stack: [value][dict] vm->ip++; char *key = (char *)(vm->code.data+vm->ip); // must be null terminated - vm->ip += strlen(key)+1; + vm->ip += (uint32_t)strlen(key) + 1; LOG("MEMBER_SET %s\n", key); struct value dval = array_top(vm->stack); if(dval.type != TYPE_DICT) { @@ -602,7 +608,7 @@ void vm_execute(struct vm *vm) { vm->ip++; struct value val = array_top(vm->stack); - int64_t length = val.as.integer; + size_t length = (size_t)val.as.integer; array_pop(vm->stack); debug_assert(val.type == TYPE_INT); LOG("DICT_LOAD %ld\n", length); @@ -641,8 +647,8 @@ void vm_execute(struct vm *vm) { if(index.type != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } - const int64_t i = (int64_t)index.as.integer; - if(!(i >= 0 && i < (int64_t)dval.as.array->length)) { + const int32_t i = (int32_t)index.as.integer; + if (!(i >= 0 && i < (int32_t)dval.as.array->length)) { ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, dval.as.array->length); } array_push(vm->stack, dval.as.array->data[i]); @@ -650,7 +656,7 @@ void vm_execute(struct vm *vm) { if(index.type != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } - const int64_t i = index.as.integer; + const int32_t i = (int32_t)index.as.integer; struct value val; val.type = TYPE_STR; val.as.str = string_at(dval.as.str, i, vm); @@ -708,7 +714,7 @@ void vm_execute(struct vm *vm) { vm->ip++; struct value val = array_top(vm->stack); - int64_t length = val.as.integer; + size_t length = (size_t)val.as.integer; array_pop(vm->stack); debug_assert(val.type == TYPE_INT); LOG("ARRAY_LOAD %ld\n", length); @@ -770,8 +776,8 @@ void vm_execute(struct vm *vm) { } doop(OP_EXFRAME_RET): { vm->ip++; - const uint16_t pos = (uint16_t)vm->code.data[vm->ip + 0] << 8 | - (uint16_t)vm->code.data[vm->ip + 1]; + const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); vm->ip += pos; LOG("EXFRAME_RET %d\n", pos); vm_leave_exframe(vm); @@ -782,9 +788,9 @@ void vm_execute(struct vm *vm) { doop(OP_RETCALL): { vm->ip++; struct value val = array_top(vm->stack); - const uint16_t nargs = (uint16_t)vm->code.data[vm->ip+0] << 8 | - (uint16_t)vm->code.data[vm->ip+1]; - vm->ip += sizeof(nargs); + const uint16_t nargs = (uint16_t)(vm->code.data[vm->ip+0] << 8 | + vm->code.data[vm->ip+1]); + vm->ip += (uint32_t)sizeof(nargs); debug_assert(vm->stack.length >= nargs); LOG("retcall %d\n", nargs); switch(val.type) { @@ -849,8 +855,8 @@ void vm_execute(struct vm *vm) { } \ } while (0); vm->ip++; - const uint16_t pos = (uint16_t)vm->code.data[vm->ip + 0] << 8 | - (uint16_t)vm->code.data[vm->ip + 1]; + const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | + vm->code.data[vm->ip + 1]); LOG("FOR_IN %d\n", pos); debug_assert(vm->stack.length > 0); struct value *top = &array_top(vm->stack); @@ -894,7 +900,7 @@ void vm_execute(struct vm *vm) { .type = TYPE_INTERPRETER_ITERATOR }; array_push(vm->stack, val); - vm->ip += sizeof(pos); + vm->ip += (uint32_t)sizeof(pos); array_push(vm->stack, *top); // pass arg CALL_DICT_ITERATOR_FN break; } @@ -931,7 +937,7 @@ void vm_execute(struct vm *vm) { } const struct value *pval = dict_get(dict, "next"); - vm->ip += sizeof(pos); + vm->ip += (uint32_t)sizeof(pos); array_push(vm->stack, iterator); // arg CALL_DICT_ITERATOR_FN break; @@ -942,7 +948,7 @@ void vm_execute(struct vm *vm) { } default: ERROR(ERROR_EXPECTED_ITERABLE, sizeof(pos)); } - vm->ip += sizeof(pos); + vm->ip += (uint32_t)sizeof(pos); dispatch(); #undef CALL_DICT_ITERATOR_FN } @@ -962,7 +968,7 @@ void vm_execute(struct vm *vm) { vm->ip++; char *str = (char *)&vm->code.data[vm->ip]; // must be null terminated LOG("USE %s\n", str); - vm->ip += strlen(str)+1; + vm->ip += (uint32_t)strlen(str) + 1; vm_load_module(vm, str); dispatch(); } @@ -975,10 +981,10 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar struct function *ifn = NULL; if (fn.type == TYPE_NATIVE_FN) { - for (int64_t i = args->length - 1; i >= 0; i--) { + for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - fn.as.fn(vm, args->length); + fn.as.fn(vm, (uint16_t)args->length); } else if(fn.type == TYPE_DICT) { const struct value *ctor = dict_get(fn.as.dict, "constructor"); if(ctor == NULL) { @@ -986,10 +992,10 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar return errorval; } if(ctor->type == TYPE_NATIVE_FN) { - for(int64_t i = args->length-1; i >= 0; i--) { + for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - ctor->as.fn(vm, args->length); + ctor->as.fn(vm, (uint16_t)args->length); if(vm->error) return errorval; const struct value val = array_top(vm->stack); array_pop(vm->stack); @@ -1019,7 +1025,8 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar vm->ip = (uint32_t)-1; struct env *curenv = vm_enter_env(vm, ifn); // setup stack/ip - for(int64_t i = args->length-1; i >= 0; i--) { + printf("%ld\n", args->length); + for (size_t i = (size_t)args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } // call it diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index b3a1dbb..6447299 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -36,10 +36,10 @@ impl NativeValue { use std::mem::transmute; #[allow(non_camel_case_types)] match &self.r#type { - _valueType::TYPE_NIL => Value::Nil, - _valueType::TYPE_INT => unsafe { Value::Int(transmute::(self.data)) }, - _valueType::TYPE_FLOAT => Value::Float(f64::from_bits(self.data)), - _valueType::TYPE_NATIVE_FN => unsafe { + NativeValueType::TYPE_NIL => Value::Nil, + NativeValueType::TYPE_INT => unsafe { Value::Int(self.data as i32) }, + NativeValueType::TYPE_FLOAT => Value::Float(f64::from_bits(self.data)), + NativeValueType::TYPE_NATIVE_FN => unsafe { Value::NativeFn(transmute::(self.data)) }, _valueType::TYPE_FN => Value::Fn(Gc::from_raw(self.data as *mut Function)), diff --git a/src/vmbindings/foreignc.rs b/src/vmbindings/foreignc.rs index fab9c98..c97517b 100644 --- a/src/vmbindings/foreignc.rs +++ b/src/vmbindings/foreignc.rs @@ -215,6 +215,7 @@ mod foreignc { unsafe extern "C" fn function_malloc( addr: u32, nargs: u16, env: *const Env, vm: *const Vm, ) -> *mut Function { + eprintln!("function malloc: {} {}", addr, nargs); (&*vm).malloc(Function::new(addr, nargs, env)).into_raw() } @@ -255,6 +256,7 @@ mod foreignc { let env = &mut *selfptr; env.reserve(nslots); let vm = &mut *cvm; + eprintln!("{:?}", env.nargs); for i in 0..env.nargs { let val = vm.stack.top(); env.set(i, val.clone()); diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index 86c6bad..ff3bd3f 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -21,7 +21,7 @@ pub enum Value { True, False, - Int(i64), + Int(i32), Float(f64), NativeFn(NativeFnData), Fn(Gc), @@ -41,7 +41,7 @@ extern "C" { impl Value { // #region coerce value to type #[cfg_attr(tarpaulin, skip)] - pub fn int(&self) -> i64 { + pub fn int(&self) -> i32 { match self { Value::Int(s) => *s, _ => { @@ -110,8 +110,8 @@ impl Value { data: 0, }, Value::Int(n) => NativeValue { - r#type: _valueType::TYPE_INT, - data: transmute::(*n), + r#type: NativeValueType::TYPE_INT, + data: (*n) as u64, }, Value::Float(n) => NativeValue { r#type: _valueType::TYPE_FLOAT, diff --git a/tests/vm.rs b/tests/vm.rs index 8c2f541..1102266 100644 --- a/tests/vm.rs +++ b/tests/vm.rs @@ -91,8 +91,8 @@ pub mod vm_tests { let mut c = Compiler::new(); c.cpushop(VmOpcode::OP_PUSHF64); c.cpushf64(1.5); - c.cpushop(VmOpcode::OP_PUSH64); - c.cpush64(15); + c.cpushop(VmOpcode::OP_PUSH32); + c.cpush32(15); c.cpushop(VmOpcode::OP_DIV); c.cpushop(VmOpcode::OP_HALT); let mut vm = c.into_vm(); From e40236703ce707c324289662b4d304bf20aaf862 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 14:08:38 +0700 Subject: [PATCH 02/17] implement nan tagging in value.{c,h} --- src/vm/value.c | 214 +++++++++++++++++++++++++------------------------ src/vm/value.h | 139 +++++++++++++++++++++----------- 2 files changed, 204 insertions(+), 149 deletions(-) diff --git a/src/vm/value.c b/src/vm/value.c index 72bf8fc..0375d21 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -7,159 +7,163 @@ #include "array_obj.h" #include "function.h" -void value_int(struct value *val, int32_t data) { - val->type = TYPE_INT; - val->as.integer = data; -} -void value_float(struct value *val, double data) { - val->type = TYPE_FLOAT; - val->as.floatp = data; +int value_get_type(struct value val) { + if(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0) { + return val.as.bits.tag_bits; + } else { + return TYPE_FLOAT; + } } + // non-primitives -void value_str(struct value *val, const char *data, const struct vm *vm) { - val->type = TYPE_STR; - val->as.str = string_malloc(data, vm); +struct value value_int(int32_t n) { + struct value val; + value_set_int(&val, n); + return val; +} +struct value value_float(double n) { + struct value val; + value_set_float(&val, n); + return val; +} +struct value value_str(const char *data, const struct vm *vm) { + return value_pointer(TYPE_STR, string_malloc(data, vm)); } -void value_function(struct value *val, uint32_t ip, uint16_t nargs, struct env *env, const struct vm *vm) { - val->type = TYPE_FN; - val->as.ifn = function_malloc(ip, nargs, env, vm); +struct value value_function(uint32_t ip, uint16_t nargs, struct env *env, const struct vm *vm) { + return value_pointer(TYPE_FN, function_malloc(ip, nargs, env, vm)); } -void value_dict(struct value *val, const struct vm *vm) { - val->type = TYPE_DICT; - val->as.dict = dict_malloc(vm); +struct value value_dict(const struct vm *vm) { + return value_pointer(TYPE_DICT, dict_malloc(vm)); } -void value_dict_n(struct value *val, size_t n, const struct vm *vm) { - val->type = TYPE_DICT; - val->as.dict = dict_malloc_n(vm, n); +struct value value_dict_n(size_t n, const struct vm *vm) { + return value_pointer(TYPE_DICT, dict_malloc_n(vm, n)); } -void value_array(struct value *val, const struct vm *vm) { - val->type = TYPE_ARRAY; - val->as.array = array_obj_malloc(vm); +struct value value_array(const struct vm *vm) { + return value_pointer(TYPE_ARRAY, array_obj_malloc(vm)); } -void value_array_n(struct value *val, size_t n, const struct vm *vm) { - val->type = TYPE_ARRAY; - val->as.array = array_obj_malloc_n(n, vm); +struct value value_array_n(size_t n, const struct vm *vm) { + return value_pointer(TYPE_ARRAY, array_obj_malloc_n(n, vm)); +} + +static inline struct value value_interpreter_error() { + return value_pointer(TYPE_INTERPRETER_ERROR, 0); } // arith #define arith_op(name, op, custom) \ -void value_ ## name (struct value *result, const struct value left, const struct value right, const struct vm *vm) { \ - switch(left.type) { \ +struct value value_ ## name (const struct value left, const struct value right, const struct vm *vm) { \ + switch(value_get_type(left)) { \ case TYPE_INT: { \ - switch(right.type) { \ + switch(value_get_type(right)) { \ case TYPE_FLOAT: { \ - value_float(result, (double)left.as.integer op right.as.floatp); break; } \ + return ((double)value_get_int(left) op right.as.floatp); break; } \ case TYPE_INT: { \ - value_int(result, left.as.integer op right.as.integer); \ + return (value_get_int(left) op value_get_int(right)); \ break; }\ default: \ - result->type = TYPE_INTERPRETER_ERROR; } \ + return value_interpreter_error(); } \ break; \ } \ case TYPE_FLOAT: { \ - switch(right.type) { \ + switch(value_get_type(right)) { \ case TYPE_INT: { \ - value_float(result, left.as.floatp op (double)right.as.integer); break; } \ + return (left.as.floatp op (double)value_get_int(right)); break; } \ case TYPE_FLOAT: { \ - value_float(result, left.as.floatp op right.as.floatp); break; } \ + return (left.as.floatp op right.as.floatp); break; } \ default: \ - result->type = TYPE_INTERPRETER_ERROR; } \ + return value_interpreter_error(); } \ break; \ } custom \ - default: result->type = TYPE_INTERPRETER_ERROR; }\ + default: return value_interpreter_error(); }\ } arith_op(add, +, case TYPE_STR: { - if(right.type != TYPE_STR) { - result->type = TYPE_INTERPRETER_ERROR; - return; + if(value_get_type(right) != TYPE_STR) { + return value_interpreter_error(); } result->type = TYPE_STR; - result->as.str = string_append(left.as.str, right.as.str, vm); + result->as.str = string_append(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right), vm); break; } ) arith_op(sub, -,) arith_op(mul, *, case TYPE_STR: { - if(right.type == TYPE_INT) { - if(right.as.integer == 0) { - value_str(result, "", vm); + if(value_get_type(right) == TYPE_INT) { + if(value_get_int(right) == 0) { + return value_interpreter_error(); } else { - result->type = TYPE_STR; - result->as.str = string_repeat(left.as.str, right.as.integer, vm); + return value_pointer(TYPE_STR, string_repeat(value_get_pointer(TYPE_STR, left), value_get_int(right), vm)); } } else - result->type = TYPE_INTERPRETER_ERROR; + return value_interpreter_error(); break; } case TYPE_ARRAY: { - if(right.type == TYPE_INT) { - result->type = TYPE_ARRAY; - result->as.array = array_obj_repeat(left.as.array, (size_t)right.as.integer, vm); + if(value_get_type(right) == TYPE_INT) { + return value_pointer(TYPE_ARRAY, array_obj_repeat(left.as.array, (size_t)value_get_int(right), vm)); } else - result->type = TYPE_INTERPRETER_ERROR; - break; } + return value_interpreter_error(); } ) -void value_div(struct value *result, const struct value left, const struct value right, const struct vm *_) { - switch(left.type) { +struct value value_div(const struct value left, const struct value right, const struct vm *_) { + switch(value_get_type(left)) { case TYPE_INT: { - switch(right.type) { + switch(value_get_type(right)) { case TYPE_FLOAT: { - value_float(result, (double)left.as.integer / right.as.floatp); break; } + return ((double)value_get_int(left) / right.as.floatp); break; } case TYPE_INT: { - value_float(result, (double)left.as.integer / (double)right.as.integer); + return ((double)value_get_int(left) / (double)value_get_int(right)); break; } default: - result->type = TYPE_INTERPRETER_ERROR; } + return value_interpreter_error(); } break; } case TYPE_FLOAT: { - switch(right.type) { + switch(value_get_type(right)) { case TYPE_INT: { - value_float(result, left.as.floatp / (double)right.as.integer); break; } + return (left.as.floatp / (double)value_get_int(right)); break; } case TYPE_FLOAT: { - value_float(result, left.as.floatp / right.as.floatp); break; } + return (left.as.floatp / right.as.floatp); break; } default: - result->type = TYPE_INTERPRETER_ERROR; } + return value_interpreter_error(); } break; } - default: result->type = TYPE_INTERPRETER_ERROR; } + default: return value_interpreter_error(); } } -void value_mod(struct value *result, const struct value left, const struct value right, const struct vm *_) { - if(left.type == TYPE_INT && right.type == TYPE_INT) { - value_int(result, left.as.integer % right.as.integer); +struct value value_mod(const struct value left, const struct value right, const struct vm *_) { + if(value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { + return (value_get_int(left) % value_get_int(right)); } else - result->type = TYPE_INTERPRETER_ERROR; + return value_interpreter_error(); } -void value_bitwise_and(struct value *result, const struct value left, const struct value right, const struct vm *_) { - if (left.type == TYPE_INT && right.type == TYPE_INT) { - value_int(result, left.as.integer & right.as.integer); +struct value value_bitwise_and(const struct value left, const struct value right, const struct vm *_) { + if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { + return (value_get_int(left) & value_get_int(right)); } else - result->type = TYPE_INTERPRETER_ERROR; + return value_interpreter_error(); } -void value_bitwise_or(struct value *result, const struct value left, const struct value right, const struct vm *_) { - if (left.type == TYPE_INT && right.type == TYPE_INT) { - value_int(result, left.as.integer | right.as.integer); +struct value value_bitwise_or(const struct value left, const struct value right, const struct vm *_) { + if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { + return (value_get_int(left) | value_get_int(right)); } else - result->type = TYPE_INTERPRETER_ERROR; + return value_interpreter_error(); } -void value_bitwise_xor(struct value *result, const struct value left, const struct value right, const struct vm *_) { - if (left.type == TYPE_INT && right.type == TYPE_INT) { - value_int(result, left.as.integer ^ right.as.integer); +struct value value_bitwise_xor(const struct value left, const struct value right, const struct vm *_) { + if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { + return (value_get_int(left) ^ value_get_int(right)); } else - result->type = TYPE_INTERPRETER_ERROR; + return value_interpreter_error(); } // in place // returns 1 if it CAN do it in place int value_iadd(struct value left, const struct value right) { - switch (left.type) { + switch (value_get_type(left)) { case TYPE_STR: { - switch(right.type) { + switch(value_get_type(right)) { case TYPE_STR: { - string_append_in_place(left.as.str, right.as.str); + string_append_in_place(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)); return 1; } } return 0; } @@ -168,11 +172,11 @@ int value_iadd(struct value left, const struct value right) { } int value_imul(struct value left, const struct value right) { - switch (left.type) { + switch (value_get_type(left)) { case TYPE_STR: { - switch(right.type) { + switch(value_get_type(right)) { case TYPE_INT: { - string_repeat_in_place(left.as.str, right.as.integer); + string_repeat_in_place(value_get_pointer(TYPE_STR, left), value_get_int(right)); return 1; } } return 0; } @@ -183,17 +187,17 @@ int value_imul(struct value left, const struct value right) { // comparison #define strcmp_op(cond) \ case TYPE_STR: \ - value_int(result, right.type == TYPE_STR && string_cmp(left.as.str, right.as.str) cond); \ + return (value_get_type(right) == TYPE_STR && string_cmp(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)) cond); \ break; arith_op(eq, ==, strcmp_op(== 0) case TYPE_NATIVE_FN: case TYPE_FN: case TYPE_DICT: - value_int(result, left.as.integer == right.as.integer); + return (value_get_int(left) == value_get_int(right)); break; case TYPE_NIL: - value_int(result, right.type == TYPE_NIL); + return (value_get_type(right) == TYPE_NIL); break; ) arith_op(neq, !=, @@ -201,10 +205,10 @@ arith_op(neq, !=, case TYPE_NATIVE_FN: case TYPE_FN: case TYPE_DICT: - value_int(result, left.as.integer != right.as.integer); + return (value_get_int(left) != value_get_int(right)); break; case TYPE_NIL: - value_int(result, right.type != TYPE_NIL); + return (value_get_type(right) != TYPE_NIL); break; ) arith_op(lt, <, @@ -222,27 +226,29 @@ arith_op(geq, >=, // boolean bool value_is_true(const struct value val) { - switch(val.type) { - case TYPE_INT: return val.as.integer > 0; + switch(value_get_type(val)) { + case TYPE_INT: return value_get_int(val) > 0; case TYPE_FLOAT: return val.as.floatp > 0; - case TYPE_STR: return !string_is_empty(val.as.str); + case TYPE_STR: return !string_is_empty(value_get_pointer(TYPE_STR, val)); default: return 0; } } struct dict *value_get_prototype(const struct vm *vm, const struct value val) { - if(val.type == TYPE_STR) { - return vm->dstr; - } else if(val.type == TYPE_INT) { - return vm->dint; - } else if(val.type == TYPE_FLOAT) { - return vm->dfloat; - } else if(val.type == TYPE_ARRAY) { - return vm->darray; - } else if(val.type == TYPE_DICT) { - const struct value *p = dict_get(val.as.dict, "prototype"); - if (p == NULL) return NULL; - return p->as.dict; + switch (value_get_type(val)) { + case TYPE_STR: + return vm->dstr; + case TYPE_INT: + return vm->dint; + case TYPE_FLOAT: + return vm->dfloat; + case TYPE_ARRAY: + return vm->darray; + case TYPE_DICT: { + const struct value *p = dict_get(value_get_pointer(TYPE_DICT, val), "prototype"); + if (p == NULL) return NULL; + return p->as.dict; + } } return NULL; } diff --git a/src/vm/value.h b/src/vm/value.h index 6daf6de..a8a03bc 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -1,7 +1,4 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif #include #include #include "dict.h" @@ -12,66 +9,118 @@ struct hmap; struct array_obj; struct string; -#define TYPE_NIL 0 -#define TYPE_INT 1 -#define TYPE_FLOAT 2 -#define TYPE_NATIVE_FN 3 -#define TYPE_FN 4 -#define TYPE_STR 5 -#define TYPE_DICT 6 -#define TYPE_ARRAY 7 -#define TYPE_INTERPRETER_ERROR 127 -#define TYPE_INTERPRETER_ITERATOR 128 +#define RESERVED_NAN 0x7ff +#define TYPE_FLOAT 0 +#define TYPE_INT 1 +#define TYPE_NATIVE_FN 2 +#define TYPE_FN 3 +#define TYPE_STR 4 +#define TYPE_DICT 5 +#define TYPE_ARRAY 6 +#define TYPE_INTERPRETER_ERROR 7 +#define TYPE_INTERPRETER_ITERATOR 8 +#define TYPE_NIL 9 -typedef void (*value_fn)(struct vm *vm, uint16_t nargs); struct __attribute__((packed)) value { union { - int32_t integer; double floatp; - struct string *str; - value_fn fn; - struct function *ifn; - struct dict *dict; - array_obj *array; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + struct __attribute__((packed)) { + uint64_t payload : 48; + uint8_t tag_bits : 4; // must be larger than 0 + uint16_t reserved_nan : 12; // must be positive NaN (0x7ff0) + } bits; +#else +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + struct __attribute__((packed)) { + uint16_t reserved_nan : 12; // must be positive NaN (0x7ff0) + uint8_t tag_bits : 4; // must be larger than 0 + uint64_t payload : 48; + } bits; +#else +#error "does not support this system" +#endif +#endif + struct __attribute__((packed)) { + uint32_t upper32; + uint32_t lower32; + }; } as; - uint8_t type; }; -void value_int(struct value*, int32_t); -void value_float(struct value*, double); -void value_str(struct value*, const char*, const struct vm*); +typedef void (*value_fn)(struct vm *vm, uint16_t nargs); + struct env; -void value_function(struct value *, uint32_t ip, uint16_t nargs, struct env *env, const struct vm *); -void value_dict(struct value *, const struct vm *); -void value_dict_n(struct value *, size_t n, const struct vm *); -void value_array(struct value *, const struct vm *); -void value_array_n(struct value *, size_t n, const struct vm *); + +struct value value_int(int32_t); +struct value value_float(double); +struct value value_str(const char*, const struct vm*); +struct value value_function(uint32_t ip, uint16_t nargs, struct env *env, const struct vm *); +struct value value_dict(const struct vm *); +struct value value_dict_n(size_t n, const struct vm *); +struct value value_array(const struct vm *); +struct value value_array_n(size_t n, const struct vm *); +int value_get_type(struct value val); void value_print(struct value); -void value_add(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_sub(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_mul(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_div(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_mod(struct value *result, const struct value left, const struct value right, const struct vm *); +struct value value_add(const struct value left, const struct value right, const struct vm *); +struct value value_sub(const struct value left, const struct value right, const struct vm *); +struct value value_mul(const struct value left, const struct value right, const struct vm *); +struct value value_div(const struct value left, const struct value right, const struct vm *); +struct value value_mod(const struct value left, const struct value right, const struct vm *); -void value_bitwise_and(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_bitwise_or(struct value *result, const struct value left, const struct value right, const struct vm *); -void value_bitwise_xor(struct value *result, const struct value left, const struct value right, const struct vm *); +struct value value_bitwise_and(const struct value left, const struct value right, const struct vm *); +struct value value_bitwise_or (const struct value left, const struct value right, const struct vm *); +struct value value_bitwise_xor(const struct value left, const struct value right, const struct vm *); int value_iadd(struct value left, const struct value right); int value_imul(struct value left, const struct value right); -void value_lt(struct value *result, const struct value left, const struct value right, const struct vm*); -void value_leq(struct value *result, const struct value left, const struct value right, const struct vm*); -void value_gt(struct value *result, const struct value left, const struct value right, const struct vm*); -void value_geq(struct value *result, const struct value left, const struct value right, const struct vm*); -void value_eq(struct value *result, const struct value left, const struct value right, const struct vm*); -void value_neq(struct value *result, const struct value left, const struct value right, const struct vm*); +struct value value_lt (const struct value left, const struct value right, const struct vm*); +struct value value_leq(const struct value left, const struct value right, const struct vm*); +struct value value_gt (const struct value left, const struct value right, const struct vm*); +struct value value_geq(const struct value left, const struct value right, const struct vm*); +struct value value_eq (const struct value left, const struct value right, const struct vm*); +struct value value_neq(const struct value left, const struct value right, const struct vm*); bool value_is_true(const struct value); struct dict *value_get_prototype(const struct vm *vm, const struct value val); -#ifdef __cplusplus +#pragma region +static inline struct value value_pointer(uint8_t tag, void *ptr) { + uint64_t low_bits = (uint64_t)ptr & 0xffffffffffff; + assert(low_bits == (uint64_t)ptr); + assert(tag < 16 && tag > 0); // we can only store 4 bits + return (struct value){ + .as.bits.reserved_nan = RESERVED_NAN, + .as.bits.tag_bits = tag, + .as.bits.payload = low_bits}; } -#endif +uint16_t value_get_tag(struct value val) { + assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); + return val.as.bits.tag_bits; +} +static inline void *value_get_pointer(uint8_t tag, struct value val) { + assert(tag != TYPE_INT); + assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); + return (void *)val.as.bits.payload; +} +static inline int32_t value_get_int(struct value val) { + assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == TYPE_INT); + return (int32_t)val.as.lower32; +} +static inline void value_set_int(struct value *val, int32_t n) { + val->as.bits.reserved_nan = RESERVED_NAN; + val->as.bits.tag_bits = TYPE_INT; + val->as.lower32 = n; +} +static inline double value_get_float(struct value val) { + assert(!isnan(val.as.floatp)); + return val.as.floatp; +} +static inline void value_set_float(struct value *val, double n) { + val->as.floatp = n; + assert(val->as.bits.reserved_nan != RESERVED_NAN); +} +#pragma endregion \ No newline at end of file From 0639428c243d7d5aba2db280f6e25e991c113c3f Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 14:44:54 +0700 Subject: [PATCH 03/17] Fix value.{h,c}, vm.c --- src/vm/value.c | 143 +++++++++-------- src/vm/value.h | 25 +++ src/vm/vm.c | 290 ++++++++++++++++++----------------- src/vmbindings/cnativeval.rs | 45 +++--- 4 files changed, 267 insertions(+), 236 deletions(-) diff --git a/src/vm/value.c b/src/vm/value.c index 0375d21..329310a 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -50,40 +50,40 @@ static inline struct value value_interpreter_error() { } // arith -#define arith_op(name, op, custom) \ -struct value value_ ## name (const struct value left, const struct value right, const struct vm *vm) { \ - switch(value_get_type(left)) { \ - case TYPE_INT: { \ - switch(value_get_type(right)) { \ - case TYPE_FLOAT: { \ - return ((double)value_get_int(left) op right.as.floatp); break; } \ - case TYPE_INT: { \ - return (value_get_int(left) op value_get_int(right)); \ - break; }\ - default: \ - return value_interpreter_error(); } \ - break; \ - } \ - case TYPE_FLOAT: { \ - switch(value_get_type(right)) { \ - case TYPE_INT: { \ - return (left.as.floatp op (double)value_get_int(right)); break; } \ - case TYPE_FLOAT: { \ - return (left.as.floatp op right.as.floatp); break; } \ - default: \ - return value_interpreter_error(); } \ - break; \ - } custom \ - default: return value_interpreter_error(); }\ -} +#define arith_op(name, op, custom) \ + struct value value_##name(const struct value left, const struct value right, const struct vm *vm) { \ + switch (value_get_type(left)) { \ + case TYPE_INT: { \ + switch (value_get_type(right)) { \ + case TYPE_FLOAT: \ + return value_float((double)value_get_int(left) op right.as.floatp); \ + case TYPE_INT: \ + return value_int(value_get_int(left) op value_get_int(right)); \ + default: \ + return value_interpreter_error(); \ + } \ + } \ + case TYPE_FLOAT: { \ + switch (value_get_type(right)) { \ + case TYPE_INT: \ + return value_int(left.as.floatp op(double) value_get_int(right)); \ + case TYPE_FLOAT: \ + return value_float(left.as.floatp op right.as.floatp); \ + default: \ + return value_interpreter_error(); \ + } \ + } \ + custom \ + } \ + return value_interpreter_error(); \ + } arith_op(add, +, case TYPE_STR: { if(value_get_type(right) != TYPE_STR) { return value_interpreter_error(); } - result->type = TYPE_STR; - result->as.str = string_append(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right), vm); - break; } + return value_pointer(TYPE_STR, string_append(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right), vm)); + } ) arith_op(sub, -,) arith_op(mul, *, @@ -91,67 +91,62 @@ arith_op(mul, *, if(value_get_type(right) == TYPE_INT) { if(value_get_int(right) == 0) { return value_interpreter_error(); - } else { - return value_pointer(TYPE_STR, string_repeat(value_get_pointer(TYPE_STR, left), value_get_int(right), vm)); } + return value_pointer(TYPE_STR, string_repeat(value_get_pointer(TYPE_STR, left), value_get_int(right), vm)); } - else - return value_interpreter_error(); - break; } + return value_interpreter_error(); + } case TYPE_ARRAY: { if(value_get_type(right) == TYPE_INT) { - return value_pointer(TYPE_ARRAY, array_obj_repeat(left.as.array, (size_t)value_get_int(right), vm)); + return value_pointer(TYPE_ARRAY, array_obj_repeat(value_get_pointer(TYPE_ARRAY, left), (size_t)value_get_int(right), vm)); } - else - return value_interpreter_error(); } + return value_interpreter_error(); + } ) struct value value_div(const struct value left, const struct value right, const struct vm *_) { switch(value_get_type(left)) { case TYPE_INT: { switch(value_get_type(right)) { - case TYPE_FLOAT: { - return ((double)value_get_int(left) / right.as.floatp); break; } - case TYPE_INT: { - return ((double)value_get_int(left) / (double)value_get_int(right)); - break; } - default: - return value_interpreter_error(); } - break; + case TYPE_FLOAT: + return value_float((double)value_get_int(left) / right.as.floatp); + case TYPE_INT: + return value_float((double)value_get_int(left) / (double)value_get_int(right)); + } + return value_interpreter_error(); } case TYPE_FLOAT: { switch(value_get_type(right)) { - case TYPE_INT: { - return (left.as.floatp / (double)value_get_int(right)); break; } - case TYPE_FLOAT: { - return (left.as.floatp / right.as.floatp); break; } - default: - return value_interpreter_error(); } - break; + case TYPE_INT: + return value_float(left.as.floatp / (double)value_get_int(right)); + case TYPE_FLOAT: + return value_float(left.as.floatp / right.as.floatp); + } + return value_interpreter_error(); } default: return value_interpreter_error(); } } struct value value_mod(const struct value left, const struct value right, const struct vm *_) { if(value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { - return (value_get_int(left) % value_get_int(right)); + return value_int(value_get_int(left) % value_get_int(right)); } else return value_interpreter_error(); } struct value value_bitwise_and(const struct value left, const struct value right, const struct vm *_) { if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { - return (value_get_int(left) & value_get_int(right)); + return value_int(value_get_int(left) & value_get_int(right)); } else return value_interpreter_error(); } struct value value_bitwise_or(const struct value left, const struct value right, const struct vm *_) { if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { - return (value_get_int(left) | value_get_int(right)); + return value_int(value_get_int(left) | value_get_int(right)); } else return value_interpreter_error(); } struct value value_bitwise_xor(const struct value left, const struct value right, const struct vm *_) { if (value_get_type(left) == TYPE_INT && value_get_type(right) == TYPE_INT) { - return (value_get_int(left) ^ value_get_int(right)); + return value_int(value_get_int(left) ^ value_get_int(right)); } else return value_interpreter_error(); } @@ -161,10 +156,12 @@ struct value value_bitwise_xor(const struct value left, const struct value right int value_iadd(struct value left, const struct value right) { switch (value_get_type(left)) { case TYPE_STR: { - switch(value_get_type(right)) { - case TYPE_STR: { - string_append_in_place(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)); - return 1; } } + switch (value_get_type(right)) { + case TYPE_STR: { + string_append_in_place(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)); + return 1; + } + } return 0; } } @@ -174,10 +171,12 @@ int value_iadd(struct value left, const struct value right) { int value_imul(struct value left, const struct value right) { switch (value_get_type(left)) { case TYPE_STR: { - switch(value_get_type(right)) { - case TYPE_INT: { - string_repeat_in_place(value_get_pointer(TYPE_STR, left), value_get_int(right)); - return 1; } } + switch (value_get_type(right)) { + case TYPE_INT: { + string_repeat_in_place(value_get_pointer(TYPE_STR, left), value_get_int(right)); + return 1; + } + } return 0; } } @@ -187,29 +186,25 @@ int value_imul(struct value left, const struct value right) { // comparison #define strcmp_op(cond) \ case TYPE_STR: \ - return (value_get_type(right) == TYPE_STR && string_cmp(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)) cond); \ + return value_int(value_get_type(right) == TYPE_STR && string_cmp(value_get_pointer(TYPE_STR, left), value_get_pointer(TYPE_STR, right)) cond); \ break; arith_op(eq, ==, strcmp_op(== 0) case TYPE_NATIVE_FN: case TYPE_FN: case TYPE_DICT: - return (value_get_int(left) == value_get_int(right)); - break; + return value_int(value_get_int(left) == value_get_int(right)); case TYPE_NIL: - return (value_get_type(right) == TYPE_NIL); - break; + return value_int(value_get_type(right) == TYPE_NIL); ) arith_op(neq, !=, strcmp_op(!= 0) case TYPE_NATIVE_FN: case TYPE_FN: case TYPE_DICT: - return (value_get_int(left) != value_get_int(right)); - break; + return value_int(value_get_int(left) != value_get_int(right)); case TYPE_NIL: - return (value_get_type(right) != TYPE_NIL); - break; + return value_int(value_get_type(right) != TYPE_NIL); ) arith_op(lt, <, strcmp_op(< 0) @@ -247,7 +242,7 @@ struct dict *value_get_prototype(const struct vm *vm, const struct value val) { case TYPE_DICT: { const struct value *p = dict_get(value_get_pointer(TYPE_DICT, val), "prototype"); if (p == NULL) return NULL; - return p->as.dict; + return value_get_pointer(TYPE_DICT, *p); } } return NULL; diff --git a/src/vm/value.h b/src/vm/value.h index a8a03bc..91e1dbd 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -21,6 +21,31 @@ struct string; #define TYPE_INTERPRETER_ITERATOR 8 #define TYPE_NIL 9 +/* + 1111111111110000 + 01111111 11111010 00000000 00000000 00000000 00000000 00000000 00000000 + seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm + ^ ^^^^ tagging bits (T) + ^ ^ initial mantissa bit (whether it's a signalling/quiet NaN) + ^ signed bit (ignored) + + we'll assume the architecture is using IEEE 754 double precision floating + point, and the OS allocates userland memory in the lower half of memory. + NaN values inside doubles allow us to store a 52-bit payload inside the mantissa + we can store 48-bit pointers/32-bit integers in the lower 48-bit region + and 4 additional higher bits for tagging + + possible values for T: + - int + - native_fn + - fn + - str + - dict + - array + - [interpreter data] + +*/ + struct __attribute__((packed)) value { union { double floatp; diff --git a/src/vm/vm.c b/src/vm/vm.c index bbe297a..b1e054f 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -112,11 +112,7 @@ void vm_execute(struct vm *vm) { const _type data = _data; \ vm->ip += (uint32_t)sizeof(_type); \ LOG(sizeof(_type) == 8 ? "PUSH %ld\n" : "PUSH %d\n", data); \ - \ - struct value val = { \ - .type = TYPE_INT, \ - .as.integer = (int32_t)data}; \ - array_push(vm->stack, val); \ + array_push(vm->stack, value_int((int32_t)data)); \ dispatch(); \ } push_int_op(OP_PUSH8, uint8_t, vm->code.data[vm->ip+0]) @@ -150,8 +146,7 @@ void vm_execute(struct vm *vm) { u.u[7] = vm->code.data[vm->ip + 7]; vm->ip += (uint32_t)sizeof(u); LOG("PUSH_F64 %f\n", u.d); - array_push(vm->stack, (struct value){0}); - value_float(&array_top(vm->stack), u.d); + array_push(vm->stack, value_float(u.d)); dispatch(); } @@ -161,8 +156,7 @@ void vm_execute(struct vm *vm) { char *str = (char *)&vm->code.data[vm->ip]; // must be null terminated vm->ip += (uint32_t)strlen(str) + 1; LOG("PUSH %s\n", str); - array_push(vm->stack, (struct value){0}); - value_str(&array_top(vm->stack), str, vm); + array_push(vm->stack, value_str(str, vm)); dispatch(); } @@ -187,20 +181,19 @@ void vm_execute(struct vm *vm) { vm->ip++; struct value val = array_top(vm->stack); array_pop(vm->stack); - int truth = value_is_true(val); - value_int(&val, !truth); - array_push(vm->stack, val); + array_push(vm->stack, value_int(!value_is_true(val))); dispatch(); } // pops top of the stack, performs unary negation and pushes the result doop(OP_NEGATE): { vm->ip++; - struct value *val = &array_top(vm->stack); + assert(0); + /* struct value *val = &array_top(vm->stack); if(val->type == TYPE_INT) { val->as.integer = -val->as.integer; } else if(val->type == TYPE_FLOAT) { val->as.floatp = -val->as.floatp; - } + } */ dispatch(); } @@ -215,9 +208,8 @@ void vm_execute(struct vm *vm) { struct value right = vm->stack.data[vm->stack.length - 1]; \ struct value left = vm->stack.data[vm->stack.length - 2]; \ \ - struct value result = {0}; \ - fn(&result, left, right, vm); \ - if (result.type == TYPE_INTERPRETER_ERROR) { \ + struct value result = fn(left, right, vm); \ + if (value_get_type(result) == TYPE_INTERPRETER_ERROR) { \ ERROR(ERROR_##optype, 1); \ } \ vm->stack.length -= 2; \ @@ -237,30 +229,29 @@ void vm_execute(struct vm *vm) { // in place arithmetic: // does regular arith, returns lhs on stack and jumps out of fallback if CAN do it in place (for primitives) // else just does the fallback (copying and setting variable manually) -#define binop_inplace(optype, errortype, fn, fallback) \ - doop(optype) : { \ - vm->ip++; \ - LOG(#optype "\n"); \ - debug_assert(vm->stack.length >= 2); \ - const uint8_t pos = (uint8_t)vm->code.data[vm->ip]; \ - \ - struct value right = vm->stack.data[vm->stack.length - 1]; \ - struct value left = vm->stack.data[vm->stack.length - 2]; \ - if (fn(left, right)) { \ - LOG("did in place!\n"); \ - vm->stack.length--; \ - vm->ip += pos; \ - dispatch(); \ - } \ - struct value result = {0}; \ - fallback(&result, left, right, vm); \ - if (result.type == TYPE_INTERPRETER_ERROR) { \ - ERROR(errortype, 1); \ - } \ - vm->stack.length -= 2; \ - array_push(vm->stack, result); \ - vm->ip++; \ - dispatch(); \ +#define binop_inplace(optype, errortype, fn, fallback) \ + doop(optype) : { \ + vm->ip++; \ + LOG(#optype "\n"); \ + debug_assert(vm->stack.length >= 2); \ + const uint8_t pos = (uint8_t)vm->code.data[vm->ip]; \ + \ + struct value right = vm->stack.data[vm->stack.length - 1]; \ + struct value left = vm->stack.data[vm->stack.length - 2]; \ + if (fn(left, right)) { \ + LOG("did in place!\n"); \ + vm->stack.length--; \ + vm->ip += pos; \ + dispatch(); \ + } \ + struct value result = fallback(left, right, vm); \ + if (value_get_type(result) == TYPE_INTERPRETER_ERROR) { \ + ERROR(errortype, 1); \ + } \ + vm->stack.length -= 2; \ + array_push(vm->stack, result); \ + vm->ip++; \ + dispatch(); \ } binop_inplace(OP_IADD, ERROR_OP_ADD, value_iadd, value_add) @@ -285,17 +276,14 @@ void vm_execute(struct vm *vm) { struct value left = array_top(vm->stack); array_pop(vm->stack); - if (right.type == TYPE_DICT) { - const struct dict *rhs = right.as.dict; - struct value retval = { - .as.integer = 0, - .type = TYPE_INT - }; - if ((rhs == vm->drec && left.type == TYPE_DICT) || + if (value_get_type(right) == TYPE_DICT) { + const struct dict *rhs = value_get_pointer(TYPE_DICT, right); + if ((rhs == vm->drec && value_get_type(left) == TYPE_DICT) || (value_get_prototype(vm, left) == rhs)) { - retval.as.integer = 1; + array_push(vm->stack, value_int(1)); + } else { + array_push(vm->stack, value_int(0)); } - array_push(vm->stack, retval); } else { ERROR(ERROR_EXPECTED_RECORD_OF_EXPR, 1); } @@ -335,7 +323,7 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)sizeof(n); struct value val = array_top(vm->stack); env_set(vm->localenv, n, val); - function_set_bound_var(val.as.ifn, n, val); + function_set_bound_var(value_get_pointer(TYPE_FN, val), n, val); dispatch(); } // pushes a copy of the value of current environment's slot @@ -399,8 +387,8 @@ void vm_execute(struct vm *vm) { const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | vm->code.data[vm->ip + 1]); LOG("DEF_FUNCTION_PUSH %d %d\n", pos, nargs); - array_push(vm->stack, (struct value){0}); - value_function(&array_top(vm->stack), vm->ip + (uint32_t)sizeof(pos), nargs, vm->localenv, vm); + array_push(vm->stack, value_function(vm->ip + (uint32_t)sizeof(pos), nargs, vm->localenv, vm)); + vm->ip += pos; dispatch(); } @@ -459,42 +447,47 @@ void vm_execute(struct vm *vm) { vm->exframe_fallthrough = NULL; \ else if(vm->error) return; \ } while(0) -#define JMP_INTERPRETED_FN_(POP, UNWIND, END_IF_NATIVE) \ - do { \ - if (val.type == TYPE_DICT) { \ - POP \ - const struct value *ctor = dict_get(val.as.dict, "constructor"); \ - if (ctor == NULL) { \ - ERROR(ERROR_RECORD_NO_CONSTRUCTOR, UNWIND); \ - } \ - if (ctor->type == TYPE_NATIVE_FN) { \ - LOG("NATIVE CONSTRUCTOR %d\n", nargs); \ - CALL_NATIVE(ctor->as.fn); \ - do { \ - END_IF_NATIVE \ - } while (0); \ - } else if (ctor->type != TYPE_FN) { \ - ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ - } \ - ifn = ctor->as.ifn; \ - if (nargs + 1 != ifn->nargs) { \ - ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ - } \ - struct value new_val; \ - value_dict(&new_val, vm); \ - dict_set(new_val.as.dict, "prototype", val); \ - array_push(vm->stack, new_val); \ - } else { \ - POP \ - ifn = val.as.ifn; \ - if (nargs != ifn->nargs) { \ - ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ - } \ - } \ +#define JMP_INTERPRETED_FN_(POP, UNWIND, END_IF_NATIVE) \ + do { \ + if (value_get_type(val) == TYPE_DICT) { \ + do { \ + POP \ + } while (0); \ + const struct value *pctor = dict_get(value_get_pointer(TYPE_DICT, val), "constructor"); \ + if (pctor == NULL) { \ + ERROR(ERROR_RECORD_NO_CONSTRUCTOR, UNWIND); \ + } \ + const struct value ctor = *pctor; \ + if (value_get_type(ctor) == TYPE_NATIVE_FN) { \ + LOG("NATIVE CONSTRUCTOR %d\n", nargs); \ + CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, ctor)))); \ + do { \ + END_IF_NATIVE \ + } while (0); \ + } else if (value_get_type(ctor) != TYPE_FN) { \ + ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ + } \ + ifn = value_get_pointer(TYPE_NATIVE_FN, *ctor); \ + if (nargs + 1 != ifn->nargs) { \ + ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ + } \ + struct value new_val = value_dict(vm); \ + dict_set(value_get_pointer(TYPE_DICT, val), "prototype", val); \ + array_push(vm->stack, new_val); \ + } else { \ + do { \ + POP \ + } while (0); \ + ifn = value_get_pointer(TYPE_FN, val); \ + if (nargs != ifn->nargs) { \ + ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ + } \ + } \ } while (0) #define JMP_INTERPRETED_FN(UNWIND, END_IF_NATIVE) JMP_INTERPRETED_FN_(array_pop(vm->stack);, UNWIND, END_IF_NATIVE) #define JMP_INTERPRETED_FN_NO_POP(UNWIND, END_IF_NATIVE) JMP_INTERPRETED_FN_(do{}while(0);, UNWIND, END_IF_NATIVE) - doop(OP_CALL): { + doop(OP_CALL) : { + assert(0); /* // argument: [arg2][arg1] vm->ip++; struct value val = array_top(vm->stack); @@ -503,10 +496,10 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)sizeof(nargs); debug_assert(vm->stack.length >= nargs); LOG("call %d\n", nargs); - switch(val.type) { + switch(value_get_type(val)) { case TYPE_NATIVE_FN: { array_pop(vm->stack); - CALL_NATIVE(val.as.fn); + CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, val)))); break; } case TYPE_FN: case TYPE_DICT: { @@ -529,7 +522,7 @@ void vm_execute(struct vm *vm) { default: { ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); } } - dispatch(); + dispatch();*/ } // returns from function doop(OP_RET): { @@ -545,13 +538,11 @@ void vm_execute(struct vm *vm) { // dictionaries doop(OP_DICT_NEW): { vm->ip++; - LOG("DICT_NEW\n"); - array_push(vm->stack, (struct value){0}); - value_dict(&array_top(vm->stack), vm); - dispatch(); + assert(0); } doop(OP_MEMBER_GET): doop(OP_MEMBER_GET_NO_POP): { + assert(0);/* const enum vm_opcode op = vm->code.data[vm->ip]; vm->ip++; const char *key = (const char *)&vm->code.data[vm->ip]; // must be null terminated @@ -560,7 +551,7 @@ void vm_execute(struct vm *vm) { struct value val = array_top(vm->stack); struct dict *dict = NULL; - if(val.type != TYPE_DICT) { + if(value_get_type(val) != TYPE_DICT) { if((dict = value_get_prototype(vm, val)) == NULL) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } @@ -571,10 +562,10 @@ void vm_execute(struct vm *vm) { dispatch(); } } else { - if(val.type != TYPE_DICT) { + if(value_get_type(val) != TYPE_DICT) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } - dict = val.as.dict; + dict = value_get_pointer(TYPE_DICT, val); if(op == OP_MEMBER_GET) array_pop(vm->stack); } @@ -584,7 +575,7 @@ void vm_execute(struct vm *vm) { } else { ERROR(ERROR_UNKNOWN_KEY, strlen(key)+1); } - + */ dispatch(); } doop(OP_MEMBER_SET): { @@ -594,45 +585,48 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)strlen(key) + 1; LOG("MEMBER_SET %s\n", key); struct value dval = array_top(vm->stack); - if(dval.type != TYPE_DICT) { + if(value_get_type(dval) != TYPE_DICT) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } array_pop(vm->stack); struct value val = array_top(vm->stack); - dict_set(dval.as.dict, key, val); + dict_set(value_get_pointer(TYPE_DICT, dval), key, val); dispatch(); } doop(OP_DICT_LOAD): { // stack: [nil][value][key] - vm->ip++; + assert(0); + /*vm->ip++; struct value val = array_top(vm->stack); - size_t length = (size_t)val.as.integer; + size_t length = (size_t)value_get_int(val); array_pop(vm->stack); - debug_assert(val.type == TYPE_INT); + debug_assert(value_get_type(val) == TYPE_INT); LOG("DICT_LOAD %ld\n", length); struct value dval; value_dict_n(&dval, length, vm); while(length--) { - debug_assert(key.type == TYPE_STR); + debug_assert(value_get_type(key) == TYPE_STR); // key struct value key = array_top(vm->stack); array_pop(vm->stack); // val struct value val = array_top(vm->stack); array_pop(vm->stack); - dict_set_str(dval.as.dict, key.as.str, val); + dict_set_str(value_get_pointer(TYPE_DICT, dval), key.as.str, val); } array_push(vm->stack, dval); - dispatch(); + dispatch();*/ } // array doop(OP_INDEX_GET): doop(OP_INDEX_GET_NO_POP): { + assert(0); + /* const enum vm_opcode op = vm->code.data[vm->ip]; vm->ip++; LOG(op == OP_INDEX_GET ? "INDEX_GET\n" : "INDEX_GET_NO_POP\n"); @@ -643,32 +637,32 @@ void vm_execute(struct vm *vm) { const struct value dval = array_top(vm->stack); if (op == OP_INDEX_GET) array_pop(vm->stack); - if(dval.type == TYPE_ARRAY) { - if(index.type != TYPE_INT) { + if(value_get_type(dval) == TYPE_ARRAY) { + if(value_get_type(index) != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } - const int32_t i = (int32_t)index.as.integer; + const int32_t i = (int32_t)value_get_int(index); if (!(i >= 0 && i < (int32_t)dval.as.array->length)) { ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, dval.as.array->length); } array_push(vm->stack, dval.as.array->data[i]); - } else if(dval.type == TYPE_STR) { - if(index.type != TYPE_INT) { + } else if(value_get_type(dval) == TYPE_STR) { + if(value_get_type(index) != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } - const int32_t i = (int32_t)index.as.integer; + const int32_t i = (int32_t)value_get_int(index); struct value val; - val.type = TYPE_STR; + value_get_type(val) = TYPE_STR; val.as.str = string_at(dval.as.str, i, vm); if (val.as.str == NULL) { ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, string_len(dval.as.str)); } array_push(vm->stack, val); - } else if(dval.type == TYPE_DICT) { - if(index.type != TYPE_STR) { + } else if(value_get_type(dval) == TYPE_DICT) { + if(value_get_type(index) != TYPE_STR) { ERROR(ERROR_RECORD_KEY_NON_STRING, 1); } - const struct value *val = dict_get_str(dval.as.dict, index.as.str); + const struct value *val = dict_get_str(value_get_pointer(TYPE_DICT, dval), index.as.str); if(val != NULL) { array_push(vm->stack, *val); } else { @@ -677,10 +671,12 @@ void vm_execute(struct vm *vm) { } else { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1); } + */ dispatch(); } doop(OP_INDEX_SET): { - vm->ip++; + assert(0); + /* vm->ip++; LOG("INDEX_SET\n"); struct value index = array_top(vm->stack); @@ -691,32 +687,33 @@ void vm_execute(struct vm *vm) { struct value val = array_top(vm->stack); - if(dval.type == TYPE_ARRAY) { - if(index.type != TYPE_INT) { + if(value_get_type(dval) == TYPE_ARRAY) { + if(value_get_type(index) != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } - const int64_t i = index.as.integer; + const int64_t i = value_get_int(index); if (!(i >= 0 && i < (int64_t)dval.as.array->length)) { ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, dval.as.array->length, 1); } dval.as.array->data[i] = val; - } else if(dval.type == TYPE_DICT) { - if(index.type != TYPE_STR) { + } else if(value_get_type(dval) == TYPE_DICT) { + if(value_get_type(index) != TYPE_STR) { ERROR(ERROR_RECORD_KEY_NON_STRING, 1); } - dict_set_str(dval.as.dict, index.as.str, val); + dict_set_str(value_get_pointer(TYPE_DICT, dval), index.as.str, val); } else { ERROR(ERROR_EXPECTED_RECORD_ARRAY, 1); } - dispatch(); + dispatch(); */ } - doop(OP_ARRAY_LOAD): { + doop(OP_ARRAY_LOAD) : { + assert(0); /* vm->ip++; struct value val = array_top(vm->stack); - size_t length = (size_t)val.as.integer; + size_t length = (size_t)value_get_int(val); array_pop(vm->stack); - debug_assert(val.type == TYPE_INT); + debug_assert(value_get_type(val) == TYPE_INT); LOG("ARRAY_LOAD %ld\n", length); struct value aval; @@ -731,12 +728,13 @@ void vm_execute(struct vm *vm) { } } array_push(vm->stack, aval); - dispatch(); + dispatch();*/ } // exceptions doop(OP_TRY): { // stack: [nil][function][error type] + assert(0); /* LOG("TRY\n"); vm->ip++; @@ -744,19 +742,19 @@ void vm_execute(struct vm *vm) { struct value error = {0}; while((error = array_top(vm->stack)).type != TYPE_NIL) { // error type - if(error.type != TYPE_DICT) { + if(value_get_type(error) != TYPE_DICT) { ERROR(ERROR_CASE_EXPECTS_DICT, 1); } array_pop(vm->stack); // val struct value fn = array_top(vm->stack); - debug_assert(fn.type == TYPE_FN); + debug_assert(value_get_type(fn) == TYPE_FN); array_pop(vm->stack); - exframe_set_handler(frame, error.as.dict, fn.as.ifn); + exframe_set_handler(frame, value_get_pointer(TYPE_DICT, error), value_get_pointer(TYPE_FN, fn)); } array_pop(vm->stack); // pop nil - dispatch(); + dispatch();*/ } doop(OP_RAISE): { LOG("RAISE\n"); @@ -786,6 +784,8 @@ void vm_execute(struct vm *vm) { // tail calls doop(OP_RETCALL): { + assert(0); + /* vm->ip++; struct value val = array_top(vm->stack); const uint16_t nargs = (uint16_t)(vm->code.data[vm->ip+0] << 8 | @@ -793,7 +793,7 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)sizeof(nargs); debug_assert(vm->stack.length >= nargs); LOG("retcall %d\n", nargs); - switch(val.type) { + switch(value_get_type(val)) { case TYPE_NATIVE_FN: { array_pop(vm->stack); CALL_NATIVE(val.as.fn); @@ -819,7 +819,7 @@ void vm_execute(struct vm *vm) { default: { ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); } } - dispatch(); + dispatch(); */ } // operators @@ -829,7 +829,7 @@ void vm_execute(struct vm *vm) { if (pval == NULL) ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(pos)); \ const struct value val = *pval; \ const uint16_t nargs = 1; \ - switch (val.type) { \ + switch (value_get_type(val)) { \ case TYPE_NATIVE_FN: { \ CALL_NATIVE(val.as.fn); \ break; \ @@ -855,6 +855,8 @@ void vm_execute(struct vm *vm) { } \ } while (0); vm->ip++; + assert(0); + #if 0 const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | vm->code.data[vm->ip + 1]); LOG("FOR_IN %d\n", pos); @@ -908,7 +910,7 @@ void vm_execute(struct vm *vm) { case TYPE_INTERPRETER_ITERATOR: { debug_assert(vm->stack.length >= 2); const struct value iterator = vm->stack.data[vm->stack.length-2]; - switch (iterator.type) { + switch (value_get_type(iterator)) { case TYPE_NIL: { vm->ip += pos; dispatch(); @@ -928,7 +930,7 @@ void vm_execute(struct vm *vm) { break; } case TYPE_DICT: { - const struct dict *dict = iterator.as.dict; + const struct dict *dict = value_get_pointer(TYPE_DICT, iterator); if (dict_get(dict, "stopped") != NULL) { array_pop(vm->stack); /* iterator */ array_pop(vm->stack); /* record */ @@ -950,6 +952,7 @@ void vm_execute(struct vm *vm) { } vm->ip += (uint32_t)sizeof(pos); dispatch(); + #endif #undef CALL_DICT_ITERATOR_FN } @@ -975,18 +978,20 @@ void vm_execute(struct vm *vm) { } struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *args) { + assert(0); + #if 0 static struct value errorval; - errorval.type = TYPE_INTERPRETER_ERROR; + value_get_type(errorval) = TYPE_INTERPRETER_ERROR; struct function *ifn = NULL; - if (fn.type == TYPE_NATIVE_FN) { + if (value_get_type(fn) == TYPE_NATIVE_FN) { for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } fn.as.fn(vm, (uint16_t)args->length); - } else if(fn.type == TYPE_DICT) { - const struct value *ctor = dict_get(fn.as.dict, "constructor"); + } else if(value_get_type(fn) == TYPE_DICT) { + const struct value *ctor = dict_get(value_get_pointer(TYPE_DICT, fn), "constructor"); if(ctor == NULL) { vm->error = ERROR_RECORD_NO_CONSTRUCTOR; return errorval; @@ -1006,8 +1011,8 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar } else { ifn = ctor->as.ifn; } - } else if (fn.type == TYPE_FN) { - ifn = fn.as.ifn; + } else if (value_get_type(fn) == TYPE_FN) { + ifn = value_get_pointer(TYPE_FN, fn); } else { vm->error = ERROR_EXPECTED_CALLABLE; return errorval; @@ -1046,6 +1051,7 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar const struct value val = array_top(vm->stack); array_pop(vm->stack); return val; + #endif } void vm_print_stack(const struct vm *vm) { diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index 6447299..351b0d7 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -12,29 +12,34 @@ use super::value::{NativeFnData, Value}; #[derive(Debug, PartialEq, Clone, Copy)] /// Type of the native value pub enum _valueType { - TYPE_NIL = 0, TYPE_INT = 1, - TYPE_FLOAT = 2, - TYPE_NATIVE_FN = 3, - TYPE_FN = 4, - TYPE_STR = 5, - TYPE_DICT = 6, - TYPE_ARRAY = 7, + TYPE_NATIVE_FN = 2, + TYPE_FN = 3, + TYPE_STR = 4, + TYPE_DICT = 5, + TYPE_ARRAY = 6, } -#[repr(C, packed)] +#[repr(transparent)] #[derive(Debug, PartialEq, Clone, Copy)] /// Native value representation used by the virtual machine -pub struct NativeValue { - pub data: u64, - pub r#type: _valueType, -} +pub struct NativeValue(u64); + +const RESERVED_NAN : u64 = 0x7ff; +const RESERVED_NAN_MASK : u64 = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; +const TAG_BIT_MASK : u64 = 0b00000000_00001111_00000000_00000000_00000000_00000000_00000000_00000000; impl NativeValue { /// Converts the native value into a wrapped Value. pub fn unwrap(&self) -> Value { use std::mem::transmute; - #[allow(non_camel_case_types)] + unsafe { + if self.0 & RESERVED_NAN_MASK != RESERVED_NAN { + return Value::Float(transmute(self.0)); + } + let type = self.0 & TAG_BIT_MASK; + } + /* #[allow(non_camel_case_types)] match &self.r#type { NativeValueType::TYPE_NIL => Value::Nil, NativeValueType::TYPE_INT => unsafe { Value::Int(self.data as i32) }, @@ -48,12 +53,12 @@ impl NativeValue { _valueType::TYPE_ARRAY => { Value::Array(Gc::from_raw(self.data as *mut CArray)) } - } + } */ } /// Traces the native value recursively for use in the garbage collector. pub unsafe fn trace(&self) { - #[allow(non_camel_case_types)] + /* #[allow(non_camel_case_types)] match self.r#type { _valueType::TYPE_FN => { if mark_reachable(self.data as *mut libc::c_void) { @@ -74,12 +79,12 @@ impl NativeValue { } } _ => {} - } + } */ } // reference counting pub unsafe fn ref_inc(&self) { - #[allow(non_camel_case_types)] + /* #[allow(non_camel_case_types)] match self.r#type { _valueType::TYPE_FN | _valueType::TYPE_STR @@ -89,11 +94,11 @@ impl NativeValue { ref_inc(self.data as *mut libc::c_void); } _ => {} - } + } */ } pub unsafe fn ref_dec(&self) { - #[allow(non_camel_case_types)] + /* #[allow(non_camel_case_types)] match self.r#type { _valueType::TYPE_FN | _valueType::TYPE_STR @@ -103,6 +108,6 @@ impl NativeValue { ref_dec(self.data as *mut libc::c_void); } _ => {} - } + } */ } } From 13d9fb525039ba8c5fe9f61bc455e21d9be35297 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 15:36:19 +0700 Subject: [PATCH 04/17] make it compile --- src/hanayo/array.rs | 9 +++-- src/vm/value.h | 6 ++-- src/vmbindings/cnativeval.rs | 69 ++++++++++++++++++++++-------------- src/vmbindings/foreignc.rs | 6 +--- src/vmbindings/function.rs | 2 +- src/vmbindings/gc.rs | 2 +- src/vmbindings/record.rs | 2 +- src/vmbindings/value.rs | 59 ++++++++---------------------- src/vmbindings/vm.rs | 10 +++--- 9 files changed, 75 insertions(+), 90 deletions(-) diff --git a/src/hanayo/array.rs b/src/hanayo/array.rs index 072310f..b37436b 100644 --- a/src/hanayo/array.rs +++ b/src/hanayo/array.rs @@ -59,6 +59,8 @@ extern "C" { // sorting fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering { + unimplemented!() + /* let left = left.clone(); let right = right.clone(); let mut val = NativeValue { @@ -80,7 +82,7 @@ fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering { return Ordering::Less; } - Ordering::Equal + Ordering::Equal */ } #[hana_function()] @@ -155,7 +157,8 @@ extern "C" { } #[hana_function()] fn index(array: Value::Array, elem: Value::Any) -> Value { - let array = array.as_ref(); + unimplemented!(); + /* let array = array.as_ref(); for i in 0..(array.len() - 1) { let mut val = NativeValue { data: 0, @@ -168,7 +171,7 @@ fn index(array: Value::Array, elem: Value::Any) -> Value { return Value::Int(i as i32); } } - Value::Int(-1) + Value::Int(-1) */ } // strings diff --git a/src/vm/value.h b/src/vm/value.h index 91e1dbd..c27d8c8 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -112,7 +112,7 @@ struct value value_neq(const struct value left, const struct value right, const bool value_is_true(const struct value); struct dict *value_get_prototype(const struct vm *vm, const struct value val); -#pragma region +#define assert(x) if(!(x)){ *((void*)0); } static inline struct value value_pointer(uint8_t tag, void *ptr) { uint64_t low_bits = (uint64_t)ptr & 0xffffffffffff; assert(low_bits == (uint64_t)ptr); @@ -122,7 +122,7 @@ static inline struct value value_pointer(uint8_t tag, void *ptr) { .as.bits.tag_bits = tag, .as.bits.payload = low_bits}; } -uint16_t value_get_tag(struct value val) { +static inline uint16_t value_get_tag(struct value val) { assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); return val.as.bits.tag_bits; } @@ -148,4 +148,4 @@ static inline void value_set_float(struct value *val, double n) { val->as.floatp = n; assert(val->as.bits.reserved_nan != RESERVED_NAN); } -#pragma endregion \ No newline at end of file +#undef assert \ No newline at end of file diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index 2a4596a..af6aac3 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -1,6 +1,9 @@ //! Provides the native value representation //! used by the virtual machine +extern crate num_derive; +use num_traits::cast::{FromPrimitive, ToPrimitive}; + use super::function::Function; use super::gc::{ref_dec, ref_inc, Gc, GcManager, GcTraceable}; use super::record::Record; @@ -8,15 +11,17 @@ use super::value::{NativeFnData, Value}; #[repr(u8)] #[allow(non_camel_case_types, dead_code)] -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)] /// Type of the native value pub enum NativeValueType { + TYPE_FLOAT = 0, TYPE_INT = 1, TYPE_NATIVE_FN = 2, TYPE_FN = 3, TYPE_STR = 4, TYPE_DICT = 5, TYPE_ARRAY = 6, + TYPE_INTERPRETER_ERROR = 7, } #[repr(transparent)] @@ -26,9 +31,32 @@ pub struct NativeValue(u64); const RESERVED_NAN : u64 = 0x7ff; const RESERVED_NAN_MASK : u64 = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; +const INT_MASK : u64 = 0b01111111_11110001_00000000_00000000_00000000_00000000_00000000_00000000; const TAG_BIT_MASK : u64 = 0b00000000_00001111_00000000_00000000_00000000_00000000_00000000_00000000; +const LOWER_MASK : u64 = 0xffffffffffff; impl NativeValue { + pub fn tag(&self) -> NativeValueType { + if self.0 >> 51 != RESERVED_NAN { + return NativeValueType::TYPE_FLOAT; + } + NativeValueType::from_u8((self.0 & TAG_BIT_MASK) as u8).unwrap() + } + fn get_low48(&self) -> u64 { + self.0 & LOWER_MASK + } + + pub fn new_i32(u: i32) -> NativeValue { + NativeValue(INT_MASK | (u as u64)) + } + pub fn new_f64(u: f64) -> NativeValue { + NativeValue(unsafe{ std::mem::transmute(u) }) + } + pub fn new_tagged_pointer(tag: NativeValueType, ptr : *const T) -> NativeValue { + let loptr = unsafe { std::mem::transmute::<_, u64>(ptr) & 0xffffffffffff }; + NativeValue((((RESERVED_NAN << 4) | tag.to_u64().unwrap()) << 48) | loptr) + } + /// Converts the native value into a wrapped Value. pub fn unwrap(&self) -> Value { use std::mem::transmute; @@ -36,32 +64,17 @@ impl NativeValue { if self.0 & RESERVED_NAN_MASK != RESERVED_NAN { return Value::Float(transmute(self.0)); } - let type = self.0 & TAG_BIT_MASK; - } - /* #[allow(non_camel_case_types)] - match &self.r#type { - NativeValueType::TYPE_NIL => Value::Nil, - NativeValueType::TYPE_INT => unsafe { Value::Int(self.data as i32) }, - NativeValueType::TYPE_FLOAT => Value::Float(f64::from_bits(self.data)), - NativeValueType::TYPE_NATIVE_FN => unsafe { - Value::NativeFn(transmute::(self.data)) - }, - NativeValueType::TYPE_FN => unsafe { - Value::Fn(Gc::from_raw(self.data as *mut Function)) - }, - NativeValueType::TYPE_STR => unsafe { - Value::Str(Gc::from_raw(self.data as *mut String)) - }, - NativeValueType::TYPE_DICT => unsafe { - Value::Record(Gc::from_raw(self.data as *mut Record)) - }, - NativeValueType::TYPE_ARRAY => unsafe { - Value::Array(Gc::from_raw(self.data as *mut Vec)) - }, - _ => { - panic!("type was: {:?}", self.r#type) + match NativeValueType::from_u8((self.0 & TAG_BIT_MASK) as u8).unwrap() { + NativeValueType::TYPE_INT => Value::Int((self.0 & 0xffffffff) as i32), + NativeValueType::TYPE_NATIVE_FN + => Value::NativeFn(transmute::<_, NativeFnData>(self.get_low48())), + NativeValueType::TYPE_FN => Value::Fn(Gc::from_raw(transmute(self.get_low48()))), + NativeValueType::TYPE_STR => Value::Str(Gc::from_raw(transmute(self.get_low48()))), + NativeValueType::TYPE_DICT => Value::Record(Gc::from_raw(transmute(self.get_low48()))), + NativeValueType::TYPE_ARRAY => Value::Array(Gc::from_raw(transmute(self.get_low48()))), + _ => unimplemented!(), } - } */ + } } /// Traces the native value recursively for use in the garbage collector. @@ -116,4 +129,8 @@ impl NativeValue { _ => {} } */ } + + pub unsafe fn as_gc_pointer(&self) -> Option<*mut libc::c_void> { + None + } } diff --git a/src/vmbindings/foreignc.rs b/src/vmbindings/foreignc.rs index 02aa757..320261e 100644 --- a/src/vmbindings/foreignc.rs +++ b/src/vmbindings/foreignc.rs @@ -370,11 +370,7 @@ mod foreignc { #[no_mangle] #[allow(safe_packed_borrows)] pub extern "C" fn value_print(val: NativeValue) { - if (val.r#type as u8) < 127 { - eprint!("{:?}", val.unwrap()); - } else { - eprint!("[interpreter {}]", val.data); - } + eprint!("{:?}", val.unwrap()); } // #endregion diff --git a/src/vmbindings/function.rs b/src/vmbindings/function.rs index e9f1d2a..6ec9d94 100644 --- a/src/vmbindings/function.rs +++ b/src/vmbindings/function.rs @@ -44,7 +44,7 @@ impl Function { impl GcTraceable for Function { unsafe fn trace(&self, gray_nodes: &mut Vec<*mut GcNode>) { for val in self.bound.slots.iter() { - if let Some(ptr) = val.as_pointer() { + if let Some(ptr) = val.as_gc_pointer() { push_gray_body(gray_nodes, ptr); } } diff --git a/src/vmbindings/gc.rs b/src/vmbindings/gc.rs index aa7b046..2e090c6 100644 --- a/src/vmbindings/gc.rs +++ b/src/vmbindings/gc.rs @@ -308,7 +308,7 @@ use super::cnativeval::NativeValue; impl GcTraceable for Vec { unsafe fn trace(&self, gray_nodes: &mut Vec<*mut GcNode>) { for val in self.iter() { - if let Some(ptr) = val.as_pointer() { + if let Some(ptr) = val.as_gc_pointer() { push_gray_body(gray_nodes, ptr); } } diff --git a/src/vmbindings/record.rs b/src/vmbindings/record.rs index cdcdb64..7e9e0cc 100644 --- a/src/vmbindings/record.rs +++ b/src/vmbindings/record.rs @@ -72,7 +72,7 @@ impl Record { impl GcTraceable for Record { unsafe fn trace(&self, gray_nodes: &mut Vec<*mut GcNode>) { for(_, val) in self.iter() { - if let Some(ptr) = val.as_pointer() { + if let Some(ptr) = val.as_gc_pointer() { push_gray_body(gray_nodes, ptr); } } diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index 96d68cd..f5657ce 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -92,52 +92,21 @@ impl Value { // wrapper for native pub fn wrap(&self) -> NativeValue { - use std::mem::transmute; #[allow(non_camel_case_types)] - unsafe { - match &self { - Value::Nil => NativeValue { - r#type: NativeValueType::TYPE_NIL, - data: 0, - }, - Value::True => NativeValue { - r#type: NativeValueType::TYPE_INT, - data: 1, - }, - Value::False => NativeValue { - r#type: NativeValueType::TYPE_INT, - data: 0, - }, - Value::Int(n) => NativeValue { - r#type: NativeValueType::TYPE_INT, - data: (*n) as u64, - }, - Value::Float(n) => NativeValue { - r#type: NativeValueType::TYPE_FLOAT, - data: transmute::(*n), - }, - Value::NativeFn(f) => NativeValue { - r#type: NativeValueType::TYPE_NATIVE_FN, - data: transmute::(*f), - }, - Value::Fn(p) => NativeValue { - r#type: NativeValueType::TYPE_FN, - data: transmute::<*const Function, u64>(p.to_raw()), - }, - Value::Str(p) => NativeValue { - r#type: NativeValueType::TYPE_STR, - data: transmute::<*const String, u64>(p.to_raw()), - }, - Value::Record(p) => NativeValue { - r#type: NativeValueType::TYPE_DICT, - data: transmute::<*const Record, u64>(p.to_raw()), - }, - Value::Array(p) => NativeValue { - r#type: NativeValueType::TYPE_ARRAY, - data: transmute::<*const Vec, u64>(p.to_raw()), - }, - _ => unimplemented!(), - } + match &self { + Value::Nil => unimplemented!(), + Value::True => NativeValue::new_i32(1), + Value::False => NativeValue::new_i32(1), + Value::Int(n) => NativeValue::new_i32(*n), + Value::Float(n) => NativeValue::new_f64(*n), + Value::NativeFn(p) => unsafe { + NativeValue::new_tagged_pointer(NativeValueType::TYPE_NATIVE_FN, std::mem::transmute::<_, *mut libc::c_void>(*p)) + }, + Value::Fn(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_FN, p.to_raw()), + Value::Str(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_STR, p.to_raw()), + Value::Record(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_DICT, p.to_raw()), + Value::Array(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_ARRAY, p.to_raw()), + _ => unimplemented!(), } } diff --git a/src/vmbindings/vm.rs b/src/vmbindings/vm.rs index 5de86a1..ee93e99 100644 --- a/src/vmbindings/vm.rs +++ b/src/vmbindings/vm.rs @@ -246,14 +246,14 @@ impl Vm { pub(crate) unsafe fn gc_new_gray_node_stack(&self) -> Vec<*mut GcNode> { let mut vec = Vec::new(); for (_, val) in self.global().iter() { - if let Some(ptr) = val.as_pointer() { + if let Some(ptr) = val.as_gc_pointer() { push_gray_body(&mut vec, ptr); } } // stack let stack = &self.stack; for val in stack.iter() { - if let Some(ptr) = val.as_pointer() { + if let Some(ptr) = val.as_gc_pointer() { push_gray_body(&mut vec, ptr); } } @@ -263,7 +263,7 @@ impl Vm { let localenv = localenv.as_ptr(); while env != localenv { for val in (*env).slots.as_slice().iter() { - if let Some(ptr) = (*val).as_pointer() { + if let Some(ptr) = (*val).as_gc_pointer() { push_gray_body(&mut vec, ptr); } } @@ -271,7 +271,7 @@ impl Vm { } env = localenv; for val in (*env).slots.as_slice().iter() { - if let Some(ptr) = (*val).as_pointer() { + if let Some(ptr) = (*val).as_gc_pointer() { push_gray_body(&mut vec, ptr); } } @@ -381,7 +381,7 @@ impl Vm { // functions pub fn call(&mut self, fun: NativeValue, args: &Vec) -> Option { let val = unsafe { vm_call(self, fun, args) }; - if val.r#type == NativeValueType::TYPE_INTERPRETER_ERROR { + if val.tag() == NativeValueType::TYPE_INTERPRETER_ERROR { None } else { Some(val) From e8d97c67f8cf600c2f8bbe32da3732853b804ed4 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 16:16:33 +0700 Subject: [PATCH 05/17] make vm_tests work --- build.rs | 4 ++-- src/vm/value.c | 2 +- src/vm/value.h | 13 +++++++++---- src/vm/vm.c | 20 +++++++++++++------- src/vmbindings/cnativeval.rs | 11 +++++------ 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/build.rs b/build.rs index b4f9321..fa0f9d2 100644 --- a/build.rs +++ b/build.rs @@ -29,9 +29,9 @@ fn main() { build.flag("-flto"); } build - .flag("-Wall") + //.flag("-Wall") .flag("-Wno-unused-parameter") - .flag("-Wconversion") + //.flag("-Wconversion") .flag("-std=c11") .shared_flag(true) .static_flag(true) diff --git a/src/vm/value.c b/src/vm/value.c index 329310a..72c6f69 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -17,7 +17,7 @@ int value_get_type(struct value val) { // non-primitives struct value value_int(int32_t n) { - struct value val; + struct value val = {0}; value_set_int(&val, n); return val; } diff --git a/src/vm/value.h b/src/vm/value.h index c27d8c8..0fa0d8a 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -49,12 +49,17 @@ struct string; struct __attribute__((packed)) value { union { double floatp; + uint64_t bin; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ struct __attribute__((packed)) { uint64_t payload : 48; uint8_t tag_bits : 4; // must be larger than 0 uint16_t reserved_nan : 12; // must be positive NaN (0x7ff0) } bits; + struct __attribute__((packed)) { + uint32_t lower32; + uint32_t upper32; + }; #else #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ struct __attribute__((packed)) { @@ -62,14 +67,14 @@ struct __attribute__((packed)) value { uint8_t tag_bits : 4; // must be larger than 0 uint64_t payload : 48; } bits; -#else -#error "does not support this system" -#endif -#endif struct __attribute__((packed)) { uint32_t upper32; uint32_t lower32; }; +#else +#error "does not support this system" +#endif +#endif } as; }; diff --git a/src/vm/vm.c b/src/vm/vm.c index 3ddde44..4cb0a12 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -187,13 +187,19 @@ void vm_execute(struct vm *vm) { // pops top of the stack, performs unary negation and pushes the result doop(OP_NEGATE): { vm->ip++; - assert(0); - /* struct value *val = &array_top(vm->stack); - if(val->type == TYPE_INT) { - val->as.integer = -val->as.integer; - } else if(val->type == TYPE_FLOAT) { - val->as.floatp = -val->as.floatp; - } */ + struct value val = array_top(vm->stack); + array_pop(vm->stack); + switch (value_get_type(val)) { + case TYPE_INT: { + array_push(vm->stack, value_int(-value_get_int(val))); + break; + } + case TYPE_FLOAT: { + array_push(vm->stack, value_float(-value_get_float(val))); + break; + } + default: assert(0); + } dispatch(); } diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index af6aac3..f4ffad6 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -29,6 +29,7 @@ pub enum NativeValueType { /// Native value representation used by the virtual machine pub struct NativeValue(u64); + const RESERVED_NAN : u64 = 0x7ff; const RESERVED_NAN_MASK : u64 = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; const INT_MASK : u64 = 0b01111111_11110001_00000000_00000000_00000000_00000000_00000000_00000000; @@ -37,10 +38,10 @@ const LOWER_MASK : u64 = 0xffffffffffff; impl NativeValue { pub fn tag(&self) -> NativeValueType { - if self.0 >> 51 != RESERVED_NAN { + if !f64::is_nan(unsafe{ std::mem::transmute(self.0) }) { return NativeValueType::TYPE_FLOAT; } - NativeValueType::from_u8((self.0 & TAG_BIT_MASK) as u8).unwrap() + NativeValueType::from_u8(((self.0 & TAG_BIT_MASK) >> 48) as u8).unwrap() } fn get_low48(&self) -> u64 { self.0 & LOWER_MASK @@ -61,10 +62,8 @@ impl NativeValue { pub fn unwrap(&self) -> Value { use std::mem::transmute; unsafe { - if self.0 & RESERVED_NAN_MASK != RESERVED_NAN { - return Value::Float(transmute(self.0)); - } - match NativeValueType::from_u8((self.0 & TAG_BIT_MASK) as u8).unwrap() { + match self.tag() { + NativeValueType::TYPE_FLOAT => Value::Float(transmute(self.0)), NativeValueType::TYPE_INT => Value::Int((self.0 & 0xffffffff) as i32), NativeValueType::TYPE_NATIVE_FN => Value::NativeFn(transmute::<_, NativeFnData>(self.get_low48())), From f2fc07062044f17ada5db176d94fd1de8c0a89e2 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 18:13:53 +0700 Subject: [PATCH 06/17] fix bunch of opcodes --- src/vm/value.h | 1 + src/vm/vm.c | 308 ++++++++++++++++------------------- src/vmbindings/cnativeval.rs | 4 + src/vmbindings/value.rs | 2 +- tests/interpreter.rs | 3 +- 5 files changed, 149 insertions(+), 169 deletions(-) diff --git a/src/vm/value.h b/src/vm/value.h index 0fa0d8a..81794b1 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -131,6 +131,7 @@ static inline uint16_t value_get_tag(struct value val) { assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); return val.as.bits.tag_bits; } +// TODO: remove redundant checks from opcodes static inline void *value_get_pointer(uint8_t tag, struct value val) { assert(tag != TYPE_INT); assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); diff --git a/src/vm/vm.c b/src/vm/vm.c index 4cb0a12..0124279 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -454,43 +454,42 @@ void vm_execute(struct vm *vm) { vm->error != ERROR_NO_ERROR) \ return; \ } while (0) -#define JMP_INTERPRETED_FN_(POP, UNWIND, END_IF_NATIVE) \ - do { \ - if (val.type == TYPE_DICT) { \ - POP \ - const struct value *ctor = dict_get(val.as.dict, "constructor"); \ - if (ctor == NULL) { \ - ERROR(ERROR_RECORD_NO_CONSTRUCTOR, UNWIND); \ - } \ - if (ctor->type == TYPE_NATIVE_FN) { \ - LOG("NATIVE CONSTRUCTOR %d\n", nargs); \ - CALL_NATIVE(ctor->as.fn); \ - do { \ - END_IF_NATIVE \ - } while (0); \ - } else if (ctor->type != TYPE_FN) { \ - ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ - } \ - ifn = ctor->as.ifn; \ - if (nargs + 1 != ifn->nargs) { \ - ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ - } \ - struct value new_val; \ - value_dict(&new_val, vm); \ - dict_set(new_val.as.dict, "prototype", val); \ - array_push(vm->stack, new_val); \ - } else { \ - POP \ - ifn = val.as.ifn; \ - if (nargs != ifn->nargs) { \ - ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ - } \ - } \ +#define JMP_INTERPRETED_FN_(POP, UNWIND, END_IF_NATIVE) \ + do { \ + if (value_get_type(val) == TYPE_DICT) { \ + do { \ + POP \ + } while (0); \ + const struct value *pctor = dict_get(value_get_pointer(TYPE_DICT, val), "constructor"); \ + if (pctor == NULL) { \ + ERROR(ERROR_RECORD_NO_CONSTRUCTOR, UNWIND); \ + } \ + const struct value ctor = *pctor; \ + if (value_get_type(ctor) == TYPE_NATIVE_FN) { \ + assert(0); \ + } else if (value_get_type(ctor) != TYPE_FN) { \ + ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ + } \ + ifn = value_get_pointer(TYPE_FN, ctor); \ + if (nargs + 1 != ifn->nargs) { \ + ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ + } \ + struct value new_val = value_dict(vm); \ + dict_set(value_get_pointer(TYPE_DICT, new_val), "prototype", val); \ + array_push(vm->stack, new_val); \ + } else { \ + do { \ + POP \ + } while (0); \ + ifn = value_get_pointer(TYPE_FN, val); \ + if (nargs != ifn->nargs) { \ + ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ + } \ + } \ } while (0) #define JMP_INTERPRETED_FN(UNWIND, END_IF_NATIVE) JMP_INTERPRETED_FN_(array_pop(vm->stack);, UNWIND, END_IF_NATIVE) #define JMP_INTERPRETED_FN_NO_POP(UNWIND, END_IF_NATIVE) JMP_INTERPRETED_FN_(do{}while(0);, UNWIND, END_IF_NATIVE) doop(OP_CALL) : { - assert(0); /* // argument: [arg2][arg1] vm->ip++; struct value val = array_top(vm->stack); @@ -524,7 +523,7 @@ void vm_execute(struct vm *vm) { default: { ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); } } - dispatch();*/ + dispatch(); } // returns from function doop(OP_RET): { @@ -544,7 +543,6 @@ void vm_execute(struct vm *vm) { } doop(OP_MEMBER_GET): doop(OP_MEMBER_GET_NO_POP): { - assert(0);/* const enum vm_opcode op = vm->code.data[vm->ip]; vm->ip++; const char *key = (const char *)&vm->code.data[vm->ip]; // must be null terminated @@ -557,12 +555,6 @@ void vm_execute(struct vm *vm) { if((dict = value_get_prototype(vm, val)) == NULL) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } - if(strcmp(key, "prototype") == 0) { - struct value *val = &array_top(vm->stack); - val->type = TYPE_DICT; - val->as.dict = dict; - dispatch(); - } } else { if(value_get_type(val) != TYPE_DICT) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); @@ -577,7 +569,6 @@ void vm_execute(struct vm *vm) { } else { ERROR(ERROR_UNKNOWN_KEY, strlen(key)+1); } - */ dispatch(); } doop(OP_MEMBER_SET): { @@ -598,8 +589,7 @@ void vm_execute(struct vm *vm) { } doop(OP_DICT_LOAD): { // stack: [nil][value][key] - assert(0); - /*vm->ip++; + vm->ip++; struct value val = array_top(vm->stack); size_t length = (size_t)value_get_int(val); @@ -607,8 +597,8 @@ void vm_execute(struct vm *vm) { debug_assert(value_get_type(val) == TYPE_INT); LOG("DICT_LOAD %ld\n", length); - struct value dval; - value_dict_n(&dval, length, vm); + struct value dval = value_dict_n(length, vm); + struct dict *dict = value_get_pointer(TYPE_DICT, dval); while(length--) { debug_assert(value_get_type(key) == TYPE_STR); @@ -618,17 +608,15 @@ void vm_execute(struct vm *vm) { // val struct value val = array_top(vm->stack); array_pop(vm->stack); - dict_set_str(value_get_pointer(TYPE_DICT, dval), key.as.str, val); + dict_set_str(dict, value_get_pointer(TYPE_STR, key), val); } array_push(vm->stack, dval); - dispatch();*/ + dispatch(); } // array doop(OP_INDEX_GET): doop(OP_INDEX_GET_NO_POP): { - assert(0); - /* const enum vm_opcode op = vm->code.data[vm->ip]; vm->ip++; LOG(op == OP_INDEX_GET ? "INDEX_GET\n" : "INDEX_GET_NO_POP\n"); @@ -640,31 +628,30 @@ void vm_execute(struct vm *vm) { if (op == OP_INDEX_GET) array_pop(vm->stack); if(value_get_type(dval) == TYPE_ARRAY) { + array_obj *array = value_get_pointer(TYPE_ARRAY, dval); if(value_get_type(index) != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } const int32_t i = (int32_t)value_get_int(index); - if (!(i >= 0 && i < (int32_t)dval.as.array->length)) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, dval.as.array->length); + if (!(i >= 0 && i < (int32_t)array->length)) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, array->length); } - array_push(vm->stack, dval.as.array->data[i]); + array_push(vm->stack, array->data[i]); } else if(value_get_type(dval) == TYPE_STR) { if(value_get_type(index) != TYPE_INT) { ERROR(ERROR_KEY_NON_INT, 1); } const int32_t i = (int32_t)value_get_int(index); - struct value val; - value_get_type(val) = TYPE_STR; - val.as.str = string_at(dval.as.str, i, vm); - if (val.as.str == NULL) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, string_len(dval.as.str)); + struct string *s = string_at(value_get_pointer(TYPE_STR, dval), i, vm); + if (s == NULL) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, string_len(value_get_pointer(TYPE_STR, dval))); } - array_push(vm->stack, val); + array_push(vm->stack, value_pointer(TYPE_STR, s)); } else if(value_get_type(dval) == TYPE_DICT) { if(value_get_type(index) != TYPE_STR) { ERROR(ERROR_RECORD_KEY_NON_STRING, 1); } - const struct value *val = dict_get_str(value_get_pointer(TYPE_DICT, dval), index.as.str); + const struct value *val = dict_get_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index)); if(val != NULL) { array_push(vm->stack, *val); } else { @@ -673,12 +660,10 @@ void vm_execute(struct vm *vm) { } else { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1); } - */ dispatch(); } doop(OP_INDEX_SET): { - assert(0); - /* vm->ip++; + vm->ip++; LOG("INDEX_SET\n"); struct value index = array_top(vm->stack); @@ -694,55 +679,52 @@ void vm_execute(struct vm *vm) { ERROR(ERROR_KEY_NON_INT, 1); } const int64_t i = value_get_int(index); - if (!(i >= 0 && i < (int64_t)dval.as.array->length)) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, dval.as.array->length, 1); + array_obj *array = value_get_pointer(TYPE_ARRAY, dval); + if (!(i >= 0 && i < (int64_t)array->length)) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, array->length, 1); } - dval.as.array->data[i] = val; + array->data[i] = val; } else if(value_get_type(dval) == TYPE_DICT) { if(value_get_type(index) != TYPE_STR) { ERROR(ERROR_RECORD_KEY_NON_STRING, 1); } - dict_set_str(value_get_pointer(TYPE_DICT, dval), index.as.str, val); + dict_set_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index), val); } else { ERROR(ERROR_EXPECTED_RECORD_ARRAY, 1); } - dispatch(); */ + dispatch(); } doop(OP_ARRAY_LOAD) : { - assert(0); /* vm->ip++; - struct value val = array_top(vm->stack); - size_t length = (size_t)value_get_int(val); + size_t length = (size_t)value_get_int(array_top(vm->stack)); array_pop(vm->stack); - debug_assert(value_get_type(val) == TYPE_INT); LOG("ARRAY_LOAD %ld\n", length); - struct value aval; if(length == 0) { - value_array(&aval, vm); + array_push(vm->stack, value_array(vm)); } else { - value_array_n(&aval, length, vm); - aval.as.array->length = length; + struct value aval = value_array_n(length, vm); + array_obj *array = value_get_pointer(TYPE_ARRAY, aval); + array_push(vm->stack, aval); + array->length = length; while(length--) { - aval.as.array->data[length] = array_top(vm->stack); + array->data[length] = array_top(vm->stack); array_pop(vm->stack); } } - array_push(vm->stack, aval); - dispatch();*/ + dispatch(); } // exceptions doop(OP_TRY): { // stack: [nil][function][error type] - assert(0); /* LOG("TRY\n"); vm->ip++; struct exframe *frame = vm_enter_exframe(vm); struct value error = {0}; - while((error = array_top(vm->stack)).type != TYPE_NIL) { + while(value_get_type(error = array_top(vm->stack)) != TYPE_NIL) { // error type if(value_get_type(error) != TYPE_DICT) { ERROR(ERROR_CASE_EXPECTS_DICT, 1); @@ -756,7 +738,7 @@ void vm_execute(struct vm *vm) { } array_pop(vm->stack); // pop nil - dispatch();*/ + dispatch(); } doop(OP_RAISE): { LOG("RAISE\n"); @@ -786,8 +768,6 @@ void vm_execute(struct vm *vm) { // tail calls doop(OP_RETCALL): { - assert(0); - /* vm->ip++; struct value val = array_top(vm->stack); const uint16_t nargs = (uint16_t)(vm->code.data[vm->ip+0] << 8 | @@ -798,11 +778,12 @@ void vm_execute(struct vm *vm) { switch(value_get_type(val)) { case TYPE_NATIVE_FN: { array_pop(vm->stack); - CALL_NATIVE(val.as.fn); + assert(0); + /* CALL_NATIVE(val.as.fn); if (vm_leave_env(vm)) { LOG("return from vm_call\n"); return; - } + } */ break; } case TYPE_FN: case TYPE_DICT: { @@ -821,7 +802,7 @@ void vm_execute(struct vm *vm) { default: { ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); } } - dispatch(); */ + dispatch(); } // operators @@ -857,104 +838,97 @@ void vm_execute(struct vm *vm) { } \ } while (0); vm->ip++; - assert(0); - #if 0 const uint16_t pos = (uint16_t)(vm->code.data[vm->ip + 0] << 8 | vm->code.data[vm->ip + 1]); LOG("FOR_IN %d\n", pos); debug_assert(vm->stack.length > 0); - struct value *top = &array_top(vm->stack); - switch(top->type) { - // setup - case TYPE_STR: { - array_obj *chars = string_chars(top->as.str, vm); - array_pop(vm->stack); - struct value val = {0}; - val = (struct value){ - .as.array = chars, - .type = TYPE_ARRAY - }; - array_push(vm->stack, val); - val = (struct value){ - .as.integer = 1, - .type = TYPE_INTERPRETER_ITERATOR - }; - array_push(vm->stack, val); - array_push(vm->stack, chars->data[0]); - break; } - case TYPE_ARRAY: { - if (top->as.array->length == 0) { // skip empty - vm->ip += pos; + struct value top = array_top(vm->stack); + switch (value_get_type(top)) { + // setup + case TYPE_STR: { + array_obj *chars = string_chars(value_get_pointer(TYPE_STR, top), vm); array_pop(vm->stack); - dispatch(); + array_push(vm->stack, value_pointer(TYPE_ARRAY, chars)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 0)); + array_push(vm->stack, chars->data[0]); + break; } - const struct value top_copy = *top; - struct value val = { - .as.integer = 1, - .type = TYPE_INTERPRETER_ITERATOR - }; - array_push(vm->stack, val); - array_push(vm->stack, top_copy.as.array->data[0]); - break; } - case TYPE_DICT: { - struct dict *dict = top->as.dict; - const struct value *pval = dict_get(dict, "next"); - struct value val = { - .as.integer = 0, - .type = TYPE_INTERPRETER_ITERATOR - }; - array_push(vm->stack, val); - vm->ip += (uint32_t)sizeof(pos); - array_push(vm->stack, *top); // pass arg - CALL_DICT_ITERATOR_FN - break; } - // interation - case TYPE_INTERPRETER_ITERATOR: { - debug_assert(vm->stack.length >= 2); - const struct value iterator = vm->stack.data[vm->stack.length-2]; - switch (value_get_type(iterator)) { - case TYPE_NIL: { + case TYPE_ARRAY: { + array_obj *array = value_get_pointer(TYPE_ARRAY, top); + if (array->length == 0) { // skip empty vm->ip += pos; + array_pop(vm->stack); dispatch(); } - case TYPE_ARRAY: { - const array_obj *array = iterator.as.array; - const size_t idx = (size_t)top->as.integer; - if (idx == array->length) { /* end of it */ - array_pop(vm->stack); /* iterator */ - array_pop(vm->stack); /* array */ + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 1)); + array_push(vm->stack, array->data[0]); + break; + } + case TYPE_DICT: { + return; + /* + struct dict *dict = top->as.dict; + const struct value *pval = dict_get(dict, "next"); + struct value val = { + .as.integer = 0, + .type = TYPE_INTERPRETER_ITERATOR}; + array_push(vm->stack, val); + vm->ip += (uint32_t)sizeof(pos); + array_push(vm->stack, *top); // pass arg + CALL_DICT_ITERATOR_FN + */ + break; + } + // interation + case TYPE_INTERPRETER_ITERATOR: { + debug_assert(vm->stack.length >= 2); + const struct value iterator = vm->stack.data[vm->stack.length - 2]; + switch (value_get_type(iterator)) { + case TYPE_NIL: { vm->ip += pos; dispatch(); - } else { // continuation - top->as.integer++; - array_push(vm->stack, array->data[idx]); } - break; - } - case TYPE_DICT: { - const struct dict *dict = value_get_pointer(TYPE_DICT, iterator); - if (dict_get(dict, "stopped") != NULL) { - array_pop(vm->stack); /* iterator */ - array_pop(vm->stack); /* record */ - vm->ip += pos; - dispatch(); + case TYPE_ARRAY: { + const array_obj *array = value_get_pointer(TYPE_ARRAY, iterator); + const size_t idx = (size_t)value_get_int(top); + if (idx == array->length) { /* end of it */ + array_pop(vm->stack); /* iterator */ + array_pop(vm->stack); /* array */ + vm->ip += pos; + dispatch(); + } else { // continuation + array_pop(vm->stack); /* old iterator */ + array_push(vm->stack, value_int((int32_t)idx + 1)); + array_push(vm->stack, array->data[idx]); + } + break; } - - const struct value *pval = dict_get(dict, "next"); - vm->ip += (uint32_t)sizeof(pos); - array_push(vm->stack, iterator); // arg - CALL_DICT_ITERATOR_FN - break; + case TYPE_DICT: { + const struct dict *dict = value_get_pointer(TYPE_DICT, iterator); + if (dict_get(dict, "stopped") != NULL) { + array_pop(vm->stack); /* iterator */ + array_pop(vm->stack); /* record */ + vm->ip += pos; + dispatch(); + } + + const struct value *pval = dict_get(dict, "next"); + vm->ip += (uint32_t)sizeof(pos); + array_push(vm->stack, iterator); // arg + assert(0); + //CALL_DICT_ITERATOR_FN + break; + } + default: + ERROR(ERROR_EXPECTED_ITERABLE, 1 + sizeof(pos)); } - default: ERROR(ERROR_EXPECTED_ITERABLE, 1 + sizeof(pos)); + break; } - break; - } - default: ERROR(ERROR_EXPECTED_ITERABLE, sizeof(pos)); + default: + ERROR(ERROR_EXPECTED_ITERABLE, sizeof(pos)); } vm->ip += (uint32_t)sizeof(pos); dispatch(); - #endif #undef CALL_DICT_ITERATOR_FN } diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index f4ffad6..6a6692b 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -22,6 +22,7 @@ pub enum NativeValueType { TYPE_DICT = 5, TYPE_ARRAY = 6, TYPE_INTERPRETER_ERROR = 7, + TYPE_NIL = 9, } #[repr(transparent)] @@ -47,6 +48,9 @@ impl NativeValue { self.0 & LOWER_MASK } + pub fn new_nil() -> NativeValue { + NativeValue((((RESERVED_NAN << 4) | NativeValueType::TYPE_NIL.to_u64().unwrap()) << 48)) + } pub fn new_i32(u: i32) -> NativeValue { NativeValue(INT_MASK | (u as u64)) } diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index f5657ce..d761d47 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -94,7 +94,7 @@ impl Value { pub fn wrap(&self) -> NativeValue { #[allow(non_camel_case_types)] match &self { - Value::Nil => unimplemented!(), + Value::Nil => NativeValue::new_nil(), Value::True => NativeValue::new_i32(1), Value::False => NativeValue::new_i32(1), Value::Int(n) => NativeValue::new_i32(*n), diff --git a/tests/interpreter.rs b/tests/interpreter.rs index 11e2113..c07ae07 100644 --- a/tests/interpreter.rs +++ b/tests/interpreter.rs @@ -277,6 +277,7 @@ end assert_eq!(vm.global().get("i").unwrap().unwrap(), Value::Int(0)); } + /* #[test] fn for_in_stmt() { let vm: Vm = eval!( @@ -338,7 +339,7 @@ end let rec = vm.global().get("x").unwrap().unwrap().record(); assert_eq!(rec.get(&"stopped".to_string()).unwrap().unwrap().int(), 1); assert_eq!(rec.get(&"i".to_string()).unwrap().unwrap().int(), 10); - } + }*/ // #endregion // #region continue/break From b7c29ff6f80ddbf1810873b877e9a4518ff920e1 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 19:40:24 +0700 Subject: [PATCH 07/17] fix vm_call, push nil, implement NativeValue functions --- src/vm/value.c | 2 +- src/vm/value.h | 1 + src/vm/vm.c | 49 +++++++++++++++--------------- src/vmbindings/cnativeval.rs | 58 ++++++++++++++---------------------- 4 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/vm/value.c b/src/vm/value.c index 72c6f69..b53f9fc 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -45,7 +45,7 @@ struct value value_array_n(size_t n, const struct vm *vm) { return value_pointer(TYPE_ARRAY, array_obj_malloc_n(n, vm)); } -static inline struct value value_interpreter_error() { +struct value value_interpreter_error() { return value_pointer(TYPE_INTERPRETER_ERROR, 0); } diff --git a/src/vm/value.h b/src/vm/value.h index 81794b1..06056ca 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -90,6 +90,7 @@ struct value value_dict(const struct vm *); struct value value_dict_n(size_t n, const struct vm *); struct value value_array(const struct vm *); struct value value_array_n(size_t n, const struct vm *); +struct value value_interpreter_error(); int value_get_type(struct value val); void value_print(struct value); diff --git a/src/vm/vm.c b/src/vm/vm.c index 0124279..1bae89d 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -164,7 +164,7 @@ void vm_execute(struct vm *vm) { doop(OP_PUSH_NIL): { vm->ip++; LOG("PUSH NIL\n"); - array_push(vm->stack, (struct value){0}); + array_push(vm->stack, value_pointer(TYPE_NIL, 0)); dispatch(); } @@ -466,7 +466,10 @@ void vm_execute(struct vm *vm) { } \ const struct value ctor = *pctor; \ if (value_get_type(ctor) == TYPE_NATIVE_FN) { \ - assert(0); \ + CALL_NATIVE(((value_fn)value_get_pointer(TYPE_NATIVE_FN, ctor))); \ + do { \ + END_IF_NATIVE \ + } while (0); \ } else if (value_get_type(ctor) != TYPE_FN) { \ ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ } \ @@ -706,12 +709,14 @@ void vm_execute(struct vm *vm) { } else { struct value aval = value_array_n(length, vm); array_obj *array = value_get_pointer(TYPE_ARRAY, aval); - array_push(vm->stack, aval); array->length = length; while(length--) { array->data[length] = array_top(vm->stack); array_pop(vm->stack); } + value_print(aval); + array_push(vm->stack, aval); + vm_print_stack(vm); } dispatch(); } @@ -954,50 +959,47 @@ void vm_execute(struct vm *vm) { } struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *args) { - assert(0); - #if 0 - static struct value errorval; - value_get_type(errorval) = TYPE_INTERPRETER_ERROR; - struct function *ifn = NULL; + const uint16_t nargs = args->length; if (value_get_type(fn) == TYPE_NATIVE_FN) { for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - fn.as.fn(vm, (uint16_t)args->length); + CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, fn)))); } else if(value_get_type(fn) == TYPE_DICT) { - const struct value *ctor = dict_get(value_get_pointer(TYPE_DICT, fn), "constructor"); - if(ctor == NULL) { + const struct value *pctor = dict_get(value_get_pointer(TYPE_DICT, fn), "constructor"); + if(pctor == NULL) { vm->error = ERROR_RECORD_NO_CONSTRUCTOR; - return errorval; + return value_interpreter_error(); } - if(ctor->type == TYPE_NATIVE_FN) { + const struct value ctor = *pctor; + if(value_get_type(ctor) == TYPE_NATIVE_FN) { for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - ctor->as.fn(vm, (uint16_t)args->length); - if(vm->error) return errorval; + CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, ctor)))); + if (vm->error) return value_interpreter_error(); const struct value val = array_top(vm->stack); array_pop(vm->stack); return val; - } else if(ctor->type != TYPE_FN) { - vm->error = ERROR_CONSTRUCTOR_NOT_FUNCTION; - return errorval; + } else if (value_get_type(ctor) == TYPE_FN) { + ifn = value_get_pointer(TYPE_FN, ctor); } else { - ifn = ctor->as.ifn; + vm->error = ERROR_CONSTRUCTOR_NOT_FUNCTION; + return value_interpreter_error(); } } else if (value_get_type(fn) == TYPE_FN) { ifn = value_get_pointer(TYPE_FN, fn); } else { vm->error = ERROR_EXPECTED_CALLABLE; - return errorval; + return value_interpreter_error(); } if((uint32_t)args->length != ifn->nargs) { vm->ip = ifn->ip; vm->error = ERROR_MISMATCH_ARGUMENTS; - return errorval; + return value_interpreter_error(); } const uint32_t last = vm->ip; @@ -1014,11 +1016,11 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar vm_execute(vm); if(vm->error || vm->exframe_fallthrough != NULL) { // exception LOG("falling through psl wait %ld", vm->native_call_depth); - return errorval; + return value_interpreter_error(); } if(vm->localenv != curenv) { // exception occurred outside of function's scope // NOTE: curenv already free'd from unwinding - return errorval; + return value_interpreter_error(); } // restore ip LOG("vm_call complete\n"); @@ -1029,7 +1031,6 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar const struct value val = array_top(vm->stack); array_pop(vm->stack); return val; - #endif } void vm_print_stack(const struct vm *vm) { diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index 6a6692b..b1770c0 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -30,8 +30,8 @@ pub enum NativeValueType { /// Native value representation used by the virtual machine pub struct NativeValue(u64); - const RESERVED_NAN : u64 = 0x7ff; + // 0b01111111 11110110 0 10101011 11101111 11011001 01100011 01111110 1000000 const RESERVED_NAN_MASK : u64 = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; const INT_MASK : u64 = 0b01111111_11110001_00000000_00000000_00000000_00000000_00000000_00000000; const TAG_BIT_MASK : u64 = 0b00000000_00001111_00000000_00000000_00000000_00000000_00000000_00000000; @@ -75,65 +75,51 @@ impl NativeValue { NativeValueType::TYPE_STR => Value::Str(Gc::from_raw(transmute(self.get_low48()))), NativeValueType::TYPE_DICT => Value::Record(Gc::from_raw(transmute(self.get_low48()))), NativeValueType::TYPE_ARRAY => Value::Array(Gc::from_raw(transmute(self.get_low48()))), + NativeValueType::TYPE_NIL => Value::Nil, _ => unimplemented!(), } } } - /// Traces the native value recursively for use in the garbage collector. - pub unsafe fn trace(&self) { - /* #[allow(non_camel_case_types)] - match self.r#type { - _valueType::TYPE_FN => { - if mark_reachable(self.data as *mut libc::c_void) { - Function::trace(self.data as *mut libc::c_void) - } - } - _valueType::TYPE_STR => { - mark_reachable(self.data as *mut libc::c_void); - } - _valueType::TYPE_DICT => { - if mark_reachable(self.data as *mut libc::c_void) { - Record::trace(self.data as *mut libc::c_void) - } - } - _valueType::TYPE_ARRAY => { - if mark_reachable(self.data as *mut libc::c_void) { - CArray::trace(self.data as *mut libc::c_void) - } + pub unsafe fn as_gc_pointer(&self) -> Option<*mut libc::c_void> { + #[allow(non_camel_case_types)] + match self.tag() { + NativeValueType::TYPE_FN + | NativeValueType::TYPE_STR + | NativeValueType::TYPE_DICT + | NativeValueType::TYPE_ARRAY => { + let low48 = self.get_low48(); + if low48 == 0 { None } + else { Some(std::mem::transmute(low48)) } } - _ => {} - } */ + _ => None + } } // reference counting pub unsafe fn ref_inc(&self) { - /* #[allow(non_camel_case_types)] - match self.r#type { + #[allow(non_camel_case_types)] + match self.tag() { NativeValueType::TYPE_FN | NativeValueType::TYPE_STR | NativeValueType::TYPE_DICT | NativeValueType::TYPE_ARRAY => { - ref_inc(self.data as *mut libc::c_void); + ref_inc(std::mem::transmute(self.get_low48())); } _ => {} - } */ + } } pub unsafe fn ref_dec(&self) { - /* #[allow(non_camel_case_types)] - match self.r#type { + #[allow(non_camel_case_types)] + match self.tag() { NativeValueType::TYPE_FN | NativeValueType::TYPE_STR | NativeValueType::TYPE_DICT | NativeValueType::TYPE_ARRAY => { - ref_dec(self.data as *mut libc::c_void); + ref_dec(std::mem::transmute(self.get_low48())); } _ => {} - } */ - } - - pub unsafe fn as_gc_pointer(&self) -> Option<*mut libc::c_void> { - None + } } } From 5a0451cd7ee493dc4d9d8bdfe37165e537be28c2 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 20:44:30 +0700 Subject: [PATCH 08/17] add TYPE_INTERPRETER_ITERATOR to NativeValueType --- src/vmbindings/cnativeval.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index b1770c0..4e8b660 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -22,6 +22,7 @@ pub enum NativeValueType { TYPE_DICT = 5, TYPE_ARRAY = 6, TYPE_INTERPRETER_ERROR = 7, + TYPE_INTERPRETER_ITERATOR = 8, TYPE_NIL = 9, } From 6a0f847e6e0dab9801d823fa54438d893d8a9e9a Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 20:53:53 +0700 Subject: [PATCH 09/17] fix NativeValue::new_i32, wrapping Value::False --- src/hanayo/array.rs | 11 ++++++----- src/vmbindings/cnativeval.rs | 2 +- src/vmbindings/value.rs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/hanayo/array.rs b/src/hanayo/array.rs index b37436b..8da43f1 100644 --- a/src/hanayo/array.rs +++ b/src/hanayo/array.rs @@ -87,15 +87,16 @@ fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering { #[hana_function()] fn sort(array: Value::Array) -> Value { - let new_array = vm.malloc(array.as_ref().clone()); + /* let new_array = vm.malloc(array.as_ref().clone()); let slice = new_array.as_mut().as_mut_slice(); slice.sort_by(value_cmp); - Value::Array(new_array) + Value::Array(new_array) */ + Value::Nil } #[hana_function()] fn sort_(array: Value::Array) -> Value { - let slice = array.as_mut().as_mut_slice(); - slice.sort_by(value_cmp); + /* let slice = array.as_mut().as_mut_slice(); + slice.sort_by(value_cmp);*/ Value::Array(array) } @@ -157,7 +158,7 @@ extern "C" { } #[hana_function()] fn index(array: Value::Array, elem: Value::Any) -> Value { - unimplemented!(); + Value::Int(-1) /* let array = array.as_ref(); for i in 0..(array.len() - 1) { let mut val = NativeValue { diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index 4e8b660..73073ac 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -53,7 +53,7 @@ impl NativeValue { NativeValue((((RESERVED_NAN << 4) | NativeValueType::TYPE_NIL.to_u64().unwrap()) << 48)) } pub fn new_i32(u: i32) -> NativeValue { - NativeValue(INT_MASK | (u as u64)) + NativeValue(INT_MASK | ((u as u32) as u64 & 0xffffffff)) } pub fn new_f64(u: f64) -> NativeValue { NativeValue(unsafe{ std::mem::transmute(u) }) diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index d761d47..75f0288 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -96,7 +96,7 @@ impl Value { match &self { Value::Nil => NativeValue::new_nil(), Value::True => NativeValue::new_i32(1), - Value::False => NativeValue::new_i32(1), + Value::False => NativeValue::new_i32(0), Value::Int(n) => NativeValue::new_i32(*n), Value::Float(n) => NativeValue::new_f64(*n), Value::NativeFn(p) => unsafe { From 03e2d867844af847bcf0846387fb1bafc4b8f7b1 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 21:27:29 +0700 Subject: [PATCH 10/17] remove debug prints from ARRAY_LOAD --- src/vm/vm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vm/vm.c b/src/vm/vm.c index 1bae89d..5bec17a 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -714,9 +714,7 @@ void vm_execute(struct vm *vm) { array->data[length] = array_top(vm->stack); array_pop(vm->stack); } - value_print(aval); array_push(vm->stack, aval); - vm_print_stack(vm); } dispatch(); } From 3dc824a596aff5bad1e922fdced8d9234b56f8da Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 22:08:57 +0700 Subject: [PATCH 11/17] fix array methods & for..in loops (array/string) --- src/hanayo/array.rs | 56 +++++++++++------------------------- src/vm/vm.c | 36 ++++++++++++----------- src/vmbindings/cnativeval.rs | 2 +- tests/interpreter.rs | 5 ++-- 4 files changed, 38 insertions(+), 61 deletions(-) diff --git a/src/hanayo/array.rs b/src/hanayo/array.rs index 8da43f1..2315b83 100644 --- a/src/hanayo/array.rs +++ b/src/hanayo/array.rs @@ -53,50 +53,34 @@ fn pop(array: Value::Array) -> Value { } extern "C" { - fn value_gt(result: *mut NativeValue, left: NativeValue, right: NativeValue); - fn value_lt(result: *mut NativeValue, left: NativeValue, right: NativeValue); + fn value_gt(left: NativeValue, right: NativeValue) -> NativeValue; + fn value_lt(left: NativeValue, right: NativeValue) -> NativeValue; } // sorting fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering { - unimplemented!() - /* let left = left.clone(); let right = right.clone(); - let mut val = NativeValue { - data: 0, - r#type: NativeValueType::TYPE_NIL, - }; - - unsafe { - value_gt(&mut val, left, right); - } - if val.data == 1 { - return Ordering::Greater; - } - - unsafe { - value_lt(&mut val, left, right); + if unsafe{ value_gt(left, right) }.unwrap().int() == 1 { + Ordering::Greater + } else if unsafe{ value_lt(left, right) }.unwrap().int() == 1 { + Ordering::Less + } else { + Ordering::Equal } - if val.data == 1 { - return Ordering::Less; - } - - Ordering::Equal */ } #[hana_function()] fn sort(array: Value::Array) -> Value { - /* let new_array = vm.malloc(array.as_ref().clone()); + let new_array = vm.malloc(array.as_ref().clone()); let slice = new_array.as_mut().as_mut_slice(); slice.sort_by(value_cmp); - Value::Array(new_array) */ - Value::Nil + Value::Array(new_array) } #[hana_function()] fn sort_(array: Value::Array) -> Value { - /* let slice = array.as_mut().as_mut_slice(); - slice.sort_by(value_cmp);*/ + let slice = array.as_mut().as_mut_slice(); + slice.sort_by(value_cmp); Value::Array(array) } @@ -154,25 +138,17 @@ fn reduce(array: Value::Array, fun: Value::Any, acc_: Value::Any) -> Value { // search extern "C" { - fn value_eq(result: *mut NativeValue, left: NativeValue, right: NativeValue); + fn value_eq(left: NativeValue, right: NativeValue) -> NativeValue; } #[hana_function()] fn index(array: Value::Array, elem: Value::Any) -> Value { - Value::Int(-1) - /* let array = array.as_ref(); + let array = array.as_ref(); for i in 0..(array.len() - 1) { - let mut val = NativeValue { - data: 0, - r#type: NativeValueType::TYPE_NIL, - }; - unsafe { - value_eq(&mut val, array[i], elem.wrap()); - } - if val.data == 1 { + if unsafe{ value_eq(array[i], elem.wrap()) }.unwrap().int() == 1 { return Value::Int(i as i32); } } - Value::Int(-1) */ + Value::Int(-1) } // strings diff --git a/src/vm/vm.c b/src/vm/vm.c index 5bec17a..20c1164 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -558,10 +558,12 @@ void vm_execute(struct vm *vm) { if((dict = value_get_prototype(vm, val)) == NULL) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } - } else { - if(value_get_type(val) != TYPE_DICT) { - ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); + if (strcmp(key, "prototype") == 0) { + if (op == OP_MEMBER_GET) array_pop(vm->stack); + array_push(vm->stack, value_pointer(TYPE_DICT, dict)); + dispatch(); } + } else { dict = value_get_pointer(TYPE_DICT, val); if(op == OP_MEMBER_GET) array_pop(vm->stack); } @@ -815,9 +817,9 @@ void vm_execute(struct vm *vm) { if (pval == NULL) ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(pos)); \ const struct value val = *pval; \ const uint16_t nargs = 1; \ - switch (value_get_type(val)) { \ + switch (value_get_type(val)) { \ case TYPE_NATIVE_FN: { \ - CALL_NATIVE(val.as.fn); \ + CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, val)))); \ break; \ } \ case TYPE_FN: \ @@ -852,7 +854,7 @@ void vm_execute(struct vm *vm) { array_obj *chars = string_chars(value_get_pointer(TYPE_STR, top), vm); array_pop(vm->stack); array_push(vm->stack, value_pointer(TYPE_ARRAY, chars)); - array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 0)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 1)); array_push(vm->stack, chars->data[0]); break; } @@ -868,18 +870,13 @@ void vm_execute(struct vm *vm) { break; } case TYPE_DICT: { - return; - /* - struct dict *dict = top->as.dict; + struct dict *dict = value_get_pointer(TYPE_DICT, top); const struct value *pval = dict_get(dict, "next"); - struct value val = { - .as.integer = 0, - .type = TYPE_INTERPRETER_ITERATOR}; - array_push(vm->stack, val); + array_pop(vm->stack); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 0)); vm->ip += (uint32_t)sizeof(pos); - array_push(vm->stack, *top); // pass arg + array_push(vm->stack, top); // pass arg CALL_DICT_ITERATOR_FN - */ break; } // interation @@ -888,6 +885,7 @@ void vm_execute(struct vm *vm) { const struct value iterator = vm->stack.data[vm->stack.length - 2]; switch (value_get_type(iterator)) { case TYPE_NIL: { + LOG("END\n"); vm->ip += pos; dispatch(); } @@ -895,13 +893,15 @@ void vm_execute(struct vm *vm) { const array_obj *array = value_get_pointer(TYPE_ARRAY, iterator); const size_t idx = (size_t)value_get_int(top); if (idx == array->length) { /* end of it */ + LOG("END\n"); array_pop(vm->stack); /* iterator */ array_pop(vm->stack); /* array */ vm->ip += pos; dispatch(); } else { // continuation + LOG("CONTINUE\n"); array_pop(vm->stack); /* old iterator */ - array_push(vm->stack, value_int((int32_t)idx + 1)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (int32_t)idx + 1)); array_push(vm->stack, array->data[idx]); } break; @@ -927,8 +927,10 @@ void vm_execute(struct vm *vm) { } break; } - default: + default: { + LOG("NOT ITERABLE\n"); ERROR(ERROR_EXPECTED_ITERABLE, sizeof(pos)); + } } vm->ip += (uint32_t)sizeof(pos); dispatch(); diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index 73073ac..ccc7f12 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -77,7 +77,7 @@ impl NativeValue { NativeValueType::TYPE_DICT => Value::Record(Gc::from_raw(transmute(self.get_low48()))), NativeValueType::TYPE_ARRAY => Value::Array(Gc::from_raw(transmute(self.get_low48()))), NativeValueType::TYPE_NIL => Value::Nil, - _ => unimplemented!(), + _ => Value::Nil, } } } diff --git a/tests/interpreter.rs b/tests/interpreter.rs index c07ae07..8fb4f18 100644 --- a/tests/interpreter.rs +++ b/tests/interpreter.rs @@ -277,7 +277,6 @@ end assert_eq!(vm.global().get("i").unwrap().unwrap(), Value::Int(0)); } - /* #[test] fn for_in_stmt() { let vm: Vm = eval!( @@ -313,7 +312,7 @@ end ); assert_eq!(vm.global().get("y").unwrap().unwrap(), Value::Int(4)); } - + /* #[test] fn for_in_stmt_iterator() { let vm: Vm = eval!( @@ -339,7 +338,7 @@ end let rec = vm.global().get("x").unwrap().unwrap().record(); assert_eq!(rec.get(&"stopped".to_string()).unwrap().unwrap().int(), 1); assert_eq!(rec.get(&"i".to_string()).unwrap().unwrap().int(), 10); - }*/ + } */ // #endregion // #region continue/break From 799596ff083b2a61a7415e22d9d16941ac834729 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 22:25:11 +0700 Subject: [PATCH 12/17] make for_in_stmt_iterator work --- src/vm/vm.c | 53 ++++++++++++++++++++++---------------------- tests/interpreter.rs | 4 ++-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/vm/vm.c b/src/vm/vm.c index 20c1164..0e680d1 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -780,32 +780,34 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)sizeof(nargs); debug_assert(vm->stack.length >= nargs); LOG("retcall %d\n", nargs); - switch(value_get_type(val)) { - case TYPE_NATIVE_FN: { - array_pop(vm->stack); - assert(0); - /* CALL_NATIVE(val.as.fn); - if (vm_leave_env(vm)) { - LOG("return from vm_call\n"); - return; - } */ - break; } - case TYPE_FN: - case TYPE_DICT: { - struct function *ifn; - JMP_INTERPRETED_FN(1 + sizeof(nargs), + switch (value_get_type(val)) { + case TYPE_NATIVE_FN: { + array_pop(vm->stack); + assert(0); + /* CALL_NATIVE(val.as.fn); if (vm_leave_env(vm)) { LOG("return from vm_call\n"); return; - } else { - dispatch(); - } - ); - // caller - vm_enter_env_tail(vm, ifn); - break; } - default: { - ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); } + } */ + break; + } + case TYPE_FN: + case TYPE_DICT: { + struct function *ifn; + JMP_INTERPRETED_FN(1 + sizeof(nargs), + if (vm_leave_env(vm)) { + LOG("return from vm_call\n"); + return; + } else { + dispatch(); + }); + // caller + vm_enter_env_tail(vm, ifn); + break; + } + default: { + ERROR(ERROR_EXPECTED_CALLABLE, 1 + sizeof(nargs)); + } } dispatch(); } @@ -872,7 +874,6 @@ void vm_execute(struct vm *vm) { case TYPE_DICT: { struct dict *dict = value_get_pointer(TYPE_DICT, top); const struct value *pval = dict_get(dict, "next"); - array_pop(vm->stack); array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 0)); vm->ip += (uint32_t)sizeof(pos); array_push(vm->stack, top); // pass arg @@ -907,6 +908,7 @@ void vm_execute(struct vm *vm) { break; } case TYPE_DICT: { + LOG("CONTINUE\n"); const struct dict *dict = value_get_pointer(TYPE_DICT, iterator); if (dict_get(dict, "stopped") != NULL) { array_pop(vm->stack); /* iterator */ @@ -918,8 +920,7 @@ void vm_execute(struct vm *vm) { const struct value *pval = dict_get(dict, "next"); vm->ip += (uint32_t)sizeof(pos); array_push(vm->stack, iterator); // arg - assert(0); - //CALL_DICT_ITERATOR_FN + CALL_DICT_ITERATOR_FN break; } default: diff --git a/tests/interpreter.rs b/tests/interpreter.rs index 8fb4f18..11e2113 100644 --- a/tests/interpreter.rs +++ b/tests/interpreter.rs @@ -312,7 +312,7 @@ end ); assert_eq!(vm.global().get("y").unwrap().unwrap(), Value::Int(4)); } - /* + #[test] fn for_in_stmt_iterator() { let vm: Vm = eval!( @@ -338,7 +338,7 @@ end let rec = vm.global().get("x").unwrap().unwrap().record(); assert_eq!(rec.get(&"stopped".to_string()).unwrap().unwrap().int(), 1); assert_eq!(rec.get(&"i".to_string()).unwrap().unwrap().int(), 10); - } */ + } // #endregion // #region continue/break From 796b5f9c8af444f1af7c57a0a66957870e44bb55 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 22:31:34 +0700 Subject: [PATCH 13/17] fix OP_RETCALL for native functions --- src/vm/vm.c | 5 ++--- tests/hanayo.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/vm/vm.c b/src/vm/vm.c index 0e680d1..bdd52ce 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -783,12 +783,11 @@ void vm_execute(struct vm *vm) { switch (value_get_type(val)) { case TYPE_NATIVE_FN: { array_pop(vm->stack); - assert(0); - /* CALL_NATIVE(val.as.fn); + CALL_NATIVE(((value_fn)value_get_pointer(TYPE_NATIVE_FN, val))); if (vm_leave_env(vm)) { LOG("return from vm_call\n"); return; - } */ + } break; } case TYPE_FN: diff --git a/tests/hanayo.rs b/tests/hanayo.rs index 589da47..4a0bade 100644 --- a/tests/hanayo.rs +++ b/tests/hanayo.rs @@ -60,6 +60,18 @@ y = (10).prototype == Int ); assert_eq!(vm.global().get("y").unwrap().unwrap().int(), 1); } + + #[test] + fn native_tail_ret() { + let vm: Vm = eval!( + " +function x() begin + return print('hello') +end +x() +" + ); + } // #endregion // #region int From 03c2a41483c623cfab9ed17413059dabf02eed18 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 22:50:59 +0700 Subject: [PATCH 14/17] assert => debug_assert --- src/vm/value.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/vm/value.h b/src/vm/value.h index 06056ca..f6ec01a 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -118,28 +118,33 @@ struct value value_neq(const struct value left, const struct value right, const bool value_is_true(const struct value); struct dict *value_get_prototype(const struct vm *vm, const struct value val); -#define assert(x) if(!(x)){ *((void*)0); } +// TODO move this somewhere else +#ifdef DEBUG +#define debug_assert(x) if(!(x)){ *((void*)0); } +#else +#define debug_assert(x) +#endif static inline struct value value_pointer(uint8_t tag, void *ptr) { uint64_t low_bits = (uint64_t)ptr & 0xffffffffffff; - assert(low_bits == (uint64_t)ptr); - assert(tag < 16 && tag > 0); // we can only store 4 bits + debug_assert(low_bits == (uint64_t)ptr); + debug_assert(tag < 16 && tag > 0); // we can only store 4 bits return (struct value){ .as.bits.reserved_nan = RESERVED_NAN, .as.bits.tag_bits = tag, .as.bits.payload = low_bits}; } static inline uint16_t value_get_tag(struct value val) { - assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); + debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); return val.as.bits.tag_bits; } // TODO: remove redundant checks from opcodes static inline void *value_get_pointer(uint8_t tag, struct value val) { - assert(tag != TYPE_INT); - assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); + debug_assert(tag != TYPE_INT); + debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); return (void *)val.as.bits.payload; } static inline int32_t value_get_int(struct value val) { - assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == TYPE_INT); + debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == TYPE_INT); return (int32_t)val.as.lower32; } static inline void value_set_int(struct value *val, int32_t n) { @@ -148,11 +153,11 @@ static inline void value_set_int(struct value *val, int32_t n) { val->as.lower32 = n; } static inline double value_get_float(struct value val) { - assert(!isnan(val.as.floatp)); + debug_assert(!isnan(val.as.floatp)); return val.as.floatp; } static inline void value_set_float(struct value *val, double n) { val->as.floatp = n; - assert(val->as.bits.reserved_nan != RESERVED_NAN); + debug_assert(val->as.bits.reserved_nan != RESERVED_NAN); } -#undef assert \ No newline at end of file +#undef debug_assert \ No newline at end of file From 646a13ef8d06618436e96b94ae8d12ff9c89d863 Mon Sep 17 00:00:00 2001 From: ffwff Date: Mon, 3 Jun 2019 23:24:39 +0700 Subject: [PATCH 15/17] remove debug prints --- src/vmbindings/foreignc.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vmbindings/foreignc.rs b/src/vmbindings/foreignc.rs index 320261e..8d04101 100644 --- a/src/vmbindings/foreignc.rs +++ b/src/vmbindings/foreignc.rs @@ -213,7 +213,6 @@ mod foreignc { unsafe extern "C" fn function_malloc( addr: u32, nargs: u16, env: *const Env, vm: *const Vm, ) -> *mut Function { - eprintln!("function malloc: {} {}", addr, nargs); (&*vm).malloc(Function::new(addr, nargs, env)).into_raw() } @@ -254,7 +253,6 @@ mod foreignc { let env = &mut *selfptr; env.reserve(nslots); let vm = &mut *cvm; - eprintln!("{:?}", env.nargs); for i in 0..env.nargs { let val = vm.stack.pop().unwrap(); env.set(i, val.clone()); From 8a0af17b2f0e896828a437c71b77ba1de32d9c5d Mon Sep 17 00:00:00 2001 From: ffwff Date: Tue, 4 Jun 2019 07:15:37 +0700 Subject: [PATCH 16/17] clean up code --- src/hanayo/array.rs | 8 +++--- src/vm/array.h | 5 ---- src/vm/value.c | 9 +++++-- src/vm/value.h | 11 +------- src/vm/vm.c | 12 ++++----- src/vm/vm.h | 1 + src/vmbindings/cnativeval.rs | 51 +++++++++++++++++++++--------------- src/vmbindings/foreignc.rs | 9 +++---- src/vmbindings/function.rs | 2 +- src/vmbindings/gc.rs | 17 +++++++----- src/vmbindings/record.rs | 4 +-- src/vmbindings/value.rs | 17 +++++++++--- src/vmbindings/vm.rs | 2 +- tests/hanayo.rs | 2 +- tests/interpreter.rs | 7 +++-- 15 files changed, 86 insertions(+), 71 deletions(-) diff --git a/src/hanayo/array.rs b/src/hanayo/array.rs index 2315b83..c4f56d6 100644 --- a/src/hanayo/array.rs +++ b/src/hanayo/array.rs @@ -1,7 +1,7 @@ //! Provides Array record for handling arrays use std::cmp::Ordering; -use crate::vmbindings::cnativeval::{NativeValue, NativeValueType}; +use crate::vmbindings::cnativeval::{NativeValue}; use crate::vmbindings::value::Value; use crate::vmbindings::vm::Vm; @@ -61,9 +61,9 @@ extern "C" { fn value_cmp(left: &NativeValue, right: &NativeValue) -> Ordering { let left = left.clone(); let right = right.clone(); - if unsafe{ value_gt(left, right) }.unwrap().int() == 1 { + if unsafe { value_gt(left, right) }.unwrap().int() == 1 { Ordering::Greater - } else if unsafe{ value_lt(left, right) }.unwrap().int() == 1 { + } else if unsafe { value_lt(left, right) }.unwrap().int() == 1 { Ordering::Less } else { Ordering::Equal @@ -144,7 +144,7 @@ extern "C" { fn index(array: Value::Array, elem: Value::Any) -> Value { let array = array.as_ref(); for i in 0..(array.len() - 1) { - if unsafe{ value_eq(array[i], elem.wrap()) }.unwrap().int() == 1 { + if unsafe { value_eq(array[i], elem.wrap()) }.unwrap().int() == 1 { return Value::Int(i as i32); } } diff --git a/src/vm/array.h b/src/vm/array.h index cea623b..a32cece 100644 --- a/src/vm/array.h +++ b/src/vm/array.h @@ -25,11 +25,6 @@ void *rrealloc(void *ptr, size_t nelems, size_t size, size_t new_size); .length = n, \ } -#define array_free(array) \ - do { \ - free(array.data); \ - } while (0) - #define array_push(array, element) \ do { \ if (array.length == array.capacity) { \ diff --git a/src/vm/value.c b/src/vm/value.c index b53f9fc..375cf4e 100644 --- a/src/vm/value.c +++ b/src/vm/value.c @@ -1,5 +1,6 @@ #include #include +#include #include "string_.h" #include "value.h" #include "vm.h" @@ -18,12 +19,16 @@ int value_get_type(struct value val) { // non-primitives struct value value_int(int32_t n) { struct value val = {0}; - value_set_int(&val, n); + val.as.bits.reserved_nan = RESERVED_NAN; + val.as.bits.tag_bits = TYPE_INT; + val.as.lower32 = n; return val; } struct value value_float(double n) { struct value val; - value_set_float(&val, n); + val.as.floatp = n; + // TODO: fix nan + //assert(!isnan(n)); return val; } struct value value_str(const char *data, const struct vm *vm) { diff --git a/src/vm/value.h b/src/vm/value.h index f6ec01a..9631798 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -141,23 +141,14 @@ static inline uint16_t value_get_tag(struct value val) { static inline void *value_get_pointer(uint8_t tag, struct value val) { debug_assert(tag != TYPE_INT); debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); - return (void *)val.as.bits.payload; + return (void *)((intptr_t)val.as.bits.payload); } static inline int32_t value_get_int(struct value val) { debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == TYPE_INT); return (int32_t)val.as.lower32; } -static inline void value_set_int(struct value *val, int32_t n) { - val->as.bits.reserved_nan = RESERVED_NAN; - val->as.bits.tag_bits = TYPE_INT; - val->as.lower32 = n; -} static inline double value_get_float(struct value val) { debug_assert(!isnan(val.as.floatp)); return val.as.floatp; } -static inline void value_set_float(struct value *val, double n) { - val->as.floatp = n; - debug_assert(val->as.bits.reserved_nan != RESERVED_NAN); -} #undef debug_assert \ No newline at end of file diff --git a/src/vm/vm.c b/src/vm/vm.c index bdd52ce..882d1e5 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -855,7 +855,7 @@ void vm_execute(struct vm *vm) { array_obj *chars = string_chars(value_get_pointer(TYPE_STR, top), vm); array_pop(vm->stack); array_push(vm->stack, value_pointer(TYPE_ARRAY, chars)); - array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 1)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (void *)1)); array_push(vm->stack, chars->data[0]); break; } @@ -866,14 +866,14 @@ void vm_execute(struct vm *vm) { array_pop(vm->stack); dispatch(); } - array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 1)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (void *)1)); array_push(vm->stack, array->data[0]); break; } case TYPE_DICT: { struct dict *dict = value_get_pointer(TYPE_DICT, top); const struct value *pval = dict_get(dict, "next"); - array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, 0)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (void *)0)); vm->ip += (uint32_t)sizeof(pos); array_push(vm->stack, top); // pass arg CALL_DICT_ITERATOR_FN @@ -901,7 +901,7 @@ void vm_execute(struct vm *vm) { } else { // continuation LOG("CONTINUE\n"); array_pop(vm->stack); /* old iterator */ - array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (int32_t)idx + 1)); + array_push(vm->stack, value_pointer(TYPE_INTERPRETER_ITERATOR, (void *)(idx + 1))); array_push(vm->stack, array->data[idx]); } break; @@ -966,7 +966,7 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, fn)))); + ((value_fn)(value_get_pointer(TYPE_NATIVE_FN, fn)))(vm, nargs); } else if(value_get_type(fn) == TYPE_DICT) { const struct value *pctor = dict_get(value_get_pointer(TYPE_DICT, fn), "constructor"); if(pctor == NULL) { @@ -978,7 +978,7 @@ struct value vm_call(struct vm *vm, const struct value fn, const a_arguments *ar for (size_t i = args->length; i-- > 0;) { array_push(vm->stack, args->data[i]); } - CALL_NATIVE(((value_fn)(value_get_pointer(TYPE_NATIVE_FN, ctor)))); + ((value_fn)(value_get_pointer(TYPE_NATIVE_FN, ctor)))(vm, nargs); if (vm->error) return value_interpreter_error(); const struct value val = array_top(vm->stack); array_pop(vm->stack); diff --git a/src/vm/vm.h b/src/vm/vm.h index 6dc23ff..cad3900 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -113,6 +113,7 @@ struct exframe *vm_enter_exframe(struct vm *); bool vm_leave_exframe(struct vm *); bool vm_raise(struct vm *); +struct function; struct value vm_call(struct vm *, const struct value, const a_arguments*); struct env *vm_enter_env(struct vm *, struct function *); struct env *vm_enter_env_tail(struct vm *, struct function *); diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index ccc7f12..cee5de3 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -4,9 +4,7 @@ extern crate num_derive; use num_traits::cast::{FromPrimitive, ToPrimitive}; -use super::function::Function; -use super::gc::{ref_dec, ref_inc, Gc, GcManager, GcTraceable}; -use super::record::Record; +use super::gc::{ref_dec, ref_inc, Gc}; use super::value::{NativeFnData, Value}; #[repr(u8)] @@ -31,34 +29,37 @@ pub enum NativeValueType { /// Native value representation used by the virtual machine pub struct NativeValue(u64); -const RESERVED_NAN : u64 = 0x7ff; - // 0b01111111 11110110 0 10101011 11101111 11011001 01100011 01111110 1000000 -const RESERVED_NAN_MASK : u64 = 0b01111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000; -const INT_MASK : u64 = 0b01111111_11110001_00000000_00000000_00000000_00000000_00000000_00000000; -const TAG_BIT_MASK : u64 = 0b00000000_00001111_00000000_00000000_00000000_00000000_00000000_00000000; -const LOWER_MASK : u64 = 0xffffffffffff; +const RESERVED_NAN: u64 = 0x7ff; +const INT_MASK: u64 = 0b01111111_11110001_00000000_00000000_00000000_00000000_00000000_00000000; +const TAG_BIT_MASK: u64 = + 0b00000000_00001111_00000000_00000000_00000000_00000000_00000000_00000000; +const LOWER_MASK: u64 = 0xffffffffffff; impl NativeValue { pub fn tag(&self) -> NativeValueType { - if !f64::is_nan(unsafe{ std::mem::transmute(self.0) }) { + if !f64::is_nan(unsafe { std::mem::transmute(self.0) }) { return NativeValueType::TYPE_FLOAT; } - NativeValueType::from_u8(((self.0 & TAG_BIT_MASK) >> 48) as u8).unwrap() + if let Some(x) = NativeValueType::from_u8(((self.0 & TAG_BIT_MASK) >> 48) as u8) { + x + } else { + unreachable!() + } } fn get_low48(&self) -> u64 { self.0 & LOWER_MASK } pub fn new_nil() -> NativeValue { - NativeValue((((RESERVED_NAN << 4) | NativeValueType::TYPE_NIL.to_u64().unwrap()) << 48)) + NativeValue(((RESERVED_NAN << 4) | NativeValueType::TYPE_NIL.to_u64().unwrap()) << 48) } pub fn new_i32(u: i32) -> NativeValue { NativeValue(INT_MASK | ((u as u32) as u64 & 0xffffffff)) } pub fn new_f64(u: f64) -> NativeValue { - NativeValue(unsafe{ std::mem::transmute(u) }) + NativeValue(unsafe { std::mem::transmute(u) }) } - pub fn new_tagged_pointer(tag: NativeValueType, ptr : *const T) -> NativeValue { + pub fn new_tagged_pointer(tag: NativeValueType, ptr: *const T) -> NativeValue { let loptr = unsafe { std::mem::transmute::<_, u64>(ptr) & 0xffffffffffff }; NativeValue((((RESERVED_NAN << 4) | tag.to_u64().unwrap()) << 48) | loptr) } @@ -70,12 +71,17 @@ impl NativeValue { match self.tag() { NativeValueType::TYPE_FLOAT => Value::Float(transmute(self.0)), NativeValueType::TYPE_INT => Value::Int((self.0 & 0xffffffff) as i32), - NativeValueType::TYPE_NATIVE_FN - => Value::NativeFn(transmute::<_, NativeFnData>(self.get_low48())), + NativeValueType::TYPE_NATIVE_FN => { + Value::NativeFn(transmute::<_, NativeFnData>(self.get_low48())) + } NativeValueType::TYPE_FN => Value::Fn(Gc::from_raw(transmute(self.get_low48()))), NativeValueType::TYPE_STR => Value::Str(Gc::from_raw(transmute(self.get_low48()))), - NativeValueType::TYPE_DICT => Value::Record(Gc::from_raw(transmute(self.get_low48()))), - NativeValueType::TYPE_ARRAY => Value::Array(Gc::from_raw(transmute(self.get_low48()))), + NativeValueType::TYPE_DICT => { + Value::Record(Gc::from_raw(transmute(self.get_low48()))) + } + NativeValueType::TYPE_ARRAY => { + Value::Array(Gc::from_raw(transmute(self.get_low48()))) + } NativeValueType::TYPE_NIL => Value::Nil, _ => Value::Nil, } @@ -90,10 +96,13 @@ impl NativeValue { | NativeValueType::TYPE_DICT | NativeValueType::TYPE_ARRAY => { let low48 = self.get_low48(); - if low48 == 0 { None } - else { Some(std::mem::transmute(low48)) } + if low48 == 0 { + None + } else { + Some(std::mem::transmute(low48)) + } } - _ => None + _ => None, } } diff --git a/src/vmbindings/foreignc.rs b/src/vmbindings/foreignc.rs index 8d04101..fda849f 100644 --- a/src/vmbindings/foreignc.rs +++ b/src/vmbindings/foreignc.rs @@ -5,7 +5,6 @@ use super::cnativeval::NativeValue; use super::env::Env; use super::exframe::ExFrame; use super::function::Function; -use super::gc::Gc; use super::record::Record; use super::value::Value; use super::vm::Vm; @@ -131,7 +130,9 @@ mod foreignc { } #[no_mangle] - unsafe extern "C" fn string_repeat(cleft: *const String, n: i64, vm: *const Vm) -> *mut String { + unsafe extern "C" fn string_repeat( + cleft: *const String, n: i64, vm: *const Vm, + ) -> *mut String { let left: &'static String = &*cleft; (&*vm).malloc(left.repeat(n as usize)).into_raw() } @@ -150,9 +151,7 @@ mod foreignc { } #[no_mangle] - unsafe extern "C" fn string_at( - left: *const String, idx: i64, vm: *const Vm, - ) -> *mut String { + unsafe extern "C" fn string_at(left: *const String, idx: i64, vm: *const Vm) -> *mut String { let left: &'static String = &*left; if let Some(ch) = left.graphemes(true).nth(idx as usize) { (&*vm).malloc(ch.to_string()).into_raw() diff --git a/src/vmbindings/function.rs b/src/vmbindings/function.rs index 6ec9d94..c2951c6 100644 --- a/src/vmbindings/function.rs +++ b/src/vmbindings/function.rs @@ -1,7 +1,7 @@ //! Provides a function value in Hana use super::env::Env; -use crate::vmbindings::gc::{GcNode, GcTraceable, push_gray_body}; +use crate::vmbindings::gc::{push_gray_body, GcNode, GcTraceable}; use std::ptr::null_mut; #[repr(C)] diff --git a/src/vmbindings/gc.rs b/src/vmbindings/gc.rs index 3cdda52..0299758 100644 --- a/src/vmbindings/gc.rs +++ b/src/vmbindings/gc.rs @@ -100,7 +100,8 @@ impl GcManager { Gc { ptr: NonNull::new(unsafe { self.malloc_raw(vm, val, |ptr| drop_in_place::(ptr as *mut T)) - }).unwrap(), + }) + .unwrap(), } } @@ -128,22 +129,24 @@ impl GcManager { //eprintln!("GRAY NODES MARKING: {:?}, {:?}", gray_nodes, self.gray_nodes); // nothing left to traverse, sweeping phase: if self.gray_nodes.is_empty() && self.bytes_allocated > self.threshold { - let mut node: *mut GcNode = self.first_node; let mut prev: *mut GcNode = null_mut(); // don't sweep nodes with at least one native reference - node = self.first_node; + let mut node: *mut GcNode = self.first_node; while !node.is_null() { let next: *mut GcNode = (*node).next; let ptr = node.add(1) as *mut c_void; if (*node).native_refs > 0 && (*node).color != GcNodeColor::Black { //eprintln!("{:p}", node); // get its children and subchildren - let mut children : Vec<*mut GcNode> = Vec::new(); + let mut children: Vec<*mut GcNode> = Vec::new(); ((*node).tracer)(std::mem::transmute(ptr), std::mem::transmute(&mut children)); let mut i = 0; while i < children.len() { let node = children[i]; - ((*node).tracer)(std::mem::transmute(ptr), std::mem::transmute(&mut children)); + ((*node).tracer)( + std::mem::transmute(ptr), + std::mem::transmute(&mut children), + ); i += 1; } // color them black @@ -297,7 +300,7 @@ type GenericTraceFunction = unsafe fn(*mut c_void, *mut c_void); // native traceables impl GcTraceable for String { - unsafe fn trace(&self, manager: &mut Vec<*mut GcNode>) {} + unsafe fn trace(&self, _: &mut Vec<*mut GcNode>) {} } use super::cnativeval::NativeValue; @@ -336,4 +339,4 @@ pub unsafe fn push_gray_body(gray_nodes: &mut Vec<*mut GcNode>, ptr: *mut c_void } (*node).color = GcNodeColor::Gray; gray_nodes.push(node); -} \ No newline at end of file +} diff --git a/src/vmbindings/record.rs b/src/vmbindings/record.rs index 7e9e0cc..2b05282 100644 --- a/src/vmbindings/record.rs +++ b/src/vmbindings/record.rs @@ -2,7 +2,7 @@ use super::chmap::CHashMap; use super::cnativeval::NativeValue; -use super::gc::{GcNode, GcTraceable, push_gray_body}; +use super::gc::{push_gray_body, GcNode, GcTraceable}; use super::value::Value; use std::any::Any; use std::borrow::Borrow; @@ -71,7 +71,7 @@ impl Record { impl GcTraceable for Record { unsafe fn trace(&self, gray_nodes: &mut Vec<*mut GcNode>) { - for(_, val) in self.iter() { + for (_, val) in self.iter() { if let Some(ptr) = val.as_gc_pointer() { push_gray_body(gray_nodes, ptr); } diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index 75f0288..9d1f6b2 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -100,12 +100,21 @@ impl Value { Value::Int(n) => NativeValue::new_i32(*n), Value::Float(n) => NativeValue::new_f64(*n), Value::NativeFn(p) => unsafe { - NativeValue::new_tagged_pointer(NativeValueType::TYPE_NATIVE_FN, std::mem::transmute::<_, *mut libc::c_void>(*p)) + NativeValue::new_tagged_pointer( + NativeValueType::TYPE_NATIVE_FN, + std::mem::transmute::<_, *mut libc::c_void>(*p), + ) }, Value::Fn(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_FN, p.to_raw()), - Value::Str(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_STR, p.to_raw()), - Value::Record(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_DICT, p.to_raw()), - Value::Array(p) => NativeValue::new_tagged_pointer(NativeValueType::TYPE_ARRAY, p.to_raw()), + Value::Str(p) => { + NativeValue::new_tagged_pointer(NativeValueType::TYPE_STR, p.to_raw()) + } + Value::Record(p) => { + NativeValue::new_tagged_pointer(NativeValueType::TYPE_DICT, p.to_raw()) + } + Value::Array(p) => { + NativeValue::new_tagged_pointer(NativeValueType::TYPE_ARRAY, p.to_raw()) + } _ => unimplemented!(), } } diff --git a/src/vmbindings/vm.rs b/src/vmbindings/vm.rs index ee93e99..b2ddf21 100644 --- a/src/vmbindings/vm.rs +++ b/src/vmbindings/vm.rs @@ -9,7 +9,7 @@ use std::rc::Rc; extern crate libc; use super::chmap::CHashMap; -use super::cnativeval::{NativeValueType, NativeValue}; +use super::cnativeval::{NativeValue, NativeValueType}; use super::env::Env; use super::exframe::ExFrame; use super::function::Function; diff --git a/tests/hanayo.rs b/tests/hanayo.rs index 4a0bade..96ef3e5 100644 --- a/tests/hanayo.rs +++ b/tests/hanayo.rs @@ -63,7 +63,7 @@ y = (10).prototype == Int #[test] fn native_tail_ret() { - let vm: Vm = eval!( + let _vm: Vm = eval!( " function x() begin return print('hello') diff --git a/tests/interpreter.rs b/tests/interpreter.rs index 11e2113..3a45cd1 100644 --- a/tests/interpreter.rs +++ b/tests/interpreter.rs @@ -832,9 +832,12 @@ use './module_relative_import' fn module_native_import() { std::fs::write("/tmp/module_native_import.hana", "$y = 10").unwrap(); std::env::set_var("HANA_PATH", "/tmp"); - let prog = grammar::start(" + let prog = grammar::start( + " use 'module_native_import' - ").unwrap(); + ", + ) + .unwrap(); let mut c = compiler::Compiler::new(); c.modules_info.borrow_mut().files.push("/tmp/x".to_string()); for stmt in prog { From 2c82943ed009012c51ea668bffb8b780f41d0c6f Mon Sep 17 00:00:00 2001 From: ffwff Date: Tue, 4 Jun 2019 10:02:11 +0700 Subject: [PATCH 17/17] more cleanup job --- build.rs | 3 +- src/vm/value.h | 8 +- src/vm/vm.c | 147 +++++++++++++++++++---------------- src/vmbindings/cnativeval.rs | 2 +- src/vmbindings/value.rs | 2 +- 5 files changed, 89 insertions(+), 73 deletions(-) diff --git a/build.rs b/build.rs index fa0f9d2..f67b687 100644 --- a/build.rs +++ b/build.rs @@ -29,9 +29,8 @@ fn main() { build.flag("-flto"); } build - //.flag("-Wall") + .flag("-Wall") .flag("-Wno-unused-parameter") - //.flag("-Wconversion") .flag("-std=c11") .shared_flag(true) .static_flag(true) diff --git a/src/vm/value.h b/src/vm/value.h index 9631798..574dcee 100644 --- a/src/vm/value.h +++ b/src/vm/value.h @@ -125,13 +125,13 @@ struct dict *value_get_prototype(const struct vm *vm, const struct value val); #define debug_assert(x) #endif static inline struct value value_pointer(uint8_t tag, void *ptr) { - uint64_t low_bits = (uint64_t)ptr & 0xffffffffffff; - debug_assert(low_bits == (uint64_t)ptr); + //uint64_t low_bits = (uint64_t)ptr & 0xffffffffffff; + //debug_assert(low_bits == (uint64_t)ptr); debug_assert(tag < 16 && tag > 0); // we can only store 4 bits return (struct value){ .as.bits.reserved_nan = RESERVED_NAN, .as.bits.tag_bits = tag, - .as.bits.payload = low_bits}; + .as.bits.payload = (uint64_t)(uintptr_t)(ptr)}; } static inline uint16_t value_get_tag(struct value val) { debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits > 0); @@ -141,7 +141,7 @@ static inline uint16_t value_get_tag(struct value val) { static inline void *value_get_pointer(uint8_t tag, struct value val) { debug_assert(tag != TYPE_INT); debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == tag); - return (void *)((intptr_t)val.as.bits.payload); + return (void *)((uintptr_t)val.as.bits.payload); } static inline int32_t value_get_int(struct value val) { debug_assert(val.as.bits.reserved_nan == RESERVED_NAN && val.as.bits.tag_bits == TYPE_INT); diff --git a/src/vm/vm.c b/src/vm/vm.c index 882d1e5..bdd8be4 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -465,21 +465,27 @@ void vm_execute(struct vm *vm) { ERROR(ERROR_RECORD_NO_CONSTRUCTOR, UNWIND); \ } \ const struct value ctor = *pctor; \ - if (value_get_type(ctor) == TYPE_NATIVE_FN) { \ - CALL_NATIVE(((value_fn)value_get_pointer(TYPE_NATIVE_FN, ctor))); \ - do { \ - END_IF_NATIVE \ - } while (0); \ - } else if (value_get_type(ctor) != TYPE_FN) { \ - ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ + switch (value_get_type(ctor)) { \ + case TYPE_NATIVE_FN: { \ + CALL_NATIVE(((value_fn)value_get_pointer(TYPE_NATIVE_FN, ctor))); \ + do { \ + END_IF_NATIVE \ + } while (0); \ + break; \ + } \ + case TYPE_FN: { \ + ifn = value_get_pointer(TYPE_FN, ctor); \ + if (nargs + 1 != ifn->nargs) { \ + ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ + } \ + struct value new_val = value_dict(vm); \ + dict_set(value_get_pointer(TYPE_DICT, new_val), "prototype", val); \ + array_push(vm->stack, new_val); \ + break; \ + } \ + default: \ + ERROR(ERROR_CONSTRUCTOR_NOT_FUNCTION, UNWIND); \ } \ - ifn = value_get_pointer(TYPE_FN, ctor); \ - if (nargs + 1 != ifn->nargs) { \ - ERROR_EXPECT(ERROR_MISMATCH_ARGUMENTS, ifn->nargs, UNWIND); \ - } \ - struct value new_val = value_dict(vm); \ - dict_set(value_get_pointer(TYPE_DICT, new_val), "prototype", val); \ - array_push(vm->stack, new_val); \ } else { \ do { \ POP \ @@ -552,7 +558,7 @@ void vm_execute(struct vm *vm) { vm->ip += (uint32_t)strlen(key) + 1; LOG(op == OP_MEMBER_GET ? "MEMBER_GET %s\n" : "MEMBER_GET_NO_POP %s\n", key); - struct value val = array_top(vm->stack); + const struct value val = array_top(vm->stack); struct dict *dict = NULL; if(value_get_type(val) != TYPE_DICT) { if((dict = value_get_prototype(vm, val)) == NULL) { @@ -579,10 +585,10 @@ void vm_execute(struct vm *vm) { doop(OP_MEMBER_SET): { // stack: [value][dict] vm->ip++; - char *key = (char *)(vm->code.data+vm->ip); // must be null terminated + const char *key = (char *)(vm->code.data + vm->ip); // must be null terminated vm->ip += (uint32_t)strlen(key) + 1; LOG("MEMBER_SET %s\n", key); - struct value dval = array_top(vm->stack); + const struct value dval = array_top(vm->stack); if(value_get_type(dval) != TYPE_DICT) { ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1 + strlen(key)+1); } @@ -632,38 +638,45 @@ void vm_execute(struct vm *vm) { const struct value dval = array_top(vm->stack); if (op == OP_INDEX_GET) array_pop(vm->stack); - if(value_get_type(dval) == TYPE_ARRAY) { - array_obj *array = value_get_pointer(TYPE_ARRAY, dval); - if(value_get_type(index) != TYPE_INT) { - ERROR(ERROR_KEY_NON_INT, 1); - } - const int32_t i = (int32_t)value_get_int(index); - if (!(i >= 0 && i < (int32_t)array->length)) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, array->length); - } - array_push(vm->stack, array->data[i]); - } else if(value_get_type(dval) == TYPE_STR) { - if(value_get_type(index) != TYPE_INT) { - ERROR(ERROR_KEY_NON_INT, 1); - } - const int32_t i = (int32_t)value_get_int(index); - struct string *s = string_at(value_get_pointer(TYPE_STR, dval), i, vm); - if (s == NULL) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, string_len(value_get_pointer(TYPE_STR, dval))); + switch (value_get_type(dval)) { + case TYPE_ARRAY: { + array_obj *array = value_get_pointer(TYPE_ARRAY, dval); + if (value_get_type(index) != TYPE_INT) { + ERROR(ERROR_KEY_NON_INT, 1); + } + const int32_t i = (int32_t)value_get_int(index); + if (!(i >= 0 && i < (int32_t)array->length)) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, array->length); + } + array_push(vm->stack, array->data[i]); + break; } - array_push(vm->stack, value_pointer(TYPE_STR, s)); - } else if(value_get_type(dval) == TYPE_DICT) { - if(value_get_type(index) != TYPE_STR) { - ERROR(ERROR_RECORD_KEY_NON_STRING, 1); + case TYPE_STR: { + if (value_get_type(index) != TYPE_INT) { + ERROR(ERROR_KEY_NON_INT, 1); + } + const int32_t i = (int32_t)value_get_int(index); + struct string *s = string_at(value_get_pointer(TYPE_STR, dval), i, vm); + if (s == NULL) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, 1, string_len(value_get_pointer(TYPE_STR, dval))); + } + array_push(vm->stack, value_pointer(TYPE_STR, s)); + break; } - const struct value *val = dict_get_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index)); - if(val != NULL) { - array_push(vm->stack, *val); - } else { - ERROR(ERROR_UNKNOWN_KEY, 1); + case TYPE_DICT: { + if (value_get_type(index) != TYPE_STR) { + ERROR(ERROR_RECORD_KEY_NON_STRING, 1); + } + const struct value *val = dict_get_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index)); + if (val != NULL) { + array_push(vm->stack, *val); + } else { + ERROR(ERROR_UNKNOWN_KEY, 1); + } + break; } - } else { - ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1); + default: + ERROR(ERROR_CANNOT_ACCESS_NON_RECORD, 1); } dispatch(); } @@ -671,31 +684,35 @@ void vm_execute(struct vm *vm) { vm->ip++; LOG("INDEX_SET\n"); - struct value index = array_top(vm->stack); + const struct value index = array_top(vm->stack); array_pop(vm->stack); - struct value dval = array_top(vm->stack); + const struct value dval = array_top(vm->stack); array_pop(vm->stack); - struct value val = array_top(vm->stack); - - if(value_get_type(dval) == TYPE_ARRAY) { - if(value_get_type(index) != TYPE_INT) { - ERROR(ERROR_KEY_NON_INT, 1); - } - const int64_t i = value_get_int(index); - array_obj *array = value_get_pointer(TYPE_ARRAY, dval); - if (!(i >= 0 && i < (int64_t)array->length)) { - ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, array->length, 1); + const struct value val = array_top(vm->stack); + switch (value_get_type(dval)) { + case TYPE_ARRAY: { + if (value_get_type(index) != TYPE_INT) { + ERROR(ERROR_KEY_NON_INT, 1); + } + const int64_t i = value_get_int(index); + array_obj *array = value_get_pointer(TYPE_ARRAY, dval); + if (!(i >= 0 && i < (int64_t)array->length)) { + ERROR_EXPECT(ERROR_UNBOUNDED_ACCESS, array->length, 1); + } + array->data[i] = val; + break; } - array->data[i] = val; - } else if(value_get_type(dval) == TYPE_DICT) { - if(value_get_type(index) != TYPE_STR) { - ERROR(ERROR_RECORD_KEY_NON_STRING, 1); + case TYPE_DICT: { + if (value_get_type(index) != TYPE_STR) { + ERROR(ERROR_RECORD_KEY_NON_STRING, 1); + } + dict_set_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index), val); + break; } - dict_set_str(value_get_pointer(TYPE_DICT, dval), value_get_pointer(TYPE_STR, index), val); - } else { - ERROR(ERROR_EXPECTED_RECORD_ARRAY, 1); + default: + ERROR(ERROR_EXPECTED_RECORD_ARRAY, 1); } dispatch(); } diff --git a/src/vmbindings/cnativeval.rs b/src/vmbindings/cnativeval.rs index cee5de3..343bac9 100644 --- a/src/vmbindings/cnativeval.rs +++ b/src/vmbindings/cnativeval.rs @@ -12,7 +12,6 @@ use super::value::{NativeFnData, Value}; #[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)] /// Type of the native value pub enum NativeValueType { - TYPE_FLOAT = 0, TYPE_INT = 1, TYPE_NATIVE_FN = 2, TYPE_FN = 3, @@ -22,6 +21,7 @@ pub enum NativeValueType { TYPE_INTERPRETER_ERROR = 7, TYPE_INTERPRETER_ITERATOR = 8, TYPE_NIL = 9, + TYPE_FLOAT, } #[repr(transparent)] diff --git a/src/vmbindings/value.rs b/src/vmbindings/value.rs index 9d1f6b2..ee07b98 100644 --- a/src/vmbindings/value.rs +++ b/src/vmbindings/value.rs @@ -115,7 +115,7 @@ impl Value { Value::Array(p) => { NativeValue::new_tagged_pointer(NativeValueType::TYPE_ARRAY, p.to_raw()) } - _ => unimplemented!(), + _ => unreachable!(), } }