@@ -51,6 +51,16 @@ enum l2_opcode { | |||
*/ | |||
L2_OP_FUNC_CALL, | |||
/* | |||
* Call an infix function | |||
* Pop <rhs> | |||
* Pop <func> | |||
* Pop <lhs> | |||
* Call <func> | |||
* (Before returning, the function will push a return value onto the stack) | |||
*/ | |||
L2_OP_FUNC_CALL_INFIX, | |||
/* | |||
* Jump relative; rjmp <count> | |||
* Jump <count> words forwards |
@@ -51,5 +51,6 @@ void l2_gen_stack_frame_set_copy(struct l2_generator *gen, char *ident); | |||
void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident); | |||
void l2_gen_stack_frame_replace_copy(struct l2_generator *gen, char *ident); | |||
void l2_gen_func_call(struct l2_generator *gen, l2_word argc); | |||
void l2_gen_func_call_infix(struct l2_generator *gen); | |||
#endif |
@@ -221,3 +221,7 @@ void l2_gen_func_call(struct l2_generator *gen, l2_word argc) { | |||
put(gen, L2_OP_FUNC_CALL); | |||
put(gen, argc); | |||
} | |||
void l2_gen_func_call_infix(struct l2_generator *gen) { | |||
put(gen, L2_OP_FUNC_CALL_INFIX); | |||
} |
@@ -98,6 +98,11 @@ static int peek_ch(struct l2_lexer *lexer) { | |||
return ch; | |||
} | |||
static int peek_ch_n(struct l2_lexer *lexer, int n) { | |||
int ch = l2_bufio_peek(&lexer->reader, n); | |||
return ch; | |||
} | |||
static int read_ch(struct l2_lexer *lexer) { | |||
int ch = l2_bufio_get(&lexer->reader); | |||
lexer->ch += 1; | |||
@@ -568,7 +573,9 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
break; | |||
default: | |||
if (is_numeric(ch) || ch == '-') { | |||
if ( | |||
is_numeric(ch) || | |||
(ch == '-' && is_numeric(peek_ch_n(lexer, 2)))) { | |||
read_number(lexer, tok); | |||
break; | |||
} |
@@ -11,6 +11,23 @@ static int tok_is_end(struct l2_token *tok) { | |||
kind == L2_TOK_EOL; | |||
} | |||
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; | |||
} | |||
return | |||
(str[0] == '$' && str[1] != '\0') || | |||
strcmp(str, "+") == 0 || | |||
strcmp(str, "-") == 0 || | |||
strcmp(str, "*") == 0 || | |||
strcmp(str, "/") == 0; | |||
} | |||
static int parse_expression( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | |||
@@ -85,9 +102,8 @@ static int parse_function_literal_impl( | |||
// '{' and EOL already skipped by parse_object_or_function_literal | |||
// The arguments array will be at the top of the stack | |||
char *ident = malloc(2); | |||
ident[0] = '$'; ident[1] = '\0'; | |||
l2_gen_stack_frame_set(gen, &ident); | |||
char *ident = "$"; | |||
l2_gen_stack_frame_set_copy(gen, ident); | |||
int first = 1; | |||
while (1) { | |||
@@ -474,6 +490,19 @@ static int parse_expression( | |||
return -1; | |||
} | |||
if (tok_is_infix(l2_lexer_peek(lexer, 1))) { | |||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
l2_gen_func_call_infix(gen); | |||
} | |||
if (!tok_is_end(l2_lexer_peek(lexer, 1))) { | |||
if (parse_func_call_after_base(lexer, gen, err) < 0) { | |||
return -1; |
@@ -138,6 +138,10 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||
printf("FUNC_CALL %08x\n", ops[(*ptr)++]); | |||
return; | |||
case L2_OP_FUNC_CALL_INFIX: | |||
printf("FUNC_CALL_INFIX\n"); | |||
return; | |||
case L2_OP_RJMP: | |||
printf("RJMP %08x\n", ops[(*ptr)++]); | |||
return; |
@@ -319,7 +319,6 @@ void l2_vm_step(struct l2_vm *vm) { | |||
struct l2_vm_value *func = &vm->values[func_id]; | |||
l2_word stack_base = vm->sptr; | |||
enum l2_value_type typ = l2_vm_value_type(func); | |||
// C functions are called differently from language functions | |||
@@ -568,6 +567,56 @@ void l2_vm_step(struct l2_vm *vm) { | |||
} | |||
break; | |||
case L2_OP_FUNC_CALL_INFIX: | |||
{ | |||
l2_word rhs = vm->stack[--vm->sptr]; | |||
l2_word func_id = vm->stack[--vm->sptr]; | |||
l2_word lhs = vm->stack[--vm->sptr]; | |||
struct l2_vm_value *func = &vm->values[func_id]; | |||
l2_word stack_base = vm->sptr; | |||
enum l2_value_type typ = l2_vm_value_type(func); | |||
// C functions are called differently from language functions | |||
if (typ == L2_VAL_TYPE_CFUNCTION) { | |||
l2_word argv[] = { lhs, rhs }; | |||
vm->stack[vm->sptr++] = func->cfunc(vm, 2, argv); | |||
break; | |||
} | |||
// Don't interpret a non-function as a function | |||
if (typ != L2_VAL_TYPE_FUNCTION) { | |||
vm->stack[vm->sptr++] = l2_vm_error(vm, "Attempt to call non-function"); | |||
break; | |||
} | |||
l2_word arr_id = alloc_val(vm); | |||
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY; | |||
vm->values[arr_id].array = malloc( | |||
sizeof(struct l2_vm_array) + sizeof(l2_word) * 2); | |||
struct l2_vm_array *arr = vm->values[arr_id].array; | |||
arr->len = 2; | |||
arr->size = 2; | |||
arr->data[0] = lhs; | |||
arr->data[1] = rhs; | |||
vm->stack[vm->sptr++] = arr_id; | |||
l2_word ns_id = alloc_val(vm); | |||
func = &vm->values[func_id]; // func might be stale after alloc | |||
vm->values[ns_id].extra.ns_parent = func->func.ns; | |||
vm->values[ns_id].ns = NULL; | |||
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | |||
vm->fstack[vm->fsptr].ns = ns_id; | |||
vm->fstack[vm->fsptr].retptr = vm->iptr; | |||
vm->fstack[vm->fsptr].sptr = stack_base; | |||
vm->fsptr += 1; | |||
vm->iptr = func->func.pos; | |||
} | |||
break; | |||
case L2_OP_HALT: | |||
vm->halted = 1; | |||
break; |