diff --git a/src/codegen.rs b/src/codegen.rs index 95c8a3d..778a5ac 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -49,9 +49,9 @@ impl Env { } pub trait Codegen { + fn get_output(&self) -> String; fn emit_prologue(&mut self) -> Result<(), Box>; fn emit_epilogue(&mut self) -> Result<(), Box>; - fn get_output(&self) -> String; fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box>; fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box>; } diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 144b4e9..0325aaa 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -26,6 +26,10 @@ impl CodegenX86_64 { } impl Codegen for CodegenX86_64 { + fn get_output(&self) -> String { + self.output.clone() + } + fn emit_prologue(&mut self) -> Result<(), Box> { writeln!( &mut self.output, @@ -55,10 +59,6 @@ print: Ok(()) } - fn get_output(&self) -> String { - self.output.clone() - } - fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box> { match stmt { Stmt::Expression(expr) => self.compile_expr(env, expr)?, @@ -121,9 +121,15 @@ print: self.compile_stmt(env, *body)?; + writeln!(&mut self.output, " mov rax, 0")?; + writeln!(&mut self.output, " mov rsp, rbp")?; + writeln!(&mut self.output, " pop rbp")?; + writeln!(&mut self.output, " ret")?; + } + Stmt::Return(expr) => { + self.compile_expr(env, expr)?; writeln!(&mut self.output, " mov rsp, rbp")?; writeln!(&mut self.output, " pop rbp")?; - writeln!(&mut self.output, " mov rax, 0")?; writeln!(&mut self.output, " ret")?; } } @@ -245,10 +251,12 @@ print: }; // TODO - assert!(args.len() == 1); + assert!(args.len() <= 1); + if args.len() == 1 { + self.compile_expr(env, args.first().unwrap().clone())?; + writeln!(&mut self.output, " mov rdi, rax")?; + } - self.compile_expr(env, args.first().unwrap().clone())?; - writeln!(&mut self.output, " mov rdi, rax")?; writeln!(&mut self.output, " call {}", callee)?; } } diff --git a/src/parser.rs b/src/parser.rs index e61251d..00e9d88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -31,6 +31,7 @@ pub enum Stmt { params: Vec, body: Box, }, + Return(Expr), } #[derive(Debug, Clone)] @@ -139,11 +140,17 @@ impl Parser { self.if_statement() } else if self.match_token(&[TokenType::KeywordWhile]) { self.while_statement() + } else if self.match_token(&[TokenType::KeywordReturn]) { + self.return_statement() } else { Ok(Stmt::Expression(self.expression()?)) } } + fn return_statement(&mut self) -> Result> { + Ok(Stmt::Return(self.expression()?)) + } + fn if_statement(&mut self) -> Result> { let condition = self.expression()?; let then_branch = self.block()?; @@ -177,7 +184,7 @@ impl Parser { } fn assignment(&mut self) -> Result> { - let expr = self.logical_or()?; + let expr = self.pipe()?; if self.match_token(&[TokenType::Equal]) { let equals = self.previous().clone(); @@ -195,6 +202,36 @@ impl Parser { Ok(expr) } + fn pipe(&mut self) -> Result> { + let mut expr = self.logical_or()?; + + while self.match_token(&[TokenType::Pipe]) { + let pipe = self.previous().clone(); + let right = self.equality()?; + + match right { + Expr::Call { + callee, + paren, + args, + } => { + let mut new_args = args; + new_args.insert(0, expr); + expr = Expr::Call { + callee, + paren, + args: new_args, + } + } + _ => { + return error!(pipe.loc, "tried to pipe into a non-call expression"); + } + }; + } + + Ok(expr) + } + fn logical_or(&mut self) -> Result> { let mut expr = self.logical_and()?; diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a7158e7..0cc718c 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -17,6 +17,7 @@ pub enum TokenType { Colon, And, Or, + Pipe, Equal, DoubleEqual, @@ -35,6 +36,7 @@ pub enum TokenType { KeywordElse, KeywordWhile, KeywordFunc, + KeywordReturn, Indent, Dedent, @@ -159,8 +161,10 @@ impl Tokenizer { '|' => { if self.match_char('|') { self.add_token(TokenType::Or); + } else if self.match_char('>') { + self.add_token(TokenType::Pipe); } else { - return error!(self.loc, "expected '|' after '|'"); + return error!(self.loc, "expected '>' or '|' after '|'"); } } '!' => { @@ -300,6 +304,7 @@ impl Tokenizer { "else" => TokenType::KeywordElse, "while" => TokenType::KeywordWhile, "func" => TokenType::KeywordFunc, + "return" => TokenType::KeywordReturn, _ => TokenType::Identifier, }) }