mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
REFACTOR/FEATURE: Treat selectors as an operator.
This commit is contained in:
parent
fb292b4684
commit
a028960a43
168
src/ast/mod.rs
168
src/ast/mod.rs
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
|
196
src/build/mod.rs
196
src/build/mod.rs
@ -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(),
|
||||
)));
|
||||
|
@ -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)
|
||||
|
186
src/parse/mod.rs
186
src/parse/mod.rs
@ -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,60 +558,35 @@ 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!(
|
||||
list_op_expression<SliceIter<Token>, Expression>,
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
1547
src/parse/test.rs
1547
src/parse/test.rs
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user