*/ | */ | ||||
L2_OP_FUNC_CALL, | 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 relative; rjmp <count> | ||||
* Jump <count> words forwards | * Jump <count> words forwards |
void l2_gen_stack_frame_replace(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_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(struct l2_generator *gen, l2_word argc); | ||||
void l2_gen_func_call_infix(struct l2_generator *gen); | |||||
#endif | #endif |
put(gen, L2_OP_FUNC_CALL); | put(gen, L2_OP_FUNC_CALL); | ||||
put(gen, argc); | put(gen, argc); | ||||
} | } | ||||
void l2_gen_func_call_infix(struct l2_generator *gen) { | |||||
put(gen, L2_OP_FUNC_CALL_INFIX); | |||||
} |
return ch; | 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) { | static int read_ch(struct l2_lexer *lexer) { | ||||
int ch = l2_bufio_get(&lexer->reader); | int ch = l2_bufio_get(&lexer->reader); | ||||
lexer->ch += 1; | lexer->ch += 1; | ||||
break; | break; | ||||
default: | default: | ||||
if (is_numeric(ch) || ch == '-') { | |||||
if ( | |||||
is_numeric(ch) || | |||||
(ch == '-' && is_numeric(peek_ch_n(lexer, 2)))) { | |||||
read_number(lexer, tok); | read_number(lexer, tok); | ||||
break; | break; | ||||
} | } |
kind == L2_TOK_EOL; | 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( | static int parse_expression( | ||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | ||||
// '{' and EOL already skipped by parse_object_or_function_literal | // '{' and EOL already skipped by parse_object_or_function_literal | ||||
// The arguments array will be at the top of the stack | // 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; | int first = 1; | ||||
while (1) { | while (1) { | ||||
return -1; | 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 (!tok_is_end(l2_lexer_peek(lexer, 1))) { | ||||
if (parse_func_call_after_base(lexer, gen, err) < 0) { | if (parse_func_call_after_base(lexer, gen, err) < 0) { | ||||
return -1; | return -1; |
printf("FUNC_CALL %08x\n", ops[(*ptr)++]); | printf("FUNC_CALL %08x\n", ops[(*ptr)++]); | ||||
return; | return; | ||||
case L2_OP_FUNC_CALL_INFIX: | |||||
printf("FUNC_CALL_INFIX\n"); | |||||
return; | |||||
case L2_OP_RJMP: | case L2_OP_RJMP: | ||||
printf("RJMP %08x\n", ops[(*ptr)++]); | printf("RJMP %08x\n", ops[(*ptr)++]); | ||||
return; | return; |
struct l2_vm_value *func = &vm->values[func_id]; | struct l2_vm_value *func = &vm->values[func_id]; | ||||
l2_word stack_base = vm->sptr; | l2_word stack_base = vm->sptr; | ||||
enum l2_value_type typ = l2_vm_value_type(func); | enum l2_value_type typ = l2_vm_value_type(func); | ||||
// C functions are called differently from language functions | // C functions are called differently from language functions | ||||
} | } | ||||
break; | 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: | case L2_OP_HALT: | ||||
vm->halted = 1; | vm->halted = 1; | ||||
break; | break; |