From 052ea8d98a6ca85a5c45ff03fd9d9bae958d8963 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Mar 2020 19:12:31 +0800 Subject: [PATCH] support break --- src/main.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main.rs b/src/main.rs index 128e1036..80d37fae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use inkwell::types; use inkwell::types::BasicType; use inkwell::values; use inkwell::{IntPredicate, FloatPredicate}; +use inkwell::basic_block; use inkwell::passes; @@ -31,6 +32,7 @@ enum CompileErrorKind { UnknownTypeAnnotation, IncompatibleTypes, UnboundIdentifier, + BreakOutsideLoop, Internal(&'static str) } @@ -47,6 +49,8 @@ impl fmt::Display for CompileErrorKind { => write!(f, "Incompatible types"), CompileErrorKind::UnboundIdentifier => write!(f, "Unbound identifier"), + CompileErrorKind::BreakOutsideLoop + => write!(f, "Break outside loop"), CompileErrorKind::Internal(details) => write!(f, "Internal compiler error: {}", details), } @@ -76,6 +80,7 @@ struct CodeGen<'ctx> { builder: Builder<'ctx>, current_source_location: ast::Location, namespace: HashMap>, + break_bb: Option>, } impl<'ctx> CodeGen<'ctx> { @@ -98,6 +103,7 @@ impl<'ctx> CodeGen<'ctx> { builder: context.create_builder(), current_source_location: ast::Location::default(), namespace: HashMap::new(), + break_bb: None, } } @@ -438,6 +444,8 @@ impl<'ctx> CodeGen<'ctx> { let cont_bb = self.context.append_basic_block(parent, "ifcont"); self.builder.build_conditional_branch(test.into_int_value(), then_bb, else_bb); + self.break_bb = Some(cont_bb); + self.builder.position_at_end(then_bb); self.compile_suite(body, return_type)?; self.builder.build_unconditional_branch(test_bb); @@ -448,7 +456,19 @@ impl<'ctx> CodeGen<'ctx> { } self.builder.build_unconditional_branch(cont_bb); self.builder.position_at_end(cont_bb); + + self.break_bb = None; }, + Break => { + if let Some(bb) = self.break_bb { + self.builder.build_unconditional_branch(bb); + let parent = self.builder.get_insert_block().unwrap().get_parent().unwrap(); + let unreachable_bb = self.context.append_basic_block(parent, "unreachable"); + self.builder.position_at_end(unreachable_bb); + } else { + return Err(self.compile_error(CompileErrorKind::BreakOutsideLoop)); + } + } Return { value: Some(value) } => { if let Some(return_type) = return_type { let value = self.compile_expression(value)?;