@@ -123,6 +123,8 @@ enum l2_opcode { | |||
/* | |||
* Allocate an array. | |||
* Pop <count> | |||
* Pop count times | |||
* Alloc array <var> | |||
* Push <var> | |||
*/ |
@@ -32,6 +32,7 @@ void l2_gen_number(struct l2_generator *gen, double num); | |||
void l2_gen_string(struct l2_generator *gen, char **str); | |||
void l2_gen_atom(struct l2_generator *gen, char **ident); | |||
void l2_gen_function(struct l2_generator *gen, l2_word pos); | |||
void l2_gen_array(struct l2_generator *gen, l2_word count); | |||
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); |
@@ -122,6 +122,12 @@ void l2_gen_function(struct l2_generator *gen, l2_word pos) { | |||
put(gen, L2_OP_ALLOC_FUNCTION); | |||
} | |||
void l2_gen_array(struct l2_generator *gen, l2_word count) { | |||
put(gen, L2_OP_PUSH); | |||
put(gen, count); | |||
put(gen, L2_OP_ALLOC_ARRAY); | |||
} | |||
void l2_gen_namespace(struct l2_generator *gen) { | |||
put(gen, L2_OP_ALLOC_NAMESPACE); | |||
} |
@@ -13,6 +13,9 @@ static int tok_is_end(struct l2_token *tok) { | |||
static int parse_expression( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | |||
static int parse_arg_level_expression( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | |||
static int parse_object_literal( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||
l2_trace_scope("object literal"); | |||
@@ -156,6 +159,8 @@ static int parse_object_or_function_literal( | |||
if (tok->kind == L2_TOK_CLOSE_BRACE) { | |||
l2_trace_scope("empty object literal"); | |||
l2_lexer_consume(lexer); // '}' | |||
l2_gen_namespace(gen); | |||
} else if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON) { | |||
if (parse_object_literal(lexer, gen, err) < 0) { | |||
return -1; | |||
@@ -169,6 +174,31 @@ static int parse_object_or_function_literal( | |||
return 0; | |||
} | |||
static int parse_array_literal( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||
l2_trace_scope("array literal"); | |||
l2_lexer_consume(lexer); // '[' | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
int count = 0; | |||
while (1) { | |||
if (l2_lexer_peek(lexer, 1)->kind == L2_TOK_CLOSE_BRACKET) { | |||
l2_lexer_consume(lexer); // ']' | |||
break; | |||
} | |||
count += 1; | |||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
} | |||
l2_gen_array(gen, count); | |||
return 0; | |||
} | |||
static int parse_arg_level_expression_base( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||
l2_trace_scope("arg level expression base"); | |||
@@ -224,6 +254,10 @@ static int parse_arg_level_expression_base( | |||
if (parse_object_or_function_literal(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
} else if (tok->kind == L2_TOK_OPEN_BRACKET) { | |||
if (parse_array_literal(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
} else { | |||
l2_parse_err(err, tok, "Unexpected token %s", | |||
l2_token_kind_name(tok->kind)); |
@@ -17,14 +17,21 @@ static void print_val(struct l2_vm *vm, struct l2_vm_value *val) { | |||
break; | |||
case L2_VAL_TYPE_BUFFER: | |||
fwrite(val->buffer->data, 1, val->buffer->len, stdout); | |||
if (val->buffer != NULL) { | |||
fwrite(val->buffer->data, 1, val->buffer->len, stdout); | |||
} | |||
break; | |||
case L2_VAL_TYPE_ARRAY: | |||
if (val->array == NULL) { | |||
printf("[]"); | |||
break; | |||
} | |||
putchar('['); | |||
for (size_t i = 0; i < val->array->len; ++i) { | |||
if (i != 0) { | |||
printf(", "); | |||
putchar(' '); | |||
} | |||
print_val(vm, &vm->values[val->array->data[i]]); |
@@ -363,11 +363,26 @@ void l2_vm_step(struct l2_vm *vm) { | |||
break; | |||
case L2_OP_ALLOC_ARRAY: | |||
word = alloc_val(vm); | |||
vm->values[word].flags = L2_VAL_TYPE_ARRAY; | |||
vm->values[word].array = NULL; // Will be allocated on first insert | |||
vm->stack[vm->sptr] = word; | |||
vm->sptr += 1; | |||
{ | |||
l2_word count = vm->stack[--vm->sptr]; | |||
l2_word arr_id = alloc_val(vm); | |||
struct l2_vm_value *arr = &vm->values[arr_id]; | |||
arr->flags = L2_VAL_TYPE_ARRAY; | |||
if (count == 0) { | |||
arr->array = NULL; | |||
vm->stack[vm->sptr++] = arr_id; | |||
break; | |||
} | |||
arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word)); | |||
arr->array->len = count; | |||
arr->array->size = count; | |||
for (l2_word i = 0; i < count; ++i) { | |||
arr->array->data[count - 1 - i] = vm->stack[--vm->sptr]; | |||
} | |||
vm->stack[vm->sptr++] = arr_id; | |||
} | |||
break; | |||
case L2_OP_ALLOC_NAMESPACE: | |||
@@ -411,8 +426,8 @@ void l2_vm_step(struct l2_vm *vm) { | |||
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; | |||
} | |||
break; | |||
case L2_OP_HALT: | |||
break; |