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
|
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::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);
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Reference in a new issue