Compare commits
No commits in common. "8779aade2437cd6a17c93ef82f4d0be920323e05" and "9ce5794c30cbb50518e5b3919799c4a51d35d427" have entirely different histories.
8779aade24
...
9ce5794c30
3 changed files with 121 additions and 168 deletions
|
|
@ -177,13 +177,6 @@ impl<'a> Compiler<'a> {
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
// TODO: We should be looking for semantic errors and using *those*
|
|
||||||
// as the panic description and only fall back to the provided
|
|
||||||
// description if we can't find a semantic error. The idea is
|
|
||||||
// that if the compiler got confused it *might* be because
|
|
||||||
// there was actually a semantic error in the program and that
|
|
||||||
// semantic error might be a better description of what is
|
|
||||||
// wrong.
|
|
||||||
let index = self.add_string(description.into());
|
let index = self.add_string(description.into());
|
||||||
Instruction::Panic(index)
|
Instruction::Panic(index)
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +282,7 @@ pub fn compile(semantics: &Semantics) -> Rc<Module> {
|
||||||
compiler.temp_functions.resize(idx + 1, None);
|
compiler.temp_functions.resize(idx + 1, None);
|
||||||
}
|
}
|
||||||
compiler.function = func;
|
compiler.function = func;
|
||||||
let _ = compile_function(&mut compiler, fk.tree);
|
compile_function(&mut compiler, fk.tree);
|
||||||
compiler.temp_functions[idx] = Some(Rc::new(compiler.function));
|
compiler.temp_functions[idx] = Some(Rc::new(compiler.function));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -317,13 +310,13 @@ fn file(c: &mut Compiler, t: TreeRef) {
|
||||||
c.push(Instruction::Return);
|
c.push(Instruction::Return);
|
||||||
}
|
}
|
||||||
|
|
||||||
type CR = Result<(), &'static str>;
|
type CR = Option<()>;
|
||||||
const OK: CR = CR::Ok(());
|
const OK: CR = CR::Some(());
|
||||||
|
|
||||||
fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
||||||
let tree = &c.syntax[t];
|
let tree = &c.syntax[t];
|
||||||
let cr = match tree.kind {
|
let cr = match tree.kind {
|
||||||
TreeKind::Error => Err("error tree"),
|
TreeKind::Error => None,
|
||||||
|
|
||||||
TreeKind::Argument => compile_argument(c, tree),
|
TreeKind::Argument => compile_argument(c, tree),
|
||||||
TreeKind::BinaryExpression => compile_binary_expression(c, t, tree),
|
TreeKind::BinaryExpression => compile_binary_expression(c, t, tree),
|
||||||
|
|
@ -345,13 +338,13 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
||||||
|
|
||||||
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
|
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
|
||||||
};
|
};
|
||||||
if let Err(m) = cr {
|
if matches!(cr, None) {
|
||||||
c.push_panic(format!("panic compiling expression {:?}: {m}", tree));
|
c.push_panic(format!("panic compiling expression {:?}", tree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
let tok = tr.nth_token(0).ok_or("no token")?;
|
let tok = tr.nth_token(0)?;
|
||||||
match c.semantics.type_of(t) {
|
match c.semantics.type_of(t) {
|
||||||
Type::F64 => c.push(Instruction::PushFloat(
|
Type::F64 => c.push(Instruction::PushFloat(
|
||||||
tok.as_str(c.source).parse().unwrap(),
|
tok.as_str(c.source).parse().unwrap(),
|
||||||
|
|
@ -373,14 +366,14 @@ fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_grouping(c: &mut Compiler, t: &Tree) -> CR {
|
fn compile_grouping(c: &mut Compiler, t: &Tree) -> CR {
|
||||||
compile_expression(c, t.nth_tree(1).ok_or("unexpected tree")?);
|
compile_expression(c, t.nth_tree(1)?);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_unary_operator(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
fn compile_unary_operator(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
compile_expression(c, tr.nth_tree(1).ok_or("no arg")?);
|
compile_expression(c, tr.nth_tree(1)?);
|
||||||
|
|
||||||
let tok = tr.nth_token(0).ok_or("no op")?;
|
let tok = tr.nth_token(0)?;
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
TokenKind::Minus => {
|
TokenKind::Minus => {
|
||||||
c.push(Instruction::PushFloat(-1.0));
|
c.push(Instruction::PushFloat(-1.0));
|
||||||
|
|
@ -395,12 +388,12 @@ fn compile_unary_operator(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_condition_expression(c: &mut Compiler, t: &Tree) -> CR {
|
fn compile_condition_expression(c: &mut Compiler, t: &Tree) -> CR {
|
||||||
let condition = t.nth_tree(1).ok_or("no cond")?;
|
let condition = t.nth_tree(1)?;
|
||||||
compile_expression(c, condition);
|
compile_expression(c, condition);
|
||||||
|
|
||||||
let jump_else_index = c.push(Instruction::JumpFalse(0));
|
let jump_else_index = c.push(Instruction::JumpFalse(0));
|
||||||
|
|
||||||
let then_branch = t.nth_tree(2).ok_or("no then")?;
|
let then_branch = t.nth_tree(2)?;
|
||||||
compile_expression(c, then_branch);
|
compile_expression(c, then_branch);
|
||||||
|
|
||||||
let jump_end_index = c.push(Instruction::Jump(0));
|
let jump_end_index = c.push(Instruction::Jump(0));
|
||||||
|
|
@ -420,9 +413,9 @@ fn compile_simple_binary_expression<T>(c: &mut Compiler, tr: &Tree, f: T) -> CR
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Compiler, &Type) -> Instruction,
|
T: FnOnce(&mut Compiler, &Type) -> Instruction,
|
||||||
{
|
{
|
||||||
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
|
compile_expression(c, tr.nth_tree(0)?);
|
||||||
|
|
||||||
let arg_tree = tr.nth_tree(2).ok_or("no rhs")?;
|
let arg_tree = tr.nth_tree(2)?;
|
||||||
let arg_type = c.semantics.type_of(arg_tree);
|
let arg_type = c.semantics.type_of(arg_tree);
|
||||||
|
|
||||||
compile_expression(c, arg_tree);
|
compile_expression(c, arg_tree);
|
||||||
|
|
@ -434,7 +427,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
let op = tr.nth_token(1).ok_or("no op")?;
|
let op = tr.nth_token(1)?;
|
||||||
match op.kind {
|
match op.kind {
|
||||||
TokenKind::Plus => compile_simple_binary_expression(c, tr, |c, t| match t {
|
TokenKind::Plus => compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::FloatAdd,
|
Type::F64 => Instruction::FloatAdd,
|
||||||
|
|
@ -461,7 +454,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Type::F64 => Instruction::GreaterFloat,
|
Type::F64 => Instruction::GreaterFloat,
|
||||||
Type::String => Instruction::GreaterString,
|
Type::String => Instruction::GreaterString,
|
||||||
_ => c.inst_panic(format!("panic less equal {}", t)),
|
_ => c.inst_panic(format!("panic less equal {}", t)),
|
||||||
})?;
|
});
|
||||||
c.push(Instruction::BoolNot);
|
c.push(Instruction::BoolNot);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
@ -475,14 +468,14 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Type::F64 => Instruction::LessFloat,
|
Type::F64 => Instruction::LessFloat,
|
||||||
Type::String => Instruction::LessString,
|
Type::String => Instruction::LessString,
|
||||||
_ => c.inst_panic(format!("panic greater equal {}", t)),
|
_ => c.inst_panic(format!("panic greater equal {}", t)),
|
||||||
})?;
|
});
|
||||||
c.push(Instruction::BoolNot);
|
c.push(Instruction::BoolNot);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenKind::And => {
|
TokenKind::And => {
|
||||||
// Compile the left hand side, it leaves a bool on the stack
|
// Compile the left hand side, it leaves a bool on the stack
|
||||||
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
|
compile_expression(c, tr.nth_tree(0)?);
|
||||||
|
|
||||||
// If the first part is true (hooray!) then we need to evaluate
|
// If the first part is true (hooray!) then we need to evaluate
|
||||||
// the right hand side, so jump around the short circuit...
|
// the right hand side, so jump around the short circuit...
|
||||||
|
|
@ -500,7 +493,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
|
|
||||||
// The right hand side leaves true or false on the stack, it's
|
// The right hand side leaves true or false on the stack, it's
|
||||||
// the result of the expression.
|
// the result of the expression.
|
||||||
compile_expression(c, tr.nth_tree(2).ok_or("no rhs")?);
|
compile_expression(c, tr.nth_tree(2)?);
|
||||||
|
|
||||||
// (here's where you go after you leave the "false" on the stack.)
|
// (here's where you go after you leave the "false" on the stack.)
|
||||||
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
||||||
|
|
@ -508,7 +501,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
TokenKind::Or => {
|
TokenKind::Or => {
|
||||||
// Compile the left hand side, it leaves a bool on the stack
|
// Compile the left hand side, it leaves a bool on the stack
|
||||||
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
|
compile_expression(c, tr.nth_tree(0)?);
|
||||||
|
|
||||||
// If the first part is false (boo!) then we need to evaluate the
|
// If the first part is false (boo!) then we need to evaluate the
|
||||||
// right hand side, so jump around the short circuit...
|
// right hand side, so jump around the short circuit...
|
||||||
|
|
@ -526,7 +519,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
|
|
||||||
// The right hand side leaves true or false on the stack, it's
|
// The right hand side leaves true or false on the stack, it's
|
||||||
// the result of the expression.
|
// the result of the expression.
|
||||||
compile_expression(c, tr.nth_tree(2).ok_or("no rhs")?);
|
compile_expression(c, tr.nth_tree(2)?);
|
||||||
|
|
||||||
// (here's where you go after you leave "true" on the stack.)
|
// (here's where you go after you leave "true" on the stack.)
|
||||||
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
||||||
|
|
@ -549,31 +542,31 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TokenKind::Equal => {
|
TokenKind::Equal => {
|
||||||
compile_expression(c, tr.nth_tree(2).ok_or("no value")?);
|
compile_expression(c, tr.nth_tree(2)?);
|
||||||
c.push(Instruction::Dup);
|
c.push(Instruction::Dup);
|
||||||
|
|
||||||
let lvalue = tr.nth_tree(0).ok_or("no lvalue")?;
|
let lvalue = tr.nth_tree(0)?;
|
||||||
let ltree = &c.syntax[lvalue];
|
let ltree = &c.syntax[lvalue];
|
||||||
|
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
let mut environment = Environment::error("??");
|
let mut environment = Environment::error();
|
||||||
|
|
||||||
let declaration = match ltree.kind {
|
let declaration = match ltree.kind {
|
||||||
// TODO: Assign to list access
|
// TODO: Assign to list access
|
||||||
TreeKind::Identifier => {
|
TreeKind::Identifier => {
|
||||||
let id = ltree.nth_token(0).ok_or("no id")?.as_str(&c.source);
|
let id = ltree.nth_token(0)?.as_str(&c.source);
|
||||||
environment = c.semantics.environment_of(lvalue);
|
environment = c.semantics.environment_of(lvalue);
|
||||||
environment.bind(id).ok_or("cannot bind destination")?
|
environment.bind(id)?
|
||||||
}
|
}
|
||||||
TreeKind::MemberAccess => {
|
TreeKind::MemberAccess => {
|
||||||
let id = ltree.nth_token(2).ok_or("no member")?.as_str(&c.source);
|
let id = ltree.nth_token(2)?.as_str(&c.source);
|
||||||
|
|
||||||
let t = ltree.nth_tree(0).ok_or("no lhs exp")?;
|
let t = ltree.nth_tree(0)?;
|
||||||
let typ = c.semantics.type_of(t);
|
let typ = c.semantics.type_of(t);
|
||||||
environment = c.semantics.member_environment(t, &typ);
|
environment = c.semantics.member_environment(t, &typ);
|
||||||
environment.bind(id).ok_or("cannot bind field")?
|
environment.bind(id)?
|
||||||
}
|
}
|
||||||
_ => return Err("unsupported lval expression"),
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let instruction = match declaration {
|
let instruction = match declaration {
|
||||||
|
|
@ -597,7 +590,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Instruction::StoreModule(index)
|
Instruction::StoreModule(index)
|
||||||
}
|
}
|
||||||
Location::Slot => {
|
Location::Slot => {
|
||||||
compile_expression(c, ltree.nth_tree(0).ok_or("no obj lhs")?);
|
compile_expression(c, ltree.nth_tree(0)?);
|
||||||
Instruction::StoreSlot(index)
|
Instruction::StoreSlot(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -621,10 +614,10 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> Option<()> {
|
||||||
let ident = tree.nth_token(0).ok_or("no ident")?.as_str(&c.source);
|
let ident = tree.nth_token(0)?.as_str(&c.source);
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
let declaration = environment.bind(ident).ok_or("not found")?;
|
let declaration = environment.bind(ident)?;
|
||||||
|
|
||||||
compile_load_declaration(c, t, declaration)
|
compile_load_declaration(c, t, declaration)
|
||||||
}
|
}
|
||||||
|
|
@ -696,24 +689,22 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
|
||||||
compile_expression(c, tree.nth_tree(1).ok_or("no val")?);
|
compile_expression(c, tree.nth_tree(1)?);
|
||||||
|
|
||||||
let mut patches = Vec::new();
|
let mut patches = Vec::new();
|
||||||
let match_body = tree
|
let match_body = tree.child_tree_of_kind(c.syntax, TreeKind::MatchBody)?;
|
||||||
.child_tree_of_kind(c.syntax, TreeKind::MatchBody)
|
|
||||||
.ok_or("no body")?;
|
|
||||||
for arm in match_body.children_of_kind(c.syntax, TreeKind::MatchArm) {
|
for arm in match_body.children_of_kind(c.syntax, TreeKind::MatchArm) {
|
||||||
let arm = &c.syntax[arm];
|
let arm = &c.syntax[arm];
|
||||||
|
|
||||||
// Evaluate pattern...
|
// Evaluate pattern...
|
||||||
compile_pattern(c, arm.nth_tree(0).ok_or("no arm pat")?)?;
|
compile_pattern(c, arm.nth_tree(0)?)?;
|
||||||
|
|
||||||
// ...If false jump to next arm.
|
// ...If false jump to next arm.
|
||||||
let jump_next_index = c.push(Instruction::JumpFalse(0));
|
let jump_next_index = c.push(Instruction::JumpFalse(0));
|
||||||
|
|
||||||
// ...If true run expression and jump out.
|
// ...If true run expression and jump out.
|
||||||
compile_expression(c, arm.nth_tree(2).ok_or("no arm expr")?);
|
compile_expression(c, arm.nth_tree(2)?);
|
||||||
patches.push(c.push(Instruction::Jump(0)));
|
patches.push(c.push(Instruction::Jump(0)));
|
||||||
|
|
||||||
c.patch(jump_next_index, |i| Instruction::JumpFalse(i));
|
c.patch(jump_next_index, |i| Instruction::JumpFalse(i));
|
||||||
|
|
@ -728,13 +719,13 @@ fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
|
||||||
compile_expression(c, tree.nth_tree(0).ok_or("no val")?);
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
|
|
||||||
compile_pattern(c, tree.nth_tree(2).ok_or("no pat")?)
|
compile_pattern(c, tree.nth_tree(2)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
|
fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
|
||||||
let tree = &c.syntax[t];
|
let tree = &c.syntax[t];
|
||||||
|
|
||||||
// Let's *try* to generate good code in the presence of a wildcard pattern....
|
// Let's *try* to generate good code in the presence of a wildcard pattern....
|
||||||
|
|
@ -752,11 +743,8 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
|
||||||
// If you have a binding, dup and store now, it is in scope.
|
// If you have a binding, dup and store now, it is in scope.
|
||||||
if let Some(binding) = tree.child_tree_of_kind(&c.syntax, TreeKind::VariableBinding) {
|
if let Some(binding) = tree.child_tree_of_kind(&c.syntax, TreeKind::VariableBinding) {
|
||||||
if let Some(variable) = binding.nth_token(0) {
|
if let Some(variable) = binding.nth_token(0) {
|
||||||
let id = variable.as_str(&c.source);
|
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
let Some(declaration) = environment.bind(id) else {
|
let declaration = environment.bind(variable.as_str(&c.source))?;
|
||||||
ice!(c, t, "cannot bind pattern variable `{id}`");
|
|
||||||
};
|
|
||||||
|
|
||||||
let Declaration::Variable {
|
let Declaration::Variable {
|
||||||
location: Location::Local,
|
location: Location::Local,
|
||||||
|
|
@ -778,8 +766,8 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_wildcard {
|
if !is_wildcard {
|
||||||
let type_expr = type_expr.ok_or("wild but no type")?;
|
let type_expr = type_expr?;
|
||||||
compile_type_expr_eq(c, type_expr.nth_tree(0).ok_or("no type expr")?);
|
compile_type_expr_eq(c, type_expr.nth_tree(0)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(and_index) = and_index {
|
if let Some(and_index) = and_index {
|
||||||
|
|
@ -801,7 +789,7 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
|
||||||
Some(jump_end_index)
|
Some(jump_end_index)
|
||||||
};
|
};
|
||||||
|
|
||||||
compile_expression(c, tree.nth_tree(and_index + 1).ok_or("no condition")?);
|
compile_expression(c, tree.nth_tree(and_index + 1)?);
|
||||||
|
|
||||||
// If we wound up with a jump what needs patching, patch it.
|
// If we wound up with a jump what needs patching, patch it.
|
||||||
if let Some(jump_end_index) = jump_end_index {
|
if let Some(jump_end_index) = jump_end_index {
|
||||||
|
|
@ -824,16 +812,13 @@ fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
|
||||||
_ => ice!(c, t, "tree is not a type expression"),
|
_ => ice!(c, t, "tree is not a type expression"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(m) = result {
|
if result.is_none() {
|
||||||
c.push_panic(format!(
|
c.push_panic(format!("panic compiling type expression eq {:?}", tree));
|
||||||
"internal error compiling type expression eq {:?}: {m}",
|
|
||||||
tree
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
let identifier = tree.nth_token(0).ok_or("no id")?.as_str(&c.source);
|
let identifier = tree.nth_token(0)?.as_str(&c.source);
|
||||||
match identifier {
|
match identifier {
|
||||||
"f64" => {
|
"f64" => {
|
||||||
c.push(Instruction::IsFloat);
|
c.push(Instruction::IsFloat);
|
||||||
|
|
@ -849,7 +834,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
match environment.bind(identifier).ok_or("cannot bind")? {
|
match environment.bind(identifier)? {
|
||||||
Declaration::Class { declaration, .. } => {
|
Declaration::Class { declaration, .. } => {
|
||||||
// The runtime identifier of the class is the tree index of the
|
// The runtime identifier of the class is the tree index of the
|
||||||
// class declaration sure why not.
|
// class declaration sure why not.
|
||||||
|
|
@ -857,7 +842,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
c.push(Instruction::IsClass(index.try_into().unwrap()));
|
c.push(Instruction::IsClass(index.try_into().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => return Err("unsupported type decl"),
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -867,7 +852,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
|
|
||||||
fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
// Compile the left hand side, it leaves a bool on the stack
|
// Compile the left hand side, it leaves a bool on the stack
|
||||||
compile_type_expr_eq(c, tree.nth_tree(0).ok_or("no lhs")?);
|
compile_type_expr_eq(c, tree.nth_tree(0)?);
|
||||||
|
|
||||||
// If the first part is false (boo!) then we need to evaluate the
|
// If the first part is false (boo!) then we need to evaluate the
|
||||||
// right hand side, so jump around the short circuit...
|
// right hand side, so jump around the short circuit...
|
||||||
|
|
@ -885,7 +870,7 @@ fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
|
|
||||||
// The right hand side leaves true or false on the stack, it's
|
// The right hand side leaves true or false on the stack, it's
|
||||||
// the result of the expression.
|
// the result of the expression.
|
||||||
compile_type_expr_eq(c, tree.nth_tree(2).ok_or("no rhs")?);
|
compile_type_expr_eq(c, tree.nth_tree(2)?);
|
||||||
|
|
||||||
// (here's where you go after you leave "true" on the stack.)
|
// (here's where you go after you leave "true" on the stack.)
|
||||||
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
c.patch(jump_end_index, |i| Instruction::Jump(i));
|
||||||
|
|
@ -893,9 +878,7 @@ fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
let arg_list = tree
|
let arg_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ArgumentList)?;
|
||||||
.child_tree_of_kind(&c.syntax, TreeKind::ArgumentList)
|
|
||||||
.ok_or("no arglist")?;
|
|
||||||
let mut args: Vec<_> = arg_list.child_trees().collect();
|
let mut args: Vec<_> = arg_list.child_trees().collect();
|
||||||
let arg_count = args.len();
|
let arg_count = args.len();
|
||||||
|
|
||||||
|
|
@ -904,7 +887,7 @@ fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
compile_expression(c, arg);
|
compile_expression(c, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let func = tree.nth_tree(0).ok_or("no func")?;
|
let func = tree.nth_tree(0)?;
|
||||||
let func_type = c.semantics.type_of(func);
|
let func_type = c.semantics.type_of(func);
|
||||||
let arg_count = match func_type {
|
let arg_count = match func_type {
|
||||||
// TODO: Consider being guided by syntax here?
|
// TODO: Consider being guided by syntax here?
|
||||||
|
|
@ -927,14 +910,14 @@ fn compile_block_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
let last_index = tree.children.len() - if last_is_brace { 2 } else { 1 };
|
let last_index = tree.children.len() - if last_is_brace { 2 } else { 1 };
|
||||||
|
|
||||||
for i in 1..last_index {
|
for i in 1..last_index {
|
||||||
compile_statement(c, tree.nth_tree(i).ok_or("no stat")?, false);
|
compile_statement(c, tree.nth_tree(i)?, false);
|
||||||
}
|
}
|
||||||
compile_statement(c, tree.nth_tree(last_index).ok_or("no last")?, true);
|
compile_statement(c, tree.nth_tree(last_index)?, true);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -947,13 +930,11 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
||||||
|
|
||||||
let class = c.semantics.class_of(mid, ct);
|
let class = c.semantics.class_of(mid, ct);
|
||||||
|
|
||||||
let field_list = tree
|
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
|
||||||
.child_tree_of_kind(&c.syntax, TreeKind::FieldList)
|
|
||||||
.ok_or("no field list")?;
|
|
||||||
let mut field_bindings = HashMap::new();
|
let mut field_bindings = HashMap::new();
|
||||||
for field in field_list.children_of_kind(&c.syntax, TreeKind::FieldValue) {
|
for field in field_list.children_of_kind(&c.syntax, TreeKind::FieldValue) {
|
||||||
let f = &c.syntax[field];
|
let f = &c.syntax[field];
|
||||||
let name = f.nth_token(0).ok_or("no field name")?;
|
let name = f.nth_token(0)?;
|
||||||
field_bindings.insert(name.as_str(&c.source), field);
|
field_bindings.insert(name.as_str(&c.source), field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -961,23 +942,16 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
||||||
// (stack!) we compile them in reverse order. Missing fields panic,
|
// (stack!) we compile them in reverse order. Missing fields panic,
|
||||||
// obviously.
|
// obviously.
|
||||||
for field in class.fields.iter().rev() {
|
for field in class.fields.iter().rev() {
|
||||||
let binding = field_bindings
|
let binding = field_bindings.get(&*field.name)?;
|
||||||
.get(&*field.name)
|
|
||||||
.ok_or("cannot bind field")?;
|
|
||||||
compile_expression(c, *binding);
|
compile_expression(c, *binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the correct constructor.
|
// Fetch the correct constructor.
|
||||||
// TODO: Binding this type should be done by semantics, and we should borrow it.
|
// TODO: Binding this type should be done by semantics, and we should borrow it.
|
||||||
let type_reference = tree
|
let type_reference = tree.child_tree_of_kind(&c.syntax, TreeKind::TypeIdentifier)?;
|
||||||
.child_tree_of_kind(&c.syntax, TreeKind::TypeIdentifier)
|
let identifier = type_reference.nth_token(0)?.as_str(&c.source);
|
||||||
.ok_or("no type ref")?;
|
|
||||||
let identifier = type_reference
|
|
||||||
.nth_token(0)
|
|
||||||
.ok_or("no type id")?
|
|
||||||
.as_str(&c.source);
|
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
match environment.bind(identifier).ok_or("cannot bind type")? {
|
match environment.bind(identifier)? {
|
||||||
Declaration::Class { declaration, .. } => {
|
Declaration::Class { declaration, .. } => {
|
||||||
let key = FunctionKey { tree: *declaration };
|
let key = FunctionKey { tree: *declaration };
|
||||||
let index = match c.function_bindings.get(&key) {
|
let index = match c.function_bindings.get(&key) {
|
||||||
|
|
@ -995,7 +969,7 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
||||||
};
|
};
|
||||||
c.push(Instruction::LoadFunction(index));
|
c.push(Instruction::LoadFunction(index));
|
||||||
}
|
}
|
||||||
_ => return Err("unsupported type for construction"),
|
_ => return None,
|
||||||
}
|
}
|
||||||
c.push(Instruction::Call(class.fields.len()));
|
c.push(Instruction::Call(class.fields.len()));
|
||||||
OK
|
OK
|
||||||
|
|
@ -1004,15 +978,15 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
||||||
fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
if let Some(colon) = tree.nth_token(1) {
|
if let Some(colon) = tree.nth_token(1) {
|
||||||
if colon.kind == TokenKind::Colon {
|
if colon.kind == TokenKind::Colon {
|
||||||
compile_expression(c, tree.nth_tree(2).ok_or("no val")?);
|
compile_expression(c, tree.nth_tree(2)?);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form 2: { x, ... }
|
// Form 2: { x, ... }
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
let id = tree.nth_token(0).ok_or("no id")?.as_str(&c.source);
|
let id = tree.nth_token(0)?.as_str(&c.source);
|
||||||
let declaration = environment.bind(id).ok_or("cannot bind")?;
|
let declaration = environment.bind(id)?;
|
||||||
|
|
||||||
compile_load_declaration(c, t, declaration)
|
compile_load_declaration(c, t, declaration)
|
||||||
}
|
}
|
||||||
|
|
@ -1021,11 +995,10 @@ 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
|
// In member access; the lhs sets up the object and in theory the rhs
|
||||||
// binds against it. ::shrug::
|
// binds against it. ::shrug::
|
||||||
//
|
//
|
||||||
let lhs = tree.nth_tree(0).ok_or("no lhs")?;
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
compile_expression(c, lhs);
|
|
||||||
|
|
||||||
let typ = c.semantics.type_of(lhs);
|
let typ = c.semantics.type_of(tree.nth_tree(0)?);
|
||||||
let ident = tree.nth_token(2).ok_or("no ident")?.as_str(&c.source);
|
let ident = tree.nth_token(2)?.as_str(&c.source);
|
||||||
|
|
||||||
let environment = match &typ {
|
let environment = match &typ {
|
||||||
Type::Object(mid, ct, _) => {
|
Type::Object(mid, ct, _) => {
|
||||||
|
|
@ -1038,15 +1011,15 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
c.push_panic("cannot get environment of {typ}");
|
c.push_panic("cannot get environment of {typ}");
|
||||||
return Err("cannot get environment");
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let declaration = environment.bind(ident).ok_or("cannot bind")?;
|
let declaration = environment.bind(ident)?;
|
||||||
|
|
||||||
// NOTE: If this is a method call we still don't have to do anything
|
// 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*
|
// special here, since the load of the member function will *not*
|
||||||
// consume the self pointer from the stack.
|
// consume the self pointer from the stack.
|
||||||
compile_load_declaration(c, t, declaration)?;
|
compile_load_declaration(c, t, declaration);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1069,14 +1042,14 @@ fn compile_list_constructor(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_list_constructor_element(c: &mut Compiler, tree: &Tree) -> CR {
|
fn compile_list_constructor_element(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
||||||
let tree = &c.semantics.tree()[t];
|
let tree = &c.semantics.tree()[t];
|
||||||
let cr = match tree.kind {
|
let cr = match tree.kind {
|
||||||
TreeKind::Error => Err("parse error"),
|
TreeKind::Error => None,
|
||||||
|
|
||||||
TreeKind::Import => compile_import_statement(c, gen_value),
|
TreeKind::Import => compile_import_statement(c, gen_value),
|
||||||
TreeKind::Block => compile_block_statement(c, t, gen_value),
|
TreeKind::Block => compile_block_statement(c, t, gen_value),
|
||||||
|
|
@ -1091,17 +1064,13 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
||||||
|
|
||||||
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
|
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
|
||||||
};
|
};
|
||||||
|
if matches!(cr, None) {
|
||||||
if let Err(e) = cr {
|
c.push_panic(format!("stat {:?}", tree));
|
||||||
c.push_panic(format!(
|
|
||||||
"internal error compiling statement {:?}: {e}",
|
|
||||||
tree
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_if_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
fn compile_if_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
if !gen_value {
|
if !gen_value {
|
||||||
c.push(Instruction::Discard);
|
c.push(Instruction::Discard);
|
||||||
}
|
}
|
||||||
|
|
@ -1132,11 +1101,9 @@ fn compile_expression_statement(c: &mut Compiler, tree: &Tree, gen_value: bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: bool) -> CR {
|
fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: bool) -> CR {
|
||||||
compile_expression(c, tree.nth_tree(3).ok_or("no val")?);
|
compile_expression(c, tree.nth_tree(3)?);
|
||||||
let environment = c.semantics.environment_of(t);
|
let environment = c.semantics.environment_of(t);
|
||||||
let declaration = environment
|
let declaration = environment.bind(tree.nth_token(1)?.as_str(&c.source))?;
|
||||||
.bind(tree.nth_token(1).ok_or("no id")?.as_str(&c.source))
|
|
||||||
.ok_or("cannot bind")?;
|
|
||||||
|
|
||||||
let Declaration::Variable {
|
let Declaration::Variable {
|
||||||
location, index, ..
|
location, index, ..
|
||||||
|
|
@ -1177,11 +1144,9 @@ fn compile_function_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_v
|
||||||
let fk = FunctionKey { tree: t };
|
let fk = FunctionKey { tree: t };
|
||||||
if !c.function_bindings.contains_key(&fk) {
|
if !c.function_bindings.contains_key(&fk) {
|
||||||
// TODO: If this is a method the name should be different.
|
// TODO: If this is a method the name should be different.
|
||||||
let name = tree.nth_token(1).ok_or("no id")?.as_str(&c.source);
|
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||||
|
|
||||||
let param_list = tree
|
let param_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ParamList)?;
|
||||||
.child_tree_of_kind(&c.syntax, TreeKind::ParamList)
|
|
||||||
.ok_or("no paramlist")?;
|
|
||||||
let param_count = param_list.children.len() - 2;
|
let param_count = param_list.children.len() - 2;
|
||||||
|
|
||||||
let function_index = c.temp_functions.len();
|
let function_index = c.temp_functions.len();
|
||||||
|
|
@ -1207,7 +1172,7 @@ fn compile_class_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_valu
|
||||||
// Classes get compiled as constructor functions which get called.
|
// Classes get compiled as constructor functions which get called.
|
||||||
let fk = FunctionKey { tree: t };
|
let fk = FunctionKey { tree: t };
|
||||||
if !c.function_bindings.contains_key(&fk) {
|
if !c.function_bindings.contains_key(&fk) {
|
||||||
let name = tree.nth_token(1).ok_or("no name")?.as_str(&c.source);
|
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||||
|
|
||||||
let field_count = tree.children.len() - 2;
|
let field_count = tree.children.len() - 2;
|
||||||
|
|
||||||
|
|
@ -1233,9 +1198,7 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
|
||||||
let tree = &c.syntax[t];
|
let tree = &c.syntax[t];
|
||||||
match tree.kind {
|
match tree.kind {
|
||||||
TreeKind::FunctionDecl => {
|
TreeKind::FunctionDecl => {
|
||||||
let block = tree
|
let block = tree.child_of_kind(&c.syntax, TreeKind::Block)?;
|
||||||
.child_of_kind(&c.syntax, TreeKind::Block)
|
|
||||||
.ok_or("no body")?;
|
|
||||||
compile_expression(c, block);
|
compile_expression(c, block);
|
||||||
}
|
}
|
||||||
TreeKind::ClassDecl => {
|
TreeKind::ClassDecl => {
|
||||||
|
|
@ -1246,7 +1209,7 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
|
||||||
c.push(Instruction::LoadArgument(count - 1 - i));
|
c.push(Instruction::LoadArgument(count - 1 - i));
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = tree.nth_token(1).ok_or("no name")?.as_str(&c.source);
|
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||||
let name_index = c.add_string(name.to_string());
|
let name_index = c.add_string(name.to_string());
|
||||||
c.push(Instruction::PushString(name_index));
|
c.push(Instruction::PushString(name_index));
|
||||||
c.push(Instruction::PushInt(t.index().try_into().unwrap()));
|
c.push(Instruction::PushInt(t.index().try_into().unwrap()));
|
||||||
|
|
@ -1270,11 +1233,11 @@ fn compile_block_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) -> CR
|
||||||
|
|
||||||
fn compile_while_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
fn compile_while_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
let start_index = c.function.instructions.len();
|
let start_index = c.function.instructions.len();
|
||||||
compile_expression(c, tree.nth_tree(1).ok_or("no cond")?);
|
compile_expression(c, tree.nth_tree(1)?);
|
||||||
|
|
||||||
let jump_end_index = c.push(Instruction::JumpFalse(0));
|
let jump_end_index = c.push(Instruction::JumpFalse(0));
|
||||||
|
|
||||||
compile_block_statement(c, tree.nth_tree(2).ok_or("no body")?, false)?;
|
compile_block_statement(c, tree.nth_tree(2)?, false);
|
||||||
c.push(Instruction::Jump(start_index));
|
c.push(Instruction::Jump(start_index));
|
||||||
|
|
||||||
c.patch(jump_end_index, |i| Instruction::JumpFalse(i));
|
c.patch(jump_end_index, |i| Instruction::JumpFalse(i));
|
||||||
|
|
@ -1297,11 +1260,11 @@ fn compile_return_statement(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
|
|
||||||
fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
// Figure out the variable.
|
// Figure out the variable.
|
||||||
let vt = tree.nth_tree(1).ok_or("no var")?;
|
let vt = tree.nth_tree(1)?;
|
||||||
let var = &c.syntax[vt];
|
let var = &c.syntax[vt];
|
||||||
let id = var.nth_token(0).ok_or("no id")?.as_str(&c.source);
|
let id = var.nth_token(0)?.as_str(&c.source);
|
||||||
|
|
||||||
let body = tree.nth_tree(4).ok_or("no body")?;
|
let body = tree.nth_tree(4)?;
|
||||||
let env = c.semantics.environment_of(body);
|
let env = c.semantics.environment_of(body);
|
||||||
let Some(variable_decl) = env.bind(id) else {
|
let Some(variable_decl) = env.bind(id) else {
|
||||||
ice!(c, body, "Unable to bind {id} in loop body");
|
ice!(c, body, "Unable to bind {id} in loop body");
|
||||||
|
|
@ -1324,7 +1287,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Figure out the generator.
|
// Figure out the generator.
|
||||||
let iterable = tree.nth_tree(3).ok_or("no generator")?;
|
let iterable = tree.nth_tree(3)?;
|
||||||
compile_expression(c, iterable);
|
compile_expression(c, iterable);
|
||||||
|
|
||||||
// call 'get_iterator'
|
// call 'get_iterator'
|
||||||
|
|
@ -1336,7 +1299,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
));
|
));
|
||||||
c.push(Instruction::Call(1));
|
c.push(Instruction::Call(1));
|
||||||
}
|
}
|
||||||
_ => return Err("unsupported collection"), // TODO: Bind and call get_iterator() on type of iterable
|
_ => return None, // TODO: Bind and call get_iterator() on type of iterable
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate
|
// iterate
|
||||||
|
|
@ -1349,7 +1312,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
EXTERN_BUILTIN_LIST_ITERATOR_NEXT,
|
EXTERN_BUILTIN_LIST_ITERATOR_NEXT,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => return Err("unsupported iterator"), // TODO: Bind and call next() on type of iterator
|
_ => return None, // TODO: Bind and call next() on type of iterator
|
||||||
}
|
}
|
||||||
c.push(Instruction::Call(1)); // Call 'next'
|
c.push(Instruction::Call(1)); // Call 'next'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,7 @@ pub struct Environment {
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
pub next_index: usize,
|
pub next_index: usize,
|
||||||
pub declarations: HashMap<Box<str>, Declaration>,
|
pub declarations: HashMap<Box<str>, Declaration>,
|
||||||
pub error: Option<&'static str>,
|
pub is_error: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
|
|
@ -457,22 +457,18 @@ impl Environment {
|
||||||
location,
|
location,
|
||||||
next_index,
|
next_index,
|
||||||
declarations: HashMap::new(),
|
declarations: HashMap::new(),
|
||||||
error: None,
|
is_error: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_error(&self) -> bool {
|
pub fn error() -> EnvironmentRef {
|
||||||
self.error.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(why: &'static str) -> EnvironmentRef {
|
|
||||||
// TODO: Exactly once?
|
// TODO: Exactly once?
|
||||||
EnvironmentRef::new(Environment {
|
EnvironmentRef::new(Environment {
|
||||||
parent: None,
|
parent: None,
|
||||||
location: Location::Local,
|
location: Location::Local,
|
||||||
next_index: 0,
|
next_index: 0,
|
||||||
declarations: HashMap::new(),
|
declarations: HashMap::new(),
|
||||||
error: Some(why),
|
is_error: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1141,12 +1137,12 @@ impl Semantics {
|
||||||
let Some(pattern) = tree.child_tree_of_kind(&self.syntax_tree, TreeKind::Pattern) else {
|
let Some(pattern) = tree.child_tree_of_kind(&self.syntax_tree, TreeKind::Pattern) else {
|
||||||
// Should really have a pattern in there; otherwise there was a
|
// Should really have a pattern in there; otherwise there was a
|
||||||
// parse error, don't make more trouble.
|
// parse error, don't make more trouble.
|
||||||
return Environment::error("no rhs (pattern)");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The left hand side of the `is` expression is used for wildcard types.
|
// The left hand side of the `is` expression is used for wildcard types.
|
||||||
let Some(lhs) = tree.nth_tree(0) else {
|
let Some(lhs) = tree.nth_tree(0) else {
|
||||||
return Environment::error("no lhs (value)");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
self.environment_of_pattern(parent, pattern, lhs)
|
self.environment_of_pattern(parent, pattern, lhs)
|
||||||
}
|
}
|
||||||
|
|
@ -1163,7 +1159,7 @@ impl Semantics {
|
||||||
let Some(pattern) = tree.child_tree_of_kind(&self.syntax_tree, TreeKind::Pattern) else {
|
let Some(pattern) = tree.child_tree_of_kind(&self.syntax_tree, TreeKind::Pattern) else {
|
||||||
// Should really have a pattern in there; otherwise there was a
|
// Should really have a pattern in there; otherwise there was a
|
||||||
// parse error, don't make more trouble.
|
// parse error, don't make more trouble.
|
||||||
return Environment::error("arm: no lhs (pattern)");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The expression in the match expression is the binding for the wildcard pattern.
|
// The expression in the match expression is the binding for the wildcard pattern.
|
||||||
|
|
@ -1184,8 +1180,8 @@ impl Semantics {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The expression is the first tree child of match expression.
|
// The expression is the first tree child of match expression.
|
||||||
let Some(lhs) = tree.nth_tree(2) else {
|
let Some(lhs) = tree.nth_tree(1) else {
|
||||||
return Environment::error("arm: no rhs (expression)");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
self.environment_of_pattern(parent, pattern, lhs)
|
self.environment_of_pattern(parent, pattern, lhs)
|
||||||
}
|
}
|
||||||
|
|
@ -1205,7 +1201,7 @@ impl Semantics {
|
||||||
return parent;
|
return parent;
|
||||||
};
|
};
|
||||||
let Some(variable) = binding.nth_token(0) else {
|
let Some(variable) = binding.nth_token(0) else {
|
||||||
return Environment::error("no variable");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_wildcard = tree
|
let is_wildcard = tree
|
||||||
|
|
@ -1222,7 +1218,7 @@ impl Semantics {
|
||||||
// match for the variable to have a value.
|
// match for the variable to have a value.
|
||||||
let Some(type_expr) = tree.child_of_kind(&self.syntax_tree, TreeKind::TypeExpression)
|
let Some(type_expr) = tree.child_of_kind(&self.syntax_tree, TreeKind::TypeExpression)
|
||||||
else {
|
else {
|
||||||
return Environment::error("no type expression");
|
return Environment::error();
|
||||||
};
|
};
|
||||||
type_expr
|
type_expr
|
||||||
};
|
};
|
||||||
|
|
@ -1662,7 +1658,7 @@ impl Semantics {
|
||||||
let tree = &self.syntax_tree[left_tree];
|
let tree = &self.syntax_tree[left_tree];
|
||||||
|
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
let mut environment = Environment::error("?");
|
let mut environment = Environment::error();
|
||||||
|
|
||||||
let declaration = match tree.kind {
|
let declaration = match tree.kind {
|
||||||
// TODO: Assign to list access
|
// TODO: Assign to list access
|
||||||
|
|
@ -1672,7 +1668,7 @@ impl Semantics {
|
||||||
match environment.bind(id) {
|
match environment.bind(id) {
|
||||||
Some(decl) => decl,
|
Some(decl) => decl,
|
||||||
None => {
|
None => {
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
||||||
}
|
}
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
|
|
@ -1686,7 +1682,7 @@ impl Semantics {
|
||||||
match environment.bind(id) {
|
match environment.bind(id) {
|
||||||
Some(decl) => decl,
|
Some(decl) => decl,
|
||||||
None => {
|
None => {
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("'{typ}' has no member {id}"));
|
self.report_error_tree(tree, format!("'{typ}' has no member {id}"));
|
||||||
}
|
}
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
|
|
@ -1824,7 +1820,7 @@ impl Semantics {
|
||||||
.type_of_declaration(*tree, declaration),
|
.type_of_declaration(*tree, declaration),
|
||||||
),
|
),
|
||||||
None => {
|
None => {
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
|
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
|
||||||
}
|
}
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
|
|
@ -2050,7 +2046,7 @@ impl Semantics {
|
||||||
|
|
||||||
let id_str = id.as_str(&self.source);
|
let id_str = id.as_str(&self.source);
|
||||||
let Some(declaration) = env.bind(id_str) else {
|
let Some(declaration) = env.bind(id_str) else {
|
||||||
if !env.is_error() {
|
if !env.is_error {
|
||||||
self.report_error_span(
|
self.report_error_span(
|
||||||
id.start(),
|
id.start(),
|
||||||
id.end(),
|
id.end(),
|
||||||
|
|
@ -2104,10 +2100,10 @@ impl Semantics {
|
||||||
}
|
}
|
||||||
EnvironmentRef::new(result)
|
EnvironmentRef::new(result)
|
||||||
}
|
}
|
||||||
Type::Error => return Environment::error("error type has no members"),
|
Type::Error => return Environment::error(),
|
||||||
_ => {
|
_ => {
|
||||||
self.report_error_tree_ref(t, format!("cannot access members of '{typ}'"));
|
self.report_error_tree_ref(t, format!("cannot access members of '{typ}'"));
|
||||||
return Environment::error("type has no members");
|
return Environment::error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2144,7 +2140,7 @@ impl Semantics {
|
||||||
return Some(self.type_of_declaration(Some(t), declaration));
|
return Some(self.type_of_declaration(Some(t), declaration));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
||||||
}
|
}
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
|
|
@ -2206,7 +2202,7 @@ impl Semantics {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, "`self` is only valid in methods");
|
self.report_error_tree(tree, "`self` is only valid in methods");
|
||||||
}
|
}
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
|
|
@ -2344,7 +2340,7 @@ impl Semantics {
|
||||||
let declaration = match environment.bind(id) {
|
let declaration = match environment.bind(id) {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
None => {
|
None => {
|
||||||
if !environment.is_error() {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
self.report_error_tree(tree, format!("cannot find value {id} here"));
|
||||||
}
|
}
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
|
|
@ -2651,9 +2647,6 @@ impl Semantics {
|
||||||
eprintln!("\nThe environment of the tree was:");
|
eprintln!("\nThe environment of the tree was:");
|
||||||
let mut environment = Some(self.environment_of(tr));
|
let mut environment = Some(self.environment_of(tr));
|
||||||
while let Some(env) = environment {
|
while let Some(env) = environment {
|
||||||
if let Some(error) = env.error {
|
|
||||||
eprint!(" *** ERROR: {error}");
|
|
||||||
}
|
|
||||||
for (k, v) in env.declarations.iter() {
|
for (k, v) in env.declarations.iter() {
|
||||||
eprint!(" {k}: ");
|
eprint!(" {k}: ");
|
||||||
match v {
|
match v {
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,13 @@ class Monster {
|
||||||
|
|
||||||
fun print(x:string) {}
|
fun print(x:string) {}
|
||||||
|
|
||||||
fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) -> bool {
|
fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) {
|
||||||
match weapon {
|
match weapon {
|
||||||
w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange,
|
w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange,
|
||||||
_ -> distance == 1
|
_ -> distance == 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun roll_dice(x:f64) -> f64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64) {
|
fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64) {
|
||||||
// This is worse than Bob's final version but but it works. `is` operator
|
// This is worse than Bob's final version but but it works. `is` operator
|
||||||
// should be the same precedence as `and` and left-associative, so the
|
// should be the same precedence as `and` and left-associative, so the
|
||||||
|
|
@ -83,10 +79,10 @@ fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64)
|
||||||
|
|
||||||
if monster.health <= damage {
|
if monster.health <= damage {
|
||||||
print("You kill the monster!");
|
print("You kill the monster!");
|
||||||
monster.health = 0;
|
monster.health = 0
|
||||||
} else {
|
} else {
|
||||||
print("You wound the monster.");
|
print("You wound the monster.");
|
||||||
monster.health = monster.health - damage;
|
monster.health = monster.health - damage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,5 +147,6 @@ fun test() -> f64 {
|
||||||
// like the above.
|
// like the above.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ignore not finished yet, still compiler bugs
|
||||||
// @no-errors
|
// @no-errors
|
||||||
// @eval: Float(190.0)
|
// @eval: Float(90.0)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue