Skip to content

Commit

Permalink
Merge pull request #76 from sezna/alex/more-updates
Browse files Browse the repository at this point in the history
Clean up some TODOs and tests; Add more arithmetic intrinsics
  • Loading branch information
sezna authored Jun 29, 2024
2 parents 07d508f + e94349a commit 7bd6acb
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 18 deletions.
8 changes: 8 additions & 0 deletions petr-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ impl std::fmt::Display for Intrinsic {
match self {
Intrinsic::Puts => write!(f, "puts"),
Intrinsic::Add => write!(f, "add"),
Intrinsic::Subtract => write!(f, "subtract"),
Intrinsic::Multiply => write!(f, "multiply"),
Intrinsic::Divide => write!(f, "divide"),
Intrinsic::Malloc => write!(f, "malloc"),
}
}
}
Expand All @@ -151,6 +155,10 @@ pub enum Intrinsic {
/// intrinsic for `libc` puts
Puts,
Add,
Subtract,
Multiply,
Divide,
Malloc,
}

#[derive(Clone)]
Expand Down
1 change: 0 additions & 1 deletion petr-codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ impl IrContext {
Ok(data_id)
}

// TODO: lowered function type?
pub fn add_function(
&mut self,
func_name: &str,
Expand Down
19 changes: 17 additions & 2 deletions petr-fmt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,14 +474,29 @@ impl Formattable for TypeVariant {
}
let mut fields_buf = Vec::with_capacity(self.fields.len());
for field in &*self.fields {
// TODO use impl Format for 'Ty here
fields_buf.push(field.pretty_print(&ctx.interner, ctx.indentation()));
fields_buf.push(field.format(ctx).into_single_line().content.to_string());
}
buf.push_str(&fields_buf.join(" "));
FormattedLines::new(vec![ctx.new_line(buf)])
}
}

impl Formattable for Ty {
fn format(
&self,
ctx: &mut FormatterContext,
) -> FormattedLines {
let name = match self {
Ty::Bool => "bool".to_string(),
Ty::Int => "int".to_string(),
Ty::String => "string".to_string(),
Ty::Unit => "unit".to_string(),
Ty::Named(name) => ctx.interner.get(name.id).to_string(),
};
FormattedLines::new(vec![ctx.new_line(format!("'{name}"))])
}
}

impl Formattable for List {
fn format(
&self,
Expand Down
32 changes: 21 additions & 11 deletions petr-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ impl Lowerer {
}
}

// TODO we could support other return dests
let return_reg = ctx.fresh_reg();
let return_dest = ReturnDestination::Reg(return_reg);
let mut expr_body = ctx.lower_expr(&func.body, return_dest)?;
Expand Down Expand Up @@ -282,17 +281,29 @@ impl Lowerer {
buf.push(IrOpcode::LoadImmediate(reg, 0));
},
}
Ok(buf)
},
petr_typecheck::Intrinsic::Add(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 ReturnDestination::Reg(return_reg) = return_destination;
buf.push(IrOpcode::Add(return_reg, lhs_reg, rhs_reg));
},
petr_typecheck::Intrinsic::Add(lhs, rhs) => self.lower_arithmetic_op(lhs, rhs, return_destination, IrOpcode::Add),
petr_typecheck::Intrinsic::Multiply(lhs, rhs) => self.lower_arithmetic_op(lhs, rhs, return_destination, IrOpcode::Multiply),
petr_typecheck::Intrinsic::Divide(lhs, rhs) => self.lower_arithmetic_op(lhs, rhs, return_destination, IrOpcode::Divide),
petr_typecheck::Intrinsic::Subtract(lhs, rhs) => self.lower_arithmetic_op(lhs, rhs, return_destination, IrOpcode::Subtract),
}
}

fn lower_arithmetic_op(
&mut self,
lhs: &TypedExpr,
rhs: &TypedExpr,
return_destination: ReturnDestination,
op: fn(Reg, Reg, Reg) -> IrOpcode,
) -> Result<Vec<IrOpcode>, LoweringError> {
let mut buf = vec![];
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 ReturnDestination::Reg(return_reg) = return_destination;
buf.push(op(return_reg, lhs_reg, rhs_reg));
Ok(buf)
}

Expand Down Expand Up @@ -359,11 +370,10 @@ impl Lowerer {
}
}

// type VariableScope = BTreeMap<SymbolId, Reg>;

enum ReturnDestination {
Reg(Reg),
}

fn fits_in_reg(_: &TypeVariable) -> bool {
// TODO
true
Expand Down
3 changes: 3 additions & 0 deletions petr-ir/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ ir_ops! {
JumpImmediate "jumpi" FunctionId imm;
Jump "jump" Reg dest;
Add "add" Reg dest, Reg lhs, Reg rhs;
Multiply "mult" Reg dest, Reg lhs, Reg rhs;
Subtract "sub" Reg dest, Reg lhs, Reg rhs;
Divide "div" Reg dest, Reg lhs, Reg rhs;
LoadData "ld" Reg dest, DataLabel data;
StackPop "pop" TypedReg dest;
StackPush "push" TypedReg src;
Expand Down
4 changes: 4 additions & 0 deletions petr-parse/src/parse_to_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ impl Parse for IntrinsicCall {
let intrinsic = match &name[1..] {
"puts" => Intrinsic::Puts,
"add" => Intrinsic::Add,
"subtract" => Intrinsic::Subtract,
"multiply" => Intrinsic::Multiply,
"divide" => Intrinsic::Divide,
"malloc" => Intrinsic::Malloc,
a => todo!("unrecognized intrinsic error: {a:?}"),
};
p.token(Token::Intrinsic)?;
Expand Down
48 changes: 46 additions & 2 deletions petr-typecheck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ impl TypeChecker {
pub enum Intrinsic {
Puts(Box<TypedExpr>),
Add(Box<TypedExpr>, Box<TypedExpr>),
Multiply(Box<TypedExpr>, Box<TypedExpr>),
Divide(Box<TypedExpr>, Box<TypedExpr>),
Subtract(Box<TypedExpr>, Box<TypedExpr>),
}

impl std::fmt::Debug for Intrinsic {
Expand All @@ -312,6 +315,9 @@ impl std::fmt::Debug for Intrinsic {
match self {
Intrinsic::Puts(expr) => write!(f, "@puts({:?})", expr),
Intrinsic::Add(lhs, rhs) => write!(f, "@add({:?}, {:?})", lhs, rhs),
Intrinsic::Multiply(lhs, rhs) => write!(f, "@multiply({:?}, {:?})", lhs, rhs),
Intrinsic::Divide(lhs, rhs) => write!(f, "@divide({:?}, {:?})", lhs, rhs),
Intrinsic::Subtract(lhs, rhs) => write!(f, "@subtract({:?}, {:?})", lhs, rhs),
}
}
}
Expand Down Expand Up @@ -540,6 +546,46 @@ impl TypeCheck for ResolvedIntrinsic {
ty: tp!(int),
}
},
Subtract => {
if self.args.len() != 2 {
todo!("subtract arg len check");
}
let arg1 = self.args[0].type_check(ctx);
let arg2 = self.args[1].type_check(ctx);
ctx.unify(&arg1.ty(), &tp!(int));
ctx.unify(&arg2.ty(), &tp!(int));
TypedExpr::Intrinsic {
intrinsic: Intrinsic::Subtract(Box::new(arg1), Box::new(arg2)),
ty: tp!(int),
}
},
Multiply => {
if self.args.len() != 2 {
todo!("mult arg len check");
}
let arg1 = self.args[0].type_check(ctx);
let arg2 = self.args[1].type_check(ctx);
ctx.unify(&arg1.ty(), &tp!(int));
ctx.unify(&arg2.ty(), &tp!(int));
TypedExpr::Intrinsic {
intrinsic: Intrinsic::Multiply(Box::new(arg1), Box::new(arg2)),
ty: tp!(int),
}
},
Divide => {
if self.args.len() != 2 {
todo!("Divide arg len check");
}
let arg1 = self.args[0].type_check(ctx);
let arg2 = self.args[1].type_check(ctx);
ctx.unify(&arg1.ty(), &tp!(int));
ctx.unify(&arg2.ty(), &tp!(int));
TypedExpr::Intrinsic {
intrinsic: Intrinsic::Divide(Box::new(arg1), Box::new(arg2)),
ty: tp!(int),
}
},
Malloc => todo!(),
}
}
}
Expand Down Expand Up @@ -614,7 +660,6 @@ impl TypeCheck for petr_resolve::FunctionCall {

#[cfg(test)]
mod tests {

use expect_test::{expect, Expect};
use petr_resolve::resolve_symbols;
use petr_utils::{render_error, SymbolInterner};
Expand Down Expand Up @@ -732,7 +777,6 @@ mod tests {
);
}

// TODO this is maybe good for generic syntax
#[test]
fn identity_resolution_generic() {
check(
Expand Down
74 changes: 72 additions & 2 deletions petr-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ mod tests {
) {
let input = input.into();
let parser = petr_parse::Parser::new(vec![
("std/ops.pt", "function add(lhs in 'int, rhs in 'int) returns 'int @add lhs, rhs"),
(
"std/ops.pt",
"
function add(lhs in 'int, rhs in 'int) returns 'int @add lhs, rhs
function sub(lhs in 'int, rhs in 'int) returns 'int @subtract lhs, rhs
function mul(lhs in 'int, rhs in 'int) returns 'int @multiply lhs, rhs
function div(lhs in 'int, rhs in 'int) returns 'int @divide lhs, rhs
",
),
("test", &input),
]);
let (ast, errs, interner, source_map) = parser.into_result();
Expand Down Expand Up @@ -87,6 +95,50 @@ function main() returns 'int ~hi(1, 3)
expect!("Value(96)"),
)
}

#[test]
fn addition_path_res() {
check(
r#"
function hi(x in 'int, y in 'int) returns 'int
let a = x,
b = y,
c = 20,
d = 30,
e = 42,
~std.ops.add(a, + b + c + d e)
function main() returns 'int ~hi(1, 3)
"#,
expect!("Value(96)"),
)
}

#[test]
fn subtraction() {
check(
r#"
function hi(x in 'int) returns 'int
let a = + x 1,
b = - x 1,
c = - 20 x,
d = + 20 x
d
function main() returns 'int ~hi(100)
"#,
expect!("Value(120)"),
)
}
#[test]
fn overflowing_sub() {
check(
r#"
function main() returns 'int - 0 1
"#,
expect!("Value(18446744073709551615)"),
)
}
}

pub struct Vm {
Expand Down Expand Up @@ -196,7 +248,25 @@ impl Vm {
IrOpcode::Add(dest, lhs, rhs) => {
let lhs = self.get_register(lhs)?;
let rhs = self.get_register(rhs)?;
self.set_register(dest, Value(lhs.0 + rhs.0));
self.set_register(dest, Value(lhs.0.wrapping_add(rhs.0)));
Ok(Continue)
},
IrOpcode::Multiply(dest, lhs, rhs) => {
let lhs = self.get_register(lhs)?;
let rhs = self.get_register(rhs)?;
self.set_register(dest, Value(lhs.0.wrapping_mul(rhs.0)));
Ok(Continue)
},
IrOpcode::Subtract(dest, lhs, rhs) => {
let lhs = self.get_register(lhs)?;
let rhs = self.get_register(rhs)?;
self.set_register(dest, Value(lhs.0.wrapping_sub(rhs.0)));
Ok(Continue)
},
IrOpcode::Divide(dest, lhs, rhs) => {
let lhs = self.get_register(lhs)?;
let rhs = self.get_register(rhs)?;
self.set_register(dest, Value(lhs.0 / rhs.0));
Ok(Continue)
},
IrOpcode::LoadData(dest, data_label) => {
Expand Down

0 comments on commit 7bd6acb

Please sign in to comment.