Skip to content

Commit

Permalink
WIP: if expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
sezna committed Jul 26, 2024
1 parent b41a98b commit 7ac96f4
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 25 deletions.
4 changes: 4 additions & 0 deletions petr-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ impl std::fmt::Display for Intrinsic {
Intrinsic::Divide => write!(f, "divide"),
Intrinsic::Malloc => write!(f, "malloc"),
Intrinsic::SizeOf => write!(f, "size_of"),
Intrinsic::Equals => write!(f, "eq"),
}
}
}
Expand All @@ -190,6 +191,7 @@ pub enum Intrinsic {
Divide,
Malloc,
SizeOf,
Equals,
}

#[derive(Clone)]
Expand Down Expand Up @@ -257,6 +259,7 @@ pub enum Operator {
Minus,
Star,
Slash,
Eq,
}

impl Operator {
Expand All @@ -266,6 +269,7 @@ impl Operator {
Operator::Minus => "-",
Operator::Star => "*",
Operator::Slash => "/",
Operator::Eq => "=",
}
}
}
Expand Down
1 change: 1 addition & 0 deletions petr-ast/src/pretty_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ impl PrettyPrint for OperatorExpression {
Operator::Minus => "-",
Operator::Star => "*",
Operator::Slash => "/",
Operator::Eq => "=",
};
format!("{}({} {})", op, lhs, rhs)
}
Expand Down
52 changes: 37 additions & 15 deletions petr-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod opcodes;

pub use error::LoweringError;
use opcodes::*;
pub use opcodes::{DataLabel, Intrinsic, IrOpcode, Reg, ReservedRegister};
pub use opcodes::{DataLabel, Intrinsic, IrOpcode, LabelId, Reg, ReservedRegister};

pub fn lower(checker: TypeChecker) -> Result<(DataSection, Vec<IrOpcode>)> {
let lowerer = Lowerer::new(checker)?;
Expand All @@ -43,6 +43,7 @@ pub struct Lowerer {
variables_in_scope: Vec<BTreeMap<SymbolId, Reg>>,
monomorphized_functions: IndexMap<MonomorphizedFunctionId, (FunctionSignature, Function)>,
errors: Vec<SpannedItem<LoweringError>>,
label_assigner: usize,
}

#[derive(Debug, Clone)]
Expand All @@ -65,6 +66,7 @@ impl Lowerer {
type_checker,
variables_in_scope: Default::default(),
monomorphized_functions: Default::default(),
label_assigner: 0,
errors: Default::default(),
};

Expand All @@ -85,7 +87,7 @@ impl Lowerer {

// insert jump to entry point as first instr
if let Some(entry_point) = self.entry_point {
program_section.push(IrOpcode::JumpImmediate(entry_point));
program_section.push(IrOpcode::JumpImmediateFunction(entry_point));
} else {
// TODO use diagnostics here
eprintln!("Warning: Generating IR for program with no entry point");
Expand Down Expand Up @@ -196,7 +198,7 @@ impl Lowerer {
let monomorphized_func_id = self.monomorphize_function((*func, arg_petr_types.into_boxed_slice()))?;

// jump to the function
buf.push(IrOpcode::JumpImmediate(monomorphized_func_id));
buf.push(IrOpcode::JumpImmediateFunction(monomorphized_func_id));

// after returning to this function, return the register
match return_destination {
Expand Down Expand Up @@ -263,10 +265,29 @@ impl Lowerer {
condition,
then_branch,
else_branch,
} => todo!(),
} => {
let mut buf = vec![];
let condition_reg = self.fresh_reg();
buf.append(&mut self.lower_expr(condition, ReturnDestination::Reg(condition_reg))?);
let else_label = self.new_label();
let end_label = self.new_label();
buf.push(IrOpcode::JumpIfFalseImmediate(condition_reg, else_label));
buf.append(&mut self.lower_expr(then_branch, return_destination.clone())?);
buf.push(IrOpcode::JumpImmediate(end_label));
buf.push(IrOpcode::Label(else_label));
buf.append(&mut self.lower_expr(else_branch, return_destination)?);
buf.push(IrOpcode::Label(end_label));
Ok(buf)
},
}
}

fn new_label(&mut self) -> LabelId {
let label: LabelId = self.label_assigner.into();
self.label_assigner += 1;
label
}

fn insert_literal_data(
&mut self,
lit: &petr_typecheck::Literal,
Expand Down Expand Up @@ -373,6 +394,17 @@ impl Lowerer {
}
Ok(buf)
},
Equals(lhs, rhs) => {
let lhs_reg = self.fresh_reg();
let rhs_reg = self.fresh_reg();
buf.append(&mut self.lower_expr(lhs, ReturnDestination::Reg(lhs_reg))?);
buf.append(&mut self.lower_expr(rhs, ReturnDestination::Reg(rhs_reg))?);
let return_reg = match return_destination {
ReturnDestination::Reg(reg) => reg,
};
buf.push(IrOpcode::Equal(return_reg, lhs_reg, rhs_reg));
Ok(buf)
},
}
}

Expand Down Expand Up @@ -467,17 +499,7 @@ impl Lowerer {
}
}

/*
impl MonomorphizedFunction {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
label: self.id,
concrete_types: self.params.iter().map(|(_name, ty)| ty.clone()).collect(),
}
}
}
*/

#[derive(Clone)]
enum ReturnDestination {
Reg(Reg),
}
Expand Down
7 changes: 5 additions & 2 deletions petr-ir/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ macro_rules! ir_ops {
}

ir_ops! {
JumpImmediate "jumpi" MonomorphizedFunctionId: imm;
JumpImmediateFunction "fjumpi" MonomorphizedFunctionId: imm;
Jump "jump" Reg: dest;
Add "add" Reg: dest, Reg: lhs, Reg: rhs;
Multiply "mult" Reg: dest, Reg: lhs, Reg: rhs;
Expand All @@ -63,7 +63,10 @@ ir_ops! {
MallocImmediate "malloci" Reg: ptr_dest, Size<Bytes>: imm;
/// Register `src` will itself have its value written to the memory pointed to by `dest_ptr`
WriteRegisterToMemory "sri" Reg: src, Reg: dest_ptr;
Comment "comment" String: comment
Comment "comment" String: comment;
JumpIfFalseImmediate "cjump" Reg: cond, LabelId: dest;
JumpImmediate "jumpi" LabelId: dest;
Equal "eq" Reg: dest, Reg: lhs, Reg: rhs
}

idx_map_key!(LabelId);
Expand Down
2 changes: 2 additions & 0 deletions petr-parse/src/parse_to_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ impl Parse for Operator {
Token::Minus => Some(Operator::Minus),
Token::Star => Some(Operator::Star),
Token::Slash => Some(Operator::Slash),
Token::Equals => Some(Operator::Eq),
_ => {
p.push_error(p.span().with_item(ParseErrorKind::ExpectedOneOf(
vec![Token::Plus, Token::Minus, Token::Star, Token::Slash],
Expand Down Expand Up @@ -363,6 +364,7 @@ impl Parse for IntrinsicCall {
"divide" => Intrinsic::Divide,
"malloc" => Intrinsic::Malloc,
"size_of" => Intrinsic::SizeOf,
"equals" => Intrinsic::Equals,
a => todo!("unrecognized intrinsic error: {a:?}"),
};
p.token(Token::Intrinsic)?;
Expand Down
2 changes: 1 addition & 1 deletion petr-parse/src/parser/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub enum Token {
impl Token {
pub(crate) fn is_operator(&self) -> bool {
use Token::*;
matches!(self, Plus | Minus | Slash | Star)
matches!(self, Plus | Minus | Slash | Star | Equals)
}
}

Expand Down
18 changes: 18 additions & 0 deletions petr-parse/src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,21 @@ fn if_exp_basic() {
"#]],
)
}

#[test]
fn nested_if_exp() {
check(
vec![
"fn if_exp() returns 'int
if true then if false then 1 else 0 else 0
",
],
expect![[r#"
AST
____
module test =
Func if_exp() -> 'int if true then if false then 1 else 0 else 0
"#]],
)
}
1 change: 1 addition & 0 deletions petr-resolve/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ impl Resolve for SpannedItem<Expression> {
Minus => "sub",
Star => "mul",
Slash => "div",
Eq => "eq",
};
let path = ["std", "ops", func];

Expand Down
2 changes: 2 additions & 0 deletions petr-stdlib/src/ops.pt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export fn sub(lhs in 'int, rhs in 'int) returns 'int @subtract lhs, rhs
export fn mult(lhs in 'int, rhs in 'int) returns 'int @multiply lhs, rhs

export fn div(lhs in 'int, rhs in 'int) returns 'int @divide lhs, rhs

export fn eq(lhs in 'A, rhs in 'A) returns 'bool @equals lhs, rhs
27 changes: 20 additions & 7 deletions petr-typecheck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,11 +559,7 @@ impl TypeChecker {
ErrorRecovery(..) => self.ctx.error_recovery,
ExprWithBindings { expression, .. } => self.expr_ty(expression),
TypeConstructor { ty, .. } => *ty,
If {
condition,
then_branch,
else_branch,
} => todo!(),
If { then_branch, .. } => self.expr_ty(then_branch),
}
}

Expand Down Expand Up @@ -618,6 +614,7 @@ pub enum Intrinsic {
Subtract(Box<TypedExpr>, Box<TypedExpr>),
Malloc(Box<TypedExpr>),
SizeOf(Box<TypedExpr>),
Equals(Box<TypedExpr>, Box<TypedExpr>),
}

impl std::fmt::Debug for Intrinsic {
Expand All @@ -633,6 +630,7 @@ impl std::fmt::Debug for Intrinsic {
Intrinsic::Subtract(lhs, rhs) => write!(f, "@subtract({:?}, {:?})", lhs, rhs),
Intrinsic::Malloc(size) => write!(f, "@malloc({:?})", size),
Intrinsic::SizeOf(expr) => write!(f, "@sizeof({:?})", expr),
Intrinsic::Equals(lhs, rhs) => write!(f, "@equal({:?}, {:?})", lhs, rhs),
}
}
}
Expand Down Expand Up @@ -727,7 +725,9 @@ impl std::fmt::Debug for TypedExpr {
condition,
then_branch,
else_branch,
} => todo!(),
} => {
write!(f, "if {:?} then {:?} else {:?}", condition, then_branch, else_branch)
},
}
}
}
Expand Down Expand Up @@ -943,6 +943,19 @@ impl TypeCheck for SpannedItem<ResolvedIntrinsic> {
ty: ctx.int(),
}
},
Equals => {
if self.item().args.len() != 2 {
todo!("equal arg len check");
}

let lhs = self.item().args[0].type_check(ctx);
let rhs = self.item().args[1].type_check(ctx);
ctx.unify(ctx.expr_ty(&lhs), ctx.expr_ty(&rhs), self.span());
TypedExprKind::Intrinsic {
intrinsic: Intrinsic::Equals(Box::new(lhs), Box::new(rhs)),
ty: ctx.bool(),
}
},
};

TypedExpr { kind, span: self.span() }
Expand Down Expand Up @@ -1099,7 +1112,7 @@ fn replace_var_reference_types(
replace_var_reference_types(&mut a.kind, params, num_replacements);
},
// intrinsics which take two args, grouped for convenience
Add(a, b) | Subtract(a, b) | Multiply(a, b) | Divide(a, b) => {
Add(a, b) | Subtract(a, b) | Multiply(a, b) | Divide(a, b) | Equals(a, b) => {
replace_var_reference_types(&mut a.kind, params, num_replacements);
replace_var_reference_types(&mut b.kind, params, num_replacements);
},
Expand Down
Binary file modified petr-vm/src/lib.rs
Binary file not shown.

0 comments on commit 7ac96f4

Please sign in to comment.