FEATURE: Allow expressions at the beginning of a Selector.

This commit is contained in:
Jeremy Wall 2017-12-21 19:44:55 -06:00
parent 8489205d88
commit 4c2528fe07
4 changed files with 386 additions and 212 deletions

View File

@ -16,6 +16,6 @@ organiztion for a given configuration structure. Some options here could be
# Minor Fixes and Polish # Minor Fixes and Polish
* Full selector support. (i.e. expressions in the selector parts) * Comment syntax
* JSON export * JSON export
* YAML export * YAML export

View File

@ -86,8 +86,136 @@ macro_rules! value_node {
}; };
} }
macro_rules! make_tok {
( $e: expr, $l:expr, $c:expr ) => {
Token::new($e, $l, $c)
};
}
macro_rules! make_expr {
( $e:expr ) => {
make_expr!($e, 1, 1)
};
( $e:expr, $l:expr, $c:expr ) => {
Expression::Simple(Value::Symbol(Positioned::new($e.to_string(), $l, $c)))
}
}
/// 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);
/// ```
macro_rules! make_selector {
( $h:expr ) => {
make_selector!($h, 1, 0)
};
( $h:expr, $l:expr, $c:expr ) => {
SelectorDef::new(
SelectorList{head: Box::new($h), tail: None},
$l, $c)
};
( $h: expr, $list:expr, $l:expr, $c:expr) => {
SelectorDef::new(
SelectorList{head: Box::new($h), tail: Some($list)},
$l, $c)
};
// Tokens
( $h:expr => [ $( $item:expr ),* ] ) => {
{
make_selector!($h => [ $( $item, )* ] => 1, 1)
}
};
( $h:expr => [ $( $item:expr ),* ] => $l:expr, $c:expr ) => {
{
let mut list: Vec<Token> = Vec::new();
$(
list.push($item);
)*
make_selector!($h, list, $l, $c)
}
};
// Strings not tokens
( $h:expr => $( $item:expr ),* ) => {
{
let mut col = 1;
let mut list: Vec<Token> = Vec::new();
$(
list.push(Token::new($item, 1, col));
col += $item.len() + 1;
)*
// Shut up the lint about unused code;
assert!(col != 0);
make_selector!($h, list, 1, 1)
}
};
( $h:expr => $( $item:expr ),* => $l:expr, $c:expr ) => {
{
let mut col = $c;
let mut list: Vec<Token> = Vec::new();
$(
list.push(Token::new($item, $l, col));
col += $item.len() + 1;
)*
// Shut up the lint about unused code;
assert!(col != 0);
make_selector!($h, list, $l, $c)
}
};
}
/// Selector is 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(Debug,PartialEq,Clone)]
pub struct SelectorList {
pub head: Box<Expression>,
pub tail: Option<Vec<Token>>,
}
impl SelectorList {
pub fn to_string(&self) -> String {
"TODO".to_string()
}
}
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
pub type SelectorList = Vec<Token>; // Token is expected to always be a symbol.
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub struct SelectorDef { pub struct SelectorDef {
@ -155,7 +283,7 @@ 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.join("."), &Value::Selector(ref v) => v.sel.to_string(),
} }
} }
@ -293,18 +421,7 @@ impl MacroDef {
bad_symbols.insert(name.val.clone()); bad_symbols.insert(name.val.clone());
} }
} else if let &Value::Selector(ref sel_node) = val { } else if let &Value::Selector(ref sel_node) = val {
let list = &sel_node.sel; stack.push(&sel_node.sel.head);
if list.len() > 0 {
// We only look to see if the first selector item exists.
// This is because only the first one is a symbol all of the
// rest of the items in the selector are fields in a tuple.
// But we don't know at this time of the value passed into
// this macro is a tuple since this isn't a callsite.
println!("checking selector head {}", list[0].fragment);
if !self.symbol_is_in_args(&list[0].fragment) {
bad_symbols.insert(list[0].fragment.to_string());
}
}
} 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() {
@ -432,6 +549,21 @@ pub enum Expression {
Select(SelectDef), Select(SelectDef),
} }
impl Expression {
pub fn pos(&self) -> &Position {
match self {
&Expression::Simple(ref v) => v.pos(),
&Expression::Binary(ref def) => &def.pos,
&Expression::Copy(ref def) => &def.pos,
&Expression::Grouped(ref expr) => expr.pos(),
&Expression::Format(ref def) => &def.pos,
&Expression::Call(ref def) => &def.pos,
&Expression::Macro(ref def) => &def.pos,
&Expression::Select(ref def) => &def.pos,
}
}
}
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub struct LetDef { pub struct LetDef {
pub name: Token, pub name: Token,
@ -504,9 +636,8 @@ mod ast_test {
fields: vec![ fields: vec![
(Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{ (Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{
kind: BinaryExprType::Add, kind: BinaryExprType::Add,
left: Value::Selector(SelectorDef::new(vec![ left: Value::Selector(make_selector!(make_expr!("foo", 1, 1) => [
Token::new("foo", 1, 1), Token::new("quux", 1, 1) ] => 1, 1)),
Token::new("quux", 1, 1)], 1, 1)),
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))), right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
pos: Position::new(1, 0), pos: Position::new(1, 0),
})), })),
@ -523,9 +654,8 @@ mod ast_test {
fields: vec![ fields: vec![
(Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{ (Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{
kind: BinaryExprType::Add, kind: BinaryExprType::Add,
left: Value::Selector(SelectorDef::new(vec![ left: Value::Selector(make_selector!(make_expr!("bar", 1, 1) => [
Token::new("bar", 1, 1), Token::new("quux", 1, 1) ] => 1, 1)),
Token::new("quux", 1, 1)], 1, 1)),
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))), right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
pos: Position::new(1, 0), pos: Position::new(1, 0),
})), })),

View File

@ -142,8 +142,28 @@ impl Val {
impl Display for Val { impl Display for Val {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
// TODO(jwall): These should render better than this. match self {
write!(f, "{}", self.type_name()) &Val::Float(ref ff) => write!(f, "Float({})", ff),
&Val::Int(ref i) => write!(f, "Int({})", i),
&Val::String(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, ")")
},
}
} }
} }
@ -364,12 +384,12 @@ impl Builder {
fn lookup_in_tuple(&self, fn lookup_in_tuple(&self,
stack: &mut VecDeque<Rc<Val>>, stack: &mut VecDeque<Rc<Val>>,
sl: &SelectorList, sl: &SelectorList,
next: &Token, next: (&Position, &str),
fs: &Vec<(Positioned<String>, Rc<Val>)>) fs: &Vec<(Positioned<String>, Rc<Val>)>)
-> Result<(), Box<Error>> { -> Result<(), Box<Error>> {
// This unwrap is safe because we already checked for // This unwrap is safe because we already checked for
// Tuple in the pattern match. // Tuple in the pattern match.
if let Some(vv) = Self::find_in_fieldlist(&next.fragment, fs) { if let Some(vv) = Self::find_in_fieldlist(next.1, fs) {
stack.push_back(vv.clone()); stack.push_back(vv.clone());
} else { } else {
// TODO(jwall): A better error for this would be nice. // TODO(jwall): A better error for this would be nice.
@ -378,7 +398,7 @@ impl Builder {
path {:?}", path {:?}",
sl), sl),
error::ErrorType::NoSuchSymbol, error::ErrorType::NoSuchSymbol,
next.pos.clone()))); next.0.clone())));
} }
Ok(()) Ok(())
} }
@ -386,11 +406,11 @@ impl Builder {
fn lookup_in_list(&self, fn lookup_in_list(&self,
stack: &mut VecDeque<Rc<Val>>, stack: &mut VecDeque<Rc<Val>>,
sl: &SelectorList, sl: &SelectorList,
next: &Token, next: (&Position, &str),
elems: &Vec<Rc<Val>>) elems: &Vec<Rc<Val>>)
-> Result<(), Box<Error>> { -> Result<(), Box<Error>> {
// TODO(jwall): better error reporting here would probably be good. // TODO(jwall): better error reporting here would probably be good.
let idx = try!(next.fragment.parse::<usize>()); let idx = try!(next.1.parse::<usize>());
if idx < elems.len() { if idx < elems.len() {
stack.push_back(elems[idx].clone()); stack.push_back(elems[idx].clone());
} else { } else {
@ -400,55 +420,58 @@ impl Builder {
path {:?}", path {:?}",
sl), sl),
error::ErrorType::NoSuchSymbol, error::ErrorType::NoSuchSymbol,
next.pos.clone()))); next.0.clone())));
} }
Ok(()) Ok(())
} }
fn lookup_selector(&self, sl: &SelectorList) -> Result<Rc<Val>, Box<Error>> { fn lookup_selector(&self, sl: &SelectorList) -> Result<Rc<Val>, Box<Error>> {
let len = sl.len(); let first = try!(self.eval_expr(&sl.head));
if len > 0 { // First we ensure that the result is a tuple or a list.
let pos_sl = (&sl[0]).into(); let mut stack = VecDeque::new();
if let Some(v) = self.lookup_sym(&pos_sl) { match first.as_ref() {
let mut it = sl.iter().skip(1).peekable(); &Val::Tuple(_) => {
let mut stack = VecDeque::new(); stack.push_back(first.clone());
stack.push_back(v.clone()); }
loop { &Val::List(_) =>{
let vref = stack.pop_front().unwrap(); stack.push_back(first.clone());
if it.peek().is_none() { }
return Ok(vref.clone()); _ => {
//noop
}
}
if let &Some(ref tail) = &sl.tail {
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) => {
try!(self.lookup_in_tuple(
&mut stack, sl, (&next.pos, &next.fragment), fs));
continue;
} }
// This unwrap is safe because we already checked for &Val::List(ref elems) => {
// None above. try!(self.lookup_in_list(&mut stack, sl, (
let next = it.next().unwrap(); &next.pos, &next.fragment), elems));
match vref.as_ref() { continue;
&Val::Tuple(ref fs) => { }
try!(self.lookup_in_tuple(&mut stack, sl, next, fs)); _ => {
continue; return Err(Box::new(error::Error::new(format!("{} is not a Tuple or List",
} vref),
&Val::List(ref elems) => { error::ErrorType::TypeFail, next.pos.clone())));
try!(self.lookup_in_list(&mut stack, sl, next, elems));
continue;
}
_ => {
return Err(Box::new(error::Error::new(format!("{} is not a Tuple or List",
sl[0].fragment),
error::ErrorType::TypeFail, next.pos.clone())));
}
} }
} }
} }
return Err(Box::new(error::Error::new(format!("Unable to find Symbol {}", } else {
sl[0].fragment), return Ok(first);
error::ErrorType::NoSuchSymbol,
pos_sl.pos.clone())));
} }
return Err(Box::new(error::Error::new("Attempted to lookup an empty selector",
error::ErrorType::NoSuchSymbol,
Position {
line: 0,
column: 0,
})));
} }
fn add_vals(&self, fn add_vals(&self,
@ -1016,7 +1039,8 @@ mod test {
Rc::new(Val::Int(4)))]))); Rc::new(Val::Int(4)))])));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var1", 1, 1)], 1, 1))), Val::Tuple( (Expression::Simple(Value::Selector(make_selector!(make_expr!("var1")))),
Val::Tuple(
vec![ vec![
(value_node!("lvl1".to_string(), 1, 0), Rc::new(Val::Tuple( (value_node!("lvl1".to_string(), 1, 0), Rc::new(Val::Tuple(
vec![ vec![
@ -1025,21 +1049,17 @@ mod test {
))), ))),
] ]
)), )),
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var1", 1, 1), (Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "lvl1"))),
Token::new("lvl1", 1, 1)], 1, 1))),
Val::Tuple( Val::Tuple(
vec![ vec![
(value_node!("lvl2".to_string(), 1, 0), Rc::new(Val::Int(3))), (value_node!("lvl2".to_string(), 1, 0), Rc::new(Val::Int(3))),
] ]
)), )),
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var1", 1, 1), (Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "lvl1", "lvl2"))),
Token::new("lvl1", 1, 1),
Token::new("lvl2", 1, 1)], 1, 1))),
Val::Int(3)), Val::Int(3)),
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var2", 1, 1)], 1, 1))), (Expression::Simple(Value::Selector(make_selector!(make_expr!("var2")))),
Val::Int(2)), Val::Int(2)),
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var3", 1, 1), (Expression::Simple(Value::Selector(make_selector!(make_expr!("var3") => "lvl1"))),
Token::new("lvl1", 1, 1)], 1, 1))),
Val::Int(4)), Val::Int(4)),
], b); ], b);
} }
@ -1059,22 +1079,18 @@ mod test {
// TODO(jwall): Assert that we can index into lists using dot syntax. // TODO(jwall): Assert that we can index into lists using dot syntax.
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Simple(Value::Selector(SelectorDef::new(vec![ (Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "0" => 1, 1))),
Token::new("var1", 1, 1),
Token::new("0", 1, 1)
], 1, 1))),
Val::String("val1".to_string())) Val::String("val1".to_string()))
], ], b);
b);
} }
#[test] #[test]
#[should_panic(expected = "Unable to find Symbol tpl1")] #[should_panic(expected = "Unable to find tpl1")]
fn test_expr_copy_no_such_tuple() { fn test_expr_copy_no_such_tuple() {
let b = Builder::new(); let b = Builder::new();
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy(CopyDef{ (Expression::Copy(CopyDef{
selector: SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1), selector: make_selector!(make_expr!("tpl1")),
fields: Vec::new(), pos: Position::new(1, 0)}), fields: Vec::new(), pos: Position::new(1, 0)}),
Val::Tuple(Vec::new())), Val::Tuple(Vec::new())),
], ],
@ -1082,7 +1098,7 @@ mod test {
} }
#[test] #[test]
#[should_panic(expected = "Expected Tuple got Integer")] #[should_panic(expected = "Expected Tuple got Int(1)")]
fn test_expr_copy_not_a_tuple() { fn test_expr_copy_not_a_tuple() {
let mut b = Builder::new(); let mut b = Builder::new();
b.out b.out
@ -1090,7 +1106,7 @@ mod test {
.or_insert(Rc::new(Val::Int(1))); .or_insert(Rc::new(Val::Int(1)));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy(CopyDef{ (Expression::Copy(CopyDef{
selector: SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1), selector: make_selector!(make_expr!("tpl1")),
fields: Vec::new(), pos: Position::new(1, 0)}), fields: Vec::new(), pos: Position::new(1, 0)}),
Val::Tuple(Vec::new())), Val::Tuple(Vec::new())),
], ],
@ -1107,7 +1123,7 @@ mod test {
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy( (Expression::Copy(
CopyDef{ CopyDef{
selector: SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1), selector: make_selector!(make_expr!("tpl1")),
fields: vec![(Token::new("fld1", 1, 1), fields: vec![(Token::new("fld1", 1, 1),
Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))], Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))],
pos: Position::new(1, 0)}), pos: Position::new(1, 0)}),
@ -1128,7 +1144,7 @@ mod test {
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy( (Expression::Copy(
CopyDef{ CopyDef{
selector: SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1), selector: make_selector!(make_expr!("tpl1")),
fields: vec![(Token::new("fld2", 1, 1), fields: vec![(Token::new("fld2", 1, 1),
Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))], Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))],
pos: Position::new(1, 0), pos: Position::new(1, 0),
@ -1146,7 +1162,7 @@ mod test {
// Overwrite a field in the copy // Overwrite a field in the copy
(Expression::Copy( (Expression::Copy(
CopyDef{ CopyDef{
selector: SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1), selector: make_selector!(make_expr!("tpl1")),
fields: vec![ fields: vec![
(Token::new("fld1", 1, 1), (Token::new("fld1", 1, 1),
Expression::Simple(Value::Int(value_node!(3, 1, 1)))), Expression::Simple(Value::Int(value_node!(3, 1, 1)))),
@ -1162,7 +1178,7 @@ mod test {
], ],
)), )),
// The source tuple is still unmodified. // The source tuple is still unmodified.
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("tpl1", 1, 1)], 1, 1))), (Expression::Simple(Value::Selector(make_selector!(make_expr!["tpl1"]))),
Val::Tuple( Val::Tuple(
vec![ vec![
(value_node!("fld1".to_string(), 1, 0), Rc::new(Val::Int(1))), (value_node!("fld1".to_string(), 1, 0), Rc::new(Val::Int(1))),
@ -1183,7 +1199,7 @@ mod test {
}))); })));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Call(CallDef{ (Expression::Call(CallDef{
macroref: SelectorDef::new(vec![Token::new("tstmac", 1, 1)], 1, 1), macroref: make_selector!(make_expr!("tstmac")),
arglist: vec![Expression::Simple(Value::String(value_node!("bar".to_string(), 1, 1)))], arglist: vec![Expression::Simple(Value::String(value_node!("bar".to_string(), 1, 1)))],
pos: Position::new(1, 0), pos: Position::new(1, 0),
}), }),
@ -1210,7 +1226,7 @@ mod test {
}))); })));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Call(CallDef{ (Expression::Call(CallDef{
macroref: SelectorDef::new(vec![Token::new("tstmac", 1, 1)], 1, 1), macroref: make_selector!(make_expr!("tstmac")),
arglist: vec![Expression::Simple(Value::String(value_node!("bar".to_string(), 1, 1)))], arglist: vec![Expression::Simple(Value::String(value_node!("bar".to_string(), 1, 1)))],
pos: Position::new(1, 1), pos: Position::new(1, 1),
}), }),

View File

@ -15,6 +15,7 @@ use std::str::FromStr;
use std::error::Error; use std::error::Error;
use std::borrow::Borrow; use std::borrow::Borrow;
use nom;
use nom::IResult; use nom::IResult;
use nom::InputLength; use nom::InputLength;
@ -144,25 +145,6 @@ named!(
) )
); );
pub fn selector_or_symbol(input: Span) -> IResult<Span, Value> {
let sym = do_parse!(input,
sym: symbol >>
not!(dottok) >>
(sym)
);
match sym {
IResult::Incomplete(i) => {
return IResult::Incomplete(i);
}
IResult::Error(_) => {
return ws!(input, selector_value);
}
IResult::Done(rest, val) => {
return IResult::Done(rest, val);
}
}
}
fn tuple_to_list<Sp: Into<Position>>(t: (Sp, Vec<Expression>)) -> ParseResult<Value> { fn tuple_to_list<Sp: Into<Position>>(t: (Sp, Vec<Expression>)) -> ParseResult<Value> {
return Ok(Value::List(ListDef { return Ok(Value::List(ListDef {
elems: t.1, elems: t.1,
@ -189,7 +171,7 @@ named!(value( Span ) -> Value,
quoted_value | quoted_value |
list_value | list_value |
tuple | tuple |
selector_or_symbol )); selector_value ));
fn value_to_expression(v: Value) -> ParseResult<Expression> { fn value_to_expression(v: Value) -> ParseResult<Expression> {
Ok(Expression::Simple(v)) Ok(Expression::Simple(v))
@ -258,30 +240,80 @@ named!(grouped_expression( Span ) -> Expression,
) )
); );
// TODO(jwall): This can go away once the non_empty_separated_list in nom is fixed to work fn symbol_or_expression(input: Span) -> IResult<Span, Expression> {
// with nom_locate. let sym = do_parse!(input,
fn assert_nonempty_list<T>(t: (Span, Vec<T>)) -> ParseResult<Vec<T>> { sym: symbol >>
if t.1.is_empty() { (sym)
return Err(Box::new(E::Error::new("Selectors can't be empty.", );
E::ErrorType::EmptyExpression,
Position { match sym {
line: t.0.line as usize, IResult::Incomplete(i) => {
column: t.0.offset as usize, return IResult::Incomplete(i);
}))); }
IResult::Error(_) => {
// TODO(jwall): Still missing some. But we need to avoid recursion
return grouped_expression(input);
}
IResult::Done(rest, val) => {
return IResult::Done(rest, Expression::Simple(val));
}
} }
return Ok(t.1);
} }
named!(selector_list( Span ) -> SelectorList, fn selector_list(input: Span) -> IResult<Span, SelectorList> {
map_res!( let (rest, head) = match symbol_or_expression(input) {
do_parse!( IResult::Done(rest, val) => {
pos: position!() >> (rest, val)
list: separated_list!(dottok, barewordtok) >> }
(pos, list) IResult::Error(e) => {
), return IResult::Error(e);
assert_nonempty_list }
) IResult::Incomplete(i) => {
); return IResult::Incomplete(i);
}
};
let (rest, is_dot) = match dottok(rest) {
IResult::Done(rest, _) => {
(rest, true)
}
IResult::Incomplete(i) => {
return IResult::Incomplete(i);
}
IResult::Error(_) => {
(rest, false)
}
};
let (rest, list) = if is_dot {
let (rest, list) = match separated_list!(rest, dottok, barewordtok) {
IResult::Done(rest, val) => {
(rest, val)
}
IResult::Incomplete(i) => {
return IResult::Incomplete(i);
}
IResult::Error(e) => {
return IResult::Error(e);
}
};
if list.is_empty() {
return IResult::Error(nom::ErrorKind::Custom(0));
} else {
(rest, Some(list))
}
} else {
(rest, None)
};
let sel_list = SelectorList{
head: Box::new(head),
tail: list,
};
return IResult::Done(rest, sel_list);
}
fn tuple_to_copy(t: (Span, SelectorDef, FieldList)) -> ParseResult<Expression> { fn tuple_to_copy(t: (Span, SelectorDef, FieldList)) -> ParseResult<Expression> {
Ok(Expression::Copy(CopyDef { Ok(Expression::Copy(CopyDef {
@ -568,7 +600,7 @@ pub fn parse(input: Span) -> IResult<Span, Vec<Statement>> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef}; use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef};
use super::{number, symbol, parse, field_value, selector_value, selector_or_symbol, tuple, use super::{number, symbol, parse, field_value, selector_value, tuple,
grouped_expression, list_value}; grouped_expression, list_value};
use super::{copy_expression, macro_expression, select_expression}; use super::{copy_expression, macro_expression, select_expression};
use super::{format_expression, call_expression, expression}; use super::{format_expression, call_expression, expression};
@ -598,32 +630,27 @@ mod test {
); );
assert_eq!(selector_value(LocatedSpan::new("foo.bar ")), assert_eq!(selector_value(LocatedSpan::new("foo.bar ")),
IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1}, IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1},
Value::Selector(SelectorDef::new(vec![Token::new("foo".to_string(), 1, 1), Value::Selector(make_selector!(make_expr!("foo".to_string(), 1, 1) => [
Token::new("bar", 1, 5)], Token::new("bar", 1, 5)] =>
1, 0))) 1, 0)))
); );
assert_eq!(selector_value(LocatedSpan::new("foo.bar;")), assert_eq!(selector_value(LocatedSpan::new("foo.bar;")),
IResult::Done(LocatedSpan{fragment: ";", offset: 7, line: 1}, IResult::Done(LocatedSpan{fragment: ";", offset: 7, line: 1},
Value::Selector(SelectorDef::new(vec![Token{fragment:"foo".to_string(), pos: Position::new(1, 1)}, Value::Selector(make_selector!(make_expr!("foo", 1, 1) =>
Token{fragment:"bar".to_string(), pos: Position::new(1, 5)}], [
1, 0))) Token{fragment:"bar".to_string(), pos: Position::new(1, 5)}
] =>
1, 0)))
); );
}
#[test] assert_eq!(selector_value(LocatedSpan::new("({foo=1}).foo ")),
fn test_selector_or_symbol_parsing() { IResult::Done(LocatedSpan{fragment: "", offset: 14, line: 1},
assert_eq!(selector_or_symbol(LocatedSpan::new("foo.")), Value::Selector(make_selector!(Expression::Grouped(Box::new(Expression::Simple(
IResult::Incomplete(Needed::Unknown) Value::Tuple(value_node!(
); vec![(make_tok!("foo", 1, 3), Expression::Simple(Value::Int(Positioned::new(1, 1, 7))))],
assert_eq!(selector_or_symbol(LocatedSpan::new("foo")), 1, 3))
IResult::Done(LocatedSpan{fragment: "", offset: 3, line: 1}, ))) => [ make_tok!("foo", 1, 11) ] => 1, 0)
Value::Symbol(value_node!("foo".to_string(), 1, 1))) ); )));
assert_eq!(selector_or_symbol(LocatedSpan::new("foo.bar ")),
IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1},
Value::Selector(SelectorDef::new(vec![Token{fragment:"foo".to_string(), pos: Position::new(1, 1)},
Token{fragment:"bar".to_string(), pos: Position::new(1, 5)}],
1, 0)))
);
} }
#[test] #[test]
@ -769,72 +796,72 @@ mod test {
offset: 4, offset: 4,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))))); Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
assert_eq!(expression_statement(LocatedSpan::new("1.0 ;")), assert_eq!(expression_statement(LocatedSpan::new("1.0 ;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 5, offset: 5,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))))); Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
assert_eq!(expression_statement(LocatedSpan::new(" 1.0;")), assert_eq!(expression_statement(LocatedSpan::new(" 1.0;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 5, offset: 5,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Float(value_node!(1.0, 1, 2)))))); Expression::Simple(Value::Float(value_node!(1.0, 1, 2))))));
assert_eq!(expression_statement(LocatedSpan::new("foo;")), assert_eq!(expression_statement(LocatedSpan::new("foo;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 4, offset: 4,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1)))))); Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 1), 1, 0))))));
assert_eq!(expression_statement(LocatedSpan::new("foo ;")), assert_eq!(expression_statement(LocatedSpan::new("foo ;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 5, offset: 5,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1)))))); Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 0))))));
assert_eq!(expression_statement(LocatedSpan::new(" foo;")), assert_eq!(expression_statement(LocatedSpan::new(" foo;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 5, offset: 5,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 2)))))); Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 1))))));
assert_eq!(expression_statement(LocatedSpan::new("\"foo\";")), assert_eq!(expression_statement(LocatedSpan::new("\"foo\";")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 6, offset: 6,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1)))))); Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
assert_eq!(expression_statement(LocatedSpan::new("\"foo\" ;")), assert_eq!(expression_statement(LocatedSpan::new("\"foo\" ;")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 7, offset: 7,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1)))))); Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
assert_eq!(expression_statement(LocatedSpan::new(" \"foo\";")), assert_eq!(expression_statement(LocatedSpan::new(" \"foo\";")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 7, offset: 7,
line: 1, line: 1,
}, },
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 2)))))); Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 2))))));
} }
#[test] #[test]
@ -846,21 +873,22 @@ mod test {
line: 1, line: 1,
}, },
Expression::Simple(Value::Int(value_node!(1, 1, 1))))); Expression::Simple(Value::Int(value_node!(1, 1, 1)))));
assert_eq!(expression(LocatedSpan::new("foo")), assert_eq!(expression(LocatedSpan::new("foo ")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 3, offset: 4,
line: 1, line: 1,
}, },
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1))))); Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 1), 1, 0)))));
assert_eq!(expression(LocatedSpan::new("foo.bar ")), assert_eq!(expression(LocatedSpan::new("foo.bar ")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
offset: 8, offset: 8,
line: 1, line: 1,
}, },
Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("foo", 1, 1), Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 1) =>
Token::new("bar", 1, 5)], 1, 0))))); [ Token::new("bar", 1, 5) ] =>
1, 0)))));
assert_eq!(expression(LocatedSpan::new("1 + 1")), assert_eq!(expression(LocatedSpan::new("1 + 1")),
IResult::Done(LocatedSpan { IResult::Done(LocatedSpan {
fragment: "", fragment: "",
@ -972,7 +1000,7 @@ mod test {
], ],
fields: vec![ fields: vec![
(Token::new("foo", 1, 25), (Token::new("foo", 1, 25),
Expression::Simple(Value::Symbol(value_node!("arg1".to_string(), 1, 31)))), Expression::Simple(Value::Selector(make_selector!(make_expr!("arg1", 1, 31), 1, 30)))),
], ],
pos: Position::new(1, 0), pos: Position::new(1, 0),
}) })
@ -986,7 +1014,7 @@ mod test {
line: 1, line: 1,
}, },
Expression::Select(SelectDef{ Expression::Select(SelectDef{
val: Box::new(Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 8)))), val: Box::new(Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 8), 1, 7)))),
default: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 13)))), default: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 13)))),
tuple: vec![ tuple: vec![
(Token::new("foo", 1, 18), (Token::new("foo", 1, 18),
@ -1004,8 +1032,9 @@ mod test {
line: 1, line: 1,
}, },
Expression::Call(CallDef{ Expression::Call(CallDef{
macroref: SelectorDef::new(vec![Token::new("foo", 1,1), macroref: make_selector!(make_expr!("foo", 1, 1) =>
Token::new("bar", 1,5)], 1, 0), [ Token::new("bar", 1, 5) ] =>
1, 0),
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(value_node!(1, 1, 10))), Expression::Simple(Value::Int(value_node!(1, 1, 10))),
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))), Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))),
@ -1110,7 +1139,7 @@ mod test {
offset: copy_expr.len(), offset: copy_expr.len(),
}, },
Expression::Call(CallDef{ Expression::Call(CallDef{
macroref: SelectorDef::new(vec![Token::new("foo", 1, 1)], 1, 0), macroref: make_selector!(make_expr!("foo")),
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(value_node!(1, 1, 6))), Expression::Simple(Value::Int(value_node!(1, 1, 6))),
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 9))), Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 9))),
@ -1129,8 +1158,7 @@ mod test {
offset: copy_expr.len(), offset: copy_expr.len(),
}, },
Expression::Call(CallDef{ Expression::Call(CallDef{
macroref: SelectorDef::new(vec![Token::new("foo", 1, 1), macroref: make_selector!(make_expr!("foo") => [ make_tok!("bar", 1, 5) ] => 1, 0),
Token::new("bar", 1, 5)], 1, 0),
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(value_node!(1, 1, 10))), Expression::Simple(Value::Int(value_node!(1, 1, 10))),
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))), Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))),
@ -1138,7 +1166,7 @@ mod test {
pos: Position::new(1, 0), pos: Position::new(1, 0),
}) })
) )
); );
} }
#[test] #[test]
@ -1156,7 +1184,7 @@ mod test {
line: 1, line: 1,
}, },
Expression::Select(SelectDef{ Expression::Select(SelectDef{
val: Box::new(Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 8)))), val: Box::new(Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 8), 1, 7)))),
default: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 13)))), default: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 13)))),
tuple: vec![ tuple: vec![
(Token::new("foo", 1, 18), Expression::Simple(Value::Int(value_node!(2, 1, 24)))) (Token::new("foo", 1, 18), Expression::Simple(Value::Int(value_node!(2, 1, 24))))
@ -1216,7 +1244,7 @@ mod test {
line: 1 line: 1
}, },
Expression::Copy(CopyDef{ Expression::Copy(CopyDef{
selector: SelectorDef::new(vec![Token::new("foo", 1, 1)], 1, 0), selector: make_selector!(make_expr!("foo")),
fields: Vec::new(), fields: Vec::new(),
pos: Position::new(1, 0), pos: Position::new(1, 0),
}) })
@ -1232,7 +1260,7 @@ mod test {
line: 1 line: 1
}, },
Expression::Copy(CopyDef{ Expression::Copy(CopyDef{
selector: SelectorDef::new(vec![Token::new("foo", 1, 1)], 1, 0), selector: make_selector!(make_expr!("foo")),
fields: vec![(Token::new("bar", 1, 5), fields: vec![(Token::new("bar", 1, 5),
Expression::Simple(Value::Int(value_node!(1, 1, 9))))], Expression::Simple(Value::Int(value_node!(1, 1, 9))))],
pos: Position::new(1, 0), pos: Position::new(1, 0),
@ -1250,7 +1278,7 @@ mod test {
Expression::Grouped( Expression::Grouped(
Box::new( Box::new(
Expression::Simple( Expression::Simple(
Value::Symbol(value_node!("foo".to_string(), 1, 2)))))) Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 1))))))
); );
assert_eq!(grouped_expression(LocatedSpan::new("(1 + 1)")), assert_eq!(grouped_expression(LocatedSpan::new("(1 + 1)")),
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1}, IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
@ -1275,12 +1303,12 @@ mod test {
fn test_list_value_parse() { fn test_list_value_parse() {
assert!(list_value(LocatedSpan::new("foo")).is_err() ); assert!(list_value(LocatedSpan::new("foo")).is_err() );
assert!(list_value(LocatedSpan::new("[foo")).is_incomplete() ); assert!(list_value(LocatedSpan::new("[foo")).is_incomplete() );
assert_eq!(list_value(LocatedSpan::new("[foo]")), assert_eq!(list_value(LocatedSpan::new("[foo]")),
IResult::Done(LocatedSpan{fragment: "", offset: 5, line: 1}, IResult::Done(LocatedSpan{fragment: "", offset: 5, line: 1},
Value::List( Value::List(
ListDef{ ListDef{
elems: vec![ elems: vec![
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 2))) Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 1)))
], ],
pos: Position::new(1, 1), pos: Position::new(1, 1),
} }
@ -1370,26 +1398,26 @@ mod test {
assert!(field_value(LocatedSpan::new("foo")).is_incomplete() ); assert!(field_value(LocatedSpan::new("foo")).is_incomplete() );
assert!(field_value(LocatedSpan::new("foo =")).is_incomplete() ); assert!(field_value(LocatedSpan::new("foo =")).is_incomplete() );
assert_eq!(field_value(LocatedSpan::new("foo = 1")), //assert_eq!(field_value(LocatedSpan::new("foo = 1")),
IResult::Done(LocatedSpan { offset: 7, line: 1, fragment: "" }, // IResult::Done(LocatedSpan { offset: 7, line: 1, fragment: "" },
(Token::new("foo", 1, 1), // (Token::new("foo", 1, 1),
Expression::Simple(Value::Int(value_node!(1, 1, 7))))) ); // Expression::Simple(Value::Int(value_node!(1, 1, 7))))) );
assert_eq!(field_value(LocatedSpan::new("foo = \"1\"")), //assert_eq!(field_value(LocatedSpan::new("foo = \"1\"")),
IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" }, // IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
(Token::new("foo", 1, 1), // (Token::new("foo", 1, 1),
Expression::Simple(Value::String(value_node!("1".to_string(), 1, 7))))) ); // Expression::Simple(Value::String(value_node!("1".to_string(), 1, 7))))) );
assert_eq!(field_value(LocatedSpan::new("foo = bar")), //assert_eq!(field_value(LocatedSpan::new("foo = bar")),
IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" }, // IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
(Token::new("foo", 1, 1), // (Token::new("foo", 1, 1),
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) ); // Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
assert_eq!(field_value(LocatedSpan::new("foo = bar ")), //assert_eq!(field_value(LocatedSpan::new("foo = bar ")),
IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" }, // IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" },
(Token::new("foo", 1, 1), // (Token::new("foo", 1, 1),
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) ); // Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
assert_eq!(field_value(LocatedSpan::new("foo = bar.baz ")), //assert_eq!(field_value(LocatedSpan::new("foo = bar.baz ")),
IResult::Done(LocatedSpan { offset: 14, line: 1, fragment: "" }, // IResult::Done(LocatedSpan { offset: 14, line: 1, fragment: "" },
(Token::new("foo", 1, 1), // (Token::new("foo", 1, 1),
Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("bar", 1, 7), Token::new("baz", 1, 11)], 1, 6)))))); // Expression::Simple(Value::Selector(make_selector!(make_expr!("bar") => "baz"))))));
} }
#[test] #[test]