Extend the IR to include the location and the result type.
This commit is contained in:
parent
b0ab1a4717
commit
8942c04c6e
2 changed files with 278 additions and 124 deletions
|
@ -23,7 +23,7 @@ impl Builder {
|
|||
NodeType::Array => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Array");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
|
||||
let elements = node
|
||||
.array()
|
||||
|
@ -34,32 +34,41 @@ impl Builder {
|
|||
self.pop_ir().unwrap()
|
||||
})
|
||||
.collect();
|
||||
self.push_ir(IR::Constant(ty, Val::Array(elements)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Array(elements)));
|
||||
}
|
||||
NodeType::Atom => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Atom");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
let idx = context.constant_string(node.atom().unwrap().value_ref().as_str());
|
||||
self.push_ir(IR::Constant(ty, Val::Atom(idx)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Atom(idx)));
|
||||
}
|
||||
NodeType::Boolean => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Boolean");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
let value = *node.boolean().unwrap().value_ref();
|
||||
self.push_ir(IR::Constant(ty, Val::Boolean(value)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Boolean(value)));
|
||||
}
|
||||
NodeType::Binary => {
|
||||
let location = context.location(&node.location());
|
||||
let (op, lhs, rhs) = node.binary().unwrap();
|
||||
self.build(lhs.clone(), &mut context);
|
||||
self.build(rhs.clone(), &mut context);
|
||||
let rhs = self.pop_ir().unwrap();
|
||||
let lhs = self.pop_ir().unwrap();
|
||||
self.push_ir(IR::Infix(op.value_ref().clone(), Box::new((lhs, rhs))));
|
||||
let result_type = lhs.result_type();
|
||||
self.push_ir(IR::new_infix(
|
||||
result_type,
|
||||
location,
|
||||
op.value_ref().clone(),
|
||||
lhs,
|
||||
rhs,
|
||||
));
|
||||
}
|
||||
NodeType::Call => {
|
||||
let (name, args) = node.call().unwrap();
|
||||
let location = context.location(&node.location());
|
||||
let name = context.constant_string(name.value_ref().as_str());
|
||||
|
||||
self.push_block();
|
||||
|
@ -68,16 +77,22 @@ impl Builder {
|
|||
}
|
||||
let arguments = self.pop_block().unwrap().ir();
|
||||
|
||||
self.push_ir(IR::GetLocal(name));
|
||||
self.push_ir(IR::Call(arguments));
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
|
||||
self.push_ir(IR::new_get_local(
|
||||
result_type.clone(),
|
||||
location.clone(),
|
||||
name,
|
||||
));
|
||||
self.push_ir(IR::new_call(result_type, location, arguments));
|
||||
}
|
||||
NodeType::Constructor => {
|
||||
let (ty, props) = node.constructor().unwrap();
|
||||
let ty_idx = context.constant_string(ty.value_ref().as_str());
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
|
||||
let elements = props
|
||||
let properties = props
|
||||
.iter()
|
||||
.map(|(key, value)| {
|
||||
let key = context.constant_string(key.value_ref().as_str());
|
||||
|
@ -86,27 +101,29 @@ impl Builder {
|
|||
(key, value)
|
||||
})
|
||||
.collect();
|
||||
self.push_ir(IR::Constructor(ty, elements));
|
||||
self.push_ir(IR::new_constructor(ty, location, properties));
|
||||
}
|
||||
NodeType::Declaration => {
|
||||
let location = context.location(&node.location());
|
||||
let (name, rhs) = node.declaration().unwrap();
|
||||
let name = context.constant_string(name.value_ref().as_str());
|
||||
self.build(rhs.clone(), &mut context);
|
||||
let rhs = self.pop_ir().unwrap();
|
||||
self.push_ir(IR::SetLocal(name, Box::new(rhs)));
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
self.push_ir(IR::new_set_local(result_type, location, name, rhs));
|
||||
}
|
||||
NodeType::Float => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Float");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
let value = *node.float().unwrap().value_ref();
|
||||
self.push_ir(IR::Constant(ty, Val::Float(value)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Float(value)));
|
||||
}
|
||||
NodeType::Function => {
|
||||
let function = node.function().unwrap();
|
||||
let location = context.location(&node.location());
|
||||
let return_type = context.unknown_type(location);
|
||||
let mut fun = Function::new(return_type);
|
||||
let return_type = context.unknown_type(location.clone());
|
||||
let mut fun = Function::new(return_type.clone());
|
||||
|
||||
for clause in function.value_ref() {
|
||||
let arguments: Vec<(StringIdx, TyIdx)> = clause
|
||||
|
@ -141,7 +158,7 @@ impl Builder {
|
|||
}
|
||||
|
||||
let fun_idx = context.define_function(fun);
|
||||
self.push_ir(IR::Function(fun_idx));
|
||||
self.push_ir(IR::new_function_ref(return_type, location, fun_idx));
|
||||
}
|
||||
NodeType::If => {
|
||||
let (test, positive, negative) = node.if_expr().unwrap();
|
||||
|
@ -149,7 +166,7 @@ impl Builder {
|
|||
|
||||
self.build(test.clone(), &mut context);
|
||||
let test = self.pop_ir().unwrap();
|
||||
let result_type = context.unknown_type(location);
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
|
||||
self.push_block();
|
||||
for node in positive {
|
||||
|
@ -165,11 +182,12 @@ impl Builder {
|
|||
let negative = self.pop_block().unwrap();
|
||||
let negative_idx = context.push_block(negative);
|
||||
|
||||
self.push_ir(IR::If(
|
||||
Box::new(test),
|
||||
self.push_ir(IR::new_if(
|
||||
result_type,
|
||||
location,
|
||||
test,
|
||||
positive_idx,
|
||||
negative_idx,
|
||||
result_type,
|
||||
));
|
||||
}
|
||||
NodeType::ImplDef => {
|
||||
|
@ -198,19 +216,21 @@ impl Builder {
|
|||
NodeType::Integer => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Integer");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
let value = *node.integer().unwrap().value_ref();
|
||||
self.push_ir(IR::Constant(ty, Val::Integer(value)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Integer(value)));
|
||||
}
|
||||
NodeType::Local => {
|
||||
let name = node.local().unwrap();
|
||||
let location = context.location(&node.location());
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
let name = context.constant_string(name.value_ref().as_str());
|
||||
self.push_ir(IR::GetLocal(name));
|
||||
self.push_ir(IR::new_get_local(result_type, location, name));
|
||||
}
|
||||
NodeType::Map => {
|
||||
let ty_idx = context.constant_string("Huia.Native.Map");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
|
||||
let elements = node
|
||||
.map()
|
||||
|
@ -224,14 +244,18 @@ impl Builder {
|
|||
(key, value)
|
||||
})
|
||||
.collect();
|
||||
self.push_ir(IR::Constant(ty, Val::Map(elements)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::Map(elements)));
|
||||
}
|
||||
NodeType::PropertyGet => {
|
||||
let location = context.location(&node.location());
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
let ident =
|
||||
context.constant_string(node.property_get().unwrap().value_ref().as_str());
|
||||
self.push_ir(IR::GetProperty(ident));
|
||||
self.push_ir(IR::new_get_property(result_type, location, ident));
|
||||
}
|
||||
NodeType::PropertySet => {
|
||||
let location = context.location(&node.location());
|
||||
let result_type = context.unknown_type(location.clone());
|
||||
let elements: Vec<(StringIdx, IR)> = node
|
||||
.property_set()
|
||||
.unwrap()
|
||||
|
@ -245,7 +269,7 @@ impl Builder {
|
|||
})
|
||||
.collect();
|
||||
|
||||
self.push_ir(IR::SetProperties(elements))
|
||||
self.push_ir(IR::new_set_properties(result_type, location, elements))
|
||||
}
|
||||
NodeType::PrivateMethod => {
|
||||
let current_ty = self.peek_ty().unwrap();
|
||||
|
@ -412,9 +436,9 @@ impl Builder {
|
|||
NodeType::String => {
|
||||
let ty_idx = context.constant_string("Huia.Native.String");
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
let idx = context.constant_string(node.string().unwrap().value_ref().as_str());
|
||||
self.push_ir(IR::Constant(ty, Val::String(idx)));
|
||||
self.push_ir(IR::new_constant(ty, location, Val::String(idx)));
|
||||
}
|
||||
NodeType::TraitDef => {
|
||||
let (ty, typespec, body) = node.traitdef().unwrap();
|
||||
|
@ -448,10 +472,12 @@ impl Builder {
|
|||
self.pop_ty();
|
||||
}
|
||||
NodeType::Ty => {
|
||||
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
|
||||
let location = context.location(&node.location());
|
||||
let ty = context.reference_type(&ty_idx, location);
|
||||
self.push_ir(IR::TypeReference(ty));
|
||||
let result_type_idx = context.constant_string("Huia.Native.Type");
|
||||
let result_type = context.reference_type(&result_type_idx, location.clone());
|
||||
let ty_idx = context.constant_string(node.ty().unwrap().value_ref().as_str());
|
||||
let ty = context.reference_type(&ty_idx, location.clone());
|
||||
self.push_ir(IR::new_type_reference(result_type, location, ty));
|
||||
}
|
||||
NodeType::TypeDef => {
|
||||
let (ty, properties, body) = node.typedef().unwrap();
|
||||
|
@ -488,10 +514,17 @@ impl Builder {
|
|||
self.pop_ty();
|
||||
}
|
||||
NodeType::Unary => {
|
||||
let location = context.location(&node.location());
|
||||
let (op, rhs) = node.unary().unwrap();
|
||||
self.build(rhs.clone(), &mut context);
|
||||
let rhs = self.pop_ir().unwrap();
|
||||
self.push_ir(IR::Unary(op.value_ref().clone(), Box::new(rhs)));
|
||||
let result_type = rhs.result_type();
|
||||
self.push_ir(IR::new_unary(
|
||||
result_type,
|
||||
location,
|
||||
op.value_ref().clone(),
|
||||
rhs,
|
||||
));
|
||||
}
|
||||
|
||||
_ => unreachable!("Unexpected node type: {:?}", node.node_type()),
|
||||
|
|
|
@ -2,33 +2,233 @@ mod builder;
|
|||
|
||||
use crate::block::BlockIdx;
|
||||
use crate::function::FunctionIdx;
|
||||
use crate::location::Location;
|
||||
use crate::stable::StringIdx;
|
||||
use crate::ty::TyIdx;
|
||||
use huia_parser::ast::binary::Operator as BinOp;
|
||||
use huia_parser::ast::unary::Operator as UnOp;
|
||||
|
||||
/// Describes the intermediate representation as converted from the Parser's AST.
|
||||
///
|
||||
/// FIXME:
|
||||
/// IR should have a location too if possible.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum IR {
|
||||
pub struct IR {
|
||||
location: Option<Location>,
|
||||
result_type: TyIdx,
|
||||
kind: IRKind,
|
||||
}
|
||||
|
||||
impl IR {
|
||||
pub fn new_call(result_type: TyIdx, location: Location, arguments: Vec<IR>) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::Call(arguments),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_constant(result_type: TyIdx, location: Location, value: Val) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::Constant(value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_constructor(
|
||||
result_type: TyIdx,
|
||||
location: Location,
|
||||
properties: Vec<(StringIdx, IR)>,
|
||||
) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::Constructor(properties),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_function_ref(result_type: TyIdx, location: Location, function: FunctionIdx) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::FunctionRef(function),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_get_local(result_type: TyIdx, location: Location, name: StringIdx) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::GetLocal(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_get_property(result_type: TyIdx, location: Location, name: StringIdx) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::GetProperty(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_if(
|
||||
result_type: TyIdx,
|
||||
location: Location,
|
||||
test: IR,
|
||||
positive: BlockIdx,
|
||||
negative: BlockIdx,
|
||||
) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::If(Box::new(test), positive, negative),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_infix(result_type: TyIdx, location: Location, op: BinOp, lhs: IR, rhs: IR) -> IR {
|
||||
let lhs = Box::new(lhs);
|
||||
let rhs = Box::new(rhs);
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::Infix(op, lhs, rhs),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_set_local(result_type: TyIdx, location: Location, name: StringIdx, value: IR) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::SetLocal(name, Box::new(value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_set_properties(
|
||||
result_type: TyIdx,
|
||||
location: Location,
|
||||
properties: Vec<(StringIdx, IR)>,
|
||||
) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::SetProperties(properties),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_type_reference(result_type: TyIdx, location: Location, ty: TyIdx) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::TypeReference(ty),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_unary(result_type: TyIdx, location: Location, op: UnOp, rhs: IR) -> IR {
|
||||
IR {
|
||||
location: Some(location),
|
||||
result_type,
|
||||
kind: IRKind::Unary(op, Box::new(rhs)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function(&self) -> Option<&FunctionIdx> {
|
||||
match self.kind {
|
||||
IRKind::FunctionRef(ref idx) => Some(idx),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_call(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Call(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_constant(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Constant(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_constuctor(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Constructor(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_function(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::FunctionRef(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_get_local(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::GetLocal(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_get_property(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::GetProperty(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_infix(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Infix(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type_reference(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::TypeReference(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_set_local(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::SetLocal(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unary(&self) -> bool {
|
||||
match self.kind {
|
||||
IRKind::Unary(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn result_type(&self) -> TyIdx {
|
||||
self.result_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum IRKind {
|
||||
/// Call top of the stack with arguments.
|
||||
Call(Vec<IR>),
|
||||
/// A constant value of the specified type.
|
||||
Constant(TyIdx, Val),
|
||||
Constant(Val),
|
||||
/// Construct an instance of type with the provided properties.
|
||||
Constructor(TyIdx, Vec<(StringIdx, IR)>),
|
||||
Constructor(Vec<(StringIdx, IR)>),
|
||||
/// Reference an anonymous function from the context.
|
||||
Function(FunctionIdx),
|
||||
FunctionRef(FunctionIdx),
|
||||
/// Reference a local variable.
|
||||
GetLocal(StringIdx),
|
||||
/// Refernce an instance property.
|
||||
GetProperty(StringIdx),
|
||||
/// Consists of test, positives, negatives and a return type.
|
||||
If(Box<IR>, BlockIdx, BlockIdx, TyIdx),
|
||||
/// Consists of test, positives, negatives.
|
||||
If(Box<IR>, BlockIdx, BlockIdx),
|
||||
/// A binary operation with LHS and RHS.
|
||||
Infix(BinOp, Box<(IR, IR)>),
|
||||
Infix(BinOp, Box<IR>, Box<IR>),
|
||||
/// Take a value and set it as a local variable.
|
||||
SetLocal(StringIdx, Box<IR>),
|
||||
/// Set properties on an instance, returning the modified instance.
|
||||
|
@ -39,85 +239,6 @@ pub enum IR {
|
|||
Unary(UnOp, Box<IR>),
|
||||
}
|
||||
|
||||
impl IR {
|
||||
pub fn function(&self) -> Option<&FunctionIdx> {
|
||||
match self {
|
||||
IR::Function(ref idx) => Some(idx),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_call(&self) -> bool {
|
||||
match self {
|
||||
IR::Call(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_constant(&self) -> bool {
|
||||
match self {
|
||||
IR::Constant(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_constuctor(&self) -> bool {
|
||||
match self {
|
||||
IR::Constructor(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_function(&self) -> bool {
|
||||
match self {
|
||||
IR::Function(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_get_local(&self) -> bool {
|
||||
match self {
|
||||
IR::GetLocal(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_get_property(&self) -> bool {
|
||||
match self {
|
||||
IR::GetProperty(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_infix(&self) -> bool {
|
||||
match self {
|
||||
IR::Infix(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type_reference(&self) -> bool {
|
||||
match self {
|
||||
IR::TypeReference(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_set_local(&self) -> bool {
|
||||
match self {
|
||||
IR::SetLocal(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unary(&self) -> bool {
|
||||
match self {
|
||||
IR::Unary(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant value.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Val {
|
||||
|
|
Reference in a new issue