diff --git a/TODO.md b/TODO.md index 73e0583..ae9969a 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,11 @@ Inspect is probably the correct location for this. * Flags should allow different seperators for prefixed flags. * HCL export +# Documentation TODO + +* Recursive Modules +* Schema Checking With Modules + # Release Checklist * Cargo test diff --git a/src/build/mod.rs b/src/build/mod.rs index 7182ddd..3eeec91 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -1711,11 +1711,12 @@ impl<'a> FileBuilder<'a> { def: &BinaryOpDef, scope: &Scope, ) -> Result, Box> { - let typ = match def.right.as_ref() { - Expression::Simple(Value::Str(ref s)) => s.val.clone(), + let tval = self.eval_expr(def.right.as_ref(), scope)?; + let typ = match tval.as_ref() { + Val::Str(ref s) => s.clone(), _ => { return Err(Box::new(error::BuildError::new( - format!("Expected string expression but got {}", def.right), + format!("Expected string expression but got {}", tval), error::ErrorType::TypeFail, def.right.pos().clone(), ))); diff --git a/std/tests/tuples_test.ucg b/std/tests/tuples_test.ucg index b94cb52..53192bc 100644 --- a/std/tests/tuples_test.ucg +++ b/std/tests/tuples_test.ucg @@ -19,4 +19,23 @@ assert t.equal{ assert t.equal{ left = tpl.strip_nulls{tpl={foo="bar", bar=NULL}}.result, right = {foo="bar"}, +}; + +assert t.ok{ + test = tpl.has_fields{tpl={foo=1, bar=2}, fields=["foo", "bar"]}.result, + desc = "tuple has fields has foo and bar fields", +}; + +assert t.not_ok{ + test = tpl.has_fields{tpl={blah=1, bar=2}, fields=["foo", "bar"]}.result, + desc = "tuple does not have fields foo and bar", +}; + +assert t.ok{ + test = tpl.field_type{ + tpl={foo=1}, + field="foo", + type="int", + }.result, + desc = "tuple has field of type int", }; \ No newline at end of file diff --git a/std/tuples.ucg b/std/tuples.ucg index 056bc1d..7e40fc5 100644 --- a/std/tuples.ucg +++ b/std/tuples.ucg @@ -1,8 +1,15 @@ +let assert_tuple = macro(tpl) => select tpl is "tuple", NULL, { + false = fail "@ is not a tuple" % (tpl), +}; // return a list of the fields in a tuple. let fields = module{ tpl = NULL, } => { + let assert_tuple = import "std/tuples.ucg".assert_tuple; + // First we check that mod.tpl is a tuple. + assert_tuple(mod.tpl); + let reducer = macro(acc, field, value) => acc + [field]; let result = reduce reducer [], (mod.tpl); @@ -12,6 +19,10 @@ let fields = module{ let values = module{ tpl = NULL, } => { + let assert_tuple = import "std/tuples.ucg".assert_tuple; + // First we check that mod.tpl is a tuple. + assert_tuple(mod.tpl); + let reducer = macro(acc, field, value) => acc + [value]; let result = reduce reducer [], (mod.tpl); @@ -20,6 +31,10 @@ let values = module{ let iter = module{ tpl = NULL, } => { + let assert_tuple = import "std/tuples.ucg".assert_tuple; + // First we check that mod.tpl is a tuple. + assert_tuple(mod.tpl); + let reducer = macro(acc, field, value) => acc + [[field, value]]; let result = reduce reducer [], (mod.tpl); @@ -28,7 +43,59 @@ let iter = module{ let strip_nulls = module{ tpl = NULL, } => { + let assert_tuple = import "std/tuples.ucg".assert_tuple; + // First we check that mod.tpl is a tuple. + assert_tuple(mod.tpl); + let filterer = macro(name, value) => value != NULL; let result = filter filterer (mod.tpl); +}; + +let has_fields = module{ + tpl = NULL, + fields = [], +} => { + let lib = import "std/tuples.ucg"; + // First we check that mod.tpl is a tuple. + lib.assert_tuple(mod.tpl); + + let fs = lib.fields{tpl=mod.tpl}.result; + + let reducer = macro(acc, f) => acc && (f in fs); + + let result = reduce reducer true, (mod.fields); +}; + +let field_type = module{ + tpl = NULL, + field = NULL, + type = NULL, +} => { + let lib = import "std/tuples.ucg"; + // First we check that mod.tpl is a tuple. + lib.assert_tuple(mod.tpl); + + // Next we assert that mod.field is a string. + select mod.field is "str", NULL, { + false = fail "@ is not a string" % (mod.field), + }; + + // and finally that mod.type is a string + select mod.type is "str", NULL, { + false = fail "@ is not a string" % (mod.type), + }; + + let has_field = lib.has_fields{tpl=mod.tpl, fields=[mod.field]}.result; + + let it = lib.iter{tpl=mod.tpl}.result; + + let reducer = macro(acc, l) => acc && (select l.0 == mod.field, NULL, { + true = l.1 is mod.type, // if this is the field then we propagate if it's the right type. + false = true, // if this isn't the field then we propagate true + }); + + let is_type = reduce reducer true, it; + + let result = has_field && is_type; }; \ No newline at end of file