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
}
}
#[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::function::{Function, FunctionIdx};
use crate::location::Location;
@ -8,6 +9,7 @@ use huia_parser::input_location::InputLocation;
#[derive(Debug)]
pub struct Context {
blocks: Vec<Block>,
current_file: StringIdx,
errors: Vec<CompileError>,
functions: Vec<Function>,
@ -19,12 +21,14 @@ pub struct Context {
impl Context {
pub fn new(path: &str) -> Context {
let mut strings = StringTable::default();
let blocks = Vec::default();
let current_file = strings.intern(path);
let errors = Vec::default();
let functions = Vec::default();
let types = Vec::default();
let methods = Vec::default();
Context {
blocks,
current_file,
errors,
functions,
@ -134,6 +138,16 @@ impl Context {
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)]
pub fn find_type(&mut self, name: &str) -> Option<&Ty> {
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::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();
self.clauses.push(Clause::new(arguments, block));
idx.into()
@ -30,11 +30,11 @@ impl Function {
#[derive(Debug)]
pub struct Clause {
arguments: Vec<(StringIdx, TyIdx)>,
body: Block,
body: BlockIdx,
}
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 }
}
}
@ -91,7 +91,7 @@ mod test {
let mut fun = Function::new(rt);
assert!(fun.is_empty());
fun.push(Vec::new(), Block::default());
fun.push(Vec::new(), BlockIdx::from(123));
assert!(!fun.is_empty());
}

View file

@ -8,9 +8,6 @@ use crate::ty::TyIdx;
use huia_parser::ast::{Location, NodeType, Term, Value};
/// 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)]
struct Builder {
blocks: Vec<Block>,
@ -69,7 +66,7 @@ impl Builder {
for node in args {
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::Call(arguments));
@ -139,7 +136,8 @@ impl Builder {
}
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);
@ -158,14 +156,21 @@ impl Builder {
self.build(node.clone(), &mut context);
}
let positive = self.pop_block().unwrap();
let positive_idx = context.push_block(positive);
self.push_block();
for node in negative {
self.build(node.clone(), &mut context);
}
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 => {
let (ty, body) = node.impldef().unwrap();
@ -291,7 +296,8 @@ impl Builder {
self.build(node.clone(), &mut context);
}
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);
}
@ -344,7 +350,8 @@ impl Builder {
self.build(node.clone(), &mut context);
}
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);
}
@ -397,7 +404,8 @@ impl Builder {
self.build(node.clone(), &mut context);
}
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);
}

View file

@ -1,6 +1,6 @@
mod builder;
use crate::block::Block;
use crate::block::BlockIdx;
use crate::function::FunctionIdx;
use crate::stable::StringIdx;
use crate::ty::TyIdx;
@ -14,7 +14,7 @@ use huia_parser::ast::unary::Operator as UnOp;
#[derive(Debug, PartialEq)]
pub enum IR {
/// Call top of the stack with arguments.
Call(Block),
Call(Vec<IR>),
/// A constant value of the specified type.
Constant(TyIdx, Val),
/// Construct an instance of type with the provided properties.
@ -26,7 +26,7 @@ pub enum IR {
/// Refernce an instance property.
GetProperty(StringIdx),
/// 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.
Infix(BinOp, Box<(IR, IR)>),
/// 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::stable::StringIdx;
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();
self.clauses.push(Clause::new(arguments, block));
idx.into()