support if/then/else

This commit is contained in:
Sebastien Bourdeauducq 2020-03-30 17:33:01 +08:00
parent 38cdab01cb
commit aecf24c857

View File

@ -127,7 +127,7 @@ impl<'ctx> CodeGen<'ctx> {
&mut self, &mut self,
name: &str, name: &str,
args: &ast::Parameters, args: &ast::Parameters,
body: &[ast::Statement], body: &ast::Suite,
decorator_list: &[ast::Expression], decorator_list: &[ast::Expression],
returns: &Option<ast::Expression>, returns: &Option<ast::Expression>,
is_async: bool, is_async: bool,
@ -185,9 +185,8 @@ impl<'ctx> CodeGen<'ctx> {
self.namespace.insert(arg.arg.clone(), alloca); self.namespace.insert(arg.arg.clone(), alloca);
} }
for statement in body.iter() { self.compile_suite(body, return_type)?;
self.compile_statement(statement, return_type)?;
}
Ok(function) Ok(function)
} }
@ -398,7 +397,30 @@ impl<'ctx> CodeGen<'ctx> {
return Err(self.compile_error(CompileErrorKind::Unsupported("assignment target must be an identifier"))) return Err(self.compile_error(CompileErrorKind::Unsupported("assignment target must be an identifier")))
} }
} }
},
If { test, body, orelse } => {
let test = self.compile_expression(test)?;
if test.get_type() != self.context.bool_type().into() {
return Err(self.compile_error(CompileErrorKind::IncompatibleTypes));
} }
let parent = self.builder.get_insert_block().unwrap().get_parent().unwrap();
let then_bb = self.context.append_basic_block(parent, "then");
let else_bb = self.context.append_basic_block(parent, "else");
let cont_bb = self.context.append_basic_block(parent, "ifcont");
self.builder.build_conditional_branch(test.into_int_value(), then_bb, else_bb);
self.builder.position_at_end(then_bb);
self.compile_suite(body, return_type)?;
self.builder.build_unconditional_branch(cont_bb);
self.builder.position_at_end(else_bb);
if let Some(orelse) = orelse {
self.compile_suite(orelse, return_type)?;
}
self.builder.build_unconditional_branch(cont_bb);
self.builder.position_at_end(cont_bb);
},
Return { value: Some(value) } => { Return { value: Some(value) } => {
if let Some(return_type) = return_type { if let Some(return_type) = return_type {
let value = self.compile_expression(value)?; let value = self.compile_expression(value)?;
@ -422,6 +444,17 @@ impl<'ctx> CodeGen<'ctx> {
Ok(()) Ok(())
} }
fn compile_suite(
&mut self,
suite: &ast::Suite,
return_type: Option<types::BasicTypeEnum>
) -> CompileResult<()> {
for statement in suite.iter() {
self.compile_statement(statement, return_type)?;
}
Ok(())
}
fn compile_toplevel(&mut self, statement: &ast::Statement) -> CompileResult<()> { fn compile_toplevel(&mut self, statement: &ast::Statement) -> CompileResult<()> {
self.set_source_location(statement.location); self.set_source_location(statement.location);
if let ast::StatementType::FunctionDef { if let ast::StatementType::FunctionDef {