L2_OP_NAMESPACE_SET, | L2_OP_NAMESPACE_SET, | ||||
/* | /* | ||||
* Set a namespace's name to a value. | |||||
* Lookup a value from a namespace. | |||||
* Pop <key> | * Pop <key> | ||||
* Pop <ns> | * Pop <ns> | ||||
* Push <ns[<key>]> | * Push <ns[<key>]> | ||||
*/ | */ | ||||
L2_OP_NAMESPACE_LOOKUP, | 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. | * Halt execution. | ||||
*/ | */ |
void l2_gen_namespace(struct l2_generator *gen); | void l2_gen_namespace(struct l2_generator *gen); | ||||
void l2_gen_namespace_set(struct l2_generator *gen, char **ident); | 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_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_stack_frame_lookup(struct l2_generator *gen, char **ident); | ||||
void l2_gen_func_call(struct l2_generator *gen); | void l2_gen_func_call(struct l2_generator *gen); | ||||
L2_TOK_QUOT, | L2_TOK_QUOT, | ||||
L2_TOK_COMMA, | L2_TOK_COMMA, | ||||
L2_TOK_PERIOD, | L2_TOK_PERIOD, | ||||
L2_TOK_DOT_NUMBER, | |||||
L2_TOK_COLON, | L2_TOK_COLON, | ||||
L2_TOK_COLON_EQ, | L2_TOK_COLON_EQ, | ||||
L2_TOK_EOL, | L2_TOK_EOL, | ||||
union { | union { | ||||
char *str; | char *str; | ||||
double num; | double num; | ||||
int integer; | |||||
} v; | } v; | ||||
}; | }; | ||||
put(gen, L2_OP_NAMESPACE_LOOKUP); | 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) { | void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); |
return "comma"; | return "comma"; | ||||
case L2_TOK_PERIOD: | case L2_TOK_PERIOD: | ||||
return "period"; | return "period"; | ||||
case L2_TOK_DOT_NUMBER: | |||||
return "dot-number"; | |||||
case L2_TOK_COLON: | case L2_TOK_COLON: | ||||
return "colon"; | return "colon"; | ||||
case L2_TOK_COLON_EQ: | case L2_TOK_COLON_EQ: | ||||
return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'; | 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) { | static int skip_whitespace(struct l2_lexer *lexer) { | ||||
int nl = 0; | int nl = 0; | ||||
while (is_whitespace(l2_bufio_peek(&lexer->reader, 1))) { | |||||
while (is_whitespace(peek_ch(lexer))) { | |||||
int ch = read_ch(lexer); | int ch = read_ch(lexer); | ||||
if (ch == '\n') { | if (ch == '\n') { | ||||
nl = 1; | nl = 1; | ||||
return nl; | 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) { | static void read_string(struct l2_lexer *lexer, struct l2_token *tok) { | ||||
tok->kind = L2_TOK_STRING; | tok->kind = L2_TOK_STRING; | ||||
tok->v.str = malloc(16); | tok->v.str = malloc(16); | ||||
case '.': | case '.': | ||||
read_ch(lexer); | 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; | break; | ||||
case ':': | case ':': |
l2_trace_scope("function literal"); | l2_trace_scope("function literal"); | ||||
// '{' 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 | |||||
char *ident = malloc(2); | |||||
ident[0] = '$'; ident[1] = '\0'; | |||||
l2_gen_assignment(gen, &ident); | |||||
int first = 1; | int first = 1; | ||||
while (1) { | while (1) { | ||||
if (l2_lexer_peek(lexer, 1)->kind == L2_TOK_CLOSE_BRACE) { | if (l2_lexer_peek(lexer, 1)->kind == L2_TOK_CLOSE_BRACE) { | ||||
l2_token_kind_name(tok->kind)); | l2_token_kind_name(tok->kind)); | ||||
return -1; | return -1; | ||||
} | } | ||||
l2_lexer_consume(lexer); // ')' | |||||
} else if (tok->kind == L2_TOK_IDENT) { | } else if (tok->kind == L2_TOK_IDENT) { | ||||
l2_trace_scope("ident"); | l2_trace_scope("ident"); | ||||
l2_trace("ident '%s'", tok->v.str); | l2_trace("ident '%s'", tok->v.str); | ||||
l2_gen_push(gen, 0); | l2_gen_push(gen, 0); | ||||
l2_gen_func_call(gen); | l2_gen_func_call(gen); | ||||
} else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | } 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); | l2_trace("ident '%s'", tok2->v.str); | ||||
char *ident = l2_token_extract_str(tok2); | char *ident = l2_token_extract_str(tok2); | ||||
l2_lexer_consume(lexer); // '.' | l2_lexer_consume(lexer); // '.' | ||||
l2_lexer_consume(lexer); // ident | l2_lexer_consume(lexer); // ident | ||||
l2_gen_namespace_lookup(gen, &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 { | } else { | ||||
break; | break; | ||||
} | } |
printf("NAMESPACE_SET\n"); | printf("NAMESPACE_SET\n"); | ||||
break; | 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: | case L2_OP_HALT: | ||||
printf("HALT\n"); | printf("HALT\n"); | ||||
break; | break; |
} | } | ||||
break; | 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: | case L2_OP_HALT: | ||||
break; | break; | ||||
} | } |