1
0
Fork 0
forked from fun/fun
This commit is contained in:
Johannes Findeisen 2025-09-15 08:39:41 +02:00
commit 0e7fffcfe0
67 changed files with 154 additions and 65 deletions

49
examples/objects_more.fun Normal file
View 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
*/

View file

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

View file

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

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