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.
|
/// An ordered list of Name = Value pairs.
|
||||||
///
|
///
|
||||||
/// This is usually used as the body of a tuple in the UCG AST.
|
/// 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
|
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.
|
/// Represents a Value in the UCG parsed AST.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
@ -350,7 +203,6 @@ pub enum Value {
|
|||||||
// Complex Values
|
// Complex Values
|
||||||
Tuple(PositionedItem<FieldList>),
|
Tuple(PositionedItem<FieldList>),
|
||||||
List(ListDef),
|
List(ListDef),
|
||||||
Selector(SelectorDef),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
@ -365,7 +217,6 @@ impl Value {
|
|||||||
&Value::Symbol(_) => "Symbol".to_string(),
|
&Value::Symbol(_) => "Symbol".to_string(),
|
||||||
&Value::Tuple(_) => "Tuple".to_string(),
|
&Value::Tuple(_) => "Tuple".to_string(),
|
||||||
&Value::List(_) => "List".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::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.to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +261,6 @@ impl Value {
|
|||||||
&Value::Symbol(ref s) => &s.pos,
|
&Value::Symbol(ref s) => &s.pos,
|
||||||
&Value::Tuple(ref fs) => &fs.pos,
|
&Value::Tuple(ref fs) => &fs.pos,
|
||||||
&Value::List(ref def) => &def.pos,
|
&Value::List(ref def) => &def.pos,
|
||||||
&Value::Selector(ref v) => &v.pos,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +276,7 @@ impl Value {
|
|||||||
&Value::Str(_),
|
&Value::Str(_),
|
||||||
&Value::Symbol(_),
|
&Value::Symbol(_),
|
||||||
&Value::Tuple(_),
|
&Value::Tuple(_),
|
||||||
&Value::List(_),
|
&Value::List(_)
|
||||||
&Value::Selector(_)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,7 +285,7 @@ impl Value {
|
|||||||
/// defined.
|
/// defined.
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub struct CallDef {
|
pub struct CallDef {
|
||||||
pub macroref: SelectorDef,
|
pub macroref: Value,
|
||||||
pub arglist: Vec<Expression>,
|
pub arglist: Vec<Expression>,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -552,8 +400,6 @@ impl MacroDef {
|
|||||||
if !self.symbol_is_in_args(&name.val) {
|
if !self.symbol_is_in_args(&name.val) {
|
||||||
bad_symbols.insert(name.val.clone());
|
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 {
|
} 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() {
|
||||||
@ -637,6 +483,7 @@ impl MacroDef {
|
|||||||
/// UCG expression.
|
/// UCG expression.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum BinaryExprType {
|
pub enum BinaryExprType {
|
||||||
|
// Math
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
@ -648,7 +495,8 @@ pub enum BinaryExprType {
|
|||||||
NotEqual,
|
NotEqual,
|
||||||
GTEqual,
|
GTEqual,
|
||||||
LTEqual,
|
LTEqual,
|
||||||
// TODO DOT Selector operator
|
// Selector operator
|
||||||
|
DOT,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an expression with a left and a right side.
|
/// 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.
|
/// Encodes a tuple Copy expression in the UCG AST.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CopyDef {
|
pub struct CopyDef {
|
||||||
pub selector: SelectorDef,
|
pub selector: Value,
|
||||||
pub fields: FieldList,
|
pub fields: FieldList,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -694,8 +542,8 @@ pub enum ListOpType {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ListOpDef {
|
pub struct ListOpDef {
|
||||||
pub typ: ListOpType,
|
pub typ: ListOpType,
|
||||||
pub mac: SelectorDef,
|
pub mac: PositionedItem<String>,
|
||||||
pub field: String,
|
pub field: PositionedItem<String>,
|
||||||
pub target: Box<Expression>,
|
pub target: Box<Expression>,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
@ -72,10 +72,10 @@ pub fn test_macro_validation_selector_happy_path() {
|
|||||||
make_tok!("f1", Position::new(1, 1, 0)),
|
make_tok!("f1", Position::new(1, 1, 0)),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Box::new(Expression::Simple(Value::Selector(make_selector!(
|
left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
|
||||||
make_expr!("foo", Position::new(1, 1, 0)) => [
|
"foo".to_string(),
|
||||||
make_tok!("quux", Position::new(1, 1, 0)) ]
|
Position::new(1, 1, 0),
|
||||||
=> Position::new(1, 1, 0))))),
|
)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
||||||
1,
|
1,
|
||||||
Position::new(1, 1, 0)
|
Position::new(1, 1, 0)
|
||||||
@ -96,10 +96,10 @@ pub fn test_macro_validation_selector_fail() {
|
|||||||
make_tok!("f1", Position::new(1, 1, 0)),
|
make_tok!("f1", Position::new(1, 1, 0)),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Box::new(Expression::Simple(Value::Selector(
|
left: Box::new(Expression::Simple(Value::Symbol(PositionedItem::new(
|
||||||
make_selector!(make_expr!("bar", Position::new(1, 1, 0)) => [
|
"bar".to_string(),
|
||||||
make_tok!("quux", Position::new(1, 1, 0)) ] => Position::new(1, 1, 0)),
|
Position::new(1, 1, 0),
|
||||||
))),
|
)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
||||||
1,
|
1,
|
||||||
Position::new(1, 1, 0)
|
Position::new(1, 1, 0)
|
||||||
|
200
src/build/mod.rs
200
src/build/mod.rs
@ -15,7 +15,7 @@
|
|||||||
//! The build stage of the ucg compiler.
|
//! The build stage of the ucg compiler.
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -239,9 +239,6 @@ impl<'a> FileBuilder<'a> {
|
|||||||
}
|
}
|
||||||
&Value::List(ref def) => self.eval_list(def, scope),
|
&Value::List(ref def) => self.eval_list(def, scope),
|
||||||
&Value::Tuple(ref tuple) => self.eval_tuple(&tuple.val, 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(
|
fn lookup_in_env(
|
||||||
&self,
|
&self,
|
||||||
search: &Token,
|
pos: &Position,
|
||||||
stack: &mut VecDeque<Rc<Val>>,
|
field: &Rc<Val>,
|
||||||
fs: &Vec<(String, String)>,
|
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() {
|
for &(ref name, ref val) in fs.iter() {
|
||||||
if &search.fragment == name {
|
if field == name {
|
||||||
stack.push_back(Rc::new(Val::Str(val.clone())));
|
return Ok(Rc::new(Val::Str(val.clone())));
|
||||||
return Ok(());
|
|
||||||
} else if !self.strict {
|
} else if !self.strict {
|
||||||
stack.push_back(Rc::new(Val::Empty));
|
return Ok(Rc::new(Val::Empty));
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Box::new(error::BuildError::new(
|
return Err(Box::new(error::BuildError::new(
|
||||||
format!("Environment Variable {} not set", search.fragment),
|
format!("Environment Variable {} not set", field),
|
||||||
error::ErrorType::NoSuchSymbol,
|
error::ErrorType::NoSuchSymbol,
|
||||||
search.pos.clone(),
|
pos.clone(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Do as part of a binary operator selector lookup.
|
||||||
fn lookup_in_tuple(
|
fn lookup_in_tuple(
|
||||||
&self,
|
&self,
|
||||||
stack: &mut VecDeque<Rc<Val>>,
|
pos: &Position,
|
||||||
sl: &SelectorList,
|
field: &Val,
|
||||||
next: (&Position, &str),
|
|
||||||
fs: &Vec<(PositionedItem<String>, Rc<Val>)>,
|
fs: &Vec<(PositionedItem<String>, Rc<Val>)>,
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<Rc<Val>, Box<Error>> {
|
||||||
if let Some(vv) = Self::find_in_fieldlist(next.1, fs) {
|
let field = if let &Val::Str(ref name) = field {
|
||||||
stack.push_back(vv.clone());
|
name
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(error::BuildError::new(
|
return Err(Box::new(error::BuildError::new(
|
||||||
format!(
|
format!("Invalid type {} for field lookup in tuple", field),
|
||||||
"Unable to \
|
error::ErrorType::TypeFail,
|
||||||
match element {} in selector \
|
pos.clone(),
|
||||||
path [{}]",
|
|
||||||
next.1, sl,
|
|
||||||
),
|
|
||||||
error::ErrorType::NoSuchSymbol,
|
|
||||||
next.0.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(
|
fn lookup_in_list(
|
||||||
&self,
|
&self,
|
||||||
stack: &mut VecDeque<Rc<Val>>,
|
pos: &Position,
|
||||||
sl: &SelectorList,
|
field: &Rc<Val>,
|
||||||
next: (&Position, &str),
|
|
||||||
elems: &Vec<Rc<Val>>,
|
elems: &Vec<Rc<Val>>,
|
||||||
) -> Result<(), Box<Error>> {
|
) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let idx = next.1.parse::<usize>()?;
|
let idx = match field.as_ref() {
|
||||||
if idx < elems.len() {
|
&Val::Int(i) => i as usize,
|
||||||
stack.push_back(elems[idx].clone());
|
&Val::Str(ref s) => s.parse::<usize>()?,
|
||||||
} 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
|
return Err(Box::new(error::BuildError::new(
|
||||||
}
|
format!("Invalid idx type {} for list lookup", field),
|
||||||
}
|
error::ErrorType::TypeFail,
|
||||||
|
pos.clone(),
|
||||||
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;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Box::new(error::BuildError::new(
|
|
||||||
format!("{} is not a Tuple or List", vref),
|
|
||||||
error::ErrorType::TypeFail,
|
|
||||||
next.pos.clone(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if idx < elems.len() {
|
||||||
|
Ok(elems[idx].clone())
|
||||||
} else {
|
} 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>> {
|
fn eval_binary(&mut self, def: &BinaryOpDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let kind = &def.kind;
|
let kind = &def.kind;
|
||||||
let left = self.eval_expr(&def.left, scope)?;
|
let left = self.eval_expr(&def.left, scope)?;
|
||||||
let right = self.eval_expr(&def.right, scope)?;
|
let right = self.eval_expr(&def.right, scope)?;
|
||||||
match kind {
|
match kind {
|
||||||
|
// Handle math and concatenation operators here
|
||||||
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
|
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
|
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
|
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Div => self.divide_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::Equal => self.do_deep_equal(&def.pos, left, right),
|
||||||
&BinaryExprType::GT => self.do_gt(&def.pos, left, right),
|
&BinaryExprType::GT => self.do_gt(&def.pos, left, right),
|
||||||
&BinaryExprType::LT => self.do_lt(&def.pos, left, right),
|
&BinaryExprType::LT => self.do_lt(&def.pos, left, right),
|
||||||
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
||||||
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
||||||
&BinaryExprType::NotEqual => self.do_not_deep_equal(&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>> {
|
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() {
|
if let &Val::Tuple(ref src_fields) = v.as_ref() {
|
||||||
let mut child_scope = scope.spawn_child();
|
let mut child_scope = scope.spawn_child();
|
||||||
child_scope.set_curr_val(v.clone());
|
child_scope.set_curr_val(v.clone());
|
||||||
@ -1011,14 +986,14 @@ impl<'a> FileBuilder<'a> {
|
|||||||
mod_def.arg_tuple
|
mod_def.arg_tuple
|
||||||
),
|
),
|
||||||
error::ErrorType::TypeFail,
|
error::ErrorType::TypeFail,
|
||||||
def.selector.pos.clone(),
|
def.selector.pos().clone(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Box::new(error::BuildError::new(
|
Err(Box::new(error::BuildError::new(
|
||||||
format!("Expected Tuple or Module got {}", v),
|
format!("Expected Tuple or Module got {}", v),
|
||||||
error::ErrorType::TypeFail,
|
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>> {
|
fn eval_call(&mut self, def: &CallDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let sel = &def.macroref;
|
|
||||||
let args = &def.arglist;
|
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() {
|
if let &Val::Macro(ref m) = v.deref() {
|
||||||
// Congratulations this is actually a macro.
|
// Congratulations this is actually a macro.
|
||||||
let mut argvals: Vec<Rc<Val>> = Vec::new();
|
let mut argvals: Vec<Rc<Val>> = Vec::new();
|
||||||
@ -1145,13 +1119,13 @@ impl<'a> FileBuilder<'a> {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mac = &def.mac;
|
let mac_sym = Value::Symbol(def.mac.clone());
|
||||||
if let &Val::Macro(ref macdef) = self.lookup_selector(&mac.sel, scope)?.as_ref() {
|
if let &Val::Macro(ref macdef) = self.eval_value(&mac_sym, &self.scope)?.as_ref() {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for item in l.iter() {
|
for item in l.iter() {
|
||||||
let argvals = vec![item.clone()];
|
let argvals = vec![item.clone()];
|
||||||
let fields = macdef.eval(self.file.clone(), self, argvals)?;
|
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 {
|
match def.typ {
|
||||||
ListOpType::Map => {
|
ListOpType::Map => {
|
||||||
out.push(v.clone());
|
out.push(v.clone());
|
||||||
@ -1172,7 +1146,7 @@ impl<'a> FileBuilder<'a> {
|
|||||||
return Ok(Rc::new(Val::List(out)));
|
return Ok(Rc::new(Val::List(out)));
|
||||||
}
|
}
|
||||||
return Err(Box::new(error::BuildError::new(
|
return Err(Box::new(error::BuildError::new(
|
||||||
format!("Expected macro but got {:?}", mac),
|
format!("Expected macro but got {:?}", def.mac),
|
||||||
error::ErrorType::TypeFail,
|
error::ErrorType::TypeFail,
|
||||||
def.pos.clone(),
|
def.pos.clone(),
|
||||||
)));
|
)));
|
||||||
|
@ -157,10 +157,10 @@ fn test_expr_copy_no_such_tuple() {
|
|||||||
test_expr_to_val(
|
test_expr_to_val(
|
||||||
vec![(
|
vec![(
|
||||||
Expression::Copy(CopyDef {
|
Expression::Copy(CopyDef {
|
||||||
selector: make_selector!(
|
selector: Value::Symbol(PositionedItem::new(
|
||||||
make_expr!("tpl1", Position::new(1, 1, 1)),
|
"tpl1".to_string(),
|
||||||
Position::new(1, 1, 1)
|
Position::new(1, 1, 1),
|
||||||
),
|
)),
|
||||||
fields: Vec::new(),
|
fields: Vec::new(),
|
||||||
pos: Position::new(1, 0, 0),
|
pos: Position::new(1, 0, 0),
|
||||||
}),
|
}),
|
||||||
@ -183,10 +183,10 @@ fn test_expr_copy_not_a_tuple() {
|
|||||||
test_expr_to_val(
|
test_expr_to_val(
|
||||||
vec![(
|
vec![(
|
||||||
Expression::Copy(CopyDef {
|
Expression::Copy(CopyDef {
|
||||||
selector: make_selector!(
|
selector: Value::Symbol(PositionedItem::new(
|
||||||
make_expr!("tpl1", Position::new(1, 1, 1)),
|
"tpl1".to_string(),
|
||||||
Position::new(1, 1, 1)
|
Position::new(1, 1, 1),
|
||||||
),
|
)),
|
||||||
fields: Vec::new(),
|
fields: Vec::new(),
|
||||||
pos: Position::new(1, 0, 0),
|
pos: Position::new(1, 0, 0),
|
||||||
}),
|
}),
|
||||||
@ -212,10 +212,10 @@ fn test_expr_copy_field_type_error() {
|
|||||||
test_expr_to_val(
|
test_expr_to_val(
|
||||||
vec![(
|
vec![(
|
||||||
Expression::Copy(CopyDef {
|
Expression::Copy(CopyDef {
|
||||||
selector: make_selector!(
|
selector: Value::Symbol(PositionedItem::new(
|
||||||
make_expr!("tpl1", Position::new(1, 1, 1)),
|
"tpl1".to_string(),
|
||||||
Position::new(1, 1, 1)
|
Position::new(1, 1, 1),
|
||||||
),
|
)),
|
||||||
fields: vec![(
|
fields: vec![(
|
||||||
make_tok!("fld1", Position::new(1, 1, 1)),
|
make_tok!("fld1", Position::new(1, 1, 1)),
|
||||||
Expression::Simple(Value::Str(value_node!(
|
Expression::Simple(Value::Str(value_node!(
|
||||||
@ -261,10 +261,10 @@ fn test_macro_hermetic() {
|
|||||||
test_expr_to_val(
|
test_expr_to_val(
|
||||||
vec![(
|
vec![(
|
||||||
Expression::Call(CallDef {
|
Expression::Call(CallDef {
|
||||||
macroref: make_selector!(
|
macroref: Value::Symbol(PositionedItem::new(
|
||||||
make_expr!("tstmac", Position::new(1, 1, 1)),
|
"tstmac".to_string(),
|
||||||
Position::new(1, 1, 1)
|
Position::new(1, 1, 1),
|
||||||
),
|
)),
|
||||||
arglist: vec![Expression::Simple(Value::Str(value_node!(
|
arglist: vec![Expression::Simple(Value::Str(value_node!(
|
||||||
"bar".to_string(),
|
"bar".to_string(),
|
||||||
Position::new(1, 1, 1)
|
Position::new(1, 1, 1)
|
||||||
|
210
src/parse/mod.rs
210
src/parse/mod.rs
@ -279,7 +279,7 @@ make_fn!(
|
|||||||
either!(
|
either!(
|
||||||
// TODO This should move to op_expression instead of a value now.
|
// TODO This should move to op_expression instead of a value now.
|
||||||
// We probably still need a bareword parser though?
|
// We probably still need a bareword parser though?
|
||||||
trace_parse!(selector_value),
|
trace_parse!(symbol),
|
||||||
trace_parse!(compound_value),
|
trace_parse!(compound_value),
|
||||||
trace_parse!(boolean_value),
|
trace_parse!(boolean_value),
|
||||||
trace_parse!(empty_value),
|
trace_parse!(empty_value),
|
||||||
@ -318,107 +318,14 @@ make_fn!(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
fn symbol_or_expression(input: SliceIter<Token>) -> ParseResult<Expression> {
|
fn tuple_to_copy(sym: Value, fields: Option<FieldList>) -> Expression {
|
||||||
let _i = input.clone();
|
let pos = sym.pos().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();
|
|
||||||
let fields = match fields {
|
let fields = match fields {
|
||||||
Some(fields) => fields,
|
Some(fields) => fields,
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
};
|
};
|
||||||
Expression::Copy(CopyDef {
|
Expression::Copy(CopyDef {
|
||||||
selector: def,
|
selector: sym,
|
||||||
fields: fields,
|
fields: fields,
|
||||||
pos: pos,
|
pos: pos,
|
||||||
})
|
})
|
||||||
@ -427,14 +334,13 @@ fn tuple_to_copy(def: SelectorDef, fields: Option<FieldList>) -> Expression {
|
|||||||
make_fn!(
|
make_fn!(
|
||||||
copy_expression<SliceIter<Token>, Expression>,
|
copy_expression<SliceIter<Token>, Expression>,
|
||||||
do_each!(
|
do_each!(
|
||||||
pos => pos,
|
|
||||||
// TODO This should become just a bareword symbol now
|
// TODO This should become just a bareword symbol now
|
||||||
selector => trace_parse!(selector_list),
|
sym => trace_parse!(symbol),
|
||||||
_ => punct!("{"),
|
_ => punct!("{"),
|
||||||
fields => optional!(trace_parse!(field_list)),
|
fields => optional!(trace_parse!(field_list)),
|
||||||
_ => optional!(punct!(",")), // noms opt! macro does not preserve error types properly but this one does.
|
_ => optional!(punct!(",")), // noms opt! macro does not preserve error types properly but this one does.
|
||||||
_ => punct!("}"),
|
_ => 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,
|
val: Value,
|
||||||
exprs: Option<Vec<Expression>>,
|
exprs: Option<Vec<Expression>>,
|
||||||
) -> ConvertResult<'a, Expression> {
|
) -> ConvertResult<'a, Expression> {
|
||||||
if let Value::Selector(def) = val {
|
if let Value::Symbol(_) = val {
|
||||||
Ok(Expression::Call(CallDef {
|
Ok(Expression::Call(CallDef {
|
||||||
macroref: def,
|
macroref: val,
|
||||||
arglist: exprs.unwrap_or_else(|| Vec::new()),
|
arglist: exprs.unwrap_or_else(|| Vec::new()),
|
||||||
pos: (&input).into(),
|
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> {
|
fn call_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expression> {
|
||||||
let parsed = do_each!(input.clone(),
|
let parsed = do_each!(input.clone(),
|
||||||
// TODO This should become just a bareword symbol now
|
// TODO This should become just a bareword symbol now
|
||||||
callee_name => trace_parse!(selector_value),
|
callee_name => trace_parse!(symbol),
|
||||||
_ => punct!("("),
|
_ => punct!("("),
|
||||||
args => optional!(separated!(punct!(","), trace_parse!(expression))),
|
args => optional!(separated!(punct!(","), trace_parse!(expression))),
|
||||||
_ => punct!(")"),
|
_ => punct!(")"),
|
||||||
@ -664,59 +558,34 @@ fn tuple_to_list_op<'a>(
|
|||||||
input: &'a SliceIter<Token>,
|
input: &'a SliceIter<Token>,
|
||||||
kind: ListOpType,
|
kind: ListOpType,
|
||||||
macroname: Value,
|
macroname: Value,
|
||||||
|
outfield: Value,
|
||||||
list: Expression,
|
list: Expression,
|
||||||
) -> ConvertResult<'a, Expression> {
|
) -> ConvertResult<'a, Expression> {
|
||||||
if let Value::Selector(mut def) = macroname {
|
let macroname = match macroname {
|
||||||
// First of all we need to assert that this is a selector of at least
|
Value::Symbol(sym) => sym,
|
||||||
// two sections.
|
_ => {
|
||||||
let fieldname: String = match &mut def.sel.tail {
|
return Err(Error::new(
|
||||||
&mut None => {
|
format!("Expected a macro name but got {}", macroname.type_name()),
|
||||||
if ENABLE_TRACE {
|
Box::new(input.clone()),
|
||||||
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"),
|
return Err(Error::new(
|
||||||
Box::new(input.clone()),
|
format!("Expected a field name but got {}", outfield.type_name()),
|
||||||
));
|
Box::new(input.clone()),
|
||||||
}
|
))
|
||||||
&mut Some(ref mut tl) => {
|
}
|
||||||
if tl.len() < 1 {
|
};
|
||||||
if ENABLE_TRACE {
|
return Ok(Expression::ListOp(ListOpDef {
|
||||||
eprintln!(
|
typ: kind,
|
||||||
"tuple_to_list_op had error {}",
|
mac: macroname,
|
||||||
"Missing a result field for the macro"
|
field: outfield,
|
||||||
);
|
target: Box::new(list),
|
||||||
}
|
pos: input.into(),
|
||||||
return Err(Error::new(
|
}));
|
||||||
format!("Missing a result field for the macro"),
|
|
||||||
Box::new(input.clone()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let fname = tl.pop();
|
|
||||||
fname.unwrap().fragment
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return Ok(Expression::ListOp(ListOpDef {
|
|
||||||
typ: kind,
|
|
||||||
mac: def,
|
|
||||||
field: fieldname,
|
|
||||||
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!(
|
make_fn!(
|
||||||
@ -728,9 +597,11 @@ make_fn!(
|
|||||||
do_each!(_ => word!("filter"), (ListOpType::Filter))
|
do_each!(_ => word!("filter"), (ListOpType::Filter))
|
||||||
),
|
),
|
||||||
// TODO This should become just a bareword symbol now
|
// 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),
|
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;
|
pub mod precedence;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test;
|
|
||||||
|
@ -27,6 +27,13 @@ pub enum Element {
|
|||||||
Op(BinaryExprType),
|
Op(BinaryExprType),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_fn!(
|
||||||
|
dot_op_type<SliceIter<Token>, Element>,
|
||||||
|
do_each!(
|
||||||
|
_ => punct!("."),
|
||||||
|
(Element::Op(BinaryExprType::DOT)))
|
||||||
|
);
|
||||||
|
|
||||||
make_fn!(
|
make_fn!(
|
||||||
math_op_type<SliceIter<Token>, Element>,
|
math_op_type<SliceIter<Token>, Element>,
|
||||||
either!(
|
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> {
|
fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
|
||||||
let mut i_ = i.clone();
|
let mut i_ = i.clone();
|
||||||
if eoi(i_.clone()).is_complete() {
|
if eoi(i_.clone()).is_complete() {
|
||||||
@ -182,6 +217,7 @@ make_fn!(
|
|||||||
parse_sum_operator,
|
parse_sum_operator,
|
||||||
either!(
|
either!(
|
||||||
trace_parse!(product_expression),
|
trace_parse!(product_expression),
|
||||||
|
trace_parse!(dot_expression),
|
||||||
trace_parse!(parse_expression)
|
trace_parse!(parse_expression)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -189,7 +225,10 @@ make_fn!(
|
|||||||
|
|
||||||
make_fn!(
|
make_fn!(
|
||||||
product_expression<SliceIter<Element>, Expression>,
|
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!(
|
make_fn!(
|
||||||
@ -247,7 +286,17 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
|
|||||||
|
|
||||||
make_fn!(
|
make_fn!(
|
||||||
binary_expression<SliceIter<Element>, Expression>,
|
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!(
|
make_fn!(
|
||||||
@ -256,6 +305,7 @@ make_fn!(
|
|||||||
parse_compare_operator,
|
parse_compare_operator,
|
||||||
either!(
|
either!(
|
||||||
trace_parse!(math_expression),
|
trace_parse!(math_expression),
|
||||||
|
trace_parse!(dot_expression),
|
||||||
trace_parse!(parse_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.
|
// 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) => {
|
Result::Fail(e) => {
|
||||||
if firstrun {
|
if firstrun {
|
||||||
// If we don't find an operator in our first
|
// 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