mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Dynamic Type checking with is.
Any expression for the type as long as the expression evaluates to a string.
This commit is contained in:
parent
9b84444feb
commit
1d6c850fd4
5
TODO.md
5
TODO.md
@ -20,6 +20,11 @@ Inspect is probably the correct location for this.
|
|||||||
* Flags should allow different seperators for prefixed flags.
|
* Flags should allow different seperators for prefixed flags.
|
||||||
* HCL export
|
* HCL export
|
||||||
|
|
||||||
|
# Documentation TODO
|
||||||
|
|
||||||
|
* Recursive Modules
|
||||||
|
* Schema Checking With Modules
|
||||||
|
|
||||||
# Release Checklist
|
# Release Checklist
|
||||||
|
|
||||||
* Cargo test
|
* Cargo test
|
||||||
|
@ -1711,11 +1711,12 @@ impl<'a> FileBuilder<'a> {
|
|||||||
def: &BinaryOpDef,
|
def: &BinaryOpDef,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Result<Rc<Val>, Box<dyn Error>> {
|
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||||
let typ = match def.right.as_ref() {
|
let tval = self.eval_expr(def.right.as_ref(), scope)?;
|
||||||
Expression::Simple(Value::Str(ref s)) => s.val.clone(),
|
let typ = match tval.as_ref() {
|
||||||
|
Val::Str(ref s) => s.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Box::new(error::BuildError::new(
|
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,
|
error::ErrorType::TypeFail,
|
||||||
def.right.pos().clone(),
|
def.right.pos().clone(),
|
||||||
)));
|
)));
|
||||||
|
@ -19,4 +19,23 @@ assert t.equal{
|
|||||||
assert t.equal{
|
assert t.equal{
|
||||||
left = tpl.strip_nulls{tpl={foo="bar", bar=NULL}}.result,
|
left = tpl.strip_nulls{tpl={foo="bar", bar=NULL}}.result,
|
||||||
right = {foo="bar"},
|
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",
|
||||||
};
|
};
|
@ -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.
|
// return a list of the fields in a tuple.
|
||||||
let fields = module{
|
let fields = module{
|
||||||
tpl = NULL,
|
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 reducer = macro(acc, field, value) => acc + [field];
|
||||||
|
|
||||||
let result = reduce reducer [], (mod.tpl);
|
let result = reduce reducer [], (mod.tpl);
|
||||||
@ -12,6 +19,10 @@ let fields = module{
|
|||||||
let values = module{
|
let values = module{
|
||||||
tpl = NULL,
|
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 reducer = macro(acc, field, value) => acc + [value];
|
||||||
|
|
||||||
let result = reduce reducer [], (mod.tpl);
|
let result = reduce reducer [], (mod.tpl);
|
||||||
@ -20,6 +31,10 @@ let values = module{
|
|||||||
let iter = module{
|
let iter = module{
|
||||||
tpl = NULL,
|
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 reducer = macro(acc, field, value) => acc + [[field, value]];
|
||||||
|
|
||||||
let result = reduce reducer [], (mod.tpl);
|
let result = reduce reducer [], (mod.tpl);
|
||||||
@ -28,7 +43,59 @@ let iter = module{
|
|||||||
let strip_nulls = module{
|
let strip_nulls = module{
|
||||||
tpl = NULL,
|
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 filterer = macro(name, value) => value != NULL;
|
||||||
|
|
||||||
let result = filter filterer (mod.tpl);
|
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;
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user