Some more class sugar...
This commit is contained in:
parent
5d2c6e89aa
commit
c7c4b467d5
2 changed files with 74 additions and 21 deletions
|
|
@ -55,24 +55,19 @@ p["x"] = 10
|
|||
p["y"] = -2
|
||||
print("after set -> p.x = " + to_string(p["x"]) + ", p.y = " + to_string(p["y"]))
|
||||
|
||||
// Call methods by first loading them into identifiers, then passing 'p' as first argument
|
||||
to_str = p["toString"]
|
||||
print("toString(p) => " + to_str(p))
|
||||
// Call methods directly with dot-call sugar: p.method(args) desugars to method(p, args)
|
||||
print("toString(p) => " + p.toString())
|
||||
|
||||
move_fn = p["move"]
|
||||
move_fn(p, 3, 5)
|
||||
print("after move(3,5) -> " + to_str(p)) // expect Point(13, 3)
|
||||
p.move(3, 5)
|
||||
print("after move(3,5) -> " + p.toString()) // expect Point(13, 3)
|
||||
|
||||
// Another instance with defaults
|
||||
q = Point()
|
||||
print("q initially -> " + to_str(q)) // Point(0, 0)
|
||||
print("q initially -> " + q.toString()) // Point(0, 0)
|
||||
|
||||
// Counter demo
|
||||
c = Counter()
|
||||
inc = c["inc"]
|
||||
add = c["add"]
|
||||
|
||||
print("counter inc -> " + to_string(inc(c))) // 1
|
||||
print("counter inc -> " + to_string(inc(c))) // 2
|
||||
print("counter add(5) -> " + to_string(add(c, 5))) // 7
|
||||
print("counter inc -> " + to_string(c.inc())) // 1
|
||||
print("counter inc -> " + to_string(c.inc())) // 2
|
||||
print("counter add(5) -> " + to_string(c.add(5))) // 7
|
||||
print("counter current value = " + to_string(c["value"]))
|
||||
|
|
|
|||
74
src/parser.c
74
src/parser.c
|
|
@ -995,7 +995,7 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
}
|
||||
}
|
||||
|
||||
/* dot property access: obj.field -> obj["field"] */
|
||||
/* dot property access and method-call sugar: obj.field or obj.method(...) */
|
||||
if (*pos < len && src[*pos] == '.') {
|
||||
(*pos)++; /* '.' */
|
||||
skip_spaces(src, len, pos);
|
||||
|
|
@ -1003,9 +1003,39 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
if (!read_identifier_into(src, len, pos, &mname)) { parser_fail(*pos, "Expected identifier after '.'"); free(name); return 0; }
|
||||
int kci = bytecode_add_constant(bc, make_string(mname));
|
||||
free(mname);
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0);
|
||||
continue;
|
||||
|
||||
/* Peek for immediate call: obj.method( ... ) */
|
||||
size_t callp = *pos;
|
||||
skip_spaces(src, len, &callp);
|
||||
if (callp < len && src[callp] == '(') {
|
||||
/* Prepare: stack has <obj>. Duplicate it to preserve 'this' across INDEX_GET */
|
||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0); /* -> stack: obj, func */
|
||||
bytecode_add_instruction(bc, OP_SWAP, 0); /* -> stack: func, obj (this) */
|
||||
|
||||
/* Consume '(' and parse args */
|
||||
*pos = callp + 1;
|
||||
int argc = 0;
|
||||
skip_spaces(src, len, pos);
|
||||
if (*pos < len && src[*pos] != ')') {
|
||||
do {
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "Expected expression as method argument"); free(name); return 0; }
|
||||
argc++;
|
||||
skip_spaces(src, len, pos);
|
||||
} while (*pos < len && src[*pos] == ',' && (++(*pos), skip_spaces(src, len, pos), 1));
|
||||
}
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after arguments"); free(name); return 0; }
|
||||
|
||||
/* Call with implicit 'this' (+1 arg) */
|
||||
bytecode_add_instruction(bc, OP_CALL, argc + 1);
|
||||
continue;
|
||||
} else {
|
||||
/* Plain property get: obj["field"] */
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -1047,7 +1077,7 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
}
|
||||
}
|
||||
|
||||
/* dot property access: obj.field -> obj["field"] */
|
||||
/* dot property access and method-call sugar */
|
||||
if (*pos < len && src[*pos] == '.') {
|
||||
(*pos)++;
|
||||
skip_spaces(src, len, pos);
|
||||
|
|
@ -1055,9 +1085,37 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
if (!read_identifier_into(src, len, pos, &mname)) { parser_fail(*pos, "Expected identifier after '.'"); free(name); return 0; }
|
||||
int kci = bytecode_add_constant(bc, make_string(mname));
|
||||
free(mname);
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0);
|
||||
continue;
|
||||
|
||||
/* Peek for call */
|
||||
size_t callp = *pos;
|
||||
skip_spaces(src, len, &callp);
|
||||
if (callp < len && src[callp] == '(') {
|
||||
/* Stack has obj: duplicate to preserve 'this' */
|
||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0); /* -> obj, func */
|
||||
bytecode_add_instruction(bc, OP_SWAP, 0); /* -> func, obj */
|
||||
|
||||
*pos = callp + 1;
|
||||
int argc = 0;
|
||||
skip_spaces(src, len, pos);
|
||||
if (*pos < len && src[*pos] != ')') {
|
||||
do {
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "Expected expression as method argument"); free(name); return 0; }
|
||||
argc++;
|
||||
skip_spaces(src, len, pos);
|
||||
} while (*pos < len && src[*pos] == ',' && (++(*pos), skip_spaces(src, len, pos), 1));
|
||||
}
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after arguments"); free(name); return 0; }
|
||||
|
||||
bytecode_add_instruction(bc, OP_CALL, argc + 1);
|
||||
continue;
|
||||
} else {
|
||||
/* plain property get */
|
||||
bytecode_add_instruction(bc, OP_LOAD_CONST, kci);
|
||||
bytecode_add_instruction(bc, OP_INDEX_GET, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue