@@ -59,9 +59,10 @@ struct l2_token { | |||
#define l2_token_get_kind(tok) ((enum l2_token_kind)((tok)->v.flags & ~(1 << 7))) | |||
#define l2_token_get_name(tok) (l2_token_kind_name(l2_token_get_kind(tok))) | |||
#define l2_token_is_small(tok) ((tok)->v.flags & (1 << 7)) | |||
#define l2_token_is_small(tok) ((tok)->v.flags & L2_TOK_SMALL) | |||
void l2_token_free(struct l2_token *tok); | |||
struct l2_token_value l2_token_extract_val(struct l2_token *tok); | |||
const char *l2_token_get_str(struct l2_token *tok); | |||
void l2_token_print(struct l2_token *tok, struct l2_io_writer *w); | |||
struct l2_lexer { |
@@ -90,6 +90,14 @@ struct l2_token_value l2_token_extract_val(struct l2_token *tok) { | |||
return v; | |||
} | |||
const char *l2_token_get_str(struct l2_token *tok) { | |||
if (l2_token_is_small(tok)) { | |||
return tok->v.strbuf; | |||
} else { | |||
return tok->v.str; | |||
} | |||
} | |||
void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) { | |||
lexer->toks[0].v.flags = L2_TOK_EOF, | |||
lexer->tokidx = 0; |
@@ -13,12 +13,7 @@ static int tok_is_end(struct l2_token *tok) { | |||
static int tok_is_infix(struct l2_token *tok) { | |||
if (l2_token_get_kind(tok) != L2_TOK_IDENT) return 0; | |||
char *str; | |||
if (l2_token_is_small(tok)) { | |||
str = tok->v.strbuf; | |||
} else { | |||
str = tok->v.str; | |||
} | |||
const char *str = l2_token_get_str(tok); | |||
return | |||
(str[0] == '$' && str[1] != '\0') || | |||
@@ -58,7 +53,7 @@ static int parse_object_literal( | |||
return -1; | |||
} | |||
l2_trace("key: '%s'", tok->v.str); | |||
l2_trace("key: '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value key = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // ident | |||
@@ -258,11 +253,7 @@ static int parse_arg_level_expression_base( | |||
l2_lexer_consume(lexer); // ')' | |||
} else if (l2_token_get_kind(tok) == L2_TOK_IDENT) { | |||
l2_trace_scope("ident"); | |||
if (l2_token_is_small(tok)) { | |||
l2_trace("ident '%s'", tok->v.strbuf); | |||
} else { | |||
l2_trace("ident '%s'", tok->v.str); | |||
} | |||
l2_trace("ident '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value ident = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // ident | |||
@@ -280,7 +271,7 @@ static int parse_arg_level_expression_base( | |||
l2_gen_number(gen, number); | |||
} else if (l2_token_get_kind(tok) == L2_TOK_STRING) { | |||
l2_trace_scope("string literal"); | |||
l2_trace("string '%s'", tok->v.str); | |||
l2_trace("string '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value str = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // string | |||
@@ -293,7 +284,7 @@ static int parse_arg_level_expression_base( | |||
l2_token_get_kind(tok) == L2_TOK_QUOT && | |||
l2_token_get_kind(tok2) == L2_TOK_IDENT) { | |||
l2_trace_scope("atom literal"); | |||
l2_trace("atom '%s'", tok->v.str); | |||
l2_trace("atom '%s'", l2_token_get_str(tok2)); | |||
struct l2_token_value ident = l2_token_extract_val(tok2); | |||
l2_lexer_consume(lexer); // "'" | |||
l2_lexer_consume(lexer); // ident | |||
@@ -334,10 +325,18 @@ static int parse_func_call_after_base( | |||
// so we need to parse the operator, then the rhs | |||
// Operator | |||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
int ret = parse_arg_level_expression(lexer, gen, err); | |||
if (ret < 0) { | |||
return -1; | |||
} | |||
// If the operator wasn't just the one base expression, | |||
// abort; we're not doing the infix call | |||
if (ret == 1) { | |||
argc += 1; | |||
break; | |||
} | |||
// RHS | |||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
@@ -377,6 +376,7 @@ static int parse_arg_level_expression( | |||
return -1; | |||
} | |||
int ret = 0; | |||
while (1) { | |||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); | |||
@@ -407,11 +407,7 @@ static int parse_arg_level_expression( | |||
l2_token_get_kind(tok2) == L2_TOK_IDENT && | |||
l2_token_get_kind(tok3) == L2_TOK_EQUALS) { | |||
l2_trace_scope("namespace assign"); | |||
if (l2_token_is_small(tok2)) { | |||
l2_trace("ident '%s'", tok2->v.strbuf); | |||
} else { | |||
l2_trace("ident '%s'", tok2->v.str); | |||
} | |||
l2_trace("ident '%s'", l2_token_get_str(tok2)); | |||
struct l2_token_value ident = l2_token_extract_val(tok2); | |||
l2_lexer_consume(lexer); // '.' | |||
l2_lexer_consume(lexer); // ident | |||
@@ -432,11 +428,7 @@ static int parse_arg_level_expression( | |||
l2_token_get_kind(tok) == L2_TOK_PERIOD && | |||
l2_token_get_kind(tok2) == L2_TOK_IDENT) { | |||
l2_trace_scope("namespace lookup"); | |||
if (l2_token_is_small(tok2)) { | |||
l2_trace("ident '%s'", tok2->v.strbuf); | |||
} else { | |||
l2_trace("ident '%s'", tok2->v.str); | |||
} | |||
l2_trace("ident '%s'", l2_token_get_str(tok2)); | |||
struct l2_token_value ident = l2_token_extract_val(tok2); | |||
l2_lexer_consume(lexer); // '.' | |||
l2_lexer_consume(lexer); // ident | |||
@@ -498,9 +490,11 @@ static int parse_arg_level_expression( | |||
} else { | |||
break; | |||
} | |||
ret = 1; | |||
} | |||
return 0; | |||
return ret; | |||
} | |||
static int parse_expression( | |||
@@ -513,11 +507,7 @@ static int parse_expression( | |||
l2_token_get_kind(tok) == L2_TOK_IDENT && | |||
l2_token_get_kind(tok2) == L2_TOK_COLON_EQ) { | |||
l2_trace_scope("assign expression"); | |||
if (l2_token_is_small(tok)) { | |||
l2_trace("ident '%s'", tok->v.strbuf); | |||
} else { | |||
l2_trace("ident '%s'", tok->v.str); | |||
} | |||
l2_trace("ident '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value ident = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // ident | |||
l2_lexer_consume(lexer); // := | |||
@@ -536,11 +526,7 @@ static int parse_expression( | |||
l2_token_get_kind(tok) == L2_TOK_IDENT && | |||
l2_token_get_kind(tok2) == L2_TOK_EQUALS) { | |||
l2_trace_scope("replacement assign expression"); | |||
if (l2_token_is_small(tok)) { | |||
l2_trace("ident '%s'", tok->v.strbuf); | |||
} else { | |||
l2_trace("ident '%s'", tok->v.str); | |||
} | |||
l2_trace("ident '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value ident = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // ident | |||
l2_lexer_consume(lexer); // = |
@@ -66,113 +66,39 @@ static void print_val(struct l2_vm *vm, struct l2_io_writer *out, struct l2_vm_v | |||
} | |||
} | |||
l2_word l2_builtin_add(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 1) { | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = 0; | |||
return id; | |||
} | |||
struct l2_vm_value *val = &vm->values[argv[0]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
double sum = val->real; | |||
for (l2_word i = 1; i < argc; ++i) { | |||
val = &vm->values[argv[i]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
sum += val->real; | |||
} | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = sum; | |||
return id; | |||
} | |||
l2_word l2_builtin_sub(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 1) { | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = 0; | |||
return id; | |||
} | |||
struct l2_vm_value *val = &vm->values[argv[0]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
double sum = val->real; | |||
for (l2_word i = 1; i < argc; ++i) { | |||
val = &vm->values[argv[i]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
sum -= val->real; | |||
} | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = sum; | |||
return id; | |||
} | |||
l2_word l2_builtin_mul(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 1) { | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = 1; | |||
return id; | |||
} | |||
struct l2_vm_value *val = &vm->values[argv[0]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
double sum = val->real; | |||
for (l2_word i = 1; i < argc; ++i) { | |||
val = &vm->values[argv[i]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
sum *= val->real; | |||
} | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = sum; | |||
return id; | |||
} | |||
l2_word l2_builtin_div(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 1) { | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = 1; | |||
return id; | |||
} | |||
struct l2_vm_value *val = &vm->values[argv[0]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
double sum = val->real; | |||
for (l2_word i = 1; i < argc; ++i) { | |||
val = &vm->values[argv[i]]; | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { | |||
return l2_vm_type_error(vm, val); | |||
} | |||
sum /= val->real; | |||
} | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||
vm->values[id].real = sum; | |||
return id; | |||
#define X(name, identity, op) \ | |||
l2_word name(struct l2_vm *vm, l2_word argc, l2_word *argv) { \ | |||
if (argc == 0) { \ | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \ | |||
vm->values[id].real = identity; \ | |||
return id; \ | |||
} \ | |||
struct l2_vm_value *first = &vm->values[argv[0]]; \ | |||
if (l2_value_get_type(first) != L2_VAL_TYPE_REAL) { \ | |||
return l2_vm_type_error(vm, first); \ | |||
} \ | |||
if (argc == 1) { \ | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \ | |||
vm->values[id].real = identity op first->real; \ | |||
return id; \ | |||
} \ | |||
double sum = first->real; \ | |||
for (l2_word i = 1; i < argc; ++i) { \ | |||
struct l2_vm_value *val = &vm->values[argv[i]]; \ | |||
if (l2_value_get_type(val) != L2_VAL_TYPE_REAL) { \ | |||
return l2_vm_type_error(vm, val); \ | |||
} \ | |||
sum = sum op val->real; \ | |||
} \ | |||
l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); \ | |||
vm->values[id].real = sum; \ | |||
return id; \ | |||
} | |||
X(l2_builtin_add, 0, +) | |||
X(l2_builtin_sub, 0, -) | |||
X(l2_builtin_mul, 1, *) | |||
X(l2_builtin_div, 1, /) | |||
#undef X | |||
l2_word l2_builtin_eq(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 2) { |
@@ -0,0 +1,73 @@ | |||
print "+" | |||
print +() | |||
print +(10) | |||
print 10 + 20 | |||
print (+ 10 20 30) | |||
print "\n-" | |||
print -() -(10) | |||
print 10 - 20 | |||
print (- 10 20 30) | |||
print "\n/" | |||
print /() /(10) | |||
print 10 / 2 | |||
print (/ 10 2 2) | |||
print "\n*" | |||
print *() *(10) | |||
print 10 * 2 | |||
print (* 10 20 30) | |||
print "\n==" | |||
print ==() ==(10) | |||
print 10 == 10 20 == 10 | |||
print (== 10 20 30) | |||
print (== 'a 'a 'a) | |||
print "\n!=" | |||
print !=() !=(10) | |||
print 10 != 10 20 != 10 | |||
print (!= 10 20 30) | |||
print (!= 'a 'a 'a) | |||
print "\n>" | |||
print 10 > 20 | |||
print 20 > 10 | |||
print 10 > 10 | |||
print (> 1 10 100 200) | |||
print "\n>=" | |||
print 10 >= 20 | |||
print 20 >= 10 | |||
print 10 >= 10 | |||
print (>= 1 10 100 200) | |||
print "\n<" | |||
print 10 < 20 | |||
print 20 < 10 | |||
print 10 < 10 | |||
print (< 1 10 100 200) | |||
print "\n<=" | |||
print 10 <= 20 | |||
print 20 <= 10 | |||
print 10 <= 10 | |||
print (<= 1 10 100 200) | |||
print "\nprint" | |||
print none | |||
print 'true 'false 'hello | |||
print 100 | |||
print 100.5 | |||
print 0xff | |||
print "Hello World" | |||
print [none 'true 'false 'hello 100.1 "Nope" {} {0}] | |||
print {} {a: 10} | |||
print "\nlen" | |||
print (len 10) | |||
print (len []) | |||
print (len [10 20]) | |||
print (len "Hello") | |||
print (len {a: 10; b: 20; c: 30}) |
@@ -0,0 +1,73 @@ | |||
+ | |||
0 | |||
10 | |||
30 | |||
60 | |||
- | |||
0 -10 | |||
-10 | |||
-40 | |||
/ | |||
1 0.1 | |||
5 | |||
2.5 | |||
* | |||
1 10 | |||
20 | |||
6000 | |||
== | |||
(true) (true) | |||
(true) (false) | |||
(false) | |||
(true) | |||
!= | |||
(false) (false) | |||
(false) (true) | |||
(true) | |||
(false) | |||
> | |||
(false) | |||
(true) | |||
(false) | |||
(false) | |||
>= | |||
(false) | |||
(true) | |||
(true) | |||
(false) | |||
< | |||
(true) | |||
(false) | |||
(false) | |||
(true) | |||
<= | |||
(true) | |||
(false) | |||
(true) | |||
(true) | |||
(none) | |||
(true) (false) (atom 20) | |||
100 | |||
100.5 | |||
255 | |||
Hello World | |||
[(none) (true) (false) (atom 20) 100.1 Nope (namespace) (function)] | |||
(namespace) (namespace) | |||
len | |||
0 | |||
0 | |||
2 | |||
5 | |||
3 |
@@ -131,6 +131,7 @@ describe(exaples) { | |||
check("arrays.l2"); | |||
check("functions.l2"); | |||
check("dynamic-lookups.l2"); | |||
check("builtins.l2"); | |||
if (error_message != NULL) { | |||
free(error_message); |