mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-23 18:29:50 -04:00
WIP: Track the positions of our tokens and AST elements.
This commit is contained in:
parent
31dadd47f6
commit
b4ec44323b
80
src/ast.rs
80
src/ast.rs
@ -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();
|
||||||
|
@ -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))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user