diff --git a/examples/basic/20_init.peb b/examples/basic/20_init.peb new file mode 100644 index 0000000..4f6b63e --- /dev/null +++ b/examples/basic/20_init.peb @@ -0,0 +1,20 @@ +class Person { + init(firstname, lastname) { + this.firstname = firstname + this.lastname = lastname + } + + get_fullname() { + return this.firstname + " " + this.lastname + } + + greet(person) { + print("Hello " + person.get_fullname()) + } +} + +let alice = Person("Alice", "Foo") +let bob = Person("Bob", "Bar") + +alice.greet(bob) +bob.greet(alice) \ No newline at end of file diff --git a/main.py b/main.py index 97f30e3..f5f582c 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,7 @@ from src.pebble import Pebble def main(): - path: Path = Path("examples/basic/19_this.peb") + path: Path = Path("examples/basic/20_init.peb") Pebble.run_file(path) diff --git a/src/consts.py b/src/consts.py index 22fa3d8..1c87b16 100644 --- a/src/consts.py +++ b/src/consts.py @@ -1 +1,2 @@ MAX_FUNCTION_ARGS = 255 +CONSTRUCTOR_NAME = "init" diff --git a/src/core/function.py b/src/core/function.py index 5edd8ba..92447dd 100644 --- a/src/core/function.py +++ b/src/core/function.py @@ -13,9 +13,10 @@ if TYPE_CHECKING: class PebbleFunction(PebbleCallable): - def __init__(self, declaration: FunctionStmt, closure: Environment): + def __init__(self, declaration: FunctionStmt, closure: Environment, is_init: bool = False): self.declaration: FunctionStmt = declaration self.closure: Environment = closure + self.is_init: bool = is_init def arity(self) -> int: return len(self.declaration.params) @@ -29,6 +30,9 @@ class PebbleFunction(PebbleCallable): interpreter.execute_block(self.declaration.body, env) except ReturnException as ret: return ret.value + + if self.is_init: + return self.closure.get_at(0, "this") return None def __str__(self): @@ -37,4 +41,4 @@ class PebbleFunction(PebbleCallable): def bind(self, instance: PebbleInstance): env: Environment = Environment(self.closure) env.define("this", instance) - return PebbleFunction(self.declaration, env) + return PebbleFunction(self.declaration, env, self.is_init) diff --git a/src/core/klass.py b/src/core/klass.py index 3efa9bf..0f39bf7 100644 --- a/src/core/klass.py +++ b/src/core/klass.py @@ -2,6 +2,7 @@ from __future__ import annotations from typing import Any, TYPE_CHECKING, Optional +from src.consts import CONSTRUCTOR_NAME from src.core.callable import PebbleCallable from src.core.function import PebbleFunction from src.core.instance import PebbleInstance @@ -19,10 +20,16 @@ class PebbleClass(PebbleCallable): return self.name def arity(self) -> int: - return 0 + initializer: Optional[PebbleFunction] = self.find_method(CONSTRUCTOR_NAME) + if initializer is None: + return 0 + return initializer.arity() def call(self, interpreter: Interpreter, arguments: list[Any]) -> Any: instance: PebbleInstance = PebbleInstance(self) + initializer: Optional[PebbleFunction] = self.find_method(CONSTRUCTOR_NAME) + if initializer is not None: + initializer.bind(instance).call(interpreter, arguments) return instance def find_method(self, name: str) -> Optional[PebbleFunction]: diff --git a/src/interpreter/interpreter.py b/src/interpreter/interpreter.py index a3f9b64..cfe7fa3 100644 --- a/src/interpreter/interpreter.py +++ b/src/interpreter/interpreter.py @@ -4,6 +4,7 @@ from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, CallExpr, GetExpr, T, SetExpr, ThisExpr from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \ ReturnStmt, BreakStmt, ContinueStmt, ClassStmt +from src.consts import CONSTRUCTOR_NAME from src.core.callable import PebbleCallable from src.core.function import PebbleFunction from src.core.instance import PebbleInstance @@ -179,7 +180,7 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]): self.env.define(stmt.name.lexeme, None) methods: dict[str, PebbleFunction] = {} for method in stmt.methods: - func: PebbleFunction = PebbleFunction(method, self.env) + func: PebbleFunction = PebbleFunction(method, self.env, method.name.lexeme == CONSTRUCTOR_NAME) methods[method.name.lexeme] = func klass: PebbleClass = PebbleClass(stmt.name.lexeme, methods) self.env.assign(stmt.name, klass)