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:
parent
26ed1130e7
commit
b0ab1a4717
6 changed files with 62 additions and 19 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
Reference in a new issue