| @@ -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 | |||
| } | |||