@@ -11,6 +11,8 @@ X("+", l2_builtin_add) | |||
X("-", l2_builtin_sub) | |||
X("*", l2_builtin_mul) | |||
X("/", l2_builtin_div) | |||
X("==", l2_builtin_eq) | |||
X("!=", l2_builtin_neq) | |||
X("print", l2_builtin_print) | |||
X("len", l2_builtin_len) | |||
X("if", l2_builtin_if) |
@@ -127,6 +127,16 @@ static int is_numeric(int ch) { | |||
return ch >= '0' && ch <= '9'; | |||
} | |||
static int is_ident(int ch) { | |||
return !is_whitespace(ch) && ch != EOF && | |||
ch != '(' && ch != ')' && | |||
ch != '{' && ch != '}' && | |||
ch != '[' && ch != ']' && | |||
ch != '\'' && | |||
ch != ',' && ch != '.' && | |||
ch != ':' && ch != ';'; | |||
} | |||
static int skip_whitespace(struct l2_lexer *lexer) { | |||
int nl = 0; | |||
while (1) { | |||
@@ -413,25 +423,7 @@ static void read_ident(struct l2_lexer *lexer, struct l2_token *tok) { | |||
while (1) { | |||
int ch = peek_ch(lexer); | |||
if (is_whitespace(ch)) { | |||
dest[idx] = '\0'; | |||
return; | |||
} | |||
switch (ch) { | |||
case '(': | |||
case ')': | |||
case '{': | |||
case '}': | |||
case '[': | |||
case ']': | |||
case '\'': | |||
case ',': | |||
case '.': | |||
case ':': | |||
case '=': | |||
case ';': | |||
case EOF: | |||
if (!is_ident(ch)) { | |||
dest[idx] = '\0'; | |||
return; | |||
} | |||
@@ -563,11 +555,6 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
} | |||
break; | |||
case '=': | |||
read_ch(lexer); | |||
tok->v.flags = L2_TOK_EQUALS; | |||
break; | |||
case EOF: | |||
tok->v.flags = L2_TOK_EOF; | |||
break; | |||
@@ -578,14 +565,23 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
break; | |||
default: | |||
if ( | |||
is_numeric(ch) || | |||
(ch == '-' && is_numeric(peek_ch_n(lexer, 2)))) { | |||
read_number(lexer, tok); | |||
break; | |||
} | |||
{ | |||
int ch2 = peek_ch_n(lexer, 2); | |||
read_ident(lexer, tok); | |||
if ( | |||
is_numeric(ch) || | |||
(ch == '-' && is_numeric(ch2))) { | |||
read_number(lexer, tok); | |||
break; | |||
} | |||
tok->v.flags = L2_TOK_IDENT; | |||
read_ident(lexer, tok); | |||
if (l2_token_is_small(tok) && strcmp(tok->v.strbuf, "=") == 0) { | |||
tok->v.flags = L2_TOK_EQUALS; | |||
} | |||
} | |||
} | |||
} | |||
@@ -25,7 +25,9 @@ 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; | |||
} | |||
static int parse_expression( |
@@ -164,6 +164,60 @@ l2_word l2_builtin_div(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
return id; | |||
} | |||
l2_word l2_builtin_eq(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
if (argc < 2) { | |||
return vm->ktrue; | |||
} | |||
for (l2_word i = 1; i < argc; ++i) { | |||
if (argv[i - 1] == argv[i]) continue; | |||
struct l2_vm_value *a = &vm->values[argv[i - 1]]; | |||
struct l2_vm_value *b = &vm->values[argv[i]]; | |||
if (a->flags != b->flags) { | |||
return vm->kfalse; | |||
} | |||
enum l2_value_type typ = l2_vm_value_type(a); | |||
if (typ == L2_VAL_TYPE_ATOM) { | |||
if (a->atom != b->atom) { | |||
return vm->kfalse; | |||
} | |||
} else if (typ == L2_VAL_TYPE_REAL) { | |||
if (a->real != b->real) { | |||
return vm->kfalse; | |||
} | |||
} else if (typ == L2_VAL_TYPE_BUFFER) { | |||
if (a->buffer == NULL && b->buffer == NULL) continue; | |||
if (a->buffer == NULL || b->buffer == NULL) { | |||
return vm->kfalse; | |||
} | |||
if (a->buffer->len != b->buffer->len) { | |||
return vm->kfalse; | |||
} | |||
if (memcmp(a->buffer->data, b->buffer->data, a->buffer->len) != 0) { | |||
return vm->kfalse; | |||
} | |||
} else { | |||
return vm->kfalse; | |||
} | |||
} | |||
return vm->ktrue; | |||
} | |||
l2_word l2_builtin_neq(struct l2_vm *vm, l2_word argc, l2_word *argv) { | |||
l2_word ret_id = l2_builtin_eq(vm, argc, argv); | |||
if (ret_id == vm->ktrue) { | |||
return vm->kfalse; | |||
} else if (ret_id == vm->kfalse) { | |||
return vm->ktrue; | |||
} else { | |||
return ret_id; | |||
} | |||
} | |||
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) { |
@@ -196,19 +196,21 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) { | |||
#define Y(name, k) \ | |||
if (strcmp(#k, "knone") == 0) { \ | |||
id = 0; \ | |||
l2_vm_namespace_set(&vm->values[builtins], key, id); \ | |||
} else { \ | |||
id = alloc_val(vm); \ | |||
vm->values[id].flags = L2_VAL_TYPE_ATOM | L2_VAL_CONST; \ | |||
vm->values[id].atom = key; \ | |||
} \ | |||
vm->k = id; \ | |||
l2_vm_namespace_set(&vm->values[builtins], key++, id); | |||
key += 1; | |||
#define X(name, f) \ | |||
id = alloc_val(vm); \ | |||
vm->values[id].flags = L2_VAL_TYPE_CFUNCTION | L2_VAL_CONST; \ | |||
vm->values[id].cfunc = f; \ | |||
l2_vm_namespace_set(&vm->values[builtins], key++, id); | |||
#include "builtins.x.h" | |||
#undef Y | |||
#undef X | |||
} | |||