| @@ -17,6 +17,9 @@ X("<", l2_builtin_lt) | |||
| X("<=", l2_builtin_lteq) | |||
| X(">", l2_builtin_gt) | |||
| X(">=", l2_builtin_gteq) | |||
| X("&&", l2_builtin_land) | |||
| X("||", l2_builtin_lor) | |||
| X("??", l2_builtin_first) | |||
| X("print", l2_builtin_print) | |||
| X("len", l2_builtin_len) | |||
| X("if", l2_builtin_if) | |||
| @@ -134,7 +134,6 @@ void l2_vm_free(struct l2_vm *vm); | |||
| void l2_vm_step(struct l2_vm *vm); | |||
| void l2_vm_run(struct l2_vm *vm); | |||
| size_t l2_vm_gc(struct l2_vm *vm); | |||
| int l2_vm_val_is_true(struct l2_vm *vm, l2_word id); | |||
| int l2_vm_val_is_true(struct l2_vm *vm, struct l2_vm_value *val); | |||
| #endif | |||
| @@ -26,7 +26,10 @@ static int tok_is_infix(struct l2_token *tok) { | |||
| strcmp(str, "<") == 0 || | |||
| strcmp(str, "<=") == 0 || | |||
| strcmp(str, ">") == 0 || | |||
| strcmp(str, ">=") == 0; | |||
| strcmp(str, ">=") == 0 || | |||
| strcmp(str, "&&") == 0 || | |||
| strcmp(str, "||") == 0 || | |||
| strcmp(str, "??") == 0; | |||
| } | |||
| static int parse_expression( | |||
| @@ -181,6 +181,46 @@ X(l2_builtin_gt, >) | |||
| X(l2_builtin_gteq, >=) | |||
| #undef X | |||
| l2_word l2_builtin_land(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
| for (l2_word i = 0; i < argc; ++i) { | |||
| struct l2_vm_value *val = &vm->values[argv[i]]; | |||
| if (l2_value_get_type(val) == L2_VAL_TYPE_ERROR) { | |||
| return argv[i]; | |||
| } | |||
| if (!l2_vm_val_is_true(vm, val)) { | |||
| return vm->kfalse; | |||
| } | |||
| } | |||
| return vm->ktrue; | |||
| } | |||
| l2_word l2_builtin_lor(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
| for (l2_word i = 0; i < argc; ++i) { | |||
| struct l2_vm_value *val = &vm->values[argv[i]]; | |||
| if (l2_value_get_type(val) == L2_VAL_TYPE_ERROR) { | |||
| return argv[i]; | |||
| } | |||
| if (l2_vm_val_is_true(vm, val)) { | |||
| return vm->ktrue; | |||
| } | |||
| } | |||
| return vm->kfalse; | |||
| } | |||
| l2_word l2_builtin_first(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
| for (l2_word i = 0; i < argc; ++i) { | |||
| if (l2_value_get_type(&vm->values[argv[i]]) != L2_VAL_TYPE_NONE) { | |||
| return argv[i]; | |||
| } | |||
| } | |||
| return vm->knone; | |||
| } | |||
| l2_word l2_builtin_print(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
| for (size_t i = 0; i < argc; ++i) { | |||
| if (i != 0) { | |||
| @@ -237,7 +277,7 @@ l2_word l2_builtin_if(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
| return l2_vm_error(vm, "Expected 2 or 3 arguments"); | |||
| } | |||
| if (l2_vm_val_is_true(vm, argv[0])) { | |||
| if (l2_vm_val_is_true(vm, &vm->values[argv[0]])) { | |||
| l2_word ret_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0); | |||
| struct l2_vm_value *ret = &vm->values[ret_id]; | |||
| ret->extra.cont_call = argv[1]; | |||
| @@ -258,7 +298,7 @@ struct loop_context { | |||
| }; | |||
| static l2_word loop_callback(struct l2_vm *vm, l2_word retval, l2_word cont) { | |||
| if (l2_vm_val_is_true(vm, retval)) { | |||
| if (l2_vm_val_is_true(vm, &vm->values[retval])) { | |||
| return cont; | |||
| } | |||
| @@ -302,7 +342,7 @@ static l2_word while_callback(struct l2_vm *vm, l2_word retval, l2_word cont_id) | |||
| struct while_context *ctx = (struct while_context *)cont->cont; | |||
| if (cont->extra.cont_call == ctx->cond) { | |||
| if (l2_vm_val_is_true(vm, retval)) { | |||
| if (l2_vm_val_is_true(vm, &vm->values[retval])) { | |||
| cont->extra.cont_call = ctx->body; | |||
| return cont_id; | |||
| } else { | |||
| @@ -774,8 +774,7 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| } | |||
| } | |||
| int l2_vm_val_is_true(struct l2_vm *vm, l2_word id) { | |||
| struct l2_vm_value *val = &vm->values[id]; | |||
| int l2_vm_val_is_true(struct l2_vm *vm, struct l2_vm_value *val) { | |||
| l2_word true_atom = vm->values[vm->ktrue].atom; | |||
| return l2_value_get_type(val) == L2_VAL_TYPE_ATOM && val->atom == true_atom; | |||
| } | |||
| @@ -71,3 +71,26 @@ print (len []) | |||
| print (len [10 20]) | |||
| print (len "Hello") | |||
| print (len {a: 10; b: 20; c: 30}) | |||
| print "\n&&" | |||
| print &&() | |||
| print &&('true) | |||
| print &&('false) | |||
| print 'true && 'true | |||
| print (&& 10 == 10 20 == 20 30 != 40) | |||
| print 'true && 10 | |||
| print "\n||" | |||
| print ||() | |||
| print ||('true) | |||
| print ||('false) | |||
| print 'true || 'true | |||
| print 'true || 'false | |||
| print (|| 'false 10 'true) | |||
| print (|| 'false 10 'nope) | |||
| print "\n??" | |||
| print none ?? none ?? 30 ?? 20 | |||
| print (?? 10 none none) | |||
| print (?? none none "hello") | |||
| print ??() | |||
| @@ -57,12 +57,12 @@ | |||
| (none) | |||
| (true) (false) (atom 20) | |||
| (true) (false) (atom 23) | |||
| 100 | |||
| 100.5 | |||
| 255 | |||
| Hello World | |||
| [(none) (true) (false) (atom 20) 100.1 Nope (namespace) (function)] | |||
| [(none) (true) (false) (atom 23) 100.1 Nope (namespace) (function)] | |||
| (namespace) (namespace) | |||
| len | |||
| @@ -71,3 +71,26 @@ len | |||
| 2 | |||
| 5 | |||
| 3 | |||
| && | |||
| (true) | |||
| (true) | |||
| (false) | |||
| (true) | |||
| (true) | |||
| (false) | |||
| || | |||
| (false) | |||
| (true) | |||
| (false) | |||
| (true) | |||
| (true) | |||
| (true) | |||
| (false) | |||
| ?? | |||
| 30 | |||
| 10 | |||
| hello | |||
| (none) | |||