[fine] Classes!
It's kinda amazing this works actually
This commit is contained in:
parent
0ee89bf26b
commit
4505996710
5 changed files with 319 additions and 40 deletions
|
|
@ -19,6 +19,7 @@ pub enum Instruction {
|
|||
CompareFloat,
|
||||
CompareString,
|
||||
Discard,
|
||||
Dup,
|
||||
FloatAdd,
|
||||
FloatDivide,
|
||||
FloatMultiply,
|
||||
|
|
@ -31,6 +32,8 @@ pub enum Instruction {
|
|||
LoadFunction(usize),
|
||||
LoadLocal(usize),
|
||||
LoadModule(usize),
|
||||
LoadSlot(usize),
|
||||
NewObject(usize),
|
||||
PushFalse,
|
||||
PushFloat(f64),
|
||||
PushNothing,
|
||||
|
|
@ -41,8 +44,6 @@ pub enum Instruction {
|
|||
StoreLocal(usize),
|
||||
StoreModule(usize),
|
||||
StringAdd,
|
||||
Dup,
|
||||
NewObject(usize),
|
||||
}
|
||||
|
||||
pub enum Export {
|
||||
|
|
@ -287,6 +288,9 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
|||
TreeKind::CallExpression => compile_call_expression(c, tree),
|
||||
TreeKind::Block => compile_block_expression(c, tree),
|
||||
TreeKind::Argument => compile_argument(c, tree),
|
||||
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
|
||||
TreeKind::FieldValue => compile_field_value(c, t, tree),
|
||||
TreeKind::MemberAccess => compile_member_access(c, tree),
|
||||
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
|
||||
};
|
||||
if matches!(cr, None) {
|
||||
|
|
@ -506,6 +510,10 @@ fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> O
|
|||
let environment = c.semantics.environment_of(t);
|
||||
let declaration = environment.bind(ident)?;
|
||||
|
||||
compile_load_declaration(c, t, declaration)
|
||||
}
|
||||
|
||||
fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declaration) -> CR {
|
||||
// TODO: Load function declaration. :P
|
||||
let instruction = match declaration {
|
||||
Declaration::Variable {
|
||||
|
|
@ -547,23 +555,7 @@ fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> O
|
|||
Instruction::LoadFunction(index)
|
||||
}
|
||||
Declaration::ExternFunction { id, .. } => Instruction::LoadExternFunction(id.id()),
|
||||
Declaration::Class { declaration, .. } => {
|
||||
let key = FunctionKey { tree: *declaration };
|
||||
let index = match c.function_bindings.get(&key) {
|
||||
Some(index) => *index,
|
||||
None => {
|
||||
let tree = &c.syntax[*declaration];
|
||||
compiler_assert_eq!(c, t, tree.kind, TreeKind::ClassDecl);
|
||||
|
||||
compile_class_declaration(c, t, tree, false)?;
|
||||
|
||||
*c.function_bindings
|
||||
.get(&key)
|
||||
.expect("did not compile the class constructor!")
|
||||
}
|
||||
};
|
||||
Instruction::LoadFunction(index)
|
||||
}
|
||||
Declaration::Class { .. } => Instruction::Panic,
|
||||
};
|
||||
|
||||
c.push(instruction);
|
||||
|
|
@ -609,10 +601,98 @@ fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
|
|||
OK
|
||||
}
|
||||
|
||||
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||
// We pass in the arguments.... by... field order?
|
||||
let Type::Class(class) = c.semantics.type_of(t) else {
|
||||
c.push(Instruction::Panic);
|
||||
return OK;
|
||||
};
|
||||
|
||||
let field_list = tree.child_tree_of_kind(c.syntax, TreeKind::FieldList)?;
|
||||
let mut field_bindings = HashMap::new();
|
||||
for field in field_list.children_of_kind(c.syntax, TreeKind::FieldValue) {
|
||||
let f = &c.syntax[field];
|
||||
let name = f.nth_token(0)?;
|
||||
field_bindings.insert(name.as_str(), field);
|
||||
}
|
||||
|
||||
// The fields come in this order and since arguments are backwards
|
||||
// (stack!) we compile them in reverse order. Missing fields panic,
|
||||
// obviously.
|
||||
for field in class.fields.iter().rev() {
|
||||
let binding = field_bindings.get(&*field.name)?;
|
||||
compile_expression(c, *binding);
|
||||
}
|
||||
|
||||
// Fetch the correct constructor.
|
||||
let type_reference = tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression)?;
|
||||
let identifier = type_reference.nth_token(0)?;
|
||||
let environment = c.semantics.environment_of(t);
|
||||
match environment.bind(identifier)? {
|
||||
Declaration::Class { declaration, .. } => {
|
||||
let key = FunctionKey { tree: *declaration };
|
||||
let index = match c.function_bindings.get(&key) {
|
||||
Some(index) => *index,
|
||||
None => {
|
||||
let tree = &c.syntax[*declaration];
|
||||
compiler_assert_eq!(c, t, tree.kind, TreeKind::ClassDecl);
|
||||
|
||||
compile_class_declaration(c, t, tree, false)?;
|
||||
|
||||
*c.function_bindings
|
||||
.get(&key)
|
||||
.expect("did not compile the class constructor!")
|
||||
}
|
||||
};
|
||||
c.push(Instruction::LoadFunction(index));
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
c.push(Instruction::Call(class.fields.len()));
|
||||
OK
|
||||
}
|
||||
|
||||
fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||
if let Some(colon) = tree.nth_token(1) {
|
||||
if colon.kind == TokenKind::Colon {
|
||||
compile_expression(c, tree.nth_tree(2)?);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Form 2: { x, ... }
|
||||
let environment = c.semantics.environment_of(t);
|
||||
let id = tree.nth_token(0)?;
|
||||
let declaration = environment.bind(id)?;
|
||||
|
||||
compile_load_declaration(c, t, declaration)
|
||||
}
|
||||
|
||||
fn compile_member_access(c: &mut Compiler, tree: &Tree) -> CR {
|
||||
let lhs = tree.nth_tree(0)?;
|
||||
compile_expression(c, lhs);
|
||||
|
||||
let id = tree.nth_token(2)?;
|
||||
let Type::Class(cr) = c.semantics.type_of(lhs) else {
|
||||
return None;
|
||||
};
|
||||
let Some((index, _fld)) = cr
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, f)| &*f.name == id.as_str())
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
c.push(Instruction::LoadSlot(index));
|
||||
OK
|
||||
}
|
||||
|
||||
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
||||
let tree = &c.semantics.tree()[t];
|
||||
let cr = match tree.kind {
|
||||
TreeKind::FunctionDecl => compile_function_declaration(c, t, tree, gen_value),
|
||||
TreeKind::ClassDecl => compile_class_declaration(c, t, tree, gen_value),
|
||||
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
|
||||
TreeKind::ExpressionStatement => compile_expression_statement(c, tree, gen_value),
|
||||
TreeKind::IfStatement => compile_if_statement(c, tree, gen_value),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue