Cleanup and formatting.

* Unused code warnings.
* Ran cargo fmt.
This commit is contained in:
Jeremy Wall 2018-02-05 19:41:47 -06:00
parent 1e063fd129
commit a2f689ce0d
5 changed files with 78 additions and 86 deletions

View File

@ -661,7 +661,8 @@ impl Builder {
v.insert((count, expr_result)); v.insert((count, expr_result));
count += 1; count += 1;
} }
Entry::Occupied(mut v) => { // overriding field here. Entry::Occupied(mut v) => {
// overriding field here.
// Ensure that the new type matches the old type. // Ensure that the new type matches the old type.
let src_val = v.get().clone(); let src_val = v.get().clone();
if src_val.1.type_equal(&expr_result) { if src_val.1.type_equal(&expr_result) {
@ -681,12 +682,17 @@ impl Builder {
// We want to maintain our order for the fields to make comparing tuples // We want to maintain our order for the fields to make comparing tuples
// easier in later code. So we sort by the field order before constructing a new tuple. // easier in later code. So we sort by the field order before constructing a new tuple.
new_fields.sort_by(|a, b| { new_fields.sort_by(|a, b| {
let ta = a.1.clone(); let tb = b.1.clone(); ta.0.cmp(&tb.0) let ta = a.1.clone();
let tb = b.1.clone();
ta.0.cmp(&tb.0)
}); });
return Ok(Rc::new(Val::Tuple(new_fields.iter().map(|a| { return Ok(Rc::new(Val::Tuple(new_fields.iter()
let first = a.0.clone(); let t = a.1.clone(); .map(|a| {
(first, t.1) let first = a.0.clone();
}).collect()))); let t = a.1.clone();
(first, t.1)
})
.collect())));
} }
Err(Box::new(error::Error::new(format!("Expected Tuple got {}", v), Err(Box::new(error::Error::new(format!("Expected Tuple got {}", v),
error::ErrorType::TypeFail, error::ErrorType::TypeFail,

View File

@ -33,7 +33,9 @@ impl JsonConverter {
Ok(serde_json::Value::Array(v)) Ok(serde_json::Value::Array(v))
} }
fn convert_tuple(&self, items: &Vec<(ast::Positioned<String>, Rc<Val>)>) -> Result<serde_json::Value> { fn convert_tuple(&self,
items: &Vec<(ast::Positioned<String>, Rc<Val>)>)
-> Result<serde_json::Value> {
let mut mp = serde_json::Map::new(); let mut mp = serde_json::Map::new();
for &(ref k, ref v) in items.iter() { for &(ref k, ref v) in items.iter() {
mp.entry(k.val.clone()).or_insert(try!(self.convert_value(v))); mp.entry(k.val.clone()).or_insert(try!(self.convert_value(v)));
@ -50,7 +52,7 @@ impl JsonConverter {
None => panic!("Float is too large or Not a Number {}", f), None => panic!("Float is too large or Not a Number {}", f),
}; };
serde_json::Value::Number(n) serde_json::Value::Number(n)
}, }
&Val::Int(i) => { &Val::Int(i) => {
let n = match serde_json::Number::from_f64(i as f64) { let n = match serde_json::Number::from_f64(i as f64) {
Some(n) => n, Some(n) => n,
@ -58,20 +60,20 @@ impl JsonConverter {
None => panic!("Float is too large or Not a Number {}", i), None => panic!("Float is too large or Not a Number {}", i),
}; };
serde_json::Value::Number(n) serde_json::Value::Number(n)
}, }
&Val::String(ref s) => serde_json::Value::String(s.clone()), &Val::String(ref s) => serde_json::Value::String(s.clone()),
&Val::Macro(_) => { &Val::Macro(_) => {
// TODO(jwall): We probably want to actually skip this but for now // TODO(jwall): We probably want to actually skip this but for now
// we'll use null // we'll use null
eprintln!("Skipping macro encoding as null..."); eprintln!("Skipping macro encoding as null...");
serde_json::Value::Null serde_json::Value::Null
}, }
&Val::List(ref l) => try!(self.convert_list(l)), &Val::List(ref l) => try!(self.convert_list(l)),
&Val::Tuple(ref t) => try!(self.convert_tuple(t)), &Val::Tuple(ref t) => try!(self.convert_tuple(t)),
}; };
Ok(jsn_val) Ok(jsn_val)
} }
fn write(&self, v: &Val, w: &mut Write) -> Result<()> { fn write(&self, v: &Val, w: &mut Write) -> Result<()> {
let jsn_val = try!(self.convert_value(v)); let jsn_val = try!(self.convert_value(v));
try!(serde_json::to_writer(w, &jsn_val)); try!(serde_json::to_writer(w, &jsn_val));
@ -83,4 +85,4 @@ impl Converter for JsonConverter {
fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> Result<()> { fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> Result<()> {
self.write(&v, &mut w) self.write(&v, &mut w)
} }
} }

View File

@ -14,22 +14,22 @@
// #![feature(trace_macros,log_syntax)] // #![feature(trace_macros,log_syntax)]
//! # ucg, A universal configuration grammar. //! # ucg, A universal configuration grammar.
//! //!
//! Ucg defines a common grammar for describing a collection of configuration values. //! Ucg defines a common grammar for describing a collection of configuration values.
//! ucg allows you to specify configuration values with a syntax that that is immutable, //! ucg allows you to specify configuration values with a syntax that that is immutable,
//! comoposable with copy-on-write semantics, and safe. //! comoposable with copy-on-write semantics, and safe.
//! //!
//! ## Example //! ## Example
//! //!
//! ```ucg //! ```ucg
//! // named bindings //! // named bindings
//! let host = "mysql.internal.net"; //! let host = "mysql.internal.net";
//! let port = 8080 //! let port = 8080
//! //!
//! // format strings //! // format strings
//! let connstr = "mysql://@:@" % (host, port); //! let connstr = "mysql://@:@" % (host, port);
//! //!
//! // tuples //! // tuples
//! let dbconf = { //! let dbconf = {
//! connstr = connstr, //! connstr = connstr,
//! database = "mydb", //! database = "mydb",
@ -37,17 +37,17 @@
//! tables = ["posts", "comments", "users"], //! tables = ["posts", "comments", "users"],
//! }; //! };
//! ``` //! ```
//! //!
//! ## Syntax //! ## Syntax
//! //!
//! ucg is a safe language with type inference that tries to guarantee that it will halt. //! ucg is a safe language with type inference that tries to guarantee that it will halt.
//! A valid ucg file is composesed of a series of statements. Statements are any valid //! A valid ucg file is composesed of a series of statements. Statements are any valid
//! ucg expression terminated by a semicolon. //! ucg expression terminated by a semicolon.
//! //!
//! ### Reserved words //! ### Reserved words
//! //!
//! The following words are reserved in ucg and can't be used as named bindings. //! The following words are reserved in ucg and can't be used as named bindings.
//! //!
//! * let //! * let
//! * import //! * import
//! * as //! * as
@ -55,50 +55,50 @@
//! * macro //! * macro
//! //!
//! ### Primitive types //! ### Primitive types
//! //!
//! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String. //! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String.
//! //!
//! * Int, is any integer number. //! * Int, is any integer number.
//! * Float is any number with a decimal point. //! * Float is any number with a decimal point.
//! //!
//! ```ucg //! ```ucg
//! 1.0; // A typical float. //! 1.0; // A typical float.
//! 1. // You can leave off the 0 after the decimal point. //! 1. // You can leave off the 0 after the decimal point.
//! .1 // the leading 0 is also optional. //! .1 // the leading 0 is also optional.
//! ``` //! ```
//! //!
//! * String is any quoted text. backslashes within a string escape the next preceding //! * String is any quoted text. backslashes within a string escape the next preceding
//! character. //! character.
//! //!
//! ``` ucg //! ``` ucg
//! "foo"; // a smiple string //! "foo"; // a smiple string
//! "I'm a \"fine\" looking string"; // escaped quotes in a string. //! "I'm a \"fine\" looking string"; // escaped quotes in a string.
//! ``` //! ```
//! //!
//! ### Complex types //! ### Complex types
//! //!
//! ucg has two complex data types, Lists and Tuples. //! ucg has two complex data types, Lists and Tuples.
//! //!
//! * List's start are surrounded with square brackets `[ ]` and have comma separated elements. //! * List's start are surrounded with square brackets `[ ]` and have comma separated elements.
//! //!
//! ```ucg //! ```ucg
//! [1, 2, 3]; // A simple list of numbers. //! [1, 2, 3]; // A simple list of numbers.
//! //!
//! [[1, 2], [3, 4]] // A deep list with embedded lists inside. //! [[1, 2], [3, 4]] // A deep list with embedded lists inside.
//! ``` //! ```
//! //!
//! Lists are 0 indexed and you can index into them using the dotted selector syntax. //! Lists are 0 indexed and you can index into them using the dotted selector syntax.
//! //!
//! ```ucg //! ```ucg
//! let mylist = [0, 1, 2, 3]; //! let mylist = [0, 1, 2, 3];
//! //!
//! let zero = mylist.0; //! let zero = mylist.0;
//! ``` //! ```
//! //!
//! * Tuple's are an ordered collection of name, value pairs. They are bounded by curly braces `{ }` //! * Tuple's are an ordered collection of name, value pairs. They are bounded by curly braces `{ }`
//! and contain name = value pairs separated by commas. Trailing commas are permitted. The name must //! and contain name = value pairs separated by commas. Trailing commas are permitted. The name must
//! be a bareword without quotes. //! be a bareword without quotes.
//! //!
//! ```ucg //! ```ucg
//! let mytuple = { //! let mytuple = {
//! field1 = "value1", //! field1 = "value1",
@ -111,17 +111,17 @@
//! ```ucg //! ```ucg
//! let field = mytuple.fields1; //! let field = mytuple.fields1;
//! ``` //! ```
//! //!
//! ### Expressions //! ### Expressions
//! //!
//! #### Selectors //! #### Selectors
//! //!
//! Selectors are references to a bound value in ucg. They can index arbitrarily deep into either tuples or lists. //! Selectors are references to a bound value in ucg. They can index arbitrarily deep into either tuples or lists.
//! The head of a selector can be any expression that resolves to a tuple or list. Optionally a selector can also be //! The head of a selector can be any expression that resolves to a tuple or list. Optionally a selector can also be
//! followed by either a bareword to index a tuple field or an integer to index a list position. //! followed by either a bareword to index a tuple field or an integer to index a list position.
//! //!
//! The simplest selector is just a reference to a bound value by name. //! The simplest selector is just a reference to a bound value by name.
//! //!
//! ```ucg //! ```ucg
//! let mytuple = { //! let mytuple = {
//! field1 = "a string", //! field1 = "a string",
@ -129,7 +129,7 @@
//! subfield1 = 1, //! subfield1 = 1,
//! }]; //! }];
//! }; //! };
//! //!
//! mytuple.field2.0; // descend into a deeply nested tuple and array. //! mytuple.field2.0; // descend into a deeply nested tuple and array.
//! ``` //! ```
//! //!
@ -138,59 +138,59 @@
//! ucg supports the following operators, +, -, *, /; Each one is type safe and infers the types from the values they operate on. //! ucg supports the following operators, +, -, *, /; Each one is type safe and infers the types from the values they operate on.
//! The operators expect both the left and right operands to be of the same type. All of the operators are valid on integers and floats. //! The operators expect both the left and right operands to be of the same type. All of the operators are valid on integers and floats.
//! The + operator can additionally concatenate strings or arrays. //! The + operator can additionally concatenate strings or arrays.
//! //!
//! ```ucg //! ```ucg
//! 1 + 1; // result is 2 //! 1 + 1; // result is 2
//! "foo " + "bar" // result is "foo bar" //! "foo " + "bar" // result is "foo bar"
//! [1,2] + [3,4]; // result is [1,2,3,4] //! [1,2] + [3,4]; // result is [1,2,3,4]
//! ``` //! ```
//! //!
//! #### Conditional data. //! #### Conditional data.
//! //!
//! ucg supports a limited form of conditional selection of data using the select expression. A select expression starts with the select //! ucg supports a limited form of conditional selection of data using the select expression. A select expression starts with the select
//! keyword and is followed by a an expression resolving to a string naming the field to select, an expression resolving to the default value, //! keyword and is followed by a an expression resolving to a string naming the field to select, an expression resolving to the default value,
//! and a tuple to select the field from. If the field selected is not in the tuple then the default value will be used. //! and a tuple to select the field from. If the field selected is not in the tuple then the default value will be used.
//! //!
//! ```ucg //! ```ucg
//! let want = "baz"; //! let want = "baz";
//! //!
//! // field default //! // field default
//! select want, "quux", { //! select want, "quux", {
//! baz = "foo", //! baz = "foo",
//! fuzz = "bang", //! fuzz = "bang",
//! }; // result will be "foo" //! }; // result will be "foo"
//! //!
//! // field default //! // field default
//! select "quack", "quux", { //! select "quack", "quux", {
//! baz = "foo", //! baz = "foo",
//! fuzz = "bang", //! fuzz = "bang",
//! }; // result will be "quux" //! }; // result will be "quux"
//! ``` //! ```
//! //!
//! #### Macros //! #### Macros
//! //!
//! Macros look like functions but they are resolved at compile time and configurations don't execute so they never appear in output. //! Macros look like functions but they are resolved at compile time and configurations don't execute so they never appear in output.
//! They are useful for constructing tuples of a certain shape or otherwise promoting data reuse. You define a macro with the macro //! They are useful for constructing tuples of a certain shape or otherwise promoting data reuse. You define a macro with the macro
//! keyword followed by the arguments in parentheses and then a tuple. //! keyword followed by the arguments in parentheses and then a tuple.
//! //!
//! ```ucg //! ```ucg
//! let myfunc = macro (arg1, arg2) { //! let myfunc = macro (arg1, arg2) {
//! host = arg1, //! host = arg1,
//! port = arg2, //! port = arg2,
//! connstr = "couchdb://@:@" % (arg1, arg2), //! connstr = "couchdb://@:@" % (arg1, arg2),
//! } //! }
//! //!
//! let my dbconf = myfunc("couchdb.example.org", "9090"); //! let my dbconf = myfunc("couchdb.example.org", "9090");
//! //!
//! let my dbhost = dbconf.host; //! let my dbhost = dbconf.host;
//! ``` //! ```
//! //!
//! macros always resolve to a tuple. If you want to get a single value out you can use selector syntax to retrieve it. //! macros always resolve to a tuple. If you want to get a single value out you can use selector syntax to retrieve it.
//! //!
//! ### Statements //! ### Statements
//! //!
//! There are 3 kinds of statements in a ucg configuration file. expression statements, let statements, and import statements. //! There are 3 kinds of statements in a ucg configuration file. expression statements, let statements, and import statements.
//! //!
//! * expression statements //! * expression statements
//! The simplest and least useful is the expression statements. It is any valid expression followed by a semicolon. //! The simplest and least useful is the expression statements. It is any valid expression followed by a semicolon.
//! //!
@ -199,27 +199,27 @@
//! 4 / 2; //! 4 / 2;
//! "foo"; //! "foo";
//! "foo" + "bar"; //! "foo" + "bar";
//! ``` //! ```
//! //!
//! Despite the fact that these are valid the results are thrown away and can essentially be considered a noop. If we //! Despite the fact that these are valid the results are thrown away and can essentially be considered a noop. If we
//! ever create a repl for ucg statements they may prove more useful. //! ever create a repl for ucg statements they may prove more useful.
//! //!
//! * Let statements //! * Let statements
//! The let expression binds the result of any valid expression to a name. It starts with the let keyword and is followed by //! The let expression binds the result of any valid expression to a name. It starts with the let keyword and is followed by
//! the name of the binding, =, and a valid ucg expression. //! the name of the binding, =, and a valid ucg expression.
//! //!
//! ```ucg //! ```ucg
//! let name = "foo"; //! let name = "foo";
//! ``` //! ```
//! //!
//! * Import statement //! * Import statement
//! The import statement imports the contents of another ucg file into the current file with a name. The imported files bound //! The import statement imports the contents of another ucg file into the current file with a name. The imported files bound
//! values are exposed as a tuple in the referencing file. It starts with the import keyword and is followed by a quoted path //! values are exposed as a tuple in the referencing file. It starts with the import keyword and is followed by a quoted path
//! to the ucg file, they keyword as, and a name for the imported values. //! to the ucg file, they keyword as, and a name for the imported values.
//! //!
//! ```ucg //! ```ucg
//! import "dbconfigs.ucg" as dbconfigs; //! import "dbconfigs.ucg" as dbconfigs;
//! //!
//! let mysqlconf = dbconfigs.mysql; //! let mysqlconf = dbconfigs.mysql;
//! ``` //! ```
#[macro_use] #[macro_use]

View File

@ -677,24 +677,6 @@ mod test {
} }
} }
macro_rules! assert_incomplete {
($parsemac:ident( $i:expr )) => {
assert_incomplete!($i, $parsemac)
};
($i:expr, $f:expr) => {
{
let input = LocatedSpan::new($i);
match tokenize(input) {
Err(_) => assert!(false),
Ok(val) => {
let result = $f(TokenIter{source: val.as_slice()});
assert!(result.is_incomplete(), format!("Not Incomplete: {:?}", result));
},
}
}
}
}
macro_rules! assert_error { macro_rules! assert_error {
($parsemac:ident( $i:expr )) => { ($parsemac:ident( $i:expr )) => {
assert_error!($i, $parsemac) assert_error!($i, $parsemac)

View File

@ -40,9 +40,11 @@ fn escapequoted(input: Span) -> nom::IResult<Span, String> {
let mut frag = String::new(); let mut frag = String::new();
let mut escape = false; let mut escape = false;
for (i, c) in input.iter_indices() { for (i, c) in input.iter_indices() {
if c == '\\' && ! escape { // eat this slash and set our escaping sentinel if c == '\\' && !escape {
// eat this slash and set our escaping sentinel
escape = true; escape = true;
} else if c == '"' && !escape { // Bail if this is an unescaped " } else if c == '"' && !escape {
// Bail if this is an unescaped "
// we exit here. // we exit here.
return nom::IResult::Done(input.slice(i..), frag); return nom::IResult::Done(input.slice(i..), frag);
} else { } else {