Store blocks on the context and reference them.

Because we need to build a control-flow graph from all our blocks don't
store them haphazard all over the place but in a single blocks
collection on the context object.
This commit is contained in:
James Harton 2019-03-18 11:56:44 +13:00
parent 26ed1130e7
commit b0ab1a4717
6 changed files with 62 additions and 19 deletions

View file

@ -23,3 +23,24 @@ impl Block {
self.ir self.ir
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub struct BlockIdx(usize);
impl From<usize> for BlockIdx {
fn from(i: usize) -> BlockIdx {
BlockIdx(i)
}
}
impl From<BlockIdx> for usize {
fn from(i: BlockIdx) -> usize {
i.0
}
}
impl From<&BlockIdx> for usize {
fn from(i: &BlockIdx) -> usize {
i.0
}
}

View file

@ -1,3 +1,4 @@
use crate::block::{Block, BlockIdx};
use crate::error::CompileError; use crate::error::CompileError;
use crate::function::{Function, FunctionIdx}; use crate::function::{Function, FunctionIdx};
use crate::location::Location; use crate::location::Location;
@ -8,6 +9,7 @@ use huia_parser::input_location::InputLocation;
#[derive(Debug)] #[derive(Debug)]
pub struct Context { pub struct Context {
blocks: Vec<Block>,
current_file: StringIdx, current_file: StringIdx,
errors: Vec<CompileError>, errors: Vec<CompileError>,
functions: Vec<Function>, functions: Vec<Function>,
@ -19,12 +21,14 @@ pub struct Context {
impl Context { impl Context {
pub fn new(path: &str) -> Context { pub fn new(path: &str) -> Context {
let mut strings = StringTable::default(); let mut strings = StringTable::default();
let blocks = Vec::default();
let current_file = strings.intern(path); let current_file = strings.intern(path);
let errors = Vec::default(); let errors = Vec::default();
let functions = Vec::default(); let functions = Vec::default();
let types = Vec::default(); let types = Vec::default();
let methods = Vec::default(); let methods = Vec::default();
Context { Context {
blocks,
current_file, current_file,
errors, errors,
functions, functions,
@ -134,6 +138,16 @@ impl Context {
self.functions.get(usize::from(idx)) self.functions.get(usize::from(idx))
} }
pub fn push_block(&mut self, block: Block) -> BlockIdx {
let idx = self.blocks.len();
self.blocks.push(block);
idx.into()
}
pub fn get_block(&self, idx: BlockIdx) -> Option<&Block> {
self.blocks.get(usize::from(idx))
}
#[cfg(test)] #[cfg(test)]
pub fn find_type(&mut self, name: &str) -> Option<&Ty> { pub fn find_type(&mut self, name: &str) -> Option<&Ty> {
let name = self.constant_string(name); let name = self.constant_string(name);

View file

@ -1,4 +1,4 @@
use crate::block::Block; use crate::block::BlockIdx;
use crate::stable::StringIdx; use crate::stable::StringIdx;
use crate::ty::TyIdx; use crate::ty::TyIdx;
@ -16,7 +16,7 @@ impl Function {
} }
} }
pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: Block) -> ClauseIdx { pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx {
let idx = self.clauses.len(); let idx = self.clauses.len();
self.clauses.push(Clause::new(arguments, block)); self.clauses.push(Clause::new(arguments, block));
idx.into() idx.into()
@ -30,11 +30,11 @@ impl Function {
#[derive(Debug)] #[derive(Debug)]
pub struct Clause { pub struct Clause {
arguments: Vec<(StringIdx, TyIdx)>, arguments: Vec<(StringIdx, TyIdx)>,
body: Block, body: BlockIdx,
} }
impl Clause { impl Clause {
pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: Block) -> Clause { pub fn new(arguments: Vec<(StringIdx, TyIdx)>, body: BlockIdx) -> Clause {
Clause { arguments, body } Clause { arguments, body }
} }
} }
@ -91,7 +91,7 @@ mod test {
let mut fun = Function::new(rt); let mut fun = Function::new(rt);
assert!(fun.is_empty()); assert!(fun.is_empty());
fun.push(Vec::new(), Block::default()); fun.push(Vec::new(), BlockIdx::from(123));
assert!(!fun.is_empty()); assert!(!fun.is_empty());
} }

View file

@ -8,9 +8,6 @@ use crate::ty::TyIdx;
use huia_parser::ast::{Location, NodeType, Term, Value}; use huia_parser::ast::{Location, NodeType, Term, Value};
/// The Builder is a simple stack machine for converting AST into IR. /// The Builder is a simple stack machine for converting AST into IR.
/// FIXME:
/// Maybe push a named block somehow when defining types so that we can figure
/// out where we are when building methods, etc.
#[derive(Debug)] #[derive(Debug)]
struct Builder { struct Builder {
blocks: Vec<Block>, blocks: Vec<Block>,
@ -69,7 +66,7 @@ impl Builder {
for node in args { for node in args {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let arguments = self.pop_block().unwrap(); let arguments = self.pop_block().unwrap().ir();
self.push_ir(IR::GetLocal(name)); self.push_ir(IR::GetLocal(name));
self.push_ir(IR::Call(arguments)); self.push_ir(IR::Call(arguments));
@ -139,7 +136,8 @@ impl Builder {
} }
let clause_data = self.pop_block().unwrap(); let clause_data = self.pop_block().unwrap();
fun.push(arguments, clause_data); let idx = context.push_block(clause_data);
fun.push(arguments, idx);
} }
let fun_idx = context.define_function(fun); let fun_idx = context.define_function(fun);
@ -158,14 +156,21 @@ impl Builder {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let positive = self.pop_block().unwrap(); let positive = self.pop_block().unwrap();
let positive_idx = context.push_block(positive);
self.push_block(); self.push_block();
for node in negative { for node in negative {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let negative = self.pop_block().unwrap(); let negative = self.pop_block().unwrap();
let negative_idx = context.push_block(negative);
self.push_ir(IR::If(Box::new(test), positive, negative, result_type)); self.push_ir(IR::If(
Box::new(test),
positive_idx,
negative_idx,
result_type,
));
} }
NodeType::ImplDef => { NodeType::ImplDef => {
let (ty, body) = node.impldef().unwrap(); let (ty, body) = node.impldef().unwrap();
@ -291,7 +296,8 @@ impl Builder {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let clause_data = self.pop_block().unwrap(); let clause_data = self.pop_block().unwrap();
method.push(arguments, clause_data); let idx = context.push_block(clause_data);
method.push(arguments, idx);
context.define_method(method); context.define_method(method);
} }
@ -344,7 +350,8 @@ impl Builder {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let clause_data = self.pop_block().unwrap(); let clause_data = self.pop_block().unwrap();
method.push(arguments, clause_data); let idx = context.push_block(clause_data);
method.push(arguments, idx);
context.define_method(method); context.define_method(method);
} }
@ -397,7 +404,8 @@ impl Builder {
self.build(node.clone(), &mut context); self.build(node.clone(), &mut context);
} }
let clause_data = self.pop_block().unwrap(); let clause_data = self.pop_block().unwrap();
method.push(arguments, clause_data); let idx = context.push_block(clause_data);
method.push(arguments, idx);
context.define_method(method); context.define_method(method);
} }

View file

@ -1,6 +1,6 @@
mod builder; mod builder;
use crate::block::Block; use crate::block::BlockIdx;
use crate::function::FunctionIdx; use crate::function::FunctionIdx;
use crate::stable::StringIdx; use crate::stable::StringIdx;
use crate::ty::TyIdx; use crate::ty::TyIdx;
@ -14,7 +14,7 @@ use huia_parser::ast::unary::Operator as UnOp;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum IR { pub enum IR {
/// Call top of the stack with arguments. /// Call top of the stack with arguments.
Call(Block), Call(Vec<IR>),
/// A constant value of the specified type. /// A constant value of the specified type.
Constant(TyIdx, Val), Constant(TyIdx, Val),
/// Construct an instance of type with the provided properties. /// Construct an instance of type with the provided properties.
@ -26,7 +26,7 @@ pub enum IR {
/// Refernce an instance property. /// Refernce an instance property.
GetProperty(StringIdx), GetProperty(StringIdx),
/// Consists of test, positives, negatives and a return type. /// Consists of test, positives, negatives and a return type.
If(Box<IR>, Block, Block, TyIdx), If(Box<IR>, BlockIdx, BlockIdx, TyIdx),
/// A binary operation with LHS and RHS. /// A binary operation with LHS and RHS.
Infix(BinOp, Box<(IR, IR)>), Infix(BinOp, Box<(IR, IR)>),
/// Take a value and set it as a local variable. /// Take a value and set it as a local variable.

View file

@ -1,4 +1,4 @@
use crate::block::Block; use crate::block::BlockIdx;
use crate::function::{Clause, ClauseIdx}; use crate::function::{Clause, ClauseIdx};
use crate::stable::StringIdx; use crate::stable::StringIdx;
use crate::ty::TyIdx; use crate::ty::TyIdx;
@ -43,7 +43,7 @@ impl Method {
} }
} }
pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: Block) -> ClauseIdx { pub fn push(&mut self, arguments: Vec<(StringIdx, TyIdx)>, block: BlockIdx) -> ClauseIdx {
let idx = self.clauses.len(); let idx = self.clauses.len();
self.clauses.push(Clause::new(arguments, block)); self.clauses.push(Clause::new(arguments, block));
idx.into() idx.into()