From 920621d2d8c00a80519a47267a39a6d4ecb563a3 Mon Sep 17 00:00:00 2001 From: sezna Date: Sat, 29 Jun 2024 06:58:42 -0700 Subject: [PATCH 1/2] clean up TODOs --- petr-codegen/src/lib.rs | 1 - petr-fmt/src/lib.rs | 19 +++++++++++++++++-- petr-ir/src/lib.rs | 4 +--- petr-typecheck/src/lib.rs | 1 - 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/petr-codegen/src/lib.rs b/petr-codegen/src/lib.rs index c390f5d..6231e4d 100644 --- a/petr-codegen/src/lib.rs +++ b/petr-codegen/src/lib.rs @@ -77,7 +77,6 @@ impl IrContext { Ok(data_id) } - // TODO: lowered function type? pub fn add_function( &mut self, func_name: &str, diff --git a/petr-fmt/src/lib.rs b/petr-fmt/src/lib.rs index 3aa6d92..6d37be3 100644 --- a/petr-fmt/src/lib.rs +++ b/petr-fmt/src/lib.rs @@ -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, diff --git a/petr-ir/src/lib.rs b/petr-ir/src/lib.rs index 2e87a52..b16047b 100644 --- a/petr-ir/src/lib.rs +++ b/petr-ir/src/lib.rs @@ -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)?; @@ -359,11 +358,10 @@ impl Lowerer { } } -// type VariableScope = BTreeMap; - enum ReturnDestination { Reg(Reg), } + fn fits_in_reg(_: &TypeVariable) -> bool { // TODO true diff --git a/petr-typecheck/src/lib.rs b/petr-typecheck/src/lib.rs index 69d5490..39d7f4e 100644 --- a/petr-typecheck/src/lib.rs +++ b/petr-typecheck/src/lib.rs @@ -732,7 +732,6 @@ mod tests { ); } - // TODO this is maybe good for generic syntax #[test] fn identity_resolution_generic() { check( From 11fdc29381bb0858f7027372159bf7eaf3142ed2 Mon Sep 17 00:00:00 2001 From: sezna Date: Sat, 29 Jun 2024 07:42:55 -0700 Subject: [PATCH 2/2] add all arithmetic ops --- petr-ast/src/ast.rs | 8 ++++ petr-ir/src/lib.rs | 28 +++++++++---- petr-ir/src/opcodes.rs | 3 ++ petr-parse/src/parse_to_ast.rs | 4 ++ petr-typecheck/src/lib.rs | 47 ++++++++++++++++++++- petr-vm/src/lib.rs | 74 +++++++++++++++++++++++++++++++++- 6 files changed, 153 insertions(+), 11 deletions(-) diff --git a/petr-ast/src/ast.rs b/petr-ast/src/ast.rs index c1eef66..57c1711 100644 --- a/petr-ast/src/ast.rs +++ b/petr-ast/src/ast.rs @@ -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"), } } } @@ -151,6 +155,10 @@ pub enum Intrinsic { /// intrinsic for `libc` puts Puts, Add, + Subtract, + Multiply, + Divide, + Malloc, } #[derive(Clone)] diff --git a/petr-ir/src/lib.rs b/petr-ir/src/lib.rs index b16047b..c645672 100644 --- a/petr-ir/src/lib.rs +++ b/petr-ir/src/lib.rs @@ -281,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, 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) } diff --git a/petr-ir/src/opcodes.rs b/petr-ir/src/opcodes.rs index feb8e27..c2eb30d 100644 --- a/petr-ir/src/opcodes.rs +++ b/petr-ir/src/opcodes.rs @@ -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; diff --git a/petr-parse/src/parse_to_ast.rs b/petr-parse/src/parse_to_ast.rs index 7e11e4e..5dd126e 100644 --- a/petr-parse/src/parse_to_ast.rs +++ b/petr-parse/src/parse_to_ast.rs @@ -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)?; diff --git a/petr-typecheck/src/lib.rs b/petr-typecheck/src/lib.rs index 39d7f4e..e217d41 100644 --- a/petr-typecheck/src/lib.rs +++ b/petr-typecheck/src/lib.rs @@ -302,6 +302,9 @@ impl TypeChecker { pub enum Intrinsic { Puts(Box), Add(Box, Box), + Multiply(Box, Box), + Divide(Box, Box), + Subtract(Box, Box), } impl std::fmt::Debug for Intrinsic { @@ -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), } } } @@ -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!(), } } } @@ -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}; diff --git a/petr-vm/src/lib.rs b/petr-vm/src/lib.rs index b9e438b..9733727 100644 --- a/petr-vm/src/lib.rs +++ b/petr-vm/src/lib.rs @@ -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(); @@ -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 { @@ -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) => {