ucg 0.5.7

A configuration generation grammar.
Documentation
// Assert that a value is a tuple. Generate a compile failure if it is not.
let assert_tuple = func (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,
} => (result) {
    let assert_tuple = import "std/tuples.ucg".assert_tuple;
    // First we check that mod.tpl is a tuple.
    assert_tuple(mod.tpl);
    
    let result = reduce(func (acc, field, value) =>  acc + [field], [], (mod.tpl));
};

// Return a list of the values in a tuple.
let values = module{
    tpl = NULL,
} => (result) {
    let assert_tuple = import "std/tuples.ucg".assert_tuple;
    // First we check that mod.tpl is a tuple.
    assert_tuple(mod.tpl);
    
    let result = reduce(func (acc, field, value) =>  acc + [value], [], (mod.tpl));
};

// Return a list of the key value pairs in the tuple.
let iter = module{
    tpl = NULL,
} => (result) {
    let assert_tuple = import "std/tuples.ucg".assert_tuple;
    // First we check that mod.tpl is a tuple.
    assert_tuple(mod.tpl);
    
    let result = reduce(func (acc, field, value) =>  acc + [[field, value]], [], (mod.tpl));
};

// Strip all the null fields from a tuple.
let strip_nulls = module{
    tpl = NULL,
} => (result) {
    let assert_tuple = import "std/tuples.ucg".assert_tuple;
    // First we check that mod.tpl is a tuple.
    assert_tuple(mod.tpl);
    
    let result = filter(func (name, value) =>  value != NULL, (mod.tpl));
};

// Check if a tuple has all the fields in a given list.
let has_fields = module{
    tpl = NULL,
    fields = [],
} => (result) {
    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};

    let result = reduce(func (acc, f) => acc && (f in fs), true, mod.fields);
};

// Check if a field in a tuple is a given type.
let field_type = module{
    tpl = NULL,
    field = NULL,
    type = NULL,
} => (result) {
    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),
    };

    // Get the list of field value pairs.
    let it = lib.iter{tpl=mod.tpl};

    // The reducer function used to check the field's types if it exists. 
    let reducer = func (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
    });

    // The computed answer true or false.
    let result = lib.has_fields{tpl=mod.tpl, fields=[mod.field]} && reduce(reducer, true, it);
};