From ae419ea3e7c0349c0e1192bb9b76ba1f08bdf911 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Fri, 24 Aug 2018 19:36:36 -0500 Subject: [PATCH] REFACTOR: Move the ucg IR into it's own module. --- src/build/ir.rs | 219 +++++++++++++++++++++++++++++++++++++++++++++++ src/build/mod.rs | 215 +--------------------------------------------- 2 files changed, 222 insertions(+), 212 deletions(-) create mode 100644 src/build/ir.rs diff --git a/src/build/ir.rs b/src/build/ir.rs new file mode 100644 index 0000000..736424d --- /dev/null +++ b/src/build/ir.rs @@ -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>), + Tuple(Vec<(Positioned, Rc)>), + 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 { + // 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, Rc)>> { + 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 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 for Val { + fn from(s: String) -> Val { + Val::Str(s) + } +} diff --git a/src/build/mod.rs b/src/build/mod.rs index 32152a9..6b771b8 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -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>; -/// 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>), - Tuple(Vec<(Positioned, Rc)>), - 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 { - // 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, Rc)>> { - 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 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 for Val { - fn from(s: String) -> Val { - Val::Str(s) - } -} - /// Defines a set of values in a parsed file. type ValueMap = HashMap, Rc>;