mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
List support for dotted selectors
This commit is contained in:
parent
15ef33095d
commit
3108672bd2
135
src/build.rs
135
src/build.rs
@ -205,6 +205,13 @@ impl Val {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_list(&self) -> bool {
|
||||||
|
if let &Val::Tuple(_) = self {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Val {
|
impl Display for Val {
|
||||||
@ -410,58 +417,53 @@ impl Builder {
|
|||||||
let pos_sl = (&sl[0]).into();
|
let pos_sl = (&sl[0]).into();
|
||||||
if let Some(v) = self.lookup_sym(&pos_sl) {
|
if let Some(v) = self.lookup_sym(&pos_sl) {
|
||||||
let mut it = sl.iter().skip(1).peekable();
|
let mut it = sl.iter().skip(1).peekable();
|
||||||
if it.peek().is_none() {
|
let mut stack = VecDeque::new();
|
||||||
return Ok(v.clone());
|
stack.push_back(v.clone());
|
||||||
}
|
loop {
|
||||||
if let &Val::Tuple(_) = v.as_ref() {
|
let vref = stack.pop_front().unwrap();
|
||||||
let mut stack = VecDeque::new();
|
if it.peek().is_none() {
|
||||||
stack.push_back(v.clone());
|
return Ok(vref.clone());
|
||||||
loop {
|
}
|
||||||
let vref = stack.pop_front().unwrap();
|
// This unwrap is safe because we already checked for
|
||||||
if it.peek().is_none() {
|
// None above.
|
||||||
return Ok(vref.clone());
|
let next = it.next().unwrap();
|
||||||
|
match vref.as_ref() {
|
||||||
|
&Val::Tuple(_) => {
|
||||||
|
// This unwrap is safe because we already checked for
|
||||||
|
// Tuple in the pattern match.
|
||||||
|
let fs = vref.get_fields().unwrap();
|
||||||
|
if let Some(vv) = Self::find_in_fieldlist(&next.fragment, fs) {
|
||||||
|
stack.push_back(vv.clone());
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// TODO(jwall): A better error for this would be nice.
|
||||||
|
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to \
|
||||||
|
match selector \
|
||||||
|
path {:?}",
|
||||||
|
sl))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// This unwrap is safe because we already checked for
|
&Val::List(ref elems) => {
|
||||||
// None above.
|
// FIXME(jwall): better error reporting here would probably be good.
|
||||||
let k = it.next().unwrap();
|
let idx = try!(next.fragment.parse::<usize>());
|
||||||
if !vref.is_tuple() {
|
if idx < elems.len() {
|
||||||
// TODO(jeremy) BuildErrors should take a token so they can
|
stack.push_back(elems[idx].clone());
|
||||||
// render the location of the error.
|
|
||||||
return Err(Box::new(BuildError::NoSuchSymbol(format!("Attempted \
|
|
||||||
to dereference \
|
|
||||||
non-tuple \
|
|
||||||
{:?} at field \
|
|
||||||
{}.",
|
|
||||||
sl,
|
|
||||||
k.fragment))));
|
|
||||||
}
|
|
||||||
// This unwrap is safe because we already checked for
|
|
||||||
// Tuple above.
|
|
||||||
let fs = vref.get_fields().unwrap();
|
|
||||||
if let Some(vv) = Self::find_in_fieldlist(&k.fragment, fs) {
|
|
||||||
if vv.is_tuple() {
|
|
||||||
stack.push_back(vv.clone());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
if it.peek().is_some() {
|
// TODO(jwall): A better error for this would be nice.
|
||||||
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to \
|
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to \
|
||||||
match selector \
|
match selector \
|
||||||
path {:?}",
|
path {:?}",
|
||||||
sl))));
|
sl))));
|
||||||
} else {
|
|
||||||
return Ok(vv.clone());
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// TODO(jwall): A better error for this would be nice.
|
_ => {
|
||||||
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to \
|
return Err(Box::new(BuildError::TypeFail(format!("{} is not a Tuple or List",
|
||||||
match selector \
|
sl[0].fragment))));
|
||||||
path {:?}",
|
|
||||||
sl))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Box::new(BuildError::TypeFail(format!("{} is not a Tuple",
|
|
||||||
sl[0].fragment))));
|
|
||||||
}
|
}
|
||||||
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to find Symbol {}",
|
return Err(Box::new(BuildError::NoSuchSymbol(format!("Unable to find Symbol {}",
|
||||||
sl[0].fragment))));
|
sl[0].fragment))));
|
||||||
@ -941,25 +943,16 @@ mod test {
|
|||||||
]
|
]
|
||||||
))),
|
))),
|
||||||
])));
|
])));
|
||||||
b.out
|
b.out.entry(Positioned::new("var2".to_string(),
|
||||||
.entry(Positioned::new("var2".to_string(),
|
Position {line: 1, column: 0}))
|
||||||
Position {
|
|
||||||
line: 1,
|
|
||||||
column: 0,
|
|
||||||
}))
|
|
||||||
.or_insert(Rc::new(Val::Int(2)));
|
.or_insert(Rc::new(Val::Int(2)));
|
||||||
b.out
|
b.out.entry(Positioned::new("var3".to_string(),
|
||||||
.entry(Positioned::new("var3".to_string(),
|
Position {line: 1, column: 0}))
|
||||||
Position {
|
.or_insert(Rc::new(Val::Tuple(
|
||||||
line: 1,
|
vec![(Positioned::new("lvl1".to_string(),
|
||||||
column: 0,
|
Position {line: 1, column: 0}),
|
||||||
}))
|
Rc::new(Val::Int(4)))])));
|
||||||
.or_insert(Rc::new(Val::Tuple(vec![(Positioned::new("lvl1".to_string(),
|
|
||||||
Position {
|
|
||||||
line: 1,
|
|
||||||
column: 0,
|
|
||||||
}),
|
|
||||||
Rc::new(Val::Int(4)))])));
|
|
||||||
test_expr_to_val(vec![
|
test_expr_to_val(vec![
|
||||||
(Expression::Simple(Value::Selector(make_value_node(vec![Token::new("var1", Position{line: 1, column: 1})], 1, 1))), Val::Tuple(
|
(Expression::Simple(Value::Selector(make_value_node(vec![Token::new("var1", Position{line: 1, column: 1})], 1, 1))), Val::Tuple(
|
||||||
vec![
|
vec![
|
||||||
@ -989,6 +982,28 @@ mod test {
|
|||||||
], b);
|
], b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eval_selector_list_expr() {
|
||||||
|
let mut b = Builder::new();
|
||||||
|
b.out.entry(Positioned::new("var1".to_string(), Position{line: 1, column: 1})).or_insert(Rc::new(Val::List(
|
||||||
|
vec![
|
||||||
|
Rc::new(Val::String("val1".to_string())),
|
||||||
|
Rc::new(Val::Tuple(vec![
|
||||||
|
(Positioned::new("var2".to_string(), Position{line: 1, column: 1}),
|
||||||
|
Rc::new(Val::Int(1))),
|
||||||
|
])),
|
||||||
|
])));
|
||||||
|
// TODO(jwall): Assert that we can index into lists using dot syntax.
|
||||||
|
|
||||||
|
test_expr_to_val(vec![
|
||||||
|
(Expression::Simple(Value::Selector(make_value_node(vec![
|
||||||
|
Token::new("var1", Position{line: 1, column: 1}),
|
||||||
|
Token::new("0", Position{line: 1, column: 1})
|
||||||
|
], 1, 1))),
|
||||||
|
Val::String("val1".to_string()))
|
||||||
|
], b);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Unable to find Symbol tpl1")]
|
#[should_panic(expected = "Unable to find Symbol tpl1")]
|
||||||
fn test_expr_copy_no_such_tuple() {
|
fn test_expr_copy_no_such_tuple() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user