@@ -153,13 +153,21 @@ enum l2_opcode { | |||
L2_OP_NAMESPACE_SET, | |||
/* | |||
* Set a namespace's name to a value. | |||
* Lookup a value from a namespace. | |||
* Pop <key> | |||
* Pop <ns> | |||
* Push <ns[<key>]> | |||
*/ | |||
L2_OP_NAMESPACE_LOOKUP, | |||
/* | |||
* Look up a value from an array. | |||
* Pop <key> | |||
* Pop <arr> | |||
* Push <arr[<key>]> | |||
*/ | |||
L2_OP_DIRECT_ARRAY_LOOKUP, | |||
/* | |||
* Halt execution. | |||
*/ |
@@ -35,6 +35,7 @@ void l2_gen_function(struct l2_generator *gen, l2_word pos); | |||
void l2_gen_namespace(struct l2_generator *gen); | |||
void l2_gen_namespace_set(struct l2_generator *gen, char **ident); | |||
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); | |||
void l2_gen_direct_array_lookup(struct l2_generator *gen, int number); | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident); | |||
void l2_gen_func_call(struct l2_generator *gen); | |||
@@ -13,6 +13,7 @@ enum l2_token_kind { | |||
L2_TOK_QUOT, | |||
L2_TOK_COMMA, | |||
L2_TOK_PERIOD, | |||
L2_TOK_DOT_NUMBER, | |||
L2_TOK_COLON, | |||
L2_TOK_COLON_EQ, | |||
L2_TOK_EOL, | |||
@@ -33,6 +34,7 @@ struct l2_token { | |||
union { | |||
char *str; | |||
double num; | |||
int integer; | |||
} v; | |||
}; | |||
@@ -140,6 +140,12 @@ void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { | |||
put(gen, L2_OP_NAMESPACE_LOOKUP); | |||
} | |||
void l2_gen_direct_array_lookup(struct l2_generator *gen, int number) { | |||
put(gen, L2_OP_PUSH); | |||
put(gen, number); | |||
put(gen, L2_OP_DIRECT_ARRAY_LOOKUP); | |||
} | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | |||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
put(gen, L2_OP_PUSH); |
@@ -61,6 +61,8 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
return "comma"; | |||
case L2_TOK_PERIOD: | |||
return "period"; | |||
case L2_TOK_DOT_NUMBER: | |||
return "dot-number"; | |||
case L2_TOK_COLON: | |||
return "colon"; | |||
case L2_TOK_COLON_EQ: | |||
@@ -122,9 +124,13 @@ static int is_whitespace(int ch) { | |||
return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'; | |||
} | |||
static int is_numeric(int ch) { | |||
return ch >= '0' && ch <= '9'; | |||
} | |||
static int skip_whitespace(struct l2_lexer *lexer) { | |||
int nl = 0; | |||
while (is_whitespace(l2_bufio_peek(&lexer->reader, 1))) { | |||
while (is_whitespace(peek_ch(lexer))) { | |||
int ch = read_ch(lexer); | |||
if (ch == '\n') { | |||
nl = 1; | |||
@@ -134,6 +140,24 @@ static int skip_whitespace(struct l2_lexer *lexer) { | |||
return nl; | |||
} | |||
static int read_integer(struct l2_lexer *lexer) { | |||
char buffer[16]; // Should be enough | |||
int len = 0; | |||
while (len < sizeof(buffer) - 1 && is_numeric(peek_ch(lexer))) { | |||
buffer[len++] = read_ch(lexer); | |||
} | |||
int num = 0; | |||
int power = 1; | |||
for (int i = len - 1; i >= 0; --i) { | |||
num += (buffer[i] - '0') * power; | |||
power *= 10; | |||
} | |||
return num; | |||
} | |||
static void read_string(struct l2_lexer *lexer, struct l2_token *tok) { | |||
tok->kind = L2_TOK_STRING; | |||
tok->v.str = malloc(16); | |||
@@ -316,7 +340,12 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
case '.': | |||
read_ch(lexer); | |||
tok->kind = L2_TOK_PERIOD; | |||
if (is_numeric(peek_ch(lexer))) { | |||
tok->kind = L2_TOK_DOT_NUMBER; | |||
tok->v.integer = read_integer(lexer); | |||
} else { | |||
tok->kind = L2_TOK_PERIOD; | |||
} | |||
break; | |||
case ':': |
@@ -71,6 +71,11 @@ static int parse_function_literal_impl( | |||
l2_trace_scope("function literal"); | |||
// '{' 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_assignment(gen, &ident); | |||
int first = 1; | |||
while (1) { | |||
if (l2_lexer_peek(lexer, 1)->kind == L2_TOK_CLOSE_BRACE) { | |||
@@ -184,6 +189,8 @@ static int parse_arg_level_expression_base( | |||
l2_token_kind_name(tok->kind)); | |||
return -1; | |||
} | |||
l2_lexer_consume(lexer); // ')' | |||
} else if (tok->kind == L2_TOK_IDENT) { | |||
l2_trace_scope("ident"); | |||
l2_trace("ident '%s'", tok->v.str); | |||
@@ -245,13 +252,19 @@ static int parse_arg_level_expression( | |||
l2_gen_push(gen, 0); | |||
l2_gen_func_call(gen); | |||
} else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | |||
l2_trace_scope("lookup"); | |||
l2_trace_scope("namespace lookup"); | |||
l2_trace("ident '%s'", tok2->v.str); | |||
char *ident = l2_token_extract_str(tok2); | |||
l2_lexer_consume(lexer); // '.' | |||
l2_lexer_consume(lexer); // ident | |||
l2_gen_namespace_lookup(gen, &ident); | |||
} else if (tok->kind == L2_TOK_DOT_NUMBER) { | |||
l2_trace_scope("direct array lookup"); | |||
int number = tok->v.integer; | |||
l2_lexer_consume(lexer); // dot-number | |||
l2_gen_direct_array_lookup(gen, number); | |||
} else { | |||
break; | |||
} |
@@ -197,6 +197,14 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||
printf("NAMESPACE_SET\n"); | |||
break; | |||
case L2_OP_NAMESPACE_LOOKUP: | |||
printf("NAMESPACE_LOOKUP\n"); | |||
break; | |||
case L2_OP_DIRECT_ARRAY_LOOKUP: | |||
printf("DIRECT_ARRAY_LOOKUP\n"); | |||
break; | |||
case L2_OP_HALT: | |||
printf("HALT\n"); | |||
break; |
@@ -405,6 +405,15 @@ void l2_vm_step(struct l2_vm *vm) { | |||
} | |||
break; | |||
case L2_OP_DIRECT_ARRAY_LOOKUP: | |||
{ | |||
l2_word key = vm->stack[--vm->sptr]; | |||
l2_word arr = vm->stack[--vm->sptr]; | |||
// TODO: Error if out of bounds or incorrect type | |||
vm->stack[vm->sptr++] = vm->values[arr].array->data[key]; | |||
break; | |||
} | |||
case L2_OP_HALT: | |||
break; | |||
} |