List Parsing and evaluation support.

Also some formatting and todo cleanup.
This commit is contained in:
Jeremy Wall 2017-11-26 12:22:58 -05:00
parent fc757eee1f
commit afdd2e5be8
6 changed files with 118 additions and 17 deletions

View File

@ -1,4 +1,5 @@
let dbhost = "localhost";
let dbhost1 = "db1.prod.net";
let dbhost2 = "db2.prod.net";
let dbname = "testdb";
let mk_db_conn = macro (host, port, db) => {
@ -8,9 +9,12 @@ let mk_db_conn = macro (host, port, db) => {
conn_string = "@:@/@" % (host, port, db)
};
let db_conn = mk_db_conn(dbhost, 3306, dbname);
let db_conn1 = mk_db_conn(dbhost1, 3306, dbname);
let db_conn2 = mk_db_conn(dbhost2, 3306, dbname);
let db_conns = [db_conn1.conn_string, db_conn2.conn_string];
let server_config = {
dbconn = db_conn.conn_string,
db_conn = db_conns,
tmpldir = "./templates"
};

View File

@ -59,7 +59,7 @@ pub type SelectorList = Vec<Token>; // str is expected to always be a symbol.
#[derive(Debug,PartialEq,Clone)]
pub struct LocatedNode<T> {
// TODO(jwall): Make this non-optional, Should we just use positioned instead?
// TODO(jwall): Should we just use positioned instead?
pub pos: Position,
pub val: T,
}
@ -78,7 +78,6 @@ impl<T> LocatedNode<T> {
}
// TODO(jwall): This should take a line and a column as argumentsn now.
pub fn make_value_node<T>(v: T, line: usize, column: usize) -> LocatedNode<T> {
LocatedNode::new(v,
Position {
@ -290,6 +289,9 @@ impl MacroDef {
bad_symbols.extend(syms_set.drain());
stack.push(&bexpr.right);
}
&Expression::List(ref def) => {
stack.extend(def.elems.iter());
}
&Expression::Grouped(ref expr) => {
stack.push(expr);
}
@ -366,6 +368,12 @@ pub struct FormatDef {
pub pos: Position,
}
#[derive(Debug,PartialEq,Clone)]
pub struct ListDef {
pub elems: Vec<Expression>,
pub pos: Position,
}
/// Expression encodes an expression. Expressions compute a value from operands.
#[derive(Debug,PartialEq,Clone)]
pub enum Expression {
@ -377,6 +385,7 @@ pub enum Expression {
// Complex Expressions
Copy(CopyDef),
Grouped(Box<Expression>),
List(ListDef),
Format(FormatDef),

View File

@ -106,6 +106,7 @@ pub enum Val {
Int(i64),
Float(f64),
String(String),
List(Vec<Rc<Val>>),
Tuple(Vec<(Positioned<String>, Rc<Val>)>),
Macro(MacroDef),
}
@ -116,6 +117,7 @@ impl Val {
&Val::Int(_) => "Integer".to_string(),
&Val::Float(_) => "Float".to_string(),
&Val::String(_) => "String".to_string(),
&Val::List(_) => "List".to_string(),
&Val::Tuple(_) => "Tuple".to_string(),
&Val::Macro(_) => "Macro".to_string(),
}
@ -144,6 +146,13 @@ impl Val {
false
}
}
&Val::List(_) => {
if let &Val::List(_) = target {
true
} else {
false
}
}
&Val::Tuple(_) => {
if let &Val::Tuple(_) = target {
true
@ -332,10 +341,9 @@ impl Builder {
pub fn build_file(&mut self, name: &str) -> BuildResult {
let mut f = try!(File::open(name));
let mut s = String::new();
// TODO(jwall): It would be nice to be able to do this with streaming
// TODO(jwall): It would be nice to be able to do this while streaming
try!(f.read_to_string(&mut s));
self.build_file_string(name, s)
// TODO(jwall): Call an output converter.
}
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
@ -623,6 +631,13 @@ impl Builder {
&Expression::Grouped(ref expr) => {
return self.eval_expr(expr);
}
&Expression::List(ref def) => {
let mut vals = Vec::new();
for expr in def.elems.iter() {
vals.push(try!(self.eval_expr(expr)));
}
return Ok(Rc::new(Val::List(vals)));
}
&Expression::Format(ref def) => {
let tmpl = &def.template;
let args = &def.args;
@ -918,7 +933,6 @@ mod test {
#[test]
fn test_eval_selector_expr() {
// TODO(jwall): Tests for this expression.
let mut b = Builder::new();
b.out.entry(Positioned::new("var1".to_string(), Position{line: 1, column: 0})).or_insert(Rc::new(Val::Tuple(vec![
(Positioned::new("lvl1".to_string(), Position{line: 1, column: 0}), Rc::new(Val::Tuple(
@ -1024,11 +1038,8 @@ mod test {
], b);
}
// TODO(jwall): What about the duplicate field error?
#[test]
fn test_expr_copy() {
// TODO(jwall): Tests for this expression.
let mut b = Builder::new();
b.out.entry(Positioned::new("tpl1".to_string(), Position{line: 1, column: 0})).or_insert(Rc::new(Val::Tuple(vec![
(Positioned::new("fld1".to_string(), Position{line: 1, column: 0}), Rc::new(Val::Int(1))),
@ -1248,5 +1259,4 @@ mod test {
],
b);
}
// TODO(jwall): Unit test for MacroDef Symbol Validation.
}

View File

@ -32,20 +32,24 @@ impl FlagConverter {
match v {
&Val::Float(ref f) => {
try!(write!(w, "{} ", f));
},
}
&Val::Int(ref i) => {
try!(write!(w, "{} ", i));
},
}
&Val::String(ref s) => {
try!(write!(w, "'{}' ", s));
},
}
&Val::List(ref _def) => {
// FIXME(jwall): Fill this in?
eprintln!("Skipping List...");
}
&Val::Tuple(ref flds) => {
for &(ref name, ref val) in flds.iter() {
try!(write!(w, "--{} ", name.val));
// TODO(jwall): What if the value is a tuple?
try!(self.write(&val, w));
}
},
}
&Val::Macro(ref _def) => {
// This is ignored
eprintln!("Skipping macro...");

View File

@ -442,6 +442,26 @@ named!(call_expression( Span ) -> Expression,
)
);
fn tuple_to_list<Sp: Into<Position> >(t: (Sp, Vec<Expression>)) -> ParseResult<Expression> {
return Ok(Expression::List(ListDef{
elems: t.1,
pos: t.0.into(),
}));
}
named!(list_expression( Span ) -> Expression,
map_res!(
do_parse!(
pos: position!() >>
leftsquarebracket >>
elements: ws!(separated_list!(ws!(commatok), expression)) >>
rightsquarebracket >>
(pos, elements)
),
tuple_to_list
)
);
// NOTE(jwall): HERE THERE BE DRAGONS. The order for these matters
// alot. We need to process alternatives in order of decreasing
// specificity. Unfortunately this means we are required to go in a
@ -459,6 +479,7 @@ named!(expression( Span ) -> Expression,
complete!(mul_expression) |
complete!(div_expression) |
complete!(grouped_expression) |
complete!(list_expression) |
complete!(macro_expression) |
complete!(format_expression) |
complete!(select_expression) |
@ -555,7 +576,7 @@ pub fn parse(input: Span) -> IResult<Span, Vec<Statement>> {
#[cfg(test)]
mod test {
use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef};
use super::{number, symbol, parse, field_value, selector_value, selector_or_symbol, tuple, grouped_expression};
use super::{number, symbol, parse, field_value, selector_value, selector_or_symbol, tuple, grouped_expression, list_expression};
use super::{copy_expression, macro_expression, select_expression};
use super::{format_expression, call_expression, expression};
use super::{expression_statement, let_statement, import_statement, statement};
@ -1032,6 +1053,19 @@ mod test {
)
)
);
assert_eq!(expression(LocatedSpan::new("[1, 1]")),
IResult::Done(LocatedSpan{fragment: "", offset: 6, line: 1},
Expression::List(
ListDef{
elems: vec![
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 2}))),
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 5}))),
],
pos: Position{line: 1, column: 1},
}
)
)
);
}
#[test]
@ -1256,6 +1290,38 @@ mod test {
);
}
#[test]
fn test_list_expression_parse() {
assert!(list_expression(LocatedSpan::new("foo")).is_err() );
assert!(list_expression(LocatedSpan::new("[foo")).is_incomplete() );
assert_eq!(list_expression(LocatedSpan::new("[foo]")),
IResult::Done(LocatedSpan{fragment: "", offset: 5, line: 1},
Expression::List(
ListDef{
elems: vec![
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 2})))
],
pos: Position{ line: 1, column: 1}
}
)
)
);
assert_eq!(list_expression(LocatedSpan::new("[1, 1]")),
IResult::Done(LocatedSpan{fragment: "", offset: 6, line: 1},
Expression::List(
ListDef{
elems: vec![
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 2}))),
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 5}))),
],
pos: Position{line: 1, column: 1},
}
)
)
);
}
#[test]
fn test_tuple_parse() {
assert!(tuple(LocatedSpan::new("{")).is_incomplete() );

View File

@ -137,6 +137,14 @@ named!(pub semicolontok( Span ) -> Token,
do_tag_tok!(";")
);
named!(pub leftsquarebracket( Span ) -> Token,
do_tag_tok!("[")
);
named!(pub rightsquarebracket( Span ) -> Token,
do_tag_tok!("]")
);
named!(pub fatcommatok( Span ) -> Token,
do_tag_tok!("=>")
);