Browse Source

infix functions

master
Martin Dørum 3 years ago
parent
commit
8c10cec784
7 changed files with 109 additions and 5 deletions
  1. 10
    0
      include/lang2/bytecode.h
  2. 1
    0
      include/lang2/gen/gen.h
  3. 4
    0
      lib/gen/gen.c
  4. 8
    1
      lib/parse/lex.c
  5. 32
    3
      lib/parse/parse.c
  6. 4
    0
      lib/vm/print.c
  7. 50
    1
      lib/vm/vm.c

+ 10
- 0
include/lang2/bytecode.h View File

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

+ 1
- 0
include/lang2/gen/gen.h View File

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

+ 4
- 0
lib/gen/gen.c View File

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

+ 8
- 1
lib/parse/lex.c View File

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

+ 32
- 3
lib/parse/parse.c View File

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

+ 4
- 0
lib/vm/print.c View File

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

+ 50
- 1
lib/vm/vm.c View File

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

Loading…
Cancel
Save