mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
List Parsing and evaluation support.
Also some formatting and todo cleanup.
This commit is contained in:
parent
fc757eee1f
commit
afdd2e5be8
@ -1,4 +1,5 @@
|
|||||||
let dbhost = "localhost";
|
let dbhost1 = "db1.prod.net";
|
||||||
|
let dbhost2 = "db2.prod.net";
|
||||||
let dbname = "testdb";
|
let dbname = "testdb";
|
||||||
|
|
||||||
let mk_db_conn = macro (host, port, db) => {
|
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)
|
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 = {
|
let server_config = {
|
||||||
dbconn = db_conn.conn_string,
|
db_conn = db_conns,
|
||||||
tmpldir = "./templates"
|
tmpldir = "./templates"
|
||||||
};
|
};
|
13
src/ast.rs
13
src/ast.rs
@ -59,7 +59,7 @@ pub type SelectorList = Vec<Token>; // str is expected to always be a symbol.
|
|||||||
|
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct LocatedNode<T> {
|
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 pos: Position,
|
||||||
pub val: T,
|
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> {
|
pub fn make_value_node<T>(v: T, line: usize, column: usize) -> LocatedNode<T> {
|
||||||
LocatedNode::new(v,
|
LocatedNode::new(v,
|
||||||
Position {
|
Position {
|
||||||
@ -290,6 +289,9 @@ impl MacroDef {
|
|||||||
bad_symbols.extend(syms_set.drain());
|
bad_symbols.extend(syms_set.drain());
|
||||||
stack.push(&bexpr.right);
|
stack.push(&bexpr.right);
|
||||||
}
|
}
|
||||||
|
&Expression::List(ref def) => {
|
||||||
|
stack.extend(def.elems.iter());
|
||||||
|
}
|
||||||
&Expression::Grouped(ref expr) => {
|
&Expression::Grouped(ref expr) => {
|
||||||
stack.push(expr);
|
stack.push(expr);
|
||||||
}
|
}
|
||||||
@ -366,6 +368,12 @@ pub struct FormatDef {
|
|||||||
pub pos: Position,
|
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.
|
/// Expression encodes an expression. Expressions compute a value from operands.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
@ -377,6 +385,7 @@ pub enum Expression {
|
|||||||
// Complex Expressions
|
// Complex Expressions
|
||||||
Copy(CopyDef),
|
Copy(CopyDef),
|
||||||
Grouped(Box<Expression>),
|
Grouped(Box<Expression>),
|
||||||
|
List(ListDef),
|
||||||
|
|
||||||
Format(FormatDef),
|
Format(FormatDef),
|
||||||
|
|
||||||
|
24
src/build.rs
24
src/build.rs
@ -106,6 +106,7 @@ pub enum Val {
|
|||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
String(String),
|
String(String),
|
||||||
|
List(Vec<Rc<Val>>),
|
||||||
Tuple(Vec<(Positioned<String>, Rc<Val>)>),
|
Tuple(Vec<(Positioned<String>, Rc<Val>)>),
|
||||||
Macro(MacroDef),
|
Macro(MacroDef),
|
||||||
}
|
}
|
||||||
@ -116,6 +117,7 @@ impl Val {
|
|||||||
&Val::Int(_) => "Integer".to_string(),
|
&Val::Int(_) => "Integer".to_string(),
|
||||||
&Val::Float(_) => "Float".to_string(),
|
&Val::Float(_) => "Float".to_string(),
|
||||||
&Val::String(_) => "String".to_string(),
|
&Val::String(_) => "String".to_string(),
|
||||||
|
&Val::List(_) => "List".to_string(),
|
||||||
&Val::Tuple(_) => "Tuple".to_string(),
|
&Val::Tuple(_) => "Tuple".to_string(),
|
||||||
&Val::Macro(_) => "Macro".to_string(),
|
&Val::Macro(_) => "Macro".to_string(),
|
||||||
}
|
}
|
||||||
@ -144,6 +146,13 @@ impl Val {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&Val::List(_) => {
|
||||||
|
if let &Val::List(_) = target {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
&Val::Tuple(_) => {
|
&Val::Tuple(_) => {
|
||||||
if let &Val::Tuple(_) = target {
|
if let &Val::Tuple(_) = target {
|
||||||
true
|
true
|
||||||
@ -332,10 +341,9 @@ impl Builder {
|
|||||||
pub fn build_file(&mut self, name: &str) -> BuildResult {
|
pub fn build_file(&mut self, name: &str) -> BuildResult {
|
||||||
let mut f = try!(File::open(name));
|
let mut f = try!(File::open(name));
|
||||||
let mut s = String::new();
|
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));
|
try!(f.read_to_string(&mut s));
|
||||||
self.build_file_string(name, s)
|
self.build_file_string(name, s)
|
||||||
// TODO(jwall): Call an output converter.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
|
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
|
||||||
@ -623,6 +631,13 @@ impl Builder {
|
|||||||
&Expression::Grouped(ref expr) => {
|
&Expression::Grouped(ref expr) => {
|
||||||
return self.eval_expr(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) => {
|
&Expression::Format(ref def) => {
|
||||||
let tmpl = &def.template;
|
let tmpl = &def.template;
|
||||||
let args = &def.args;
|
let args = &def.args;
|
||||||
@ -918,7 +933,6 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eval_selector_expr() {
|
fn test_eval_selector_expr() {
|
||||||
// TODO(jwall): Tests for this expression.
|
|
||||||
let mut b = Builder::new();
|
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![
|
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(
|
(Positioned::new("lvl1".to_string(), Position{line: 1, column: 0}), Rc::new(Val::Tuple(
|
||||||
@ -1024,11 +1038,8 @@ mod test {
|
|||||||
], b);
|
], b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jwall): What about the duplicate field error?
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expr_copy() {
|
fn test_expr_copy() {
|
||||||
// TODO(jwall): Tests for this expression.
|
|
||||||
let mut b = Builder::new();
|
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![
|
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))),
|
(Positioned::new("fld1".to_string(), Position{line: 1, column: 0}), Rc::new(Val::Int(1))),
|
||||||
@ -1248,5 +1259,4 @@ mod test {
|
|||||||
],
|
],
|
||||||
b);
|
b);
|
||||||
}
|
}
|
||||||
// TODO(jwall): Unit test for MacroDef Symbol Validation.
|
|
||||||
}
|
}
|
||||||
|
@ -32,20 +32,24 @@ impl FlagConverter {
|
|||||||
match v {
|
match v {
|
||||||
&Val::Float(ref f) => {
|
&Val::Float(ref f) => {
|
||||||
try!(write!(w, "{} ", f));
|
try!(write!(w, "{} ", f));
|
||||||
},
|
}
|
||||||
&Val::Int(ref i) => {
|
&Val::Int(ref i) => {
|
||||||
try!(write!(w, "{} ", i));
|
try!(write!(w, "{} ", i));
|
||||||
},
|
}
|
||||||
&Val::String(ref s) => {
|
&Val::String(ref s) => {
|
||||||
try!(write!(w, "'{}' ", s));
|
try!(write!(w, "'{}' ", s));
|
||||||
},
|
}
|
||||||
|
&Val::List(ref _def) => {
|
||||||
|
// FIXME(jwall): Fill this in?
|
||||||
|
eprintln!("Skipping List...");
|
||||||
|
}
|
||||||
&Val::Tuple(ref flds) => {
|
&Val::Tuple(ref flds) => {
|
||||||
for &(ref name, ref val) in flds.iter() {
|
for &(ref name, ref val) in flds.iter() {
|
||||||
try!(write!(w, "--{} ", name.val));
|
try!(write!(w, "--{} ", name.val));
|
||||||
// TODO(jwall): What if the value is a tuple?
|
// TODO(jwall): What if the value is a tuple?
|
||||||
try!(self.write(&val, w));
|
try!(self.write(&val, w));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
&Val::Macro(ref _def) => {
|
&Val::Macro(ref _def) => {
|
||||||
// This is ignored
|
// This is ignored
|
||||||
eprintln!("Skipping macro...");
|
eprintln!("Skipping macro...");
|
||||||
|
68
src/parse.rs
68
src/parse.rs
@ -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
|
// NOTE(jwall): HERE THERE BE DRAGONS. The order for these matters
|
||||||
// alot. We need to process alternatives in order of decreasing
|
// alot. We need to process alternatives in order of decreasing
|
||||||
// specificity. Unfortunately this means we are required to go in a
|
// specificity. Unfortunately this means we are required to go in a
|
||||||
@ -459,6 +479,7 @@ named!(expression( Span ) -> Expression,
|
|||||||
complete!(mul_expression) |
|
complete!(mul_expression) |
|
||||||
complete!(div_expression) |
|
complete!(div_expression) |
|
||||||
complete!(grouped_expression) |
|
complete!(grouped_expression) |
|
||||||
|
complete!(list_expression) |
|
||||||
complete!(macro_expression) |
|
complete!(macro_expression) |
|
||||||
complete!(format_expression) |
|
complete!(format_expression) |
|
||||||
complete!(select_expression) |
|
complete!(select_expression) |
|
||||||
@ -555,7 +576,7 @@ pub fn parse(input: Span) -> IResult<Span, Vec<Statement>> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef};
|
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::{copy_expression, macro_expression, select_expression};
|
||||||
use super::{format_expression, call_expression, expression};
|
use super::{format_expression, call_expression, expression};
|
||||||
use super::{expression_statement, let_statement, import_statement, statement};
|
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]
|
#[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]
|
#[test]
|
||||||
fn test_tuple_parse() {
|
fn test_tuple_parse() {
|
||||||
assert!(tuple(LocatedSpan::new("{")).is_incomplete() );
|
assert!(tuple(LocatedSpan::new("{")).is_incomplete() );
|
||||||
|
@ -137,6 +137,14 @@ named!(pub semicolontok( Span ) -> Token,
|
|||||||
do_tag_tok!(";")
|
do_tag_tok!(";")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
named!(pub leftsquarebracket( Span ) -> Token,
|
||||||
|
do_tag_tok!("[")
|
||||||
|
);
|
||||||
|
|
||||||
|
named!(pub rightsquarebracket( Span ) -> Token,
|
||||||
|
do_tag_tok!("]")
|
||||||
|
);
|
||||||
|
|
||||||
named!(pub fatcommatok( Span ) -> Token,
|
named!(pub fatcommatok( Span ) -> Token,
|
||||||
do_tag_tok!("=>")
|
do_tag_tok!("=>")
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user