diff --git a/examples/basic/17_class.peb b/examples/basic/17_class.peb index 281cc7a..36aec63 100644 --- a/examples/basic/17_class.peb +++ b/examples/basic/17_class.peb @@ -10,4 +10,7 @@ class Breakfast { print(Breakfast) let bf = Breakfast() -print(bf) \ No newline at end of file +print(bf) + +bf.cook() +bf.serve("Bob") \ No newline at end of file diff --git a/src/core/instance.py b/src/core/instance.py index 67a818f..a78cb61 100644 --- a/src/core/instance.py +++ b/src/core/instance.py @@ -1,7 +1,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Optional +from src.core.function import PebbleFunction from src.interpreter.error import PebbleRuntimeError from src.token import Token @@ -21,6 +22,9 @@ class PebbleInstance: try: return self.fields[name.lexeme] except KeyError: + method: Optional[PebbleFunction] = self.klass.find_method(name.lexeme) + if method is not None: + return method raise PebbleRuntimeError(name, f"Undefined property '{name.lexeme}'.") def set(self, name: Token, value: Any) -> None: diff --git a/src/core/klass.py b/src/core/klass.py index 9f107ba..3efa9bf 100644 --- a/src/core/klass.py +++ b/src/core/klass.py @@ -1,8 +1,9 @@ from __future__ import annotations -from typing import Any, TYPE_CHECKING +from typing import Any, TYPE_CHECKING, Optional from src.core.callable import PebbleCallable +from src.core.function import PebbleFunction from src.core.instance import PebbleInstance if TYPE_CHECKING: @@ -10,8 +11,9 @@ if TYPE_CHECKING: class PebbleClass(PebbleCallable): - def __init__(self, name: str): + def __init__(self, name: str, methods: dict[str, PebbleFunction]): self.name: str = name + self.methods: dict[str, PebbleFunction] = methods def __str__(self): return self.name @@ -22,3 +24,6 @@ class PebbleClass(PebbleCallable): def call(self, interpreter: Interpreter, arguments: list[Any]) -> Any: instance: PebbleInstance = PebbleInstance(self) return instance + + def find_method(self, name: str) -> Optional[PebbleFunction]: + return self.methods.get(name) diff --git a/src/interpreter/interpreter.py b/src/interpreter/interpreter.py index 46ed2d1..ba19a5e 100644 --- a/src/interpreter/interpreter.py +++ b/src/interpreter/interpreter.py @@ -174,7 +174,11 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]): def visit_class_stmt(self, stmt: ClassStmt) -> None: self.env.define(stmt.name.lexeme, None) - klass: PebbleClass = PebbleClass(stmt.name.lexeme) + methods: dict[str, PebbleFunction] = {} + for method in stmt.methods: + func: PebbleFunction = PebbleFunction(method, self.env) + methods[method.name.lexeme] = func + klass: PebbleClass = PebbleClass(stmt.name.lexeme, methods) self.env.assign(stmt.name, klass) def visit_expression_stmt(self, stmt: ExpressionStmt) -> None: diff --git a/src/interpreter/resolver.py b/src/interpreter/resolver.py index 0e1cc1c..187769d 100644 --- a/src/interpreter/resolver.py +++ b/src/interpreter/resolver.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: class FunctionType(Enum): NONE = auto() FUNCTION = auto() + METHOD = auto() class LoopType(Enum): @@ -116,6 +117,8 @@ class Resolver(Expr.Visitor[None], Stmt.Visitor[None]): def visit_class_stmt(self, stmt: ClassStmt) -> None: self.declare(stmt.name) + for method in stmt.methods: + self.resolve_function(method, FunctionType.METHOD) self.define(stmt.name) def visit_expression_stmt(self, stmt: ExpressionStmt) -> None: