ucg/std/strings.ucg
Jeremy Wall a90df8a362 REFACTOR: Cleanup the syntax for the select expr
This makes it both easier to correctly write a select expression
as well as easier to parse and report syntax errors.
2019-11-02 11:01:47 -05:00

107 lines
3.4 KiB
Plaintext

// Wraps a string and provides operations for that string.
//
// * len - property representing the length of the string in characters.
//
// * str - property the wrapped string.
//
// * split_on - module that splits the string on a character.
// - `on` field represents the string to split on.
//
// * split_at - function splits the wrapped string at an character index.
//
// * substr - module that returns a substr of the wrapped string.
// - `start` field is the index at which the substr starts (defaults to 0)
// - `end` field is the index at which the substr ends (defaults to end of string)
let ops = module {
str="",
} => ({len=len,
str=str,
chars=chars,
split_on=split_on,
split_at=split_at,
substr=substr,
}) {
let len = import "std/lists.ucg".len(mod.str);
let str = mod.str;
let chars = reduce(func(acc, char) => acc + [char], [], mod.str);
let split_on = module{
on=" ",
buf = "",
out = [],
str=mod.str,
} => (result) {
let recurse = module {
buf = "",
acc = [],
str = mod.str,
sep = NULL,
} => (result) {
(mod.sep != NULL) || fail "mod.sep can not be NULL";
let pkg = mod.pkg();
let this = mod.this;
let check_str = pkg.ops{str=mod.str};
let split_str = pkg.ops{str=mod.sep};
let maybe_prefix = check_str.substr{end=split_str.len - 1};
let maybe_suffix = check_str.substr{start=split_str.len};
let result = select (maybe_prefix.len == 0) => {
// terminal condition
true = mod.acc + [mod.buf],
//true = mod,
// recurse condition.
false = select (maybe_prefix.str == mod.sep) => {
true = this{ // this is a match to our separator
str=maybe_suffix.str,
sep=mod.sep,
acc=mod.acc + [mod.buf],
},
false = this{
buf=mod.buf + check_str.chars.0,
str=check_str.substr{start=1}.str,
sep=mod.sep,
acc=mod.acc,
},
},
};
};
let result = recurse{sep=mod.on, str=mod.str};
};
let split_at = func(idx) => filter(
func(name, val) => name != "counter",
reduce(
func(acc, char) => acc{
counter = acc.counter + 1,
left = select (acc.counter < idx, acc.left) => {
true = acc.left + char,
},
right = select (acc.counter >= idx, acc.right) => {
true = acc.right + char,
},
},
{counter = 0, left = "", right = ""},
mod.str
)
);
let substr = module{
str = mod.str,
start = 0,
end = len,
} => (result) {
let pkg = mod.pkg();
let reducer = func(acc, char) => acc{
counter = acc.counter + 1,
str = select ((acc.counter >= mod.start) && (acc.counter <= mod.end), acc.str) => {
true = acc.str + char,
},
};
let result = pkg.ops{str=reduce(
reducer, {counter = 0, str = ""}, mod.str).str};
};
};