// 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. // // * parse_int - function that parses an integer from the beginning of a string. // // * 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, parse_int=parse_int_func, }) { let lists = import "std/lists.ucg"; let len = lists.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 parse_int = module{ chars = [], acc = "", } => (f.maybe{val=result}) { let this = mod.this; let f = import "std/functional.ucg"; let lists = import "std/lists.ucg"; let is_int = func(c) => select (c, false) => { "0" = true, "1" = true, "2" = true, "3" = true, "4" = true, "5" = true, "6" = true, "7" = true, "8" = true, "9" = true, }; let result = select (lists.len(mod.chars) == 0, mod.acc) => { false = select (is_int(mod.chars.0), mod.acc) => { true = this{chars=lists.tail(mod.chars), acc=mod.acc+mod.chars.0}.unwrap(), }, }; }; let parse_int_func = func() => parse_int{chars=chars}.do(func(s) => int(s)); 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}; }; }; let wrap = func(str) => ops{str=str};