mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-21 18:10:42 -04:00
FEATURE: Allow Environment Variables to be referenced in the builder.
This commit is contained in:
parent
f2e7a8d7c9
commit
5a03cc33ef
154
README.md
154
README.md
@ -36,156 +36,6 @@ SUBCOMMANDS:
|
||||
validate Check a specific ucg file for errors.
|
||||
```
|
||||
|
||||
## Language Examples
|
||||
## Language Reference
|
||||
|
||||
#### Base Types
|
||||
|
||||
UCG has 3 simple types Integer, Float, and String as well as Tuple and List for complex
|
||||
types.
|
||||
|
||||
1;
|
||||
|
||||
1.0;
|
||||
|
||||
"string";
|
||||
|
||||
{
|
||||
field1 = 1,
|
||||
field2 = "strawberry",
|
||||
};
|
||||
|
||||
[1, 2, 3, 4];
|
||||
|
||||
To specify that a number is a Float you must include a decimal point. Otherwise
|
||||
the number will be an integer.
|
||||
|
||||
UCG does type inference for tuple fields based
|
||||
off of the value assigned.
|
||||
|
||||
### Simple Expressions
|
||||
|
||||
UCG supports simple math expressions using `+`, `-`, `*`, `/`) as well as string
|
||||
and list concatenation using `+`. The expressions enforce the same type between operands.
|
||||
|
||||
1 + 1;
|
||||
|
||||
1.0 + 1.0;
|
||||
|
||||
"foo" + "bar";
|
||||
|
||||
[1, 2] + [3, 4];
|
||||
|
||||
### String formatting
|
||||
|
||||
UCG supports some string interpolation using format strings. The syntax is
|
||||
shamelessly ripped off from python.
|
||||
|
||||
"foo @ @ \@" % (1, "bar")
|
||||
|
||||
This gets turned into "foo 1 bar @"
|
||||
|
||||
### Bindings and Tuples.
|
||||
|
||||
Let statements introduce a new name in a UCG file. Most configurations
|
||||
will be a tuple like below. Tuples are delimited by braces and have a list
|
||||
of named fields in them. Fields in a tuple can be indexed using dotted selectors.
|
||||
|
||||
let mysql_conn_base = {
|
||||
host = "db1.local.net",
|
||||
port = 3306,
|
||||
database = "place-holder",
|
||||
};
|
||||
|
||||
let mysql_host = mysql_conn_base.host;
|
||||
|
||||
Tuple fields have no ordering guarantees. All bindings are immutable and
|
||||
can not be reassigned to once defined.
|
||||
|
||||
### Lists
|
||||
|
||||
Lists are an ordered collection of elements. Lists can be indexed using dotted selectors. List indexes start at 0.
|
||||
|
||||
Lists do not at present type check their contents so you can mix types freely within the list. In the future we may enforce that lists contain only the same types but it
|
||||
is as yet unclear if that would be desirable or not.
|
||||
|
||||
let hosts = ["db1.local.net", "db2.local.net"];
|
||||
|
||||
let host1 = hosts.0;
|
||||
let host2 = hosts.1;
|
||||
|
||||
Lista can be concatenated with the + operator.
|
||||
|
||||
let more_hosts = hosts + ["db3.local.net"];
|
||||
|
||||
Both the left and the right side of the + operator must be lists or you will get a type fail.
|
||||
|
||||
### Variables
|
||||
|
||||
UCG can reference a binding using variables. Any named value using
|
||||
a let statement can be referred to with that name within the file it
|
||||
is introduced. You can descend into a tuple using a dotted syntax.
|
||||
|
||||
let var = "My value";
|
||||
let tplvar = {
|
||||
field = var,
|
||||
}
|
||||
let field_var = tplvar.field;
|
||||
|
||||
### Copying and modifying Tuples.
|
||||
|
||||
Even though all bindings are immutable, Tuples have a copy on modify syntax.
|
||||
You can use a previously defined tuple as the basis for a new tuple. Doing this
|
||||
will make a copy of the source tuple and allow you to add new fields
|
||||
or override an already existing field.
|
||||
|
||||
let mysql_app_conn = mysql_conn_base{
|
||||
database = "appdb",
|
||||
timeout = 30,
|
||||
};
|
||||
|
||||
Types are inferred for tuple fields. We enforce type consistency when
|
||||
overriding a field in a base tuple. The port field below expects an
|
||||
Integer not a String so you will get a TypeFail error.
|
||||
|
||||
|
||||
let bad_mysql_conn = mysql_conn_base{
|
||||
port = "3307",
|
||||
}
|
||||
|
||||
### Conditional Values
|
||||
|
||||
The grammar has limited support for conditionals using the select expression.
|
||||
|
||||
let my_sql_app_conn = mysql_conn_base{
|
||||
port = select "prod", 33007 {
|
||||
prod = 3307,
|
||||
qa = 3308,
|
||||
}
|
||||
};
|
||||
|
||||
The first argument to the select call is the key you wish to
|
||||
select. This argument must be a string or an expression that outputs a
|
||||
string. The second argument is a default value to use if the key
|
||||
doesn't exist. The third is a set of fields to choose from.
|
||||
|
||||
### Macros
|
||||
|
||||
We also support a limited macro facility with the macro expression.
|
||||
|
||||
let conn_string_macro = macro (host, port) {
|
||||
conn_str = "mysql://" + host + ":" + port,
|
||||
}
|
||||
|
||||
let web_conn = conn_string_macro ("proddb", "3307");
|
||||
let conn_string = web_conn.conn_str;
|
||||
|
||||
Macro's always output a tuple whose fields are evaluated at the location they
|
||||
are called from. You can acccess the generated fields from the resulting tuple
|
||||
like usual.
|
||||
|
||||
### Comments
|
||||
|
||||
Comments begin with `//` and go till the end of the line.
|
||||
|
||||
// This is a comment.
|
||||
let one = 1;
|
||||
https://docs.rs/ucg/0.0.1/
|
1
TODO.md
1
TODO.md
@ -17,6 +17,7 @@ organiztion for a given configuration structure. Some options here could be
|
||||
|
||||
# Minor Fixes and Polish
|
||||
|
||||
* Allow trailing commas
|
||||
* Flags should allow different seperators for prefixed flags.
|
||||
* None value types
|
||||
* YAML export
|
28
src/build.rs
28
src/build.rs
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! The build stage of the ucg compiler.
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::error::Error;
|
||||
@ -187,11 +188,18 @@ impl From<Val> for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Val {
|
||||
fn from(s: String) -> Val {
|
||||
Val::String(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a set of values in a parsed file.
|
||||
type ValueMap = HashMap<Positioned<String>, Rc<Val>>;
|
||||
|
||||
/// Handles building ucg code.
|
||||
pub struct Builder {
|
||||
env: Rc<Val>,
|
||||
/// assets are other parsed files from import statements. They
|
||||
/// are keyed by the normalized import path. This acts as a cache
|
||||
/// so multiple imports of the same file don't have to be parsed
|
||||
@ -260,17 +268,21 @@ impl Builder {
|
||||
|
||||
/// Constructs a new Builder.
|
||||
pub fn new() -> Self {
|
||||
Builder {
|
||||
assets: HashMap::new(),
|
||||
files: HashSet::new(),
|
||||
out: HashMap::new(),
|
||||
last: None,
|
||||
}
|
||||
// TODO(jwall): Construct a map with the environment variables in it.
|
||||
Self::new_with_scope(HashMap::new())
|
||||
}
|
||||
|
||||
/// Constructs a new Builder with a provided scope.
|
||||
pub fn new_with_scope(scope: ValueMap) -> Self {
|
||||
let env_vars: Vec<(Positioned<String>, Rc<Val>)> = env::vars()
|
||||
.map(|t| (Positioned::new(t.0, 0, 0), Rc::new(t.1.into())))
|
||||
.collect();
|
||||
Self::new_with_env_and_scope(scope, Val::Tuple(env_vars))
|
||||
}
|
||||
|
||||
pub fn new_with_env_and_scope(scope: ValueMap, env: Val) -> Self {
|
||||
Builder {
|
||||
env: Rc::new(env),
|
||||
assets: HashMap::new(),
|
||||
files: HashSet::new(),
|
||||
out: scope,
|
||||
@ -375,6 +387,9 @@ impl Builder {
|
||||
}
|
||||
|
||||
fn lookup_sym(&self, sym: &Positioned<String>) -> Option<Rc<Val>> {
|
||||
if &sym.val == "env" {
|
||||
return Some(self.env.clone());
|
||||
}
|
||||
if self.out.contains_key(sym) {
|
||||
return Some(self.out[sym].clone());
|
||||
}
|
||||
@ -449,6 +464,7 @@ impl Builder {
|
||||
|
||||
fn lookup_selector(&self, sl: &SelectorList) -> Result<Rc<Val>, Box<Error>> {
|
||||
let first = try!(self.eval_expr(&sl.head));
|
||||
// TODO(jwall): Handle environment lookups.
|
||||
// First we ensure that the result is a tuple or a list.
|
||||
let mut stack = VecDeque::new();
|
||||
match first.as_ref() {
|
||||
|
@ -53,6 +53,7 @@
|
||||
//! * as
|
||||
//! * select
|
||||
//! * macro
|
||||
//! * env
|
||||
//!
|
||||
//! ### Primitive types
|
||||
//!
|
||||
@ -138,6 +139,9 @@
|
||||
//! mytuple.field2.0; // descend into a deeply nested tuple and array.
|
||||
//! ```
|
||||
//!
|
||||
//! The env variable is a reserved variable that always contains a tuple with the any environment variables.
|
||||
//! Attempting to reference an enviroment variable that does not exist is a compile error.
|
||||
//!
|
||||
//! #### Binary operators
|
||||
//!
|
||||
//! ucg supports the following operators, +, -, *, /; Each one is type safe and infers the types from the values they operate on.
|
||||
|
Loading…
x
Reference in New Issue
Block a user