diff --git a/src/lib.rs b/src/lib.rs index 28814d0..3fa0105 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,214 @@ // limitations under the License. // #![feature(trace_macros,log_syntax)] +//! # ucg, A universal configuration grammar. +//! +//! 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, +//! comoposable with copy-on-write semantics, and safe. +//! +//! ## Example +//! +//! ```ucg +//! // named bindings +//! let host = "mysql.internal.net"; +//! let port = 8080 +//! +//! // format strings +//! let connstr = "mysql://@:@" % (host, port); +//! +//! // tuples +//! let dbconf = { +//! connstr = connstr, +//! database = "mydb", +//! // lists +//! tables = ["posts", "comments", "users"], +//! }; +//! ``` +//! +//! ## Syntax +//! +//! 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 +//! ucg expression terminated by a semicolon. +//! +//! ### Reserved words +//! +//! The following words are reserved in ucg and can't be used as named bindings. +//! +//! * let +//! * import +//! * as +//! * select +//! * macro +//! +//! ### Primitive types +//! +//! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String. +//! +//! * Int, is any integer number. +//! * Float is any number with a decimal point. +//! +//! ```ucg +//! 1.0; // A typical float. +//! 1. // You can leave off the 0 after the decimal point. +//! .1 // the leading 0 is also optional. +//! ``` +//! +//! * String is any quoted text. +//! +//! ``` ucg +//! "foo"; // a smiple string +//! "I'm a \"fine\" looking string"; // escaped quotes in a string. +//! ``` +//! +//! ### Complex types +//! +//! ucg has two complex data types, Lists and Tuples. +//! +//! * List's start are surrounded with square brackets `[ ]` and have comma separated elements. +//! +//! ```ucg +//! [1, 2, 3]; // A simple list of numbers. +//! +//! [[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. +//! +//! ```ucg +//! let mylist = [0, 1, 2, 3]; +//! +//! let zero = mylist.0; +//! ``` +//! +//! * 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 +//! be a bareword without quotes. +//! +//! ```ucg +//! let mytuple = { +//! field1 = "value1", +//! field2 = "value2", +//! }; +//! ``` +//! +//! Tuples can be indexed using dotted selector syntax. +//! +//! ```ucg +//! let field = mytuple.fields1; +//! ``` +//! +//! ### Expressions +//! +//! #### Selectors +//! +//! 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 +//! 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. +//! +//! ```ucg +//! let mytuple = { +//! field1 = "a string", +//! field2 = [{ +//! subfield1 = 1, +//! }]; +//! }; +//! +//! mytuple.field2.0; // descend into a deeply nested tuple and array. +//! ``` +//! +//! #### Binary operators +//! +//! 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 + operator can additionally concatenate strings or arrays. +//! +//! ```ucg +//! 1 + 1; // result is 2 +//! "foo " + "bar" // result is "foo bar" +//! [1,2] + [3,4]; // result is [1,2,3,4] +//! ``` +//! +//! #### Conditional data. +//! +//! 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, +//! 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 +//! let want = "baz"; +//! +//! // field default +//! select want, "quux", { +//! baz = "foo", +//! fuzz = "bang", +//! }; // result will be "foo" +//! +//! // field default +//! select "quack", "quux", { +//! baz = "foo", +//! fuzz = "bang", +//! }; // result will be "quux" +//! ``` +//! +//! #### Macros +//! +//! 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 +//! keyword followed by the arguments in parentheses and then a tuple. +//! +//! ```ucg +//! let myfunc = macro (arg1, arg2) { +//! host = arg1, +//! port = arg2, +//! connstr = "couchdb://@:@" % (arg1, arg2), +//! } +//! +//! let my dbconf = myfunc("couchdb.example.org", "9090"); +//! +//! 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. +//! +//! ### Statements +//! +//! There are 3 kinds of statements in a ucg configuration file. expression statements, let statements, and import statements. +//! +//! * expression statements +//! The simplest and least useful is the expression statements. It is any valid expression followed by a semicolon. +//! +//! ```ucg +//! 1; +//! 4 / 2; +//! "foo"; +//! "foo" + "bar"; +//! ``` +//! +//! 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. +//! +//! * 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 name of the binding, =, and a valid ucg expression. +//! +//! ```ucg +//! let name = "foo"; +//! ``` +//! +//! * Import statement +//! 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 +//! to the ucg file, they keyword as, and a name for the imported values. +//! +//! ```ucg +//! import "dbconfigs.ucg" as dbconfigs; +//! +//! let mysqlconf = dbconfigs.mysql; +//! ``` #[macro_use] extern crate nom; #[macro_use]