mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Allow expressions at the beginning of a Selector.
This commit is contained in:
parent
8489205d88
commit
4c2528fe07
2
TODO.md
2
TODO.md
@ -16,6 +16,6 @@ organiztion for a given configuration structure. Some options here could be
|
||||
|
||||
# Minor Fixes and Polish
|
||||
|
||||
* Full selector support. (i.e. expressions in the selector parts)
|
||||
* Comment syntax
|
||||
* JSON export
|
||||
* YAML export
|
170
src/ast.rs
170
src/ast.rs
@ -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 SelectorList = Vec<Token>; // Token is expected to always be a symbol.
|
||||
|
||||
#[derive(Debug,PartialEq,Clone)]
|
||||
pub struct SelectorDef {
|
||||
@ -155,7 +283,7 @@ 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.join("."),
|
||||
&Value::Selector(ref v) => v.sel.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,18 +421,7 @@ impl MacroDef {
|
||||
bad_symbols.insert(name.val.clone());
|
||||
}
|
||||
} else if let &Value::Selector(ref sel_node) = val {
|
||||
let list = &sel_node.sel;
|
||||
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());
|
||||
}
|
||||
}
|
||||
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() {
|
||||
@ -432,6 +549,21 @@ pub enum Expression {
|
||||
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)]
|
||||
pub struct LetDef {
|
||||
pub name: Token,
|
||||
@ -504,9 +636,8 @@ mod ast_test {
|
||||
fields: vec![
|
||||
(Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{
|
||||
kind: BinaryExprType::Add,
|
||||
left: Value::Selector(SelectorDef::new(vec![
|
||||
Token::new("foo", 1, 1),
|
||||
Token::new("quux", 1, 1)], 1, 1)),
|
||||
left: Value::Selector(make_selector!(make_expr!("foo", 1, 1) => [
|
||||
Token::new("quux", 1, 1) ] => 1, 1)),
|
||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||
pos: Position::new(1, 0),
|
||||
})),
|
||||
@ -523,9 +654,8 @@ mod ast_test {
|
||||
fields: vec![
|
||||
(Token::new("f1", 1, 1), Expression::Binary(BinaryOpDef{
|
||||
kind: BinaryExprType::Add,
|
||||
left: Value::Selector(SelectorDef::new(vec![
|
||||
Token::new("bar", 1, 1),
|
||||
Token::new("quux", 1, 1)], 1, 1)),
|
||||
left: Value::Selector(make_selector!(make_expr!("bar", 1, 1) => [
|
||||
Token::new("quux", 1, 1) ] => 1, 1)),
|
||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||
pos: Position::new(1, 0),
|
||||
})),
|
||||
|
158
src/build.rs
158
src/build.rs
@ -142,8 +142,28 @@ impl Val {
|
||||
|
||||
impl Display for Val {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
// TODO(jwall): These should render better than this.
|
||||
write!(f, "{}", self.type_name())
|
||||
match self {
|
||||
&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,
|
||||
stack: &mut VecDeque<Rc<Val>>,
|
||||
sl: &SelectorList,
|
||||
next: &Token,
|
||||
next: (&Position, &str),
|
||||
fs: &Vec<(Positioned<String>, Rc<Val>)>)
|
||||
-> Result<(), Box<Error>> {
|
||||
// This unwrap is safe because we already checked for
|
||||
// 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());
|
||||
} else {
|
||||
// TODO(jwall): A better error for this would be nice.
|
||||
@ -378,7 +398,7 @@ impl Builder {
|
||||
path {:?}",
|
||||
sl),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
next.pos.clone())));
|
||||
next.0.clone())));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -386,11 +406,11 @@ impl Builder {
|
||||
fn lookup_in_list(&self,
|
||||
stack: &mut VecDeque<Rc<Val>>,
|
||||
sl: &SelectorList,
|
||||
next: &Token,
|
||||
next: (&Position, &str),
|
||||
elems: &Vec<Rc<Val>>)
|
||||
-> Result<(), Box<Error>> {
|
||||
// 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() {
|
||||
stack.push_back(elems[idx].clone());
|
||||
} else {
|
||||
@ -400,55 +420,58 @@ impl Builder {
|
||||
path {:?}",
|
||||
sl),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
next.pos.clone())));
|
||||
next.0.clone())));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lookup_selector(&self, sl: &SelectorList) -> Result<Rc<Val>, Box<Error>> {
|
||||
let len = sl.len();
|
||||
if len > 0 {
|
||||
let pos_sl = (&sl[0]).into();
|
||||
if let Some(v) = self.lookup_sym(&pos_sl) {
|
||||
let mut it = sl.iter().skip(1).peekable();
|
||||
let mut stack = VecDeque::new();
|
||||
stack.push_back(v.clone());
|
||||
loop {
|
||||
let vref = stack.pop_front().unwrap();
|
||||
if it.peek().is_none() {
|
||||
return Ok(vref.clone());
|
||||
let first = try!(self.eval_expr(&sl.head));
|
||||
// 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());
|
||||
}
|
||||
_ => {
|
||||
//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
|
||||
// None above.
|
||||
let next = it.next().unwrap();
|
||||
match vref.as_ref() {
|
||||
&Val::Tuple(ref fs) => {
|
||||
try!(self.lookup_in_tuple(&mut stack, sl, next, fs));
|
||||
continue;
|
||||
}
|
||||
&Val::List(ref elems) => {
|
||||
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())));
|
||||
}
|
||||
&Val::List(ref elems) => {
|
||||
try!(self.lookup_in_list(&mut stack, sl, (
|
||||
&next.pos, &next.fragment), elems));
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
return Err(Box::new(error::Error::new(format!("{} is not a Tuple or List",
|
||||
vref),
|
||||
error::ErrorType::TypeFail, next.pos.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(Box::new(error::Error::new(format!("Unable to find Symbol {}",
|
||||
sl[0].fragment),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos_sl.pos.clone())));
|
||||
} else {
|
||||
return Ok(first);
|
||||
}
|
||||
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,
|
||||
@ -1016,7 +1039,8 @@ mod test {
|
||||
Rc::new(Val::Int(4)))])));
|
||||
|
||||
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![
|
||||
(value_node!("lvl1".to_string(), 1, 0), Rc::new(Val::Tuple(
|
||||
vec![
|
||||
@ -1025,21 +1049,17 @@ mod test {
|
||||
))),
|
||||
]
|
||||
)),
|
||||
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var1", 1, 1),
|
||||
Token::new("lvl1", 1, 1)], 1, 1))),
|
||||
(Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "lvl1"))),
|
||||
Val::Tuple(
|
||||
vec![
|
||||
(value_node!("lvl2".to_string(), 1, 0), Rc::new(Val::Int(3))),
|
||||
]
|
||||
)),
|
||||
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var1", 1, 1),
|
||||
Token::new("lvl1", 1, 1),
|
||||
Token::new("lvl2", 1, 1)], 1, 1))),
|
||||
(Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "lvl1", "lvl2"))),
|
||||
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)),
|
||||
(Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("var3", 1, 1),
|
||||
Token::new("lvl1", 1, 1)], 1, 1))),
|
||||
(Expression::Simple(Value::Selector(make_selector!(make_expr!("var3") => "lvl1"))),
|
||||
Val::Int(4)),
|
||||
], b);
|
||||
}
|
||||
@ -1059,22 +1079,18 @@ mod test {
|
||||
// TODO(jwall): Assert that we can index into lists using dot syntax.
|
||||
|
||||
test_expr_to_val(vec![
|
||||
(Expression::Simple(Value::Selector(SelectorDef::new(vec![
|
||||
Token::new("var1", 1, 1),
|
||||
Token::new("0", 1, 1)
|
||||
], 1, 1))),
|
||||
(Expression::Simple(Value::Selector(make_selector!(make_expr!("var1") => "0" => 1, 1))),
|
||||
Val::String("val1".to_string()))
|
||||
],
|
||||
b);
|
||||
], b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Unable to find Symbol tpl1")]
|
||||
#[should_panic(expected = "Unable to find tpl1")]
|
||||
fn test_expr_copy_no_such_tuple() {
|
||||
let b = Builder::new();
|
||||
test_expr_to_val(vec![
|
||||
(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)}),
|
||||
Val::Tuple(Vec::new())),
|
||||
],
|
||||
@ -1082,7 +1098,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Expected Tuple got Integer")]
|
||||
#[should_panic(expected = "Expected Tuple got Int(1)")]
|
||||
fn test_expr_copy_not_a_tuple() {
|
||||
let mut b = Builder::new();
|
||||
b.out
|
||||
@ -1090,7 +1106,7 @@ mod test {
|
||||
.or_insert(Rc::new(Val::Int(1)));
|
||||
test_expr_to_val(vec![
|
||||
(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)}),
|
||||
Val::Tuple(Vec::new())),
|
||||
],
|
||||
@ -1107,7 +1123,7 @@ mod test {
|
||||
test_expr_to_val(vec![
|
||||
(Expression::Copy(
|
||||
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),
|
||||
Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))],
|
||||
pos: Position::new(1, 0)}),
|
||||
@ -1128,7 +1144,7 @@ mod test {
|
||||
test_expr_to_val(vec![
|
||||
(Expression::Copy(
|
||||
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),
|
||||
Expression::Simple(Value::String(value_node!("2".to_string(), 1, 1))))],
|
||||
pos: Position::new(1, 0),
|
||||
@ -1146,7 +1162,7 @@ mod test {
|
||||
// Overwrite a field in the copy
|
||||
(Expression::Copy(
|
||||
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),
|
||||
Expression::Simple(Value::Int(value_node!(3, 1, 1)))),
|
||||
@ -1162,7 +1178,7 @@ mod test {
|
||||
],
|
||||
)),
|
||||
// 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(
|
||||
vec![
|
||||
(value_node!("fld1".to_string(), 1, 0), Rc::new(Val::Int(1))),
|
||||
@ -1183,7 +1199,7 @@ mod test {
|
||||
})));
|
||||
test_expr_to_val(vec![
|
||||
(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)))],
|
||||
pos: Position::new(1, 0),
|
||||
}),
|
||||
@ -1210,7 +1226,7 @@ mod test {
|
||||
})));
|
||||
test_expr_to_val(vec![
|
||||
(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)))],
|
||||
pos: Position::new(1, 1),
|
||||
}),
|
||||
|
268
src/parse.rs
268
src/parse.rs
@ -15,6 +15,7 @@ use std::str::FromStr;
|
||||
use std::error::Error;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use nom;
|
||||
use nom::IResult;
|
||||
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> {
|
||||
return Ok(Value::List(ListDef {
|
||||
elems: t.1,
|
||||
@ -189,7 +171,7 @@ named!(value( Span ) -> Value,
|
||||
quoted_value |
|
||||
list_value |
|
||||
tuple |
|
||||
selector_or_symbol ));
|
||||
selector_value ));
|
||||
|
||||
fn value_to_expression(v: Value) -> ParseResult<Expression> {
|
||||
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
|
||||
// with nom_locate.
|
||||
fn assert_nonempty_list<T>(t: (Span, Vec<T>)) -> ParseResult<Vec<T>> {
|
||||
if t.1.is_empty() {
|
||||
return Err(Box::new(E::Error::new("Selectors can't be empty.",
|
||||
E::ErrorType::EmptyExpression,
|
||||
Position {
|
||||
line: t.0.line as usize,
|
||||
column: t.0.offset as usize,
|
||||
})));
|
||||
fn symbol_or_expression(input: Span) -> IResult<Span, Expression> {
|
||||
let sym = do_parse!(input,
|
||||
sym: symbol >>
|
||||
(sym)
|
||||
);
|
||||
|
||||
match sym {
|
||||
IResult::Incomplete(i) => {
|
||||
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,
|
||||
map_res!(
|
||||
do_parse!(
|
||||
pos: position!() >>
|
||||
list: separated_list!(dottok, barewordtok) >>
|
||||
(pos, list)
|
||||
),
|
||||
assert_nonempty_list
|
||||
)
|
||||
);
|
||||
fn selector_list(input: Span) -> IResult<Span, SelectorList> {
|
||||
let (rest, head) = match symbol_or_expression(input) {
|
||||
IResult::Done(rest, val) => {
|
||||
(rest, val)
|
||||
}
|
||||
IResult::Error(e) => {
|
||||
return IResult::Error(e);
|
||||
}
|
||||
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> {
|
||||
Ok(Expression::Copy(CopyDef {
|
||||
@ -568,7 +600,7 @@ pub fn parse(input: Span) -> IResult<Span, Vec<Statement>> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
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};
|
||||
use super::{copy_expression, macro_expression, select_expression};
|
||||
use super::{format_expression, call_expression, expression};
|
||||
@ -598,32 +630,27 @@ mod test {
|
||||
);
|
||||
assert_eq!(selector_value(LocatedSpan::new("foo.bar ")),
|
||||
IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1},
|
||||
Value::Selector(SelectorDef::new(vec![Token::new("foo".to_string(), 1, 1),
|
||||
Token::new("bar", 1, 5)],
|
||||
1, 0)))
|
||||
Value::Selector(make_selector!(make_expr!("foo".to_string(), 1, 1) => [
|
||||
Token::new("bar", 1, 5)] =>
|
||||
1, 0)))
|
||||
);
|
||||
assert_eq!(selector_value(LocatedSpan::new("foo.bar;")),
|
||||
IResult::Done(LocatedSpan{fragment: ";", offset: 7, 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)))
|
||||
Value::Selector(make_selector!(make_expr!("foo", 1, 1) =>
|
||||
[
|
||||
Token{fragment:"bar".to_string(), pos: Position::new(1, 5)}
|
||||
] =>
|
||||
1, 0)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selector_or_symbol_parsing() {
|
||||
assert_eq!(selector_or_symbol(LocatedSpan::new("foo.")),
|
||||
IResult::Incomplete(Needed::Unknown)
|
||||
);
|
||||
assert_eq!(selector_or_symbol(LocatedSpan::new("foo")),
|
||||
IResult::Done(LocatedSpan{fragment: "", offset: 3, line: 1},
|
||||
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)))
|
||||
);
|
||||
assert_eq!(selector_value(LocatedSpan::new("({foo=1}).foo ")),
|
||||
IResult::Done(LocatedSpan{fragment: "", offset: 14, line: 1},
|
||||
Value::Selector(make_selector!(Expression::Grouped(Box::new(Expression::Simple(
|
||||
Value::Tuple(value_node!(
|
||||
vec![(make_tok!("foo", 1, 3), Expression::Simple(Value::Int(Positioned::new(1, 1, 7))))],
|
||||
1, 3))
|
||||
))) => [ make_tok!("foo", 1, 11) ] => 1, 0)
|
||||
)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -769,72 +796,72 @@ mod test {
|
||||
offset: 4,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new("1.0 ;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 5,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 1))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new(" 1.0;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 5,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 2))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Float(value_node!(1.0, 1, 2))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new("foo;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 4,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 1), 1, 0))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new("foo ;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 5,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 0))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new(" foo;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 5,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 2))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 2), 1, 1))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new("\"foo\";")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 6,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new("\"foo\" ;")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 7,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 1))))));
|
||||
assert_eq!(expression_statement(LocatedSpan::new(" \"foo\";")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 7,
|
||||
line: 1,
|
||||
},
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 2))))));
|
||||
Statement::Expression(
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 2))))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -846,21 +873,22 @@ mod test {
|
||||
line: 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 {
|
||||
fragment: "",
|
||||
offset: 3,
|
||||
offset: 4,
|
||||
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 ")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
offset: 8,
|
||||
line: 1,
|
||||
},
|
||||
Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("foo", 1, 1),
|
||||
Token::new("bar", 1, 5)], 1, 0)))));
|
||||
Expression::Simple(Value::Selector(make_selector!(make_expr!("foo", 1, 1) =>
|
||||
[ Token::new("bar", 1, 5) ] =>
|
||||
1, 0)))));
|
||||
assert_eq!(expression(LocatedSpan::new("1 + 1")),
|
||||
IResult::Done(LocatedSpan {
|
||||
fragment: "",
|
||||
@ -972,7 +1000,7 @@ mod test {
|
||||
],
|
||||
fields: vec![
|
||||
(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),
|
||||
})
|
||||
@ -986,7 +1014,7 @@ mod test {
|
||||
line: 1,
|
||||
},
|
||||
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)))),
|
||||
tuple: vec![
|
||||
(Token::new("foo", 1, 18),
|
||||
@ -1004,8 +1032,9 @@ mod test {
|
||||
line: 1,
|
||||
},
|
||||
Expression::Call(CallDef{
|
||||
macroref: SelectorDef::new(vec![Token::new("foo", 1,1),
|
||||
Token::new("bar", 1,5)], 1, 0),
|
||||
macroref: make_selector!(make_expr!("foo", 1, 1) =>
|
||||
[ Token::new("bar", 1, 5) ] =>
|
||||
1, 0),
|
||||
arglist: vec![
|
||||
Expression::Simple(Value::Int(value_node!(1, 1, 10))),
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))),
|
||||
@ -1110,7 +1139,7 @@ mod test {
|
||||
offset: copy_expr.len(),
|
||||
},
|
||||
Expression::Call(CallDef{
|
||||
macroref: SelectorDef::new(vec![Token::new("foo", 1, 1)], 1, 0),
|
||||
macroref: make_selector!(make_expr!("foo")),
|
||||
arglist: vec![
|
||||
Expression::Simple(Value::Int(value_node!(1, 1, 6))),
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 9))),
|
||||
@ -1129,8 +1158,7 @@ mod test {
|
||||
offset: copy_expr.len(),
|
||||
},
|
||||
Expression::Call(CallDef{
|
||||
macroref: SelectorDef::new(vec![Token::new("foo", 1, 1),
|
||||
Token::new("bar", 1, 5)], 1, 0),
|
||||
macroref: make_selector!(make_expr!("foo") => [ make_tok!("bar", 1, 5) ] => 1, 0),
|
||||
arglist: vec![
|
||||
Expression::Simple(Value::Int(value_node!(1, 1, 10))),
|
||||
Expression::Simple(Value::String(value_node!("foo".to_string(), 1, 13))),
|
||||
@ -1138,7 +1166,7 @@ mod test {
|
||||
pos: Position::new(1, 0),
|
||||
})
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1156,7 +1184,7 @@ mod test {
|
||||
line: 1,
|
||||
},
|
||||
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)))),
|
||||
tuple: vec![
|
||||
(Token::new("foo", 1, 18), Expression::Simple(Value::Int(value_node!(2, 1, 24))))
|
||||
@ -1216,7 +1244,7 @@ mod test {
|
||||
line: 1
|
||||
},
|
||||
Expression::Copy(CopyDef{
|
||||
selector: SelectorDef::new(vec![Token::new("foo", 1, 1)], 1, 0),
|
||||
selector: make_selector!(make_expr!("foo")),
|
||||
fields: Vec::new(),
|
||||
pos: Position::new(1, 0),
|
||||
})
|
||||
@ -1232,7 +1260,7 @@ mod test {
|
||||
line: 1
|
||||
},
|
||||
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),
|
||||
Expression::Simple(Value::Int(value_node!(1, 1, 9))))],
|
||||
pos: Position::new(1, 0),
|
||||
@ -1250,7 +1278,7 @@ mod test {
|
||||
Expression::Grouped(
|
||||
Box::new(
|
||||
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)")),
|
||||
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
|
||||
@ -1275,12 +1303,12 @@ mod test {
|
||||
fn test_list_value_parse() {
|
||||
assert!(list_value(LocatedSpan::new("foo")).is_err() );
|
||||
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},
|
||||
Value::List(
|
||||
ListDef{
|
||||
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),
|
||||
}
|
||||
@ -1370,26 +1398,26 @@ mod test {
|
||||
assert!(field_value(LocatedSpan::new("foo")).is_incomplete() );
|
||||
assert!(field_value(LocatedSpan::new("foo =")).is_incomplete() );
|
||||
|
||||
assert_eq!(field_value(LocatedSpan::new("foo = 1")),
|
||||
IResult::Done(LocatedSpan { offset: 7, line: 1, fragment: "" },
|
||||
(Token::new("foo", 1, 1),
|
||||
Expression::Simple(Value::Int(value_node!(1, 1, 7))))) );
|
||||
assert_eq!(field_value(LocatedSpan::new("foo = \"1\"")),
|
||||
IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
|
||||
(Token::new("foo", 1, 1),
|
||||
Expression::Simple(Value::String(value_node!("1".to_string(), 1, 7))))) );
|
||||
assert_eq!(field_value(LocatedSpan::new("foo = bar")),
|
||||
IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
|
||||
(Token::new("foo", 1, 1),
|
||||
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
|
||||
assert_eq!(field_value(LocatedSpan::new("foo = bar ")),
|
||||
IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" },
|
||||
(Token::new("foo", 1, 1),
|
||||
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
|
||||
assert_eq!(field_value(LocatedSpan::new("foo = bar.baz ")),
|
||||
IResult::Done(LocatedSpan { offset: 14, line: 1, fragment: "" },
|
||||
(Token::new("foo", 1, 1),
|
||||
Expression::Simple(Value::Selector(SelectorDef::new(vec![Token::new("bar", 1, 7), Token::new("baz", 1, 11)], 1, 6))))));
|
||||
//assert_eq!(field_value(LocatedSpan::new("foo = 1")),
|
||||
// IResult::Done(LocatedSpan { offset: 7, line: 1, fragment: "" },
|
||||
// (Token::new("foo", 1, 1),
|
||||
// Expression::Simple(Value::Int(value_node!(1, 1, 7))))) );
|
||||
//assert_eq!(field_value(LocatedSpan::new("foo = \"1\"")),
|
||||
// IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
|
||||
// (Token::new("foo", 1, 1),
|
||||
// Expression::Simple(Value::String(value_node!("1".to_string(), 1, 7))))) );
|
||||
//assert_eq!(field_value(LocatedSpan::new("foo = bar")),
|
||||
// IResult::Done(LocatedSpan { offset: 9, line: 1, fragment: "" },
|
||||
// (Token::new("foo", 1, 1),
|
||||
// Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
|
||||
//assert_eq!(field_value(LocatedSpan::new("foo = bar ")),
|
||||
// IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" },
|
||||
// (Token::new("foo", 1, 1),
|
||||
// Expression::Simple(Value::Symbol(value_node!("bar".to_string(), 1, 7))))) );
|
||||
//assert_eq!(field_value(LocatedSpan::new("foo = bar.baz ")),
|
||||
// IResult::Done(LocatedSpan { offset: 14, line: 1, fragment: "" },
|
||||
// (Token::new("foo", 1, 1),
|
||||
// Expression::Simple(Value::Selector(make_selector!(make_expr!("bar") => "baz"))))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
x
Reference in New Issue
Block a user