REFACTOR: Move the ucg IR into it's own module.

This commit is contained in:
Jeremy Wall 2018-08-24 19:36:36 -05:00
parent 3ed8fe332f
commit ae419ea3e7
2 changed files with 222 additions and 212 deletions

219
src/build/ir.rs Normal file
View File

@ -0,0 +1,219 @@
//! The ir module holds the definitions of our ucg Intermediate Representation before it is converted
//! to an output artifact.
use std::convert::From;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
use std::string::ToString;
use ast::*;
use error;
/// The Intermediate representation of a compiled UCG AST.
#[derive(PartialEq, Debug, Clone)]
pub enum Val {
Empty,
Boolean(bool),
Int(i64),
Float(f64),
Str(String),
List(Vec<Rc<Val>>),
Tuple(Vec<(Positioned<String>, Rc<Val>)>),
Macro(MacroDef),
}
impl Val {
/// Returns the Type of a Val as a string.
pub fn type_name(&self) -> String {
match self {
&Val::Empty => "EmptyValue".to_string(),
&Val::Boolean(_) => "Boolean".to_string(),
&Val::Int(_) => "Integer".to_string(),
&Val::Float(_) => "Float".to_string(),
&Val::Str(_) => "String".to_string(),
&Val::List(_) => "List".to_string(),
&Val::Tuple(_) => "Tuple".to_string(),
&Val::Macro(_) => "Macro".to_string(),
}
}
/// Returns true if called with a Val of the same type as itself.
pub fn type_equal(&self, target: &Self) -> bool {
enum_type_equality!(
self,
target,
&Val::Empty,
&Val::Boolean(_),
&Val::Int(_),
&Val::Float(_),
&Val::Str(_),
&Val::List(_),
&Val::Tuple(_),
&Val::Macro(_)
)
}
pub fn equal(
&self,
target: &Self,
file_name: &str,
pos: Position,
) -> Result<bool, error::Error> {
// first we do a type equality comparison
match (self, target) {
// Empty values are always equal.
(&Val::Empty, &Val::Empty) => Ok(true),
(&Val::Int(ref i), &Val::Int(ref ii)) => Ok(i == ii),
(&Val::Float(ref f), &Val::Float(ref ff)) => Ok(f == ff),
(&Val::Boolean(ref b), &Val::Boolean(ref bb)) => Ok(b == bb),
(&Val::Str(ref s), &Val::Str(ref ss)) => Ok(s == ss),
(&Val::List(ref ldef), &Val::List(ref rdef)) => {
if ldef.len() != rdef.len() {
Ok(false)
} else {
for (i, lv) in ldef.iter().enumerate() {
try!(lv.equal(rdef[i].as_ref(), file_name, pos.clone()));
}
Ok(true)
}
}
(&Val::Tuple(ref ldef), &Val::Tuple(ref rdef)) => {
if ldef.len() != rdef.len() {
Ok(false)
} else {
for (i, lv) in ldef.iter().enumerate() {
let field_target = &rdef[i];
if lv.0.val != field_target.0.val {
// field name equality
return Ok(false);
} else {
// field value equality.
if !try!(lv.1.equal(
field_target.1.as_ref(),
file_name,
lv.0.pos.clone()
)) {
return Ok(false);
}
}
}
Ok(true)
}
}
(&Val::Macro(_), &Val::Macro(_)) => Err(error::Error::new(
format!("Macros are not comparable in file: {}", file_name),
error::ErrorType::TypeFail,
pos,
)),
(me, tgt) => Err(error::Error::new(
format!("Types differ for {}, {} in file: {}", me, tgt, file_name),
error::ErrorType::TypeFail,
pos,
)),
}
}
/// Returns the fields if this Val is a tuple. None otherwise.
pub fn get_fields(&self) -> Option<&Vec<(Positioned<String>, Rc<Val>)>> {
if let &Val::Tuple(ref fs) = self {
Some(fs)
} else {
None
}
}
pub fn is_int(&self) -> bool {
if let &Val::Int(_) = self {
return true;
}
return false;
}
pub fn is_empty(&self) -> bool {
if let &Val::Empty = self {
return true;
}
return false;
}
pub fn is_float(&self) -> bool {
if let &Val::Float(_) = self {
return true;
}
return false;
}
pub fn is_string(&self) -> bool {
if let &Val::Str(_) = self {
return true;
}
return false;
}
pub fn is_tuple(&self) -> bool {
if let &Val::Tuple(_) = self {
return true;
}
return false;
}
pub fn is_list(&self) -> bool {
if let &Val::List(_) = self {
return true;
}
return false;
}
pub fn is_macro(&self) -> bool {
if let &Val::Macro(_) = self {
return true;
}
return false;
}
}
impl Display for Val {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
&Val::Boolean(b) => write!(f, "Boolean({})", b),
&Val::Empty => write!(f, "EmptyValue"),
&Val::Float(ref ff) => write!(f, "Float({})", ff),
&Val::Int(ref i) => write!(f, "Int({})", i),
&Val::Str(ref s) => write!(f, "String({})", s),
&Val::List(ref def) => {
try!(write!(f, "[\n"));
for v in def.iter() {
try!(write!(f, "\t{},\n", v));
}
write!(f, "]")
}
&Val::Macro(_) => write!(f, "Macro(..)"),
&Val::Tuple(ref def) => {
try!(write!(f, "Tuple(\n"));
for v in def.iter() {
try!(write!(f, "\t{} = {},\n", v.0.val, v.1));
}
write!(f, ")")
}
}
}
}
impl From<Val> for String {
fn from(v: Val) -> String {
match v {
Val::Int(ref i) => format!("{}", i),
Val::Float(ref f) => format!("{}", f),
Val::Str(ref s) => s.to_string(),
Val::Boolean(ref b) => format!("{}", b),
Val::Empty => "NULL".to_string(),
val => format!("<{}>", val),
}
}
}
impl From<String> for Val {
fn from(s: String) -> Val {
Val::Str(s)
}
}

View File

@ -16,11 +16,8 @@
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::Read;
use std::ops::Deref;
@ -35,6 +32,9 @@ use parse::parse;
use tokenizer::Span;
pub mod assets;
pub mod ir;
pub use self::ir::Val;
impl MacroDef {
/// Expands a ucg Macro using the given arguments into a new Tuple.
@ -80,215 +80,6 @@ impl MacroDef {
/// The result of a build.
type BuildResult = Result<(), Box<Error>>;
/// The Intermediate representation of a compiled UCG AST.
#[derive(PartialEq, Debug, Clone)]
pub enum Val {
Empty,
Boolean(bool),
Int(i64),
Float(f64),
Str(String),
List(Vec<Rc<Val>>),
Tuple(Vec<(Positioned<String>, Rc<Val>)>),
Macro(MacroDef),
}
impl Val {
/// Returns the Type of a Val as a string.
pub fn type_name(&self) -> String {
match self {
&Val::Empty => "EmptyValue".to_string(),
&Val::Boolean(_) => "Boolean".to_string(),
&Val::Int(_) => "Integer".to_string(),
&Val::Float(_) => "Float".to_string(),
&Val::Str(_) => "String".to_string(),
&Val::List(_) => "List".to_string(),
&Val::Tuple(_) => "Tuple".to_string(),
&Val::Macro(_) => "Macro".to_string(),
}
}
/// Returns true if called with a Val of the same type as itself.
pub fn type_equal(&self, target: &Self) -> bool {
enum_type_equality!(
self,
target,
&Val::Empty,
&Val::Boolean(_),
&Val::Int(_),
&Val::Float(_),
&Val::Str(_),
&Val::List(_),
&Val::Tuple(_),
&Val::Macro(_)
)
}
pub fn equal(
&self,
target: &Self,
file_name: &str,
pos: Position,
) -> Result<bool, error::Error> {
// first we do a type equality comparison
match (self, target) {
// Empty values are always equal.
(&Val::Empty, &Val::Empty) => Ok(true),
(&Val::Int(ref i), &Val::Int(ref ii)) => Ok(i == ii),
(&Val::Float(ref f), &Val::Float(ref ff)) => Ok(f == ff),
(&Val::Boolean(ref b), &Val::Boolean(ref bb)) => Ok(b == bb),
(&Val::Str(ref s), &Val::Str(ref ss)) => Ok(s == ss),
(&Val::List(ref ldef), &Val::List(ref rdef)) => {
if ldef.len() != rdef.len() {
Ok(false)
} else {
for (i, lv) in ldef.iter().enumerate() {
try!(lv.equal(rdef[i].as_ref(), file_name, pos.clone()));
}
Ok(true)
}
}
(&Val::Tuple(ref ldef), &Val::Tuple(ref rdef)) => {
if ldef.len() != rdef.len() {
Ok(false)
} else {
for (i, lv) in ldef.iter().enumerate() {
let field_target = &rdef[i];
if lv.0.val != field_target.0.val {
// field name equality
return Ok(false);
} else {
// field value equality.
if !try!(lv.1.equal(
field_target.1.as_ref(),
file_name,
lv.0.pos.clone()
)) {
return Ok(false);
}
}
}
Ok(true)
}
}
(&Val::Macro(_), &Val::Macro(_)) => Err(error::Error::new(
format!("Macros are not comparable in file: {}", file_name),
error::ErrorType::TypeFail,
pos,
)),
(me, tgt) => Err(error::Error::new(
format!("Types differ for {}, {} in file: {}", me, tgt, file_name),
error::ErrorType::TypeFail,
pos,
)),
}
}
/// Returns the fields if this Val is a tuple. None otherwise.
pub fn get_fields(&self) -> Option<&Vec<(Positioned<String>, Rc<Val>)>> {
if let &Val::Tuple(ref fs) = self {
Some(fs)
} else {
None
}
}
pub fn is_int(&self) -> bool {
if let &Val::Int(_) = self {
return true;
}
return false;
}
pub fn is_empty(&self) -> bool {
if let &Val::Empty = self {
return true;
}
return false;
}
pub fn is_float(&self) -> bool {
if let &Val::Float(_) = self {
return true;
}
return false;
}
pub fn is_string(&self) -> bool {
if let &Val::Str(_) = self {
return true;
}
return false;
}
pub fn is_tuple(&self) -> bool {
if let &Val::Tuple(_) = self {
return true;
}
return false;
}
pub fn is_list(&self) -> bool {
if let &Val::List(_) = self {
return true;
}
return false;
}
pub fn is_macro(&self) -> bool {
if let &Val::Macro(_) = self {
return true;
}
return false;
}
}
impl Display for Val {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
&Val::Boolean(b) => write!(f, "Boolean({})", b),
&Val::Empty => write!(f, "EmptyValue"),
&Val::Float(ref ff) => write!(f, "Float({})", ff),
&Val::Int(ref i) => write!(f, "Int({})", i),
&Val::Str(ref s) => write!(f, "String({})", s),
&Val::List(ref def) => {
try!(write!(f, "[\n"));
for v in def.iter() {
try!(write!(f, "\t{},\n", v));
}
write!(f, "]")
}
&Val::Macro(_) => write!(f, "Macro(..)"),
&Val::Tuple(ref def) => {
try!(write!(f, "Tuple(\n"));
for v in def.iter() {
try!(write!(f, "\t{} = {},\n", v.0.val, v.1));
}
write!(f, ")")
}
}
}
}
impl From<Val> for String {
fn from(v: Val) -> String {
match v {
Val::Int(ref i) => format!("{}", i),
Val::Float(ref f) => format!("{}", f),
Val::Str(ref s) => s.to_string(),
Val::Boolean(ref b) => format!("{}", b),
Val::Empty => "NULL".to_string(),
val => format!("<{}>", val),
}
}
}
impl From<String> for Val {
fn from(s: String) -> Val {
Val::Str(s)
}
}
/// Defines a set of values in a parsed file.
type ValueMap = HashMap<Positioned<String>, Rc<Val>>;