REFACTOR/FEATURE: Treat selectors as an operator.

This commit is contained in:
Jeremy Wall 2018-12-28 19:02:37 -06:00
parent fb292b4684
commit a028960a43
7 changed files with 212 additions and 2018 deletions

View File

@ -185,158 +185,11 @@ macro_rules! make_expr {
}; };
} }
/// Helper macro for making selectors.
///
/// ```
/// make_selector!(Token::new("tpl", 1, 1), Token::new("fld", 1, 4));
///
/// make_selector!(Token::new("tpl", 1, 1), vec![Token::new("fld", 1, 4)], => 1, 1);
///
/// make_selector!(foo", ["bar"]);
///
/// make_selector!(foo", ["bar"] => 1, 0);
/// ```
#[allow(unused_macros)]
macro_rules! make_selector {
( $h:expr, $i:expr) => {
SelectorDef::new(
SelectorList{head: Box::new($h), tail: None},
$i)
};
( $h: expr, $list:expr, $i:expr) => {
SelectorDef::new(
SelectorList{head: Box::new($h), tail: Some($list)},
$i)
};
// Tokens
( $h:expr => [ $( $item:expr ),* ], $i:expr ) => {
{
make_selector!($h => [ $( $item, )* ] => $i)
}
};
( $h:expr => [ $( $item:expr ),* ] => $i:expr ) => {
{
let mut list: Vec<Token> = Vec::new();
$(
list.push($item);
)*
make_selector!($h, list, $i)
}
};
// Strings not tokens
( $h:expr => $( $item:expr ),* ) => {
{
let mut col = 1;
let mut list: Vec<Token> = Vec::new();
$(
list.push(make_tok!($item, Position::new(1, col, col)));
col += $item.len() + 1;
)*
// Shut up the lint about unused code;
assert!(col != 0);
make_selector!($h, list, Position::new(1, 1, 1))
}
};
( $h:expr => $( $item:expr ),* => $l:expr, $c:expr ) => {
{
let mut col = $c;
let mut list: Vec<Token> = Vec::new();
$(
list.push(make_tok!($item, Position::new($l, col, col)));
col += $item.len() + 1;
)*
// Shut up the linter about unused code;
assert!(col != 0);
make_selector!($h, list, Position::new($l, $c, $c))
}
};
}
/// An Expression with a series of symbols specifying the key
/// with which to descend into the result of the expression.
///
/// The expression must evaluate to either a tuple or an array. The token must
/// evaluate to either a bareword Symbol or an Int.
///
/// ```ucg
/// let foo = { bar = "a thing" };
/// let thing = foo.bar;
///
/// let arr = ["one", "two"];
/// let first = arr.0;
///
/// let berry = {best = "strawberry", unique = "acai"}.best;
/// let third = ["uno", "dos", "tres"].1;
/// '''
#[derive(PartialEq, Clone)]
pub struct SelectorList {
pub head: Box<Expression>,
// TODO This should now work more like a binary operator. Perhaps move into the precendence parser code?
pub tail: Option<Vec<Token>>,
}
impl SelectorList {
/// Returns a stringified version of a SelectorList.
pub fn to_string(&self) -> String {
"TODO".to_string()
}
}
impl fmt::Debug for SelectorList {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
write!(w, "Selector({})", self)
}
}
impl fmt::Display for SelectorList {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
write!(w, "{}", self.head)?;
if let Some(ref tok_vec) = self.tail {
for t in tok_vec.iter() {
write!(w, ".{}", t.fragment)?;
}
}
return Ok(());
}
}
/// An ordered list of Name = Value pairs. /// An ordered list of Name = Value pairs.
/// ///
/// This is usually used as the body of a tuple in the UCG AST. /// This is usually used as the body of a tuple in the UCG AST.
pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
/// Encodes a selector expression in the UCG AST.
#[derive(Debug, PartialEq, Clone)]
pub struct SelectorDef {
pub pos: Position,
pub sel: SelectorList,
}
impl SelectorDef {
/// Constructs a new SelectorDef.
pub fn new<P: Into<Position>>(sel: SelectorList, p: P) -> Self {
SelectorDef {
pos: p.into(),
sel: sel,
}
}
}
/// Represents a Value in the UCG parsed AST. /// Represents a Value in the UCG parsed AST.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Value { pub enum Value {
@ -350,7 +203,6 @@ pub enum Value {
// Complex Values // Complex Values
Tuple(PositionedItem<FieldList>), Tuple(PositionedItem<FieldList>),
List(ListDef), List(ListDef),
Selector(SelectorDef),
} }
impl Value { impl Value {
@ -365,7 +217,6 @@ impl Value {
&Value::Symbol(_) => "Symbol".to_string(), &Value::Symbol(_) => "Symbol".to_string(),
&Value::Tuple(_) => "Tuple".to_string(), &Value::Tuple(_) => "Tuple".to_string(),
&Value::List(_) => "List".to_string(), &Value::List(_) => "List".to_string(),
&Value::Selector(_) => "Selector".to_string(),
} }
} }
@ -396,7 +247,6 @@ impl Value {
&Value::Symbol(ref s) => format!("{}", s.val), &Value::Symbol(ref s) => format!("{}", s.val),
&Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)), &Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)),
&Value::List(ref def) => format!("[{}]", Self::elems_to_string(&def.elems)), &Value::List(ref def) => format!("[{}]", Self::elems_to_string(&def.elems)),
&Value::Selector(ref v) => v.sel.to_string(),
} }
} }
@ -411,7 +261,6 @@ impl Value {
&Value::Symbol(ref s) => &s.pos, &Value::Symbol(ref s) => &s.pos,
&Value::Tuple(ref fs) => &fs.pos, &Value::Tuple(ref fs) => &fs.pos,
&Value::List(ref def) => &def.pos, &Value::List(ref def) => &def.pos,
&Value::Selector(ref v) => &v.pos,
} }
} }
@ -427,8 +276,7 @@ impl Value {
&Value::Str(_), &Value::Str(_),
&Value::Symbol(_), &Value::Symbol(_),
&Value::Tuple(_), &Value::Tuple(_),
&Value::List(_), &Value::List(_)
&Value::Selector(_)
) )
} }
} }
@ -437,7 +285,7 @@ impl Value {
/// defined. /// defined.
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub struct CallDef { pub struct CallDef {
pub macroref: SelectorDef, pub macroref: Value,
pub arglist: Vec<Expression>, pub arglist: Vec<Expression>,
pub pos: Position, pub pos: Position,
} }
@ -552,8 +400,6 @@ impl MacroDef {
if !self.symbol_is_in_args(&name.val) { if !self.symbol_is_in_args(&name.val) {
bad_symbols.insert(name.val.clone()); bad_symbols.insert(name.val.clone());
} }
} else if let &Value::Selector(ref sel_node) = val {
stack.push(&sel_node.sel.head);
} else if let &Value::Tuple(ref tuple_node) = val { } else if let &Value::Tuple(ref tuple_node) = val {
let fields = &tuple_node.val; let fields = &tuple_node.val;
for &(_, ref expr) in fields.iter() { for &(_, ref expr) in fields.iter() {
@ -637,6 +483,7 @@ impl MacroDef {
/// UCG expression. /// UCG expression.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum BinaryExprType { pub enum BinaryExprType {
// Math
Add, Add,
Sub, Sub,
Mul, Mul,
@ -648,7 +495,8 @@ pub enum BinaryExprType {
NotEqual, NotEqual,
GTEqual, GTEqual,
LTEqual, LTEqual,
// TODO DOT Selector operator // Selector operator
DOT,
} }
/// Represents an expression with a left and a right side. /// Represents an expression with a left and a right side.
@ -663,7 +511,7 @@ pub struct BinaryOpDef {
/// Encodes a tuple Copy expression in the UCG AST. /// Encodes a tuple Copy expression in the UCG AST.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct CopyDef { pub struct CopyDef {
pub selector: SelectorDef, pub selector: Value,
pub fields: FieldList, pub fields: FieldList,
pub pos: Position, pub pos: Position,
} }
@ -694,8 +542,8 @@ pub enum ListOpType {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct ListOpDef { pub struct ListOpDef {
pub typ: ListOpType, pub typ: ListOpType,
pub mac: SelectorDef, pub mac: PositionedItem<String>,
pub field: String, pub field: PositionedItem<String>,
pub target: Box<Expression>, pub target: Box<Expression>,
pub pos: Position, pub pos: Position,
} }

View File

@ -72,10 +72,10 @@ pub fn test_macro_validation_selector_happy_path() {
make_tok!("f1", Position::new(1, 1, 0)), make_tok!("f1", Position::new(1, 1, 0)),
Expression::Binary(BinaryOpDef { Expression::Binary(BinaryOpDef {
kind: BinaryExprType::Add, kind: BinaryExprType::Add,
left: Box::new(Expression::Simple(Value::Selector(make_selector!( left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
make_expr!("foo", Position::new(1, 1, 0)) => [ "foo".to_string(),
make_tok!("quux", Position::new(1, 1, 0)) ] Position::new(1, 1, 0),
=> Position::new(1, 1, 0))))), )))),
right: Box::new(Expression::Simple(Value::Int(value_node!( right: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)
@ -96,10 +96,10 @@ pub fn test_macro_validation_selector_fail() {
make_tok!("f1", Position::new(1, 1, 0)), make_tok!("f1", Position::new(1, 1, 0)),
Expression::Binary(BinaryOpDef { Expression::Binary(BinaryOpDef {
kind: BinaryExprType::Add, kind: BinaryExprType::Add,
left: Box::new(Expression::Simple(Value::Selector( left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
make_selector!(make_expr!("bar", Position::new(1, 1, 0)) => [ "bar".to_string(),
make_tok!("quux", Position::new(1, 1, 0)) ] => Position::new(1, 1, 0)), Position::new(1, 1, 0),
))), )))),
right: Box::new(Expression::Simple(Value::Int(value_node!( right: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)

View File

@ -15,7 +15,7 @@
//! The build stage of the ucg compiler. //! The build stage of the ucg compiler.
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque}; use std::collections::HashMap;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
@ -239,9 +239,6 @@ impl<'a> FileBuilder<'a> {
} }
&Value::List(ref def) => self.eval_list(def, scope), &Value::List(ref def) => self.eval_list(def, scope),
&Value::Tuple(ref tuple) => self.eval_tuple(&tuple.val, scope), &Value::Tuple(ref tuple) => self.eval_tuple(&tuple.val, scope),
&Value::Selector(ref selector_list_node) => {
self.lookup_selector(&selector_list_node.sel, scope)
}
} }
} }
@ -476,131 +473,86 @@ impl<'a> FileBuilder<'a> {
fn lookup_in_env( fn lookup_in_env(
&self, &self,
search: &Token, pos: &Position,
stack: &mut VecDeque<Rc<Val>>, field: &Rc<Val>,
fs: &Vec<(String, String)>, fs: &Vec<(String, String)>,
) -> Result<(), Box<Error>> { ) -> Result<Rc<Val>, Box<Error>> {
let field = if let &Val::Str(ref name) = field.as_ref() {
name
} else {
return Err(Box::new(error::BuildError::new(
format!("Invalid type {} for field lookup in env", field),
error::ErrorType::TypeFail,
pos.clone(),
)));
};
for &(ref name, ref val) in fs.iter() { for &(ref name, ref val) in fs.iter() {
if &search.fragment == name { if field == name {
stack.push_back(Rc::new(Val::Str(val.clone()))); return Ok(Rc::new(Val::Str(val.clone())));
return Ok(());
} else if !self.strict { } else if !self.strict {
stack.push_back(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
return Ok(());
} }
} }
return Err(Box::new(error::BuildError::new( return Err(Box::new(error::BuildError::new(
format!("Environment Variable {} not set", search.fragment), format!("Environment Variable {} not set", field),
error::ErrorType::NoSuchSymbol, error::ErrorType::NoSuchSymbol,
search.pos.clone(), pos.clone(),
))); )));
} }
// TODO: Do as part of a binary operator selector lookup.
fn lookup_in_tuple( fn lookup_in_tuple(
&self, &self,
stack: &mut VecDeque<Rc<Val>>, pos: &Position,
sl: &SelectorList, field: &Val,
next: (&Position, &str),
fs: &Vec<(PositionedItem<String>, Rc<Val>)>, fs: &Vec<(PositionedItem<String>, Rc<Val>)>,
) -> Result<(), Box<Error>> { ) -> Result<Rc<Val>, Box<Error>> {
if let Some(vv) = Self::find_in_fieldlist(next.1, fs) { let field = if let &Val::Str(ref name) = field {
stack.push_back(vv.clone()); name
} else { } else {
return Err(Box::new(error::BuildError::new( return Err(Box::new(error::BuildError::new(
format!( format!("Invalid type {} for field lookup in tuple", field),
"Unable to \ error::ErrorType::TypeFail,
match element {} in selector \ pos.clone(),
path [{}]",
next.1, sl,
),
error::ErrorType::NoSuchSymbol,
next.0.clone(),
))); )));
};
if let Some(vv) = Self::find_in_fieldlist(&field, fs) {
Ok(vv)
} else {
Err(Box::new(error::BuildError::new(
format!("Unable to {} match element in tuple.", field,),
error::ErrorType::NoSuchSymbol,
pos.clone(),
)))
} }
Ok(())
} }
// TODO: Do as part of a binary operator selector lookup.
fn lookup_in_list( fn lookup_in_list(
&self, &self,
stack: &mut VecDeque<Rc<Val>>, pos: &Position,
sl: &SelectorList, field: &Rc<Val>,
next: (&Position, &str),
elems: &Vec<Rc<Val>>, elems: &Vec<Rc<Val>>,
) -> Result<(), Box<Error>> { ) -> Result<Rc<Val>, Box<Error>> {
let idx = next.1.parse::<usize>()?; let idx = match field.as_ref() {
if idx < elems.len() { &Val::Int(i) => i as usize,
stack.push_back(elems[idx].clone()); &Val::Str(ref s) => s.parse::<usize>()?,
} else {
return Err(Box::new(error::BuildError::new(
format!(
"Unable to \
match element {} in selector \
path [{}]",
next.1, sl,
),
error::ErrorType::NoSuchSymbol,
next.0.clone(),
)));
}
Ok(())
}
fn lookup_selector(&mut self, sl: &SelectorList, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
let first = self.eval_expr(&sl.head, scope)?;
// First we ensure that the result is a tuple or a list.
let mut stack = VecDeque::new();
match first.as_ref() {
&Val::Tuple(_) => {
stack.push_back(first.clone());
}
&Val::List(_) => {
stack.push_back(first.clone());
}
&Val::Env(_) => {
stack.push_back(first.clone());
}
_ => { _ => {
// noop return Err(Box::new(error::BuildError::new(
} format!("Invalid idx type {} for list lookup", field),
} error::ErrorType::TypeFail,
pos.clone(),
if let &Some(ref tail) = &sl.tail { )))
if tail.len() == 0 {
return Ok(first);
}
let mut it = tail.iter().peekable();
loop {
let vref = stack.pop_front().unwrap();
if it.peek().is_none() {
return Ok(vref.clone());
}
// This unwrap is safe because we already checked for
// None above.
let next = it.next().unwrap();
match vref.as_ref() {
&Val::Tuple(ref fs) => {
self.lookup_in_tuple(&mut stack, sl, (&next.pos, &next.fragment), fs)?;
continue;
}
&Val::Env(ref fs) => {
self.lookup_in_env(&next, &mut stack, fs)?;
continue;
}
&Val::List(ref elems) => {
self.lookup_in_list(&mut stack, sl, (&next.pos, &next.fragment), elems)?;
continue;
}
_ => {
return Err(Box::new(error::BuildError::new(
format!("{} is not a Tuple or List", vref),
error::ErrorType::TypeFail,
next.pos.clone(),
)));
}
}
} }
};
if idx < elems.len() {
Ok(elems[idx].clone())
} else { } else {
return Ok(first); Err(Box::new(error::BuildError::new(
format!("idx {} out of bounds in list", idx),
error::ErrorType::NoSuchSymbol,
pos.clone(),
)))
} }
} }
@ -857,21 +809,44 @@ impl<'a> FileBuilder<'a> {
))) )))
} }
fn do_dot_lookup(
&mut self,
pos: &Position,
left: Rc<Val>,
right: Rc<Val>,
scope: &Scope,
) -> Result<Rc<Val>, Box<Error>> {
match left.as_ref() {
&Val::Tuple(ref fs) => self.lookup_in_tuple(pos, &right, fs),
&Val::List(ref fs) => self.lookup_in_list(pos, &right, fs),
&Val::Env(ref fs) => self.lookup_in_env(pos, &right, fs),
_ => Err(Box::new(error::BuildError::new(
"Invalid type left operand for dot lookup",
error::ErrorType::TypeFail,
pos.clone(),
))),
}
}
fn eval_binary(&mut self, def: &BinaryOpDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> { fn eval_binary(&mut self, def: &BinaryOpDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
let kind = &def.kind; let kind = &def.kind;
let left = self.eval_expr(&def.left, scope)?; let left = self.eval_expr(&def.left, scope)?;
let right = self.eval_expr(&def.right, scope)?; let right = self.eval_expr(&def.right, scope)?;
match kind { match kind {
// Handle math and concatenation operators here
&BinaryExprType::Add => self.add_vals(&def.pos, left, right), &BinaryExprType::Add => self.add_vals(&def.pos, left, right),
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right), &BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right), &BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
&BinaryExprType::Div => self.divide_vals(&def.pos, left, right), &BinaryExprType::Div => self.divide_vals(&def.pos, left, right),
// Handle Comparison operators here
&BinaryExprType::Equal => self.do_deep_equal(&def.pos, left, right), &BinaryExprType::Equal => self.do_deep_equal(&def.pos, left, right),
&BinaryExprType::GT => self.do_gt(&def.pos, left, right), &BinaryExprType::GT => self.do_gt(&def.pos, left, right),
&BinaryExprType::LT => self.do_lt(&def.pos, left, right), &BinaryExprType::LT => self.do_lt(&def.pos, left, right),
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right), &BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right), &BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
&BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right), &BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
// TODO Handle the whole selector lookup logic here.
&BinaryExprType::DOT => self.do_dot_lookup(&def.pos, left, right, scope),
} }
} }
@ -960,7 +935,7 @@ impl<'a> FileBuilder<'a> {
} }
fn eval_copy(&mut self, def: &CopyDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> { fn eval_copy(&mut self, def: &CopyDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
let v = self.lookup_selector(&def.selector.sel, scope)?; let v = self.eval_value(&def.selector, scope)?;
if let &Val::Tuple(ref src_fields) = v.as_ref() { if let &Val::Tuple(ref src_fields) = v.as_ref() {
let mut child_scope = scope.spawn_child(); let mut child_scope = scope.spawn_child();
child_scope.set_curr_val(v.clone()); child_scope.set_curr_val(v.clone());
@ -1011,14 +986,14 @@ impl<'a> FileBuilder<'a> {
mod_def.arg_tuple mod_def.arg_tuple
), ),
error::ErrorType::TypeFail, error::ErrorType::TypeFail,
def.selector.pos.clone(), def.selector.pos().clone(),
))); )));
} }
} }
Err(Box::new(error::BuildError::new( Err(Box::new(error::BuildError::new(
format!("Expected Tuple or Module got {}", v), format!("Expected Tuple or Module got {}", v),
error::ErrorType::TypeFail, error::ErrorType::TypeFail,
def.selector.pos.clone(), def.selector.pos().clone(),
))) )))
} }
@ -1035,9 +1010,8 @@ impl<'a> FileBuilder<'a> {
} }
fn eval_call(&mut self, def: &CallDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> { fn eval_call(&mut self, def: &CallDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
let sel = &def.macroref;
let args = &def.arglist; let args = &def.arglist;
let v = self.lookup_selector(&sel.sel, scope)?; let v = self.eval_value(&def.macroref, scope)?;
if let &Val::Macro(ref m) = v.deref() { if let &Val::Macro(ref m) = v.deref() {
// Congratulations this is actually a macro. // Congratulations this is actually a macro.
let mut argvals: Vec<Rc<Val>> = Vec::new(); let mut argvals: Vec<Rc<Val>> = Vec::new();
@ -1145,13 +1119,13 @@ impl<'a> FileBuilder<'a> {
))); )));
} }
}; };
let mac = &def.mac; let mac_sym = Value::Symbol(def.mac.clone());
if let &Val::Macro(ref macdef) = self.lookup_selector(&mac.sel, scope)?.as_ref() { if let &Val::Macro(ref macdef) = self.eval_value(&mac_sym, &self.scope)?.as_ref() {
let mut out = Vec::new(); let mut out = Vec::new();
for item in l.iter() { for item in l.iter() {
let argvals = vec![item.clone()]; let argvals = vec![item.clone()];
let fields = macdef.eval(self.file.clone(), self, argvals)?; let fields = macdef.eval(self.file.clone(), self, argvals)?;
if let Some(v) = Self::find_in_fieldlist(&def.field, &fields) { if let Some(v) = Self::find_in_fieldlist(&def.field.val, &fields) {
match def.typ { match def.typ {
ListOpType::Map => { ListOpType::Map => {
out.push(v.clone()); out.push(v.clone());
@ -1172,7 +1146,7 @@ impl<'a> FileBuilder<'a> {
return Ok(Rc::new(Val::List(out))); return Ok(Rc::new(Val::List(out)));
} }
return Err(Box::new(error::BuildError::new( return Err(Box::new(error::BuildError::new(
format!("Expected macro but got {:?}", mac), format!("Expected macro but got {:?}", def.mac),
error::ErrorType::TypeFail, error::ErrorType::TypeFail,
def.pos.clone(), def.pos.clone(),
))); )));

View File

@ -157,10 +157,10 @@ fn test_expr_copy_no_such_tuple() {
test_expr_to_val( test_expr_to_val(
vec![( vec![(
Expression::Copy(CopyDef { Expression::Copy(CopyDef {
selector: make_selector!( selector: Value::Symbol(PositionedItem::new(
make_expr!("tpl1", Position::new(1, 1, 1)), "tpl1".to_string(),
Position::new(1, 1, 1) Position::new(1, 1, 1),
), )),
fields: Vec::new(), fields: Vec::new(),
pos: Position::new(1, 0, 0), pos: Position::new(1, 0, 0),
}), }),
@ -183,10 +183,10 @@ fn test_expr_copy_not_a_tuple() {
test_expr_to_val( test_expr_to_val(
vec![( vec![(
Expression::Copy(CopyDef { Expression::Copy(CopyDef {
selector: make_selector!( selector: Value::Symbol(PositionedItem::new(
make_expr!("tpl1", Position::new(1, 1, 1)), "tpl1".to_string(),
Position::new(1, 1, 1) Position::new(1, 1, 1),
), )),
fields: Vec::new(), fields: Vec::new(),
pos: Position::new(1, 0, 0), pos: Position::new(1, 0, 0),
}), }),
@ -212,10 +212,10 @@ fn test_expr_copy_field_type_error() {
test_expr_to_val( test_expr_to_val(
vec![( vec![(
Expression::Copy(CopyDef { Expression::Copy(CopyDef {
selector: make_selector!( selector: Value::Symbol(PositionedItem::new(
make_expr!("tpl1", Position::new(1, 1, 1)), "tpl1".to_string(),
Position::new(1, 1, 1) Position::new(1, 1, 1),
), )),
fields: vec![( fields: vec![(
make_tok!("fld1", Position::new(1, 1, 1)), make_tok!("fld1", Position::new(1, 1, 1)),
Expression::Simple(Value::Str(value_node!( Expression::Simple(Value::Str(value_node!(
@ -261,10 +261,10 @@ fn test_macro_hermetic() {
test_expr_to_val( test_expr_to_val(
vec![( vec![(
Expression::Call(CallDef { Expression::Call(CallDef {
macroref: make_selector!( macroref: Value::Symbol(PositionedItem::new(
make_expr!("tstmac", Position::new(1, 1, 1)), "tstmac".to_string(),
Position::new(1, 1, 1) Position::new(1, 1, 1),
), )),
arglist: vec![Expression::Simple(Value::Str(value_node!( arglist: vec![Expression::Simple(Value::Str(value_node!(
"bar".to_string(), "bar".to_string(),
Position::new(1, 1, 1) Position::new(1, 1, 1)

View File

@ -279,7 +279,7 @@ make_fn!(
either!( either!(
// TODO This should move to op_expression instead of a value now. // TODO This should move to op_expression instead of a value now.
// We probably still need a bareword parser though? // We probably still need a bareword parser though?
trace_parse!(selector_value), trace_parse!(symbol),
trace_parse!(compound_value), trace_parse!(compound_value),
trace_parse!(boolean_value), trace_parse!(boolean_value),
trace_parse!(empty_value), trace_parse!(empty_value),
@ -318,107 +318,14 @@ make_fn!(
) )
); );
fn symbol_or_expression(input: SliceIter<Token>) -> ParseResult<Expression> { fn tuple_to_copy(sym: Value, fields: Option<FieldList>) -> Expression {
let _i = input.clone(); let pos = sym.pos().clone();
let scalar_head = do_each!(input,
sym => either!(symbol, compound_value),
(sym)
);
match scalar_head {
Result::Incomplete(offset) => Result::Incomplete(offset),
Result::Fail(_) => grouped_expression(_i),
Result::Abort(e) => Result::Abort(e),
Result::Complete(rest, val) => {
let res = peek!(rest.clone(), punct!("."));
match val {
Value::Tuple(_) => {
if res.is_complete() {
Result::Complete(rest, Expression::Simple(val))
} else {
return Result::Fail(Error::new(
"Expected (.) but no dot found".to_string(),
Box::new(rest.clone()),
));
}
}
Value::List(_) => {
if res.is_complete() {
Result::Complete(rest, Expression::Simple(val))
} else {
return Result::Fail(Error::new(
"Expected (.) but no dot found".to_string(),
Box::new(rest.clone()),
));
}
}
_ => Result::Complete(rest, Expression::Simple(val)),
}
}
}
}
fn selector_list(input: SliceIter<Token>) -> ParseResult<SelectorList> {
let (rest, head) = match symbol_or_expression(input) {
Result::Complete(rest, val) => (rest, val),
Result::Fail(e) => {
return Result::Fail(e);
}
Result::Incomplete(i) => {
return Result::Incomplete(i);
}
Result::Abort(e) => return Result::Abort(e),
};
let (rest, is_dot) = match punct!(rest, ".") {
Result::Complete(rest, tok) => (rest, Some(tok)),
Result::Incomplete(i) => {
return Result::Incomplete(i);
}
Result::Fail(_) => (rest, None),
Result::Abort(e) => return Result::Abort(e),
};
let (rest, list) = if is_dot.is_some() {
let (rest, list) = match separated!(
rest,
punct!("."),
either!(match_type!(BAREWORD), match_type!(DIGIT), match_type!(STR))
) {
Result::Complete(rest, val) => (rest, val),
Result::Incomplete(i) => return Result::Incomplete(i),
Result::Fail(e) => return Result::Fail(e),
Result::Abort(e) => return Result::Abort(e),
};
if list.is_empty() {
return Result::Fail(Error::new(
"(.) with no selector fields after".to_string(),
Box::new(rest.clone()),
));
} else {
(rest, Some(list))
}
} else {
(rest, None)
};
let sel_list = SelectorList {
head: Box::new(head),
tail: list,
};
return Result::Complete(rest, sel_list);
}
fn tuple_to_copy(def: SelectorDef, fields: Option<FieldList>) -> Expression {
let pos = def.pos.clone();
let fields = match fields { let fields = match fields {
Some(fields) => fields, Some(fields) => fields,
None => Vec::new(), None => Vec::new(),
}; };
Expression::Copy(CopyDef { Expression::Copy(CopyDef {
selector: def, selector: sym,
fields: fields, fields: fields,
pos: pos, pos: pos,
}) })
@ -427,14 +334,13 @@ fn tuple_to_copy(def: SelectorDef, fields: Option<FieldList>) -> Expression {
make_fn!( make_fn!(
copy_expression<SliceIter<Token>, Expression>, copy_expression<SliceIter<Token>, Expression>,
do_each!( do_each!(
pos => pos,
// TODO This should become just a bareword symbol now // TODO This should become just a bareword symbol now
selector => trace_parse!(selector_list), sym => trace_parse!(symbol),
_ => punct!("{"), _ => punct!("{"),
fields => optional!(trace_parse!(field_list)), fields => optional!(trace_parse!(field_list)),
_ => optional!(punct!(",")), // noms opt! macro does not preserve error types properly but this one does. _ => optional!(punct!(",")), // noms opt! macro does not preserve error types properly but this one does.
_ => punct!("}"), _ => punct!("}"),
(tuple_to_copy(SelectorDef::new(selector, pos), fields)) (tuple_to_copy(sym, fields))
) )
); );
@ -610,9 +516,9 @@ fn tuple_to_call<'a>(
val: Value, val: Value,
exprs: Option<Vec<Expression>>, exprs: Option<Vec<Expression>>,
) -> ConvertResult<'a, Expression> { ) -> ConvertResult<'a, Expression> {
if let Value::Selector(def) = val { if let Value::Symbol(_) = val {
Ok(Expression::Call(CallDef { Ok(Expression::Call(CallDef {
macroref: def, macroref: val,
arglist: exprs.unwrap_or_else(|| Vec::new()), arglist: exprs.unwrap_or_else(|| Vec::new()),
pos: (&input).into(), pos: (&input).into(),
})) }))
@ -624,22 +530,10 @@ fn tuple_to_call<'a>(
} }
} }
fn vec_to_selector_value(pos: Position, list: SelectorList) -> Value {
Value::Selector(SelectorDef::new(list, pos))
}
make_fn!(
selector_value<SliceIter<Token>, Value>,
do_each!(
sl => trace_parse!(selector_list),
(vec_to_selector_value(sl.head.pos().clone(), sl))
)
);
fn call_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expression> { fn call_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expression> {
let parsed = do_each!(input.clone(), let parsed = do_each!(input.clone(),
// TODO This should become just a bareword symbol now // TODO This should become just a bareword symbol now
callee_name => trace_parse!(selector_value), callee_name => trace_parse!(symbol),
_ => punct!("("), _ => punct!("("),
args => optional!(separated!(punct!(","), trace_parse!(expression))), args => optional!(separated!(punct!(","), trace_parse!(expression))),
_ => punct!(")"), _ => punct!(")"),
@ -664,59 +558,34 @@ fn tuple_to_list_op<'a>(
input: &'a SliceIter<Token>, input: &'a SliceIter<Token>,
kind: ListOpType, kind: ListOpType,
macroname: Value, macroname: Value,
outfield: Value,
list: Expression, list: Expression,
) -> ConvertResult<'a, Expression> { ) -> ConvertResult<'a, Expression> {
if let Value::Selector(mut def) = macroname { let macroname = match macroname {
// First of all we need to assert that this is a selector of at least Value::Symbol(sym) => sym,
// two sections. _ => {
let fieldname: String = match &mut def.sel.tail { return Err(Error::new(
&mut None => { format!("Expected a macro name but got {}", macroname.type_name()),
if ENABLE_TRACE { Box::new(input.clone()),
eprintln!( ))
"tuple_to_list_op had error {}", }
"Missing a result field for the macro" };
); let outfield = match outfield {
} Value::Symbol(sym) => sym,
return Err(Error::new( _ => {
format!("Missing a result field for the macro"), return Err(Error::new(
Box::new(input.clone()), format!("Expected a field name but got {}", outfield.type_name()),
)); Box::new(input.clone()),
} ))
&mut Some(ref mut tl) => { }
if tl.len() < 1 { };
if ENABLE_TRACE { return Ok(Expression::ListOp(ListOpDef {
eprintln!( typ: kind,
"tuple_to_list_op had error {}", mac: macroname,
"Missing a result field for the macro" field: outfield,
); target: Box::new(list),
} pos: input.into(),
return Err(Error::new( }));
format!("Missing a result field for the macro"),
Box::new(input.clone()),
));
}
let fname = tl.pop();
fname.unwrap().fragment
}
};
return Ok(Expression::ListOp(ListOpDef {
typ: kind,
mac: def,
field: fieldname,
target: Box::new(list),
pos: input.into(),
}));
}
if ENABLE_TRACE {
eprintln!(
"tuple_to_list_op had error {}",
format!("Expected a selector but got {}", macroname.type_name())
);
}
return Err(Error::new(
format!("Expected a selector but got {}", macroname.type_name()),
Box::new(input.clone()),
));
} }
make_fn!( make_fn!(
@ -728,9 +597,11 @@ make_fn!(
do_each!(_ => word!("filter"), (ListOpType::Filter)) do_each!(_ => word!("filter"), (ListOpType::Filter))
), ),
// TODO This should become just a bareword symbol now // TODO This should become just a bareword symbol now
macroname => trace_parse!(selector_value), macroname => trace_parse!(symbol),
_ => punct!("."),
outfield => trace_parse!(symbol),
list => trace_parse!(non_op_expression), list => trace_parse!(non_op_expression),
(tuple_to_list_op(&input, optype, macroname, list).unwrap()) (tuple_to_list_op(&input, optype, macroname, outfield, list).unwrap())
) )
); );
@ -916,6 +787,3 @@ pub fn parse<'a>(input: OffsetStrIter<'a>) -> std::result::Result<Vec<Statement>
} }
pub mod precedence; pub mod precedence;
#[cfg(test)]
mod test;

View File

@ -27,6 +27,13 @@ pub enum Element {
Op(BinaryExprType), Op(BinaryExprType),
} }
make_fn!(
dot_op_type<SliceIter<Token>, Element>,
do_each!(
_ => punct!("."),
(Element::Op(BinaryExprType::DOT)))
);
make_fn!( make_fn!(
math_op_type<SliceIter<Token>, Element>, math_op_type<SliceIter<Token>, Element>,
either!( either!(
@ -66,6 +73,34 @@ fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Express
)); ));
} }
fn parse_dot_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
let mut i_ = i.clone();
if eoi(i_.clone()).is_complete() {
return Result::Fail(Error::new(
format!("Expected Expression found End Of Input"),
Box::new(i_),
));
}
let el = i_.next();
if let Some(&Element::Op(ref op)) = el {
match op {
&BinaryExprType::DOT => {
return Result::Complete(i_.clone(), op.clone());
}
_other => {
// noop
}
};
}
return Result::Fail(Error::new(
format!(
"Error while parsing Binary Expression Unexpected Operator {:?}",
el
),
Box::new(i_),
));
}
fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> { fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
let mut i_ = i.clone(); let mut i_ = i.clone();
if eoi(i_.clone()).is_complete() { if eoi(i_.clone()).is_complete() {
@ -182,6 +217,7 @@ make_fn!(
parse_sum_operator, parse_sum_operator,
either!( either!(
trace_parse!(product_expression), trace_parse!(product_expression),
trace_parse!(dot_expression),
trace_parse!(parse_expression) trace_parse!(parse_expression)
) )
) )
@ -189,7 +225,10 @@ make_fn!(
make_fn!( make_fn!(
product_expression<SliceIter<Element>, Expression>, product_expression<SliceIter<Element>, Expression>,
do_binary_expr!(parse_product_operator, trace_parse!(parse_expression)) do_binary_expr!(
parse_product_operator,
either!(trace_parse!(dot_expression), trace_parse!(parse_expression))
)
); );
make_fn!( make_fn!(
@ -247,7 +286,17 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
make_fn!( make_fn!(
binary_expression<SliceIter<Element>, Expression>, binary_expression<SliceIter<Element>, Expression>,
either!(compare_expression, math_expression, parse_expression) either!(
compare_expression,
math_expression,
dot_expression,
parse_expression
)
);
make_fn!(
dot_expression<SliceIter<Element>, Expression>,
do_binary_expr!(parse_dot_operator, trace_parse!(parse_expression))
); );
make_fn!( make_fn!(
@ -256,6 +305,7 @@ make_fn!(
parse_compare_operator, parse_compare_operator,
either!( either!(
trace_parse!(math_expression), trace_parse!(math_expression),
trace_parse!(dot_expression),
trace_parse!(parse_expression) trace_parse!(parse_expression)
) )
) )
@ -290,7 +340,8 @@ fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> ParseResult<'a, Vec<Elemen
} }
} }
// 3. Parse an operator. // 3. Parse an operator.
match either!(_i.clone(), math_op_type, compare_op_type) { // TODO(jwall): Parse the dot operator.
match either!(_i.clone(), dot_op_type, math_op_type, compare_op_type) {
Result::Fail(e) => { Result::Fail(e) => {
if firstrun { if firstrun {
// If we don't find an operator in our first // If we don't find an operator in our first

File diff suppressed because it is too large Load Diff