1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00
This commit is contained in:
Natapat Samutpong 2022-03-12 10:10:41 +07:00
parent 4e040f9601
commit ebaee0ea0c
6 changed files with 91 additions and 38 deletions

View file

@ -58,7 +58,10 @@ impl Codegen {
out.push_str(&self.gen_ir(&expr)); out.push_str(&self.gen_ir(&expr));
} }
out out
} },
IRKind::If { cond, body, else_body } => {
format!("if ({}) {{\n{}}} else {{\n{}}}\n", self.gen_ir(cond), self.gen_ir(body), self.gen_ir(else_body))
},
IRKind::Value { value } => { IRKind::Value { value } => {
match value { match value {

View file

@ -51,19 +51,24 @@ pub fn ast_to_ir(ast: Vec<(Expr, Range<usize>)>) -> (Vec<IR>, Vec<LoweringError>
(irs, errors) (irs, errors)
} }
#[macro_export]
macro_rules! if_err_return {
($value:expr) => {
if let Some(err) = $value { return (None, Some(err)); };
};
}
pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) { pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
match expr { match expr {
Expr::Let { name, type_hint, value } => { Expr::Let { name, type_hint, value } => {
let value = expr_to_ir(&value.0); let value = expr_to_ir(&value.0);
if let Some(err) = value.1 { if_err_return!(value.1);
// Return error
return (None, Some(err)); let value = value.0.unwrap();
} else {
let value = value.0.unwrap(); // Unwrapping because it should always be Some
let ir_kind = IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) }; let ir_kind = IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}
}, },
Expr::Call { name, args } => { Expr::Call { name, args } => {
let name = match &name.0 { let name = match &name.0 {
Expr::Identifier(s) => { Expr::Identifier(s) => {
@ -80,16 +85,13 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
for arg in &args.0 { for arg in &args.0 {
// Lower each argument, if there is an error then return early // Lower each argument, if there is an error then return early
let arg = expr_to_ir(&arg.0); let arg = expr_to_ir(&arg.0);
if let Some(err) = arg.1 { if_err_return!(arg.1);
return (None, Some(err));
} else {
// Else push the lowered argument
largs.push(arg.0.unwrap()); largs.push(arg.0.unwrap());
} }
}
let ir_kind = IRKind::Call { name, args: largs }; let ir_kind = IRKind::Call { name, args: largs };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}, },
Expr::Intrinsic { name, args } => { Expr::Intrinsic { name, args } => {
let name = match &name.0 { let name = match &name.0 {
Expr::Identifier(s) => s.clone(), Expr::Identifier(s) => s.clone(),
@ -98,48 +100,64 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
let mut largs = Vec::new(); let mut largs = Vec::new();
for arg in &args.0 { for arg in &args.0 {
let arg = expr_to_ir(&arg.0); let arg = expr_to_ir(&arg.0);
if let Some(err) = arg.1 { return (None, Some(err)); } if_err_return!(arg.1);
else { largs.push(arg.0.unwrap()); }
largs.push(arg.0.unwrap());
} }
let ir_kind = IRKind::Intrinsic { name, args: largs }; let ir_kind = IRKind::Intrinsic { name, args: largs };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}, },
Expr::Fun { name, type_hint, args, body } => { Expr::Fun { name, type_hint, args, body } => {
// Iterate each argument and give it a type hint // Iterate each argument and give it a type hint
let args = args.0.iter().map(|arg| (arg.0.0.clone(), gen_type_hint(&arg.1.0))).collect::<Vec<_>>(); let args = args.0.iter().map(|arg| (arg.0.0.clone(), gen_type_hint(&arg.1.0))).collect::<Vec<_>>();
let body = expr_to_ir(&body.0); let body = expr_to_ir(&body.0);
if let Some(err) = body.1 { if_err_return!(body.1);
return (None, Some(err));
} else {
let body = body.0.unwrap(); let body = body.0.unwrap();
let ir_kind = IRKind::Fun { name: name.clone(), return_type_hint: gen_type_hint(type_hint), args, body: Box::new(body) }; let ir_kind = IRKind::Fun { name: name.clone(), return_type_hint: gen_type_hint(type_hint), args, body: Box::new(body) };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}
}, },
Expr::Return { expr } => { Expr::Return { expr } => {
let expr = expr_to_ir(&expr.0); let expr = expr_to_ir(&expr.0);
if let Some(err) = expr.1 { if_err_return!(expr.1);
return (None, Some(err));
} else {
let expr = expr.0.unwrap(); let expr = expr.0.unwrap();
let ir_kind = IRKind::Return { value: Box::new(expr) }; let ir_kind = IRKind::Return { value: Box::new(expr) };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}
}, },
Expr::Do { body } => { Expr::Do { body } => {
let mut lbody = Vec::new(); let mut lbody = Vec::new();
for expr in body { for expr in body {
let expr = expr_to_ir(&expr.0); let expr = expr_to_ir(&expr.0);
if let Some(err) = expr.1 { if_err_return!(expr.1);
return (None, Some(err));
} else {
lbody.push(expr.0.unwrap()); lbody.push(expr.0.unwrap());
} }
}
let ir_kind = IRKind::Do { body: lbody }; let ir_kind = IRKind::Do { body: lbody };
return (Some(ir_kind), None); return (Some(ir_kind), None);
}, },
Expr::If { cond, body, else_body } => {
let cond = expr_to_ir(&cond.0);
if_err_return!(cond.1);
let body = expr_to_ir(&body.0);
if_err_return!(body.1);
let else_body = expr_to_ir(&else_body.0);
if_err_return!(else_body.1);
let ir_kind = IRKind::If {
cond: Box::new(cond.0.unwrap()),
body: Box::new(body.0.unwrap()),
else_body: Box::new(else_body.0.unwrap())
};
return (Some(ir_kind), None);
},
// TODO: Handle primitive types error (e.g. overflow) // TODO: Handle primitive types error (e.g. overflow)
// For now it just leaves the value as is and let the target compiler handle it // For now it just leaves the value as is and let the target compiler handle it
Expr::Int(value) => (Some(IRKind::Value { value: Value::Int(*value) }), None), Expr::Int(value) => (Some(IRKind::Value { value: Value::Int(*value) }), None),

View file

@ -28,8 +28,8 @@ pub enum Expr {
If { If {
cond: Box<Spanned<Self>>, cond: Box<Spanned<Self>>,
then: Box<Spanned<Self>>, body: Box<Spanned<Self>>,
else_: Box<Spanned<Self>> else_body: Box<Spanned<Self>>
}, },
Do { Do {
body: Vec<Spanned<Self>> body: Vec<Spanned<Self>>
@ -243,10 +243,35 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
) )
}); });
let if_block = just(Token::KwIf)
.ignore_then(expr.clone())
.then_ignore(just(Token::KwThen))
.then(
do_block.clone()
.or(expr.clone())
)
.then_ignore(just(Token::KwElse))
.then(
do_block.clone()
.or(expr.clone())
)
.then_ignore(just(Token::KwEnd))
.map(|((cond, then), else_)| {
(
Expr::If {
cond: Box::new(cond.clone()),
body: Box::new(then),
else_body: Box::new(else_.clone()),
},
cond.1.start..else_.1.end,
)
});
let_ let_
.or(fun) .or(fun)
.or(return_) .or(return_)
.or(do_block) .or(do_block)
.or(if_block)
.or(compare) .or(compare)
}).labelled("expression"); }).labelled("expression");

7
example/if.hz Normal file
View file

@ -0,0 +1,7 @@
fun main: int = do
if true then
@write("True")
else
@write("False")
end;
end;