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.
///
/// 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
/// 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.
#[derive(Debug, PartialEq, Clone)]
pub enum Value {
@ -350,7 +203,6 @@ pub enum Value {
// Complex Values
Tuple(PositionedItem<FieldList>),
List(ListDef),
Selector(SelectorDef),
}
impl Value {
@ -365,7 +217,6 @@ impl Value {
&Value::Symbol(_) => "Symbol".to_string(),
&Value::Tuple(_) => "Tuple".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::Tuple(ref fs) => format!("{}", Self::fields_to_string(&fs.val)),
&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::Tuple(ref fs) => &fs.pos,
&Value::List(ref def) => &def.pos,
&Value::Selector(ref v) => &v.pos,
}
}
@ -427,8 +276,7 @@ impl Value {
&Value::Str(_),
&Value::Symbol(_),
&Value::Tuple(_),
&Value::List(_),
&Value::Selector(_)
&Value::List(_)
)
}
}
@ -437,7 +285,7 @@ impl Value {
/// defined.
#[derive(PartialEq, Debug, Clone)]
pub struct CallDef {
pub macroref: SelectorDef,
pub macroref: Value,
pub arglist: Vec<Expression>,
pub pos: Position,
}
@ -552,8 +400,6 @@ impl MacroDef {
if !self.symbol_is_in_args(&name.val) {
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 {
let fields = &tuple_node.val;
for &(_, ref expr) in fields.iter() {
@ -637,6 +483,7 @@ impl MacroDef {
/// UCG expression.
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryExprType {
// Math
Add,
Sub,
Mul,
@ -648,7 +495,8 @@ pub enum BinaryExprType {
NotEqual,
GTEqual,
LTEqual,
// TODO DOT Selector operator
// Selector operator
DOT,
}
/// 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.
#[derive(Debug, PartialEq, Clone)]
pub struct CopyDef {
pub selector: SelectorDef,
pub selector: Value,
pub fields: FieldList,
pub pos: Position,
}
@ -694,8 +542,8 @@ pub enum ListOpType {
#[derive(Debug, PartialEq, Clone)]
pub struct ListOpDef {
pub typ: ListOpType,
pub mac: SelectorDef,
pub field: String,
pub mac: PositionedItem<String>,
pub field: PositionedItem<String>,
pub target: Box<Expression>,
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)),
Expression::Binary(BinaryOpDef {
kind: BinaryExprType::Add,
left: Box::new(Expression::Simple(Value::Selector(make_selector!(
make_expr!("foo", Position::new(1, 1, 0)) => [
make_tok!("quux", Position::new(1, 1, 0)) ]
=> Position::new(1, 1, 0))))),
left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
"foo".to_string(),
Position::new(1, 1, 0),
)))),
right: Box::new(Expression::Simple(Value::Int(value_node!(
1,
Position::new(1, 1, 0)
@ -96,10 +96,10 @@ pub fn test_macro_validation_selector_fail() {
make_tok!("f1", Position::new(1, 1, 0)),
Expression::Binary(BinaryOpDef {
kind: BinaryExprType::Add,
left: Box::new(Expression::Simple(Value::Selector(
make_selector!(make_expr!("bar", Position::new(1, 1, 0)) => [
make_tok!("quux", Position::new(1, 1, 0)) ] => Position::new(1, 1, 0)),
))),
left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
"bar".to_string(),
Position::new(1, 1, 0),
)))),
right: Box::new(Expression::Simple(Value::Int(value_node!(
1,
Position::new(1, 1, 0)

View File

@ -15,7 +15,7 @@
//! The build stage of the ucg compiler.
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::fs::File;
@ -239,9 +239,6 @@ impl<'a> FileBuilder<'a> {
}
&Value::List(ref def) => self.eval_list(def, 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(
&self,
search: &Token,
stack: &mut VecDeque<Rc<Val>>,
pos: &Position,
field: &Rc<Val>,
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() {
if &search.fragment == name {
stack.push_back(Rc::new(Val::Str(val.clone())));
return Ok(());
if field == name {
return Ok(Rc::new(Val::Str(val.clone())));
} else if !self.strict {
stack.push_back(Rc::new(Val::Empty));
return Ok(());
return Ok(Rc::new(Val::Empty));
}
}
return Err(Box::new(error::BuildError::new(
format!("Environment Variable {} not set", search.fragment),
format!("Environment Variable {} not set", field),
error::ErrorType::NoSuchSymbol,
search.pos.clone(),
pos.clone(),
)));
}
// TODO: Do as part of a binary operator selector lookup.
fn lookup_in_tuple(
&self,
stack: &mut VecDeque<Rc<Val>>,
sl: &SelectorList,
next: (&Position, &str),
pos: &Position,
field: &Val,
fs: &Vec<(PositionedItem<String>, Rc<Val>)>,
) -> Result<(), Box<Error>> {
if let Some(vv) = Self::find_in_fieldlist(next.1, fs) {
stack.push_back(vv.clone());
) -> Result<Rc<Val>, Box<Error>> {
let field = if let &Val::Str(ref name) = field {
name
} 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(),
format!("Invalid type {} for field lookup in tuple", field),
error::ErrorType::TypeFail,
pos.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(
&self,
stack: &mut VecDeque<Rc<Val>>,
sl: &SelectorList,
next: (&Position, &str),
pos: &Position,
field: &Rc<Val>,
elems: &Vec<Rc<Val>>,
) -> Result<(), Box<Error>> {
let idx = next.1.parse::<usize>()?;
if idx < elems.len() {
stack.push_back(elems[idx].clone());
} 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
}
}
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;
}
) -> Result<Rc<Val>, Box<Error>> {
let idx = match field.as_ref() {
&Val::Int(i) => i as usize,
&Val::Str(ref s) => s.parse::<usize>()?,
_ => {
return Err(Box::new(error::BuildError::new(
format!("{} is not a Tuple or List", vref),
format!("Invalid idx type {} for list lookup", field),
error::ErrorType::TypeFail,
next.pos.clone(),
)));
}
}
pos.clone(),
)))
}
};
if idx < elems.len() {
Ok(elems[idx].clone())
} 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>> {
let kind = &def.kind;
let left = self.eval_expr(&def.left, scope)?;
let right = self.eval_expr(&def.right, scope)?;
match kind {
// Handle math and concatenation operators here
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
&BinaryExprType::Mul => self.multiply_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::GT => self.do_gt(&def.pos, left, right),
&BinaryExprType::LT => self.do_lt(&def.pos, left, right),
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
&BinaryExprType::LTEqual => self.do_ltequal(&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>> {
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() {
let mut child_scope = scope.spawn_child();
child_scope.set_curr_val(v.clone());
@ -1011,14 +986,14 @@ impl<'a> FileBuilder<'a> {
mod_def.arg_tuple
),
error::ErrorType::TypeFail,
def.selector.pos.clone(),
def.selector.pos().clone(),
)));
}
}
Err(Box::new(error::BuildError::new(
format!("Expected Tuple or Module got {}", v),
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>> {
let sel = &def.macroref;
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() {
// Congratulations this is actually a macro.
let mut argvals: Vec<Rc<Val>> = Vec::new();
@ -1145,13 +1119,13 @@ impl<'a> FileBuilder<'a> {
)));
}
};
let mac = &def.mac;
if let &Val::Macro(ref macdef) = self.lookup_selector(&mac.sel, scope)?.as_ref() {
let mac_sym = Value::Symbol(def.mac.clone());
if let &Val::Macro(ref macdef) = self.eval_value(&mac_sym, &self.scope)?.as_ref() {
let mut out = Vec::new();
for item in l.iter() {
let argvals = vec![item.clone()];
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 {
ListOpType::Map => {
out.push(v.clone());
@ -1172,7 +1146,7 @@ impl<'a> FileBuilder<'a> {
return Ok(Rc::new(Val::List(out)));
}
return Err(Box::new(error::BuildError::new(
format!("Expected macro but got {:?}", mac),
format!("Expected macro but got {:?}", def.mac),
error::ErrorType::TypeFail,
def.pos.clone(),
)));

View File

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

View File

@ -279,7 +279,7 @@ make_fn!(
either!(
// TODO This should move to op_expression instead of a value now.
// We probably still need a bareword parser though?
trace_parse!(selector_value),
trace_parse!(symbol),
trace_parse!(compound_value),
trace_parse!(boolean_value),
trace_parse!(empty_value),
@ -318,107 +318,14 @@ make_fn!(
)
);
fn symbol_or_expression(input: SliceIter<Token>) -> ParseResult<Expression> {
let _i = input.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();
fn tuple_to_copy(sym: Value, fields: Option<FieldList>) -> Expression {
let pos = sym.pos().clone();
let fields = match fields {
Some(fields) => fields,
None => Vec::new(),
};
Expression::Copy(CopyDef {
selector: def,
selector: sym,
fields: fields,
pos: pos,
})
@ -427,14 +334,13 @@ fn tuple_to_copy(def: SelectorDef, fields: Option<FieldList>) -> Expression {
make_fn!(
copy_expression<SliceIter<Token>, Expression>,
do_each!(
pos => pos,
// TODO This should become just a bareword symbol now
selector => trace_parse!(selector_list),
sym => trace_parse!(symbol),
_ => punct!("{"),
fields => optional!(trace_parse!(field_list)),
_ => optional!(punct!(",")), // noms opt! macro does not preserve error types properly but this one does.
_ => 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,
exprs: Option<Vec<Expression>>,
) -> ConvertResult<'a, Expression> {
if let Value::Selector(def) = val {
if let Value::Symbol(_) = val {
Ok(Expression::Call(CallDef {
macroref: def,
macroref: val,
arglist: exprs.unwrap_or_else(|| Vec::new()),
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> {
let parsed = do_each!(input.clone(),
// TODO This should become just a bareword symbol now
callee_name => trace_parse!(selector_value),
callee_name => trace_parse!(symbol),
_ => punct!("("),
args => optional!(separated!(punct!(","), trace_parse!(expression))),
_ => punct!(")"),
@ -664,59 +558,34 @@ fn tuple_to_list_op<'a>(
input: &'a SliceIter<Token>,
kind: ListOpType,
macroname: Value,
outfield: Value,
list: Expression,
) -> ConvertResult<'a, Expression> {
if let Value::Selector(mut def) = macroname {
// First of all we need to assert that this is a selector of at least
// two sections.
let fieldname: String = match &mut def.sel.tail {
&mut None => {
if ENABLE_TRACE {
eprintln!(
"tuple_to_list_op had error {}",
"Missing a result field for the macro"
);
}
let macroname = match macroname {
Value::Symbol(sym) => sym,
_ => {
return Err(Error::new(
format!("Missing a result field for the macro"),
format!("Expected a macro name but got {}", macroname.type_name()),
Box::new(input.clone()),
));
}
&mut Some(ref mut tl) => {
if tl.len() < 1 {
if ENABLE_TRACE {
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"),
format!("Expected a field name but got {}", outfield.type_name()),
Box::new(input.clone()),
));
}
let fname = tl.pop();
fname.unwrap().fragment
))
}
};
return Ok(Expression::ListOp(ListOpDef {
typ: kind,
mac: def,
field: fieldname,
mac: macroname,
field: outfield,
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!(
@ -728,9 +597,11 @@ make_fn!(
do_each!(_ => word!("filter"), (ListOpType::Filter))
),
// 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),
(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;
#[cfg(test)]
mod test;

View File

@ -27,6 +27,13 @@ pub enum Element {
Op(BinaryExprType),
}
make_fn!(
dot_op_type<SliceIter<Token>, Element>,
do_each!(
_ => punct!("."),
(Element::Op(BinaryExprType::DOT)))
);
make_fn!(
math_op_type<SliceIter<Token>, Element>,
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> {
let mut i_ = i.clone();
if eoi(i_.clone()).is_complete() {
@ -182,6 +217,7 @@ make_fn!(
parse_sum_operator,
either!(
trace_parse!(product_expression),
trace_parse!(dot_expression),
trace_parse!(parse_expression)
)
)
@ -189,7 +225,10 @@ make_fn!(
make_fn!(
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!(
@ -247,7 +286,17 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
make_fn!(
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!(
@ -256,6 +305,7 @@ make_fn!(
parse_compare_operator,
either!(
trace_parse!(math_expression),
trace_parse!(dot_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.
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) => {
if firstrun {
// If we don't find an operator in our first

File diff suppressed because it is too large Load Diff