ufff
This commit is contained in:
parent
c8b8dd820e
commit
0e7fffcfe0
67 changed files with 154 additions and 65 deletions
49
examples/objects_more.fun
Normal file
49
examples/objects_more.fun
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
// Objects as maps: nested fields, methods with explicit self
|
||||||
|
|
||||||
|
// A method to move a 2D point by dx, dy
|
||||||
|
fun move(self, dx, dy)
|
||||||
|
self["x"] = self["x"] + dx
|
||||||
|
self["y"] = self["y"] + dy
|
||||||
|
return 0
|
||||||
|
|
||||||
|
// Create a point directly and inspect fields
|
||||||
|
p = { "x": 1, "y": 2, "move": move }
|
||||||
|
print(p["x"]) // -> 1
|
||||||
|
print(p["y"]) // -> 2
|
||||||
|
|
||||||
|
// Update a field directly
|
||||||
|
p["x"] = 10
|
||||||
|
print(p["x"]) // -> 10
|
||||||
|
|
||||||
|
// Call method with explicit self
|
||||||
|
move(p, 3, -2)
|
||||||
|
print(p["x"]) // -> 13
|
||||||
|
print(p["y"]) // -> 0
|
||||||
|
|
||||||
|
// Nested object example
|
||||||
|
rect = {
|
||||||
|
"pos": { "x": 0, "y": 0 },
|
||||||
|
"size": { "w": 5, "h": 4 }
|
||||||
|
}
|
||||||
|
print(rect["pos"]["x"]) // -> 0
|
||||||
|
print(rect["size"]["w"]) // -> 5
|
||||||
|
|
||||||
|
// Mutate nested fields
|
||||||
|
rect["pos"]["x"] = rect["pos"]["x"] + 7
|
||||||
|
rect["size"]["h"] = rect["size"]["h"] + 1
|
||||||
|
print(rect["pos"]["x"]) // -> 7
|
||||||
|
print(rect["size"]["h"]) // -> 5
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
1
|
||||||
|
2
|
||||||
|
10
|
||||||
|
13
|
||||||
|
0
|
||||||
|
0
|
||||||
|
5
|
||||||
|
7
|
||||||
|
5
|
||||||
|
*/
|
||||||
|
|
@ -20,6 +20,7 @@ static int is_blank_line(const char *s) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char* lstrip(const char *s) {
|
static const char* lstrip(const char *s) {
|
||||||
while (*s == ' ' || *s == '\t') s++;
|
while (*s == ' ' || *s == '\t') s++;
|
||||||
return s;
|
return s;
|
||||||
|
|
|
||||||
42
src/parser.c
42
src/parser.c
|
|
@ -1489,9 +1489,9 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* array element assignment: name[expr] = expr */
|
/* array element assignment: name[expr] = expr and nested: name[expr1][expr2] = expr */
|
||||||
if (local_pos < len && src[local_pos] == '[') {
|
if (local_pos < len && src[local_pos] == '[') {
|
||||||
/* load array variable */
|
/* load array/map variable */
|
||||||
if (lidx >= 0) {
|
if (lidx >= 0) {
|
||||||
bytecode_add_instruction(bc, OP_LOAD_LOCAL, lidx);
|
bytecode_add_instruction(bc, OP_LOAD_LOCAL, lidx);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1509,6 +1509,44 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
skip_spaces(src, len, &local_pos);
|
skip_spaces(src, len, &local_pos);
|
||||||
|
|
||||||
|
/* Nested index: name[expr1][expr2] = value */
|
||||||
|
if (local_pos < len && src[local_pos] == '[') {
|
||||||
|
/* Reduce base: stack currently has container, index1 -> get inner container */
|
||||||
|
bytecode_add_instruction(bc, OP_INDEX_GET, 0);
|
||||||
|
|
||||||
|
local_pos++; /* second '[' */
|
||||||
|
if (!emit_expression(bc, src, len, &local_pos)) {
|
||||||
|
parser_fail(local_pos, "Expected nested index expression after '['");
|
||||||
|
free(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!consume_char(src, len, &local_pos, ']')) {
|
||||||
|
parser_fail(local_pos, "Expected ']' after nested index");
|
||||||
|
free(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
skip_spaces(src, len, &local_pos);
|
||||||
|
if (local_pos >= len || src[local_pos] != '=') {
|
||||||
|
parser_fail(local_pos, "Expected '=' after nested array index");
|
||||||
|
free(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
local_pos++; /* '=' */
|
||||||
|
if (!emit_expression(bc, src, len, &local_pos)) {
|
||||||
|
parser_fail(local_pos, "Expected expression after '='");
|
||||||
|
free(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* perform set into inner container */
|
||||||
|
bytecode_add_instruction(bc, OP_INDEX_SET, 0);
|
||||||
|
free(name);
|
||||||
|
*pos = local_pos;
|
||||||
|
skip_to_eol(src, len, pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single-level: name[expr] = value */
|
||||||
if (local_pos >= len || src[local_pos] != '=') {
|
if (local_pos >= len || src[local_pos] != '=') {
|
||||||
parser_fail(local_pos, "Expected '=' after array index");
|
parser_fail(local_pos, "Expected '=' after array index");
|
||||||
free(name);
|
free(name);
|
||||||
|
|
|
||||||
127
src/vm.c
127
src/vm.c
|
|
@ -192,69 +192,70 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
vm->instr_count++; /* count each executed instruction */
|
vm->instr_count++; /* count each executed instruction */
|
||||||
|
|
||||||
switch (inst.op) {
|
switch (inst.op) {
|
||||||
#include "vm_case_nop.inc"
|
/* All opcode handlers as .c includes */
|
||||||
#include "vm_case_load_const.inc"
|
#include "vm_case_nop.c"
|
||||||
#include "vm_case_load_local.inc"
|
#include "vm_case_load_const.c"
|
||||||
#include "vm_case_store_local.inc"
|
#include "vm_case_load_local.c"
|
||||||
#include "vm_case_add.inc"
|
#include "vm_case_store_local.c"
|
||||||
#include "vm_case_sub.inc"
|
#include "vm_case_add.c"
|
||||||
#include "vm_case_mul.inc"
|
#include "vm_case_sub.c"
|
||||||
#include "vm_case_div.inc"
|
#include "vm_case_mul.c"
|
||||||
#include "vm_case_lt.inc"
|
#include "vm_case_div.c"
|
||||||
#include "vm_case_lte.inc"
|
#include "vm_case_lt.c"
|
||||||
#include "vm_case_jump.inc"
|
#include "vm_case_lte.c"
|
||||||
#include "vm_case_gt.inc"
|
#include "vm_case_jump.c"
|
||||||
#include "vm_case_gte.inc"
|
#include "vm_case_gt.c"
|
||||||
#include "vm_case_eq.inc"
|
#include "vm_case_gte.c"
|
||||||
#include "vm_case_neq.inc"
|
#include "vm_case_eq.c"
|
||||||
#include "vm_case_jump_if_false.inc"
|
#include "vm_case_neq.c"
|
||||||
#include "vm_case_call.inc"
|
#include "vm_case_jump_if_false.c"
|
||||||
#include "vm_case_return.inc"
|
#include "vm_case_call.c"
|
||||||
#include "vm_case_print.inc"
|
#include "vm_case_return.c"
|
||||||
#include "vm_case_halt.inc"
|
#include "vm_case_print.c"
|
||||||
#include "vm_case_pop.inc"
|
#include "vm_case_halt.c"
|
||||||
#include "vm_case_dup.inc"
|
#include "vm_case_pop.c"
|
||||||
#include "vm_case_swap.inc"
|
#include "vm_case_dup.c"
|
||||||
#include "vm_case_make_array.inc"
|
#include "vm_case_swap.c"
|
||||||
#include "vm_case_index_get.inc"
|
#include "vm_case_make_array.c"
|
||||||
#include "vm_case_index_set.inc"
|
#include "vm_case_index_get.c"
|
||||||
#include "vm_case_len.inc"
|
#include "vm_case_index_set.c"
|
||||||
#include "vm_case_arr_push.inc"
|
#include "vm_case_len.c"
|
||||||
#include "vm_case_arr_pop.inc"
|
#include "vm_case_arr_push.c"
|
||||||
#include "vm_case_arr_set.inc"
|
#include "vm_case_arr_pop.c"
|
||||||
#include "vm_case_arr_insert.inc"
|
#include "vm_case_arr_set.c"
|
||||||
#include "vm_case_arr_remove.inc"
|
#include "vm_case_arr_insert.c"
|
||||||
#include "vm_case_slice.inc"
|
#include "vm_case_arr_remove.c"
|
||||||
#include "vm_case_to_number.inc"
|
#include "vm_case_slice.c"
|
||||||
#include "vm_case_to_string.inc"
|
#include "vm_case_to_number.c"
|
||||||
#include "vm_case_split.inc"
|
#include "vm_case_to_string.c"
|
||||||
#include "vm_case_join.inc"
|
#include "vm_case_split.c"
|
||||||
#include "vm_case_substr.inc"
|
#include "vm_case_join.c"
|
||||||
#include "vm_case_find.inc"
|
#include "vm_case_substr.c"
|
||||||
#include "vm_case_contains.inc"
|
#include "vm_case_find.c"
|
||||||
#include "vm_case_index_of.inc"
|
#include "vm_case_contains.c"
|
||||||
#include "vm_case_clear.inc"
|
#include "vm_case_index_of.c"
|
||||||
#include "vm_case_enumerate.inc"
|
#include "vm_case_clear.c"
|
||||||
#include "vm_case_zip.inc"
|
#include "vm_case_enumerate.c"
|
||||||
#include "vm_case_min.inc"
|
#include "vm_case_zip.c"
|
||||||
#include "vm_case_max.inc"
|
#include "vm_case_min.c"
|
||||||
#include "vm_case_clamp.inc"
|
#include "vm_case_max.c"
|
||||||
#include "vm_case_abs.inc"
|
#include "vm_case_clamp.c"
|
||||||
#include "vm_case_pow.inc"
|
#include "vm_case_abs.c"
|
||||||
#include "vm_case_random_seed.inc"
|
#include "vm_case_pow.c"
|
||||||
#include "vm_case_random_int.inc"
|
#include "vm_case_random_seed.c"
|
||||||
#include "vm_case_make_map.inc"
|
#include "vm_case_random_int.c"
|
||||||
#include "vm_case_keys.inc"
|
#include "vm_case_make_map.c"
|
||||||
#include "vm_case_values.inc"
|
#include "vm_case_keys.c"
|
||||||
#include "vm_case_has_key.inc"
|
#include "vm_case_values.c"
|
||||||
#include "vm_case_read_file.inc"
|
#include "vm_case_has_key.c"
|
||||||
#include "vm_case_write_file.inc"
|
#include "vm_case_read_file.c"
|
||||||
#include "vm_case_load_global.inc"
|
#include "vm_case_write_file.c"
|
||||||
#include "vm_case_store_global.inc"
|
#include "vm_case_load_global.c"
|
||||||
#include "vm_case_mod.inc"
|
#include "vm_case_store_global.c"
|
||||||
#include "vm_case_and.inc"
|
#include "vm_case_mod.c"
|
||||||
#include "vm_case_or.inc"
|
#include "vm_case_and.c"
|
||||||
#include "vm_case_not.inc"
|
#include "vm_case_or.c"
|
||||||
|
#include "vm_case_not.c"
|
||||||
default:
|
default:
|
||||||
if (!opcode_is_valid(inst.op)) {
|
if (!opcode_is_valid(inst.op)) {
|
||||||
fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",
|
fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue