WIP: Track the positions of our tokens and AST elements.

This commit is contained in:
Jeremy Wall 2017-09-12 20:08:58 -05:00
parent 31dadd47f6
commit b4ec44323b
2 changed files with 55 additions and 33 deletions

View File

@ -14,7 +14,19 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::borrow::Borrow; use std::borrow::Borrow;
pub type FieldList = Vec<(String, Expression)>; // str is expected to be a symbol #[derive(Debug,PartialEq,Clone)]
pub struct Position {
pub line: usize,
pub column: usize,
}
#[derive(Debug,PartialEq,Clone)]
pub struct LocatedNode<N> {
pub pos: Position,
pub node: N,
}
pub type FieldList = Vec<(String, LocatedNode<Expression>)>; // str is expected to be a symbol
pub type SelectorList = Vec<String>; // str is expected to always be a symbol. pub type SelectorList = Vec<String>; // str is expected to always be a symbol.
/// Value represents a Value in the UCG parsed AST. /// Value represents a Value in the UCG parsed AST.
@ -71,15 +83,15 @@ impl Value {
#[derive(PartialEq,Debug,Clone)] #[derive(PartialEq,Debug,Clone)]
pub struct CallDef { pub struct CallDef {
pub macroref: SelectorList, pub macroref: SelectorList,
pub arglist: Vec<Expression>, pub arglist: Vec<LocatedNode<Expression>>,
} }
/// SelectDef selects a value from a tuple with a default if the value doesn't /// SelectDef selects a value from a tuple with a default if the value doesn't
/// exist. /// exist.
#[derive(PartialEq,Debug,Clone)] #[derive(PartialEq,Debug,Clone)]
pub struct SelectDef { pub struct SelectDef {
pub val: Box<Expression>, pub val: Box<LocatedNode<Expression>>,
pub default: Box<Expression>, pub default: Box<LocatedNode<Expression>>,
pub tuple: FieldList, pub tuple: FieldList,
} }
@ -94,7 +106,7 @@ pub struct MacroDef {
} }
impl MacroDef { impl MacroDef {
fn validate_value_symbols<'a>(&'a self, stack: &mut Vec<&'a Expression>, val: &'a Value) -> HashSet<String> { fn validate_value_symbols<'a>(&'a self, stack: &mut Vec<&'a LocatedNode<Expression>>, val: &'a Value) -> HashSet<String> {
let mut bad_symbols = HashSet::new(); let mut bad_symbols = HashSet::new();
if let &Value::Symbol(ref name) = val { if let &Value::Symbol(ref name) = val {
let mut ok = true; let mut ok = true;
@ -134,56 +146,56 @@ impl MacroDef {
stack.push(expr); stack.push(expr);
while stack.len() > 0 { while stack.len() > 0 {
match stack.pop().unwrap() { match stack.pop().unwrap() {
&Expression::Add(ref bexpr) => { &LocatedNode{pos: _, node: Expression::Add(ref bexpr)} => {
let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0); let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0);
bad_symbols.extend(syms_set.drain()); bad_symbols.extend(syms_set.drain());
stack.push(&bexpr.1); stack.push(&bexpr.1);
}, },
&Expression::Sub(ref bexpr) => { &LocatedNode{pos: _, node: Expression::Sub(ref bexpr)} => {
let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0); let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0);
bad_symbols.extend(syms_set.drain()); bad_symbols.extend(syms_set.drain());
stack.push(&bexpr.1); stack.push(&bexpr.1);
}, },
&Expression::Mul(ref bexpr) => { &LocatedNode{pos: _, node: Expression::Mul(ref bexpr)} => {
let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0); let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0);
bad_symbols.extend(syms_set.drain()); bad_symbols.extend(syms_set.drain());
stack.push(&bexpr.1); stack.push(&bexpr.1);
}, },
&Expression::Div(ref bexpr) => { &LocatedNode{pos: _, node: Expression::Div(ref bexpr)} => {
let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0); let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.0);
bad_symbols.extend(syms_set.drain()); bad_symbols.extend(syms_set.drain());
stack.push(&bexpr.1); stack.push(&bexpr.1);
}, },
&Expression::Grouped(ref expr) => { &LocatedNode{pos: _, node: Expression::Grouped(ref expr)} => {
stack.push(expr); stack.push(expr);
}, },
&Expression::Format(_, ref exprs) => { &LocatedNode{pos: _, node: Expression::Format(_, ref exprs)} => {
for arg_expr in exprs.iter() { for arg_expr in exprs.iter() {
stack.push(arg_expr); stack.push(arg_expr);
} }
}, },
&Expression::Select(ref def) => { &LocatedNode{pos: _, node: Expression::Select(ref def)} => {
stack.push(def.default.borrow()); stack.push(def.default.borrow());
stack.push(def.val.borrow()); stack.push(def.val.borrow());
for &(_, ref expr) in def.tuple.iter() { for &(_, ref expr) in def.tuple.iter() {
stack.push(expr); stack.push(expr);
} }
}, },
&Expression::Copy(_, ref fields) => { &LocatedNode{pos: _, node: Expression::Copy(_, ref fields)} => {
for &(_, ref expr) in fields.iter() { for &(_, ref expr) in fields.iter() {
stack.push(expr); stack.push(expr);
} }
}, },
&Expression::Call(ref def) => { &LocatedNode{pos: _, node: Expression::Call(ref def)} => {
for expr in def.arglist.iter() { for expr in def.arglist.iter() {
stack.push(expr); stack.push(expr);
} }
} }
&Expression::Simple(ref val) => { &LocatedNode{pos: _, node: Expression::Simple(ref val)} => {
let mut syms_set = self.validate_value_symbols(&mut stack, val); let mut syms_set = self.validate_value_symbols(&mut stack, val);
bad_symbols.extend(syms_set.drain()); bad_symbols.extend(syms_set.drain());
}, },
&Expression::Macro(_) => { &LocatedNode{pos: _, node: Expression::Macro(_)} => {
// noop // noop
continue; continue;
}, },
@ -199,7 +211,7 @@ impl MacroDef {
/// BinaryExpression represents an expression with a left and a right side. /// BinaryExpression represents an expression with a left and a right side.
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub struct BinaryExpression(pub Value, pub Box<Expression>); pub struct BinaryExpression(pub Value, pub Box<LocatedNode<Expression>>);
/// Expression encodes an expression. Expressions compute a value from operands. /// Expression encodes an expression. Expressions compute a value from operands.
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
@ -216,9 +228,9 @@ pub enum Expression {
// Complex Expressions // Complex Expressions
Copy(SelectorList, FieldList), Copy(SelectorList, FieldList),
Grouped(Box<Expression>), Grouped(Box<LocatedNode<Expression>>),
Format(String, Vec<Expression>), Format(String, Vec<LocatedNode<Expression>>),
Call(CallDef), Call(CallDef),
@ -230,12 +242,12 @@ pub enum Expression {
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum Statement { pub enum Statement {
// simple expression // simple expression
Expression(Expression), Expression(LocatedNode<Expression>),
// Named bindings // Named bindings
Let { Let {
name: String, name: String,
value: Expression, value: LocatedNode<Expression>,
}, },
// Include a file. // Include a file.
@ -249,6 +261,16 @@ pub enum Statement {
mod ast_test { mod ast_test {
use super::*; use super::*;
fn wrapNode(expr: Expression) -> LocatedNode<Expression> {
LocatedNode{
pos: Position{
line: 0,
column: 0,
},
node: expr,
}
}
#[test] #[test]
pub fn test_macro_validation_happy_path() { pub fn test_macro_validation_happy_path() {
let def = MacroDef{ let def = MacroDef{
@ -256,9 +278,9 @@ mod ast_test {
"foo".to_string() "foo".to_string()
], ],
fields: vec![ fields: vec![
("f1".to_string(), Expression::Add(BinaryExpression( ("f1".to_string(), wrapNode(Expression::Add(BinaryExpression(
Value::Symbol("foo".to_string()), Value::Symbol("foo".to_string()),
Box::new(Expression::Simple(Value::Int(1)))))), Box::new(wrapNode(Expression::Simple(Value::Int(1)))))))),
], ],
}; };
assert!(def.validate_symbols().unwrap() == ()); assert!(def.validate_symbols().unwrap() == ());
@ -271,9 +293,9 @@ mod ast_test {
"foo".to_string() "foo".to_string()
], ],
fields: vec![ fields: vec![
("f1".to_string(), Expression::Add(BinaryExpression( ("f1".to_string(), wrapNode(Expression::Add(BinaryExpression(
Value::Symbol("bar".to_string()), Value::Symbol("bar".to_string()),
Box::new(Expression::Simple(Value::Int(1)))))), Box::new(wrapNode(Expression::Simple(Value::Int(1)))))))),
], ],
}; };
let mut expected = HashSet::new(); let mut expected = HashSet::new();
@ -288,9 +310,9 @@ mod ast_test {
"foo".to_string() "foo".to_string()
], ],
fields: vec![ fields: vec![
("f1".to_string(), Expression::Add(BinaryExpression( ("f1".to_string(), wrapNode(Expression::Add(BinaryExpression(
Value::Selector(vec!["foo".to_string(), "quux".to_string()]), Value::Selector(vec!["foo".to_string(), "quux".to_string()]),
Box::new(Expression::Simple(Value::Int(1)))))), Box::new(wrapNode(Expression::Simple(Value::Int(1)))))))),
], ],
}; };
assert!(def.validate_symbols().unwrap() == ()); assert!(def.validate_symbols().unwrap() == ());
@ -303,9 +325,9 @@ mod ast_test {
"foo".to_string() "foo".to_string()
], ],
fields: vec![ fields: vec![
("f1".to_string(), Expression::Add(BinaryExpression( ("f1".to_string(), wrapNode(Expression::Add(BinaryExpression(
Value::Selector(vec!["bar".to_string(), "quux".to_string()]), Value::Selector(vec!["bar".to_string(), "quux".to_string()]),
Box::new(Expression::Simple(Value::Int(1)))))), Box::new(wrapNode(Expression::Simple(Value::Int(1)))))))),
], ],
}; };
let mut expected = HashSet::new(); let mut expected = HashSet::new();

View File

@ -154,7 +154,7 @@ named!(value<Value>, alt!(number | quoted_value | symbol | tuple));
named!( named!(
#[doc="Capture a field and value pair composed of `<symbol> = <value>,`"], #[doc="Capture a field and value pair composed of `<symbol> = <value>,`"],
field_value<(String, Expression) >, field_value<(String, LocatedNode<Expression>) >,
do_parse!( do_parse!(
field: field >> field: field >>
ws!(equal) >> ws!(equal) >>
@ -189,18 +189,18 @@ named!(macro_word, tag!("macro"));
named!(import_word, tag!("import")); named!(import_word, tag!("import"));
named!(as_word, tag!("as")); named!(as_word, tag!("as"));
fn value_to_expression(v: Value) -> ParseResult<Expression> { fn value_to_expression(v: Value) -> ParseResult<LocatedNode<Expression>> {
Ok(Expression::Simple(v)) Ok(Expression::Simple(v))
} }
named!(simple_expression<Expression>, named!(simple_expression<LocatedNode<Expression>>,
map_res!( map_res!(
value, value,
value_to_expression value_to_expression
) )
); );
fn tuple_to_add_expression(tpl: (Value, Expression)) -> ParseResult<Expression> { fn tuple_to_add_expression(tpl: (Value, LocatedNode<Expression>)) -> ParseResult<LocatedNode<Expression>> {
Ok(Expression::Add(BinaryExpression(tpl.0, Box::new(tpl.1)))) Ok(Expression::Add(BinaryExpression(tpl.0, Box::new(tpl.1))))
} }