mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DOCS: Add documentation on our stdlib.
* Adds schema.ucg to our reference site. * Adds comments to the std libs themselves.
This commit is contained in:
parent
cccef4554d
commit
b571ead599
65
docsite/site/content/stdlib/schema.md
Normal file
65
docsite/site/content/stdlib/schema.md
Normal file
@ -0,0 +1,65 @@
|
||||
+++
|
||||
title = "UCG Schema Modules"
|
||||
weight = 4
|
||||
sort_by = "weight"
|
||||
in_search_index = true
|
||||
+++
|
||||
|
||||
UCG's std lib has a selection of functions and modules to help assert a base type and shape for a value. They are located in the `std/schema.ucg` import.
|
||||
|
||||
## Schema shapes
|
||||
|
||||
The primary tool in this import is the shaped module. This module allows you to match a value against a stereotype value. If the provided value is the same base type and has the same shape of that base type as the provided stereotype then the
|
||||
result field of the computed tuple will be true.
|
||||
|
||||
```
|
||||
let fits = schema.shaped{
|
||||
val={foo="bar", inner=[1, 2]},
|
||||
shape={foo="", inner=[]}
|
||||
}.result;
|
||||
|
||||
fits == true;
|
||||
```
|
||||
|
||||
By default the matching allows the shape to specify a partial or minimum shape. But you can specify exact matching if desired by setting the partial paramater to false..
|
||||
|
||||
```
|
||||
let exact_fit = schema.shaped{
|
||||
partial=false,
|
||||
val={foo="bar", count=1},
|
||||
shape={foo=""},
|
||||
}.result;
|
||||
|
||||
exact_fit == false;
|
||||
```
|
||||
|
||||
The shape algorithm does not enforce a length or set of contained types for lists at this time.
|
||||
|
||||
Besides the shaped module there are also some useful utility modules and functions to assist in some addtional type checking logic.
|
||||
## any
|
||||
|
||||
The `any` module tests a value against a list of possible shapes. If the value
|
||||
fits any of the candidate shapes then it stores true in the result field. If it does not then it returns false in that result field.
|
||||
|
||||
```
|
||||
let fits_one_of = any{val={foo="bar"}, types=[1, {foo=""}]}.result;
|
||||
fits_one_of == true;
|
||||
```
|
||||
|
||||
## base_type_of function.
|
||||
|
||||
The `base_type_of` function computes the base type of a value.
|
||||
|
||||
```
|
||||
let foo = 1;
|
||||
base_type_of(foo) == "int";
|
||||
```
|
||||
|
||||
## must
|
||||
|
||||
The `must` function turns any schema check module failure into a compile failure. It composes well with the modules in the `std/schema.ucg` import and automatically checks the result field they produce. If that field is true then it returns that true value. If the field is false they produce a compile failure.
|
||||
|
||||
```
|
||||
// results in a compile failure "Must be a string"
|
||||
must(shaped{val="foo", shape=1}, "Must be a string");
|
||||
```
|
@ -1,7 +1,14 @@
|
||||
// Joins a list into a string with an optional provided separator.
|
||||
// The string will be in the result field of the generated tuple
|
||||
// from the module.
|
||||
let str_join = module{
|
||||
// The default separator is a single space. You can override
|
||||
// this when you call the module if desired.
|
||||
sep=" ",
|
||||
// The list is a required parameter.
|
||||
list=NULL,
|
||||
} => {
|
||||
// The function used by reduce to join the list into a string.
|
||||
let joiner = func (acc, item) => select (acc.out == ""), NULL, {
|
||||
true = acc{
|
||||
out="@@" % (acc.out,item),
|
||||
@ -11,16 +18,27 @@ let str_join = module{
|
||||
},
|
||||
};
|
||||
|
||||
// The resulting joined string. Reference the result field from the
|
||||
// tuple the module produces to get the joined string.
|
||||
let result = reduce(joiner, {sep=mod.sep, out=""}, (mod.list)).out;
|
||||
};
|
||||
|
||||
// Computes the length of the provided list.
|
||||
let len = func(list) => reduce(func(acc, item) => acc + 1, 0, list);
|
||||
|
||||
// Reverses the provided list.
|
||||
let reverse = func(list) => reduce(func (acc, item) => [item] + acc, [], list);
|
||||
|
||||
// Enumerates the provided list with optional start and step parameters for the
|
||||
// enumeration. Prodices a list of pairs with the numeration and the list item.
|
||||
//
|
||||
// enumerate{list=["a","b","c"]}.result == [[0, "a"], [1, "b"], [2, "c"]]
|
||||
let enumerate = module{
|
||||
// Where to start the enumeration.
|
||||
start = 0,
|
||||
// The step amount for each enumeration.
|
||||
step = 1,
|
||||
// The list to enumerate.
|
||||
list = NULL,
|
||||
} => {
|
||||
let reducer = func (acc, item) => acc{
|
||||
@ -34,21 +52,26 @@ let enumerate = module{
|
||||
let result = enumerated.list;
|
||||
};
|
||||
|
||||
// zips two lists together.
|
||||
//
|
||||
// zip{list1=[0,2,4],list2=[1,3,5]}.result == [[0, 1], [2, 3], [4, 5]]
|
||||
let zip = module{
|
||||
list1 = NULL,
|
||||
list2 = NULL,
|
||||
} => {
|
||||
let len = import "std/lists.ucg".len;
|
||||
|
||||
|
||||
// Compute the length of each list.
|
||||
let len1 = len(mod.list1);
|
||||
let len2 = len(mod.list2);
|
||||
|
||||
// Compute the min range of the two lists.
|
||||
let rng = select (len1 >= len2), NULL, {
|
||||
true = 0:(len1 - 1),
|
||||
false = 0:(len2 - 1),
|
||||
};
|
||||
|
||||
// The reducer function for the zip operation.
|
||||
let reducer = func (acc, item) => acc{
|
||||
result = acc.result + [[acc.list1.(item), acc.list2.(item)]],
|
||||
idxs = acc.idxs + [item]
|
||||
@ -61,5 +84,6 @@ let zip = module{
|
||||
idxs = [],
|
||||
};
|
||||
|
||||
// The resulting zipped list.
|
||||
let result = reduce(reducer, acc, rng).result;
|
||||
};
|
@ -1,8 +1,9 @@
|
||||
// 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.
|
||||
// Return a list of the fields in a tuple.
|
||||
let fields = module{
|
||||
tpl = NULL,
|
||||
} => {
|
||||
@ -13,7 +14,7 @@ let fields = module{
|
||||
let result = reduce(func (acc, field, value) => acc + [field], [], (mod.tpl));
|
||||
};
|
||||
|
||||
// return a list of the values in a tuple.
|
||||
// Return a list of the values in a tuple.
|
||||
let values = module{
|
||||
tpl = NULL,
|
||||
} => {
|
||||
@ -24,6 +25,7 @@ let values = module{
|
||||
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,
|
||||
} => {
|
||||
@ -34,6 +36,7 @@ let iter = module{
|
||||
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,
|
||||
} => {
|
||||
@ -44,6 +47,7 @@ let strip_nulls = module{
|
||||
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 = [],
|
||||
@ -57,6 +61,7 @@ let has_fields = module{
|
||||
let result = reduce(reducer = 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,
|
||||
@ -76,12 +81,15 @@ let field_type = module{
|
||||
false = fail "@ is not a string" % (mod.type),
|
||||
};
|
||||
|
||||
// Get the list of field value pairs.
|
||||
let it = lib.iter{tpl=mod.tpl}.result;
|
||||
|
||||
|
||||
// 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]}.result && reduce(reducer, true, it);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user