pipe, return
This commit is contained in:
@@ -49,9 +49,9 @@ impl Env {
|
||||
}
|
||||
|
||||
pub trait Codegen {
|
||||
fn get_output(&self) -> String;
|
||||
fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>>;
|
||||
fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>>;
|
||||
fn get_output(&self) -> String;
|
||||
fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>>;
|
||||
fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
@@ -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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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")?;
|
||||
}
|
||||
|
||||
writeln!(&mut self.output, " call {}", callee)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ pub enum Stmt {
|
||||
params: Vec<Param>,
|
||||
body: Box<Stmt>,
|
||||
},
|
||||
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<Stmt, Box<dyn Error>> {
|
||||
Ok(Stmt::Return(self.expression()?))
|
||||
}
|
||||
|
||||
fn if_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
|
||||
let condition = self.expression()?;
|
||||
let then_branch = self.block()?;
|
||||
@@ -177,7 +184,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn assignment(&mut self) -> Result<Expr, Box<dyn Error>> {
|
||||
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<Expr, Box<dyn Error>> {
|
||||
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<Expr, Box<dyn Error>> {
|
||||
let mut expr = self.logical_and()?;
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user