X("<=", l2_builtin_lteq) | X("<=", l2_builtin_lteq) | ||||
X(">", l2_builtin_gt) | X(">", l2_builtin_gt) | ||||
X(">=", l2_builtin_gteq) | X(">=", l2_builtin_gteq) | ||||
X("&&", l2_builtin_land) | |||||
X("||", l2_builtin_lor) | |||||
X("??", l2_builtin_first) | |||||
X("print", l2_builtin_print) | X("print", l2_builtin_print) | ||||
X("len", l2_builtin_len) | X("len", l2_builtin_len) | ||||
X("if", l2_builtin_if) | X("if", l2_builtin_if) |
void l2_vm_step(struct l2_vm *vm); | void l2_vm_step(struct l2_vm *vm); | ||||
void l2_vm_run(struct l2_vm *vm); | void l2_vm_run(struct l2_vm *vm); | ||||
size_t l2_vm_gc(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 | #endif |
strcmp(str, "<") == 0 || | strcmp(str, "<") == 0 || | ||||
strcmp(str, "<=") == 0 || | 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( | static int parse_expression( |
X(l2_builtin_gteq, >=) | X(l2_builtin_gteq, >=) | ||||
#undef X | #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) { | l2_word l2_builtin_print(struct l2_vm *vm, l2_word argc, l2_word *argv) { | ||||
for (size_t i = 0; i < argc; ++i) { | for (size_t i = 0; i < argc; ++i) { | ||||
if (i != 0) { | if (i != 0) { | ||||
return l2_vm_error(vm, "Expected 2 or 3 arguments"); | 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); | l2_word ret_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0); | ||||
struct l2_vm_value *ret = &vm->values[ret_id]; | struct l2_vm_value *ret = &vm->values[ret_id]; | ||||
ret->extra.cont_call = argv[1]; | ret->extra.cont_call = argv[1]; | ||||
}; | }; | ||||
static l2_word loop_callback(struct l2_vm *vm, l2_word retval, l2_word cont) { | 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; | return cont; | ||||
} | } | ||||
struct while_context *ctx = (struct while_context *)cont->cont; | struct while_context *ctx = (struct while_context *)cont->cont; | ||||
if (cont->extra.cont_call == ctx->cond) { | 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; | cont->extra.cont_call = ctx->body; | ||||
return cont_id; | return cont_id; | ||||
} else { | } else { |
} | } | ||||
} | } | ||||
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; | l2_word true_atom = vm->values[vm->ktrue].atom; | ||||
return l2_value_get_type(val) == L2_VAL_TYPE_ATOM && val->atom == true_atom; | return l2_value_get_type(val) == L2_VAL_TYPE_ATOM && val->atom == true_atom; | ||||
} | } |
print (len [10 20]) | print (len [10 20]) | ||||
print (len "Hello") | print (len "Hello") | ||||
print (len {a: 10; b: 20; c: 30}) | 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 ??() |
(none) | (none) | ||||
(true) (false) (atom 20) | |||||
(true) (false) (atom 23) | |||||
100 | 100 | ||||
100.5 | 100.5 | ||||
255 | 255 | ||||
Hello World | Hello World | ||||
[(none) (true) (false) (atom 20) 100.1 Nope (namespace) (function)] | |||||
[(none) (true) (false) (atom 23) 100.1 Nope (namespace) (function)] | |||||
(namespace) (namespace) | (namespace) (namespace) | ||||
len | len | ||||
2 | 2 | ||||
5 | 5 | ||||
3 | 3 | ||||
&& | |||||
(true) | |||||
(true) | |||||
(false) | |||||
(true) | |||||
(true) | |||||
(false) | |||||
|| | |||||
(false) | |||||
(true) | |||||
(false) | |||||
(true) | |||||
(true) | |||||
(true) | |||||
(false) | |||||
?? | |||||
30 | |||||
10 | |||||
hello | |||||
(none) |