feat: add class constructor
This commit is contained in:
20
examples/basic/20_init.peb
Normal file
20
examples/basic/20_init.peb
Normal file
@@ -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)
|
||||||
2
main.py
2
main.py
@@ -4,7 +4,7 @@ from src.pebble import Pebble
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
path: Path = Path("examples/basic/19_this.peb")
|
path: Path = Path("examples/basic/20_init.peb")
|
||||||
Pebble.run_file(path)
|
Pebble.run_file(path)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
MAX_FUNCTION_ARGS = 255
|
MAX_FUNCTION_ARGS = 255
|
||||||
|
CONSTRUCTOR_NAME = "init"
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
class PebbleFunction(PebbleCallable):
|
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.declaration: FunctionStmt = declaration
|
||||||
self.closure: Environment = closure
|
self.closure: Environment = closure
|
||||||
|
self.is_init: bool = is_init
|
||||||
|
|
||||||
def arity(self) -> int:
|
def arity(self) -> int:
|
||||||
return len(self.declaration.params)
|
return len(self.declaration.params)
|
||||||
@@ -29,6 +30,9 @@ class PebbleFunction(PebbleCallable):
|
|||||||
interpreter.execute_block(self.declaration.body, env)
|
interpreter.execute_block(self.declaration.body, env)
|
||||||
except ReturnException as ret:
|
except ReturnException as ret:
|
||||||
return ret.value
|
return ret.value
|
||||||
|
|
||||||
|
if self.is_init:
|
||||||
|
return self.closure.get_at(0, "this")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -37,4 +41,4 @@ class PebbleFunction(PebbleCallable):
|
|||||||
def bind(self, instance: PebbleInstance):
|
def bind(self, instance: PebbleInstance):
|
||||||
env: Environment = Environment(self.closure)
|
env: Environment = Environment(self.closure)
|
||||||
env.define("this", instance)
|
env.define("this", instance)
|
||||||
return PebbleFunction(self.declaration, env)
|
return PebbleFunction(self.declaration, env, self.is_init)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any, TYPE_CHECKING, Optional
|
from typing import Any, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from src.consts import CONSTRUCTOR_NAME
|
||||||
from src.core.callable import PebbleCallable
|
from src.core.callable import PebbleCallable
|
||||||
from src.core.function import PebbleFunction
|
from src.core.function import PebbleFunction
|
||||||
from src.core.instance import PebbleInstance
|
from src.core.instance import PebbleInstance
|
||||||
@@ -19,10 +20,16 @@ class PebbleClass(PebbleCallable):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def arity(self) -> int:
|
def arity(self) -> int:
|
||||||
|
initializer: Optional[PebbleFunction] = self.find_method(CONSTRUCTOR_NAME)
|
||||||
|
if initializer is None:
|
||||||
return 0
|
return 0
|
||||||
|
return initializer.arity()
|
||||||
|
|
||||||
def call(self, interpreter: Interpreter, arguments: list[Any]) -> Any:
|
def call(self, interpreter: Interpreter, arguments: list[Any]) -> Any:
|
||||||
instance: PebbleInstance = PebbleInstance(self)
|
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
|
return instance
|
||||||
|
|
||||||
def find_method(self, name: str) -> Optional[PebbleFunction]:
|
def find_method(self, name: str) -> Optional[PebbleFunction]:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr,
|
|||||||
CallExpr, GetExpr, T, SetExpr, ThisExpr
|
CallExpr, GetExpr, T, SetExpr, ThisExpr
|
||||||
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
||||||
|
from src.consts import CONSTRUCTOR_NAME
|
||||||
from src.core.callable import PebbleCallable
|
from src.core.callable import PebbleCallable
|
||||||
from src.core.function import PebbleFunction
|
from src.core.function import PebbleFunction
|
||||||
from src.core.instance import PebbleInstance
|
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)
|
self.env.define(stmt.name.lexeme, None)
|
||||||
methods: dict[str, PebbleFunction] = {}
|
methods: dict[str, PebbleFunction] = {}
|
||||||
for method in stmt.methods:
|
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
|
methods[method.name.lexeme] = func
|
||||||
klass: PebbleClass = PebbleClass(stmt.name.lexeme, methods)
|
klass: PebbleClass = PebbleClass(stmt.name.lexeme, methods)
|
||||||
self.env.assign(stmt.name, klass)
|
self.env.assign(stmt.name, klass)
|
||||||
|
|||||||
Reference in New Issue
Block a user