X("-", l2_builtin_sub) | X("-", l2_builtin_sub) | ||||
X("*", l2_builtin_mul) | X("*", l2_builtin_mul) | ||||
X("/", l2_builtin_div) | X("/", l2_builtin_div) | ||||
X("==", l2_builtin_eq) | |||||
X("!=", l2_builtin_neq) | |||||
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) |
return ch >= '0' && ch <= '9'; | 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) { | static int skip_whitespace(struct l2_lexer *lexer) { | ||||
int nl = 0; | int nl = 0; | ||||
while (1) { | while (1) { | ||||
while (1) { | while (1) { | ||||
int ch = peek_ch(lexer); | 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'; | dest[idx] = '\0'; | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case '=': | |||||
read_ch(lexer); | |||||
tok->v.flags = L2_TOK_EQUALS; | |||||
break; | |||||
case EOF: | case EOF: | ||||
tok->v.flags = L2_TOK_EOF; | tok->v.flags = L2_TOK_EOF; | ||||
break; | break; | ||||
break; | break; | ||||
default: | 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; | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
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( |
return id; | 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) { | 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) { |
#define Y(name, k) \ | #define Y(name, k) \ | ||||
if (strcmp(#k, "knone") == 0) { \ | if (strcmp(#k, "knone") == 0) { \ | ||||
id = 0; \ | id = 0; \ | ||||
l2_vm_namespace_set(&vm->values[builtins], key, id); \ | |||||
} else { \ | } else { \ | ||||
id = alloc_val(vm); \ | id = alloc_val(vm); \ | ||||
vm->values[id].flags = L2_VAL_TYPE_ATOM | L2_VAL_CONST; \ | vm->values[id].flags = L2_VAL_TYPE_ATOM | L2_VAL_CONST; \ | ||||
vm->values[id].atom = key; \ | vm->values[id].atom = key; \ | ||||
} \ | } \ | ||||
vm->k = id; \ | vm->k = id; \ | ||||
l2_vm_namespace_set(&vm->values[builtins], key++, id); | |||||
key += 1; | |||||
#define X(name, f) \ | #define X(name, f) \ | ||||
id = alloc_val(vm); \ | id = alloc_val(vm); \ | ||||
vm->values[id].flags = L2_VAL_TYPE_CFUNCTION | L2_VAL_CONST; \ | vm->values[id].flags = L2_VAL_TYPE_CFUNCTION | L2_VAL_CONST; \ | ||||
vm->values[id].cfunc = f; \ | vm->values[id].cfunc = f; \ | ||||
l2_vm_namespace_set(&vm->values[builtins], key++, id); | l2_vm_namespace_set(&vm->values[builtins], key++, id); | ||||
#include "builtins.x.h" | #include "builtins.x.h" | ||||
#undef Y | |||||
#undef X | #undef X | ||||
} | } | ||||