[fine] Support assignment to member, loops with iterators
Hmm it's starting to look like something.
This commit is contained in:
parent
3415b1a3f6
commit
239e859eaf
7 changed files with 360 additions and 171 deletions
|
|
@ -3,7 +3,7 @@ use std::rc::Rc;
|
|||
|
||||
use crate::{
|
||||
parser::{Child, SyntaxTree, Tree, TreeKind, TreeRef},
|
||||
semantics::{Declaration, Location, Semantics, Type},
|
||||
semantics::{Declaration, Environment, Location, Semantics, Type},
|
||||
tokens::TokenKind,
|
||||
};
|
||||
|
||||
|
|
@ -26,7 +26,11 @@ pub enum Instruction {
|
|||
FloatSubtract,
|
||||
GreaterFloat,
|
||||
GreaterString,
|
||||
IsBool,
|
||||
IsClass(i64),
|
||||
IsFloat,
|
||||
IsNothing,
|
||||
IsString,
|
||||
Jump(usize),
|
||||
JumpFalse(usize),
|
||||
JumpTrue(usize), // TODO: Only one of these, and use BoolNot?
|
||||
|
|
@ -49,6 +53,7 @@ pub enum Instruction {
|
|||
StoreArgument(usize),
|
||||
StoreLocal(usize),
|
||||
StoreModule(usize),
|
||||
StoreSlot(usize),
|
||||
StringAdd,
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +308,7 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
|||
TreeKind::Identifier => compile_identifier_expression(c, t, tree),
|
||||
TreeKind::IsExpression => compile_is_expression(c, tree),
|
||||
TreeKind::LiteralExpression => compile_literal(c, t, tree),
|
||||
TreeKind::MemberAccess => compile_member_access(c, tree),
|
||||
TreeKind::MemberAccess => compile_member_access(c, t, tree),
|
||||
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
|
||||
TreeKind::SelfReference => compile_self_reference(c),
|
||||
TreeKind::UnaryExpression => compile_unary_operator(c, t, tree),
|
||||
|
|
@ -534,49 +539,68 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
|||
|
||||
let lvalue = tr.nth_tree(0)?;
|
||||
let ltree = &c.syntax[lvalue];
|
||||
match ltree.kind {
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
let mut environment = Environment::error();
|
||||
|
||||
let declaration = match ltree.kind {
|
||||
// TODO: Assign to list access
|
||||
TreeKind::Identifier => {
|
||||
let ident = ltree.nth_token(0)?;
|
||||
let environment = c.semantics.environment_of(lvalue);
|
||||
let declaration = environment.bind(ident)?;
|
||||
|
||||
let instruction = match declaration {
|
||||
Declaration::Variable {
|
||||
location, index, ..
|
||||
} => {
|
||||
let index = *index;
|
||||
match location {
|
||||
Location::Argument => {
|
||||
compiler_assert!(c, t, index < c.function.args);
|
||||
Instruction::StoreArgument(index)
|
||||
}
|
||||
Location::Local => {
|
||||
if index >= c.function.locals {
|
||||
c.function.locals = index + 1;
|
||||
}
|
||||
Instruction::StoreLocal(index)
|
||||
}
|
||||
Location::Module => {
|
||||
compiler_assert!(c, t, index < c.module.globals);
|
||||
Instruction::StoreModule(index)
|
||||
}
|
||||
Location::Slot => {
|
||||
ice!(c, t, "cannot have an identifier lvalue bind to a slot");
|
||||
}
|
||||
}
|
||||
let id = ltree.nth_token(0)?;
|
||||
environment = c.semantics.environment_of(lvalue);
|
||||
environment.bind(id)?
|
||||
}
|
||||
TreeKind::MemberAccess => {
|
||||
let id = ltree.nth_token(2)?;
|
||||
let typ = c.semantics.type_of(ltree.nth_tree(0)?);
|
||||
environment = match &typ {
|
||||
Type::Object(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.env.clone()
|
||||
}
|
||||
|
||||
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
||||
Declaration::Function { .. } => inst_panic!("store func"),
|
||||
Declaration::Class { .. } => inst_panic!("store class"),
|
||||
Type::Class(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.static_env.clone()
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
c.push(instruction);
|
||||
environment.bind(id)?
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let instruction = match declaration {
|
||||
Declaration::Variable {
|
||||
location, index, ..
|
||||
} => {
|
||||
let index = *index;
|
||||
match location {
|
||||
Location::Argument => {
|
||||
compiler_assert!(c, t, index < c.function.args);
|
||||
Instruction::StoreArgument(index)
|
||||
}
|
||||
Location::Local => {
|
||||
if index >= c.function.locals {
|
||||
c.function.locals = index + 1;
|
||||
}
|
||||
Instruction::StoreLocal(index)
|
||||
}
|
||||
Location::Module => {
|
||||
compiler_assert!(c, t, index < c.module.globals);
|
||||
Instruction::StoreModule(index)
|
||||
}
|
||||
Location::Slot => {
|
||||
compile_expression(c, ltree.nth_tree(0)?);
|
||||
Instruction::StoreSlot(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Member
|
||||
// TODO: List element
|
||||
_ => ice!(c, t, "Unsupported lvalue type"),
|
||||
}
|
||||
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
||||
Declaration::Function { .. } => inst_panic!("store func"),
|
||||
Declaration::Class { .. } => inst_panic!("store class"),
|
||||
};
|
||||
c.push(instruction);
|
||||
OK
|
||||
}
|
||||
_ => ice!(c, t, "Unsupported binary expression '{op}'"),
|
||||
|
|
@ -754,19 +778,33 @@ fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
|
|||
|
||||
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||
let identifier = tree.nth_token(0)?;
|
||||
let environment = c.semantics.environment_of(t);
|
||||
match environment.bind(identifier)? {
|
||||
Declaration::Class { declaration, .. } => {
|
||||
// The runtime identifier of the class is the tree index of the
|
||||
// class declaration sure why not.
|
||||
let index = declaration.index();
|
||||
c.push(Instruction::IsClass(index.try_into().unwrap()));
|
||||
match identifier.as_str() {
|
||||
"f64" => {
|
||||
c.push(Instruction::IsFloat);
|
||||
}
|
||||
"string" => {
|
||||
c.push(Instruction::IsString);
|
||||
}
|
||||
"bool" => {
|
||||
c.push(Instruction::IsBool);
|
||||
}
|
||||
"nothing" => {
|
||||
c.push(Instruction::IsNothing);
|
||||
}
|
||||
_ => {
|
||||
let environment = c.semantics.environment_of(t);
|
||||
match environment.bind(identifier)? {
|
||||
Declaration::Class { declaration, .. } => {
|
||||
// The runtime identifier of the class is the tree index of the
|
||||
// class declaration sure why not.
|
||||
let index = declaration.index();
|
||||
c.push(Instruction::IsClass(index.try_into().unwrap()));
|
||||
}
|
||||
|
||||
// TODO: enforce that type identifier binds to class in `is`
|
||||
// expresion, we don't support RTTI for other types yet.
|
||||
_ => return None,
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OK
|
||||
}
|
||||
|
|
@ -911,16 +949,35 @@ fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
|||
compile_load_declaration(c, t, declaration)
|
||||
}
|
||||
|
||||
fn compile_member_access(c: &mut Compiler, tree: &Tree) -> CR {
|
||||
fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||
// In member access; the lhs sets up the object and in theory the rhs
|
||||
// binds against it. ::shrug::
|
||||
//
|
||||
compile_expression(c, tree.nth_tree(0)?);
|
||||
|
||||
let typ = c.semantics.type_of(tree.nth_tree(0)?);
|
||||
let ident = tree.nth_token(2)?;
|
||||
|
||||
let environment = match &typ {
|
||||
Type::Object(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.env.clone()
|
||||
}
|
||||
Type::Class(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.static_env.clone()
|
||||
}
|
||||
_ => {
|
||||
c.push(inst_panic!("cannot get environment of {typ}"));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let declaration = environment.bind(ident)?;
|
||||
|
||||
// NOTE: If this is a method call we still don't have to do anything
|
||||
// special here, since the load of the member function will *not*
|
||||
// consume the self pointer from the stack.
|
||||
compile_expression(c, tree.nth_tree(2)?);
|
||||
compile_load_declaration(c, t, declaration);
|
||||
OK
|
||||
}
|
||||
|
||||
|
|
@ -938,6 +995,7 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
|||
TreeKind::FunctionDecl => compile_function_declaration(c, t, tree, gen_value),
|
||||
TreeKind::IfStatement => compile_if_statement(c, tree, gen_value),
|
||||
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
|
||||
TreeKind::ReturnStatement => compile_return_statement(c, tree),
|
||||
TreeKind::WhileStatement => compile_while_statement(c, tree, gen_value),
|
||||
|
||||
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
|
||||
|
|
@ -1129,3 +1187,13 @@ fn compile_while_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR
|
|||
|
||||
OK
|
||||
}
|
||||
|
||||
fn compile_return_statement(c: &mut Compiler, tree: &Tree) -> CR {
|
||||
if let Some(expr) = tree.nth_tree(1) {
|
||||
compile_expression(c, expr);
|
||||
} else {
|
||||
c.push(Instruction::PushNothing);
|
||||
}
|
||||
c.push(Instruction::Return);
|
||||
OK
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue