support break

This commit is contained in:
Sebastien Bourdeauducq 2020-03-30 19:12:31 +08:00
parent ef01a86c2f
commit 052ea8d98a

View File

@ -21,6 +21,7 @@ use inkwell::types;
use inkwell::types::BasicType; use inkwell::types::BasicType;
use inkwell::values; use inkwell::values;
use inkwell::{IntPredicate, FloatPredicate}; use inkwell::{IntPredicate, FloatPredicate};
use inkwell::basic_block;
use inkwell::passes; use inkwell::passes;
@ -31,6 +32,7 @@ enum CompileErrorKind {
UnknownTypeAnnotation, UnknownTypeAnnotation,
IncompatibleTypes, IncompatibleTypes,
UnboundIdentifier, UnboundIdentifier,
BreakOutsideLoop,
Internal(&'static str) Internal(&'static str)
} }
@ -47,6 +49,8 @@ impl fmt::Display for CompileErrorKind {
=> write!(f, "Incompatible types"), => write!(f, "Incompatible types"),
CompileErrorKind::UnboundIdentifier CompileErrorKind::UnboundIdentifier
=> write!(f, "Unbound identifier"), => write!(f, "Unbound identifier"),
CompileErrorKind::BreakOutsideLoop
=> write!(f, "Break outside loop"),
CompileErrorKind::Internal(details) CompileErrorKind::Internal(details)
=> write!(f, "Internal compiler error: {}", details), => write!(f, "Internal compiler error: {}", details),
} }
@ -76,6 +80,7 @@ struct CodeGen<'ctx> {
builder: Builder<'ctx>, builder: Builder<'ctx>,
current_source_location: ast::Location, current_source_location: ast::Location,
namespace: HashMap<String, values::PointerValue<'ctx>>, namespace: HashMap<String, values::PointerValue<'ctx>>,
break_bb: Option<basic_block::BasicBlock<'ctx>>,
} }
impl<'ctx> CodeGen<'ctx> { impl<'ctx> CodeGen<'ctx> {
@ -98,6 +103,7 @@ impl<'ctx> CodeGen<'ctx> {
builder: context.create_builder(), builder: context.create_builder(),
current_source_location: ast::Location::default(), current_source_location: ast::Location::default(),
namespace: HashMap::new(), namespace: HashMap::new(),
break_bb: None,
} }
} }
@ -438,6 +444,8 @@ impl<'ctx> CodeGen<'ctx> {
let cont_bb = self.context.append_basic_block(parent, "ifcont"); 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.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.builder.position_at_end(then_bb);
self.compile_suite(body, return_type)?; self.compile_suite(body, return_type)?;
self.builder.build_unconditional_branch(test_bb); self.builder.build_unconditional_branch(test_bb);
@ -448,7 +456,19 @@ impl<'ctx> CodeGen<'ctx> {
} }
self.builder.build_unconditional_branch(cont_bb); self.builder.build_unconditional_branch(cont_bb);
self.builder.position_at_end(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) } => { 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)?;