mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
if else
This commit is contained in:
parent
4e040f9601
commit
ebaee0ea0c
|
@ -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 {
|
||||||
|
|
|
@ -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 ir_kind = IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) };
|
||||||
let value = value.0.unwrap(); // Unwrapping because it should always be Some
|
return (Some(ir_kind), None);
|
||||||
let ir_kind = IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) };
|
|
||||||
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));
|
largs.push(arg.0.unwrap());
|
||||||
} else {
|
|
||||||
// Else push the lowered argument
|
|
||||||
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));
|
lbody.push(expr.0.unwrap());
|
||||||
} else {
|
|
||||||
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),
|
||||||
|
|
|
@ -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
7
example/if.hz
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fun main: int = do
|
||||||
|
if true then
|
||||||
|
@write("True")
|
||||||
|
else
|
||||||
|
@write("False")
|
||||||
|
end;
|
||||||
|
end;
|
Loading…
Reference in a new issue