diff --git a/std/functional.ucg b/std/functional.ucg index c991895..94503c0 100644 --- a/std/functional.ucg +++ b/std/functional.ucg @@ -1,5 +1,5 @@ // maybe is our monadic optional. It wraps a value that may or may not be the empty -// type NULL. It exports three operations. +// type NULL. It exports the following operations. // // * do - runs a user provided function of one argument on the value. // Returns a maybe wrapped result. diff --git a/std/lists.ucg b/std/lists.ucg index 8eea8cd..9f0bba9 100644 --- a/std/lists.ucg +++ b/std/lists.ucg @@ -138,4 +138,45 @@ let zip = module{ // The resulting zipped list. let result = reduce(reducer, acc, rng).result; +}; + +// Wraps a list and provides a number of helpful operations. +// +// * len - property the length of the wrapped list. +// +// * str_join - function joins list into string with provided separator `sep`. +// +// * slice - function returns a slice of the list from `start` to `end`. +// +// * enumerate - function returns a list of pairs of [index, value] from the list. +// The returned list is wrapped in the ops module. +// +// * head - function returns the head of the list as list of one item. +// +// * tail - function returns the tail of the list. +// The returned list is wrapped in the ops module. +// +// * reverse - function returns the list reversed. +// The returned list is wrapped in the ops module. +let ops = module{ + list=NULL, +} => ({len=len, + str_join=str_join, + slice=slice, + enumerate=enumerate, + tail=tail, + head=head, + reverse=reverse, + list=list, + }) { + let super = import "std/lists.ucg"; + let list = mod.list; + let len = super.len(mod.list); + let str_join = func(sep) => super.str_join{list=mod.list, sep=sep}; + + let slice = func(start, end) => super.slice{start=start, end=end, list=mod.list}; + let enumerate = func() => super.ops{list=super.enumerate{start=0, step=1, list=mod.list}}; + let tail = func() => super.ops{list=super.tail(mod.list)}; + let head = func() => super.head(mod.list); + let reverse = func() => super.ops{list=super.reverse(mod.list)}; }; \ No newline at end of file diff --git a/std/strings.ucg b/std/strings.ucg index 03790ca..e0f2a90 100644 --- a/std/strings.ucg +++ b/std/strings.ucg @@ -1,7 +1,29 @@ +// 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 character to split on. +// - `str` field defaults to the wrapped string. you can override this +// if desired. +// +// * 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, + split_on=split_on, + split_at=split_at, + substr=substr, + }) { let len = import "std/lists.ucg".len(mod.str); + let str = mod.str; let split_on = module{ on=" ", @@ -20,7 +42,7 @@ let ops = module { let result = accumulated.out + [accumulated.buf]; }; - + let split_at = func(idx) => filter( func(name, val) => name != "counter", reduce( @@ -43,13 +65,14 @@ let ops = module { start = 0, end = len, } => (result) { + let filepkg = import "std/strings.ucg"; 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 = reduce( - reducer, {counter = 0, str = ""}, mod.str).str; + let result = filepkg.ops{str=reduce( + reducer, {counter = 0, str = ""}, mod.str).str}; }; }; \ No newline at end of file diff --git a/std/testing.ucg b/std/testing.ucg index d4e6a25..526f334 100644 --- a/std/testing.ucg +++ b/std/testing.ucg @@ -7,7 +7,7 @@ let ok = module{ // descriptive message to use in output. desc=todo_desc, } => ({ok=ok, desc=desc}) { - assert mod.desc != NULL; + (mod.desc != NULL) || fail "description can't be null"; let ok = mod.test; let desc = "@" % (mod.desc); @@ -20,7 +20,7 @@ let not_ok = module{ // descriptive message to use in output. desc=todo_desc, } => ({ok=ok, desc=desc}) { - assert mod.desc != NULL; + (mod.desc != NULL) || fail "description can't be null"; let ok = not mod.test; let desc = "@" % (mod.desc); @@ -35,7 +35,7 @@ let equal = module{ right=NULL, desc="", } => ({ok=ok, desc=desc}) { - assert mod.desc != NULL; + (mod.desc != NULL) || fail "description can't be null"; let ok = mod.left == mod.right; let desc = select (mod.desc == ""), "@ == @" % (mod.left, mod.right), { @@ -51,7 +51,7 @@ let not_equal = module{ right=NULL, desc="", } => ({ok=ok, desc=desc}) { - assert mod.desc != NULL; + (mod.desc != NULL) || fail "description can't be null"; let ok = mod.left != mod.right; let desc = select (mod.desc == ""), "@ != @" % (mod.left, mod.right), { diff --git a/std/tests/lists_test.ucg b/std/tests/lists_test.ucg index d6542f0..6b2217e 100644 --- a/std/tests/lists_test.ucg +++ b/std/tests/lists_test.ucg @@ -4,22 +4,22 @@ let asserts = import "std/testing.ucg"; let list_to_join = [1, 2, 3]; assert asserts.equal{ - left=list.str_join{sep=",", list=list_to_join}, + left=list.ops{list=list_to_join}.str_join(","), right="1,2,3" }; assert asserts.equal{ - left=list.len([0, 1, 2, 3]), + left=list.ops{list=[0, 1, 2, 3]}.len, right=4, }; assert asserts.equal{ - left = list.reverse([0, 1, 2, 3]), + left = list.ops{list=[0, 1, 2, 3]}.reverse().list, right = [3, 2, 1, 0], }; assert asserts.equal{ - left=list.enumerate{list=["foo", "bar"]}, + left=list.ops{list=["foo", "bar"]}.enumerate().list, right=[[0, "foo"], [1, "bar"]], }; @@ -48,10 +48,15 @@ assert asserts.equal{ }; assert asserts.equal{ - left=list.head([0,1,2,3,4]), + left=list.ops{list=[0,1,2,3,4]}.head(), right=[0], }; +assert asserts.equal{ + left=list.ops{list=[0,1,2,3,4]}.tail().list, + right=[1,2,3,4], +}; + assert asserts.equal{ left=list.slice{end=2, list=[0,1,2,3]}, right=[0,1,2], diff --git a/std/tests/strings_test.ucg b/std/tests/strings_test.ucg index 24af532..192d5c6 100644 --- a/std/tests/strings_test.ucg +++ b/std/tests/strings_test.ucg @@ -29,16 +29,16 @@ assert asserts.equal{ }; assert asserts.equal{ - left = str_class.substr{start=1}, + left = str_class.substr{start=1}.str, right = "oo bar", }; assert asserts.equal{ - left = str_class.substr{end=5}, + left = str_class.substr{end=5}.str, right = "foo ba", }; assert asserts.equal{ - left = str_class.substr{end=8}, + left = str_class.substr{end=8}.str, right = "foo bar", }; \ No newline at end of file diff --git a/std/tests/tuples_test.ucg b/std/tests/tuples_test.ucg index 2a5f2a8..ae3e759 100644 --- a/std/tests/tuples_test.ucg +++ b/std/tests/tuples_test.ucg @@ -6,16 +6,31 @@ assert t.equal{ right = ["foo", "bar"], }; +assert t.equal{ + left = tpl.ops{tpl={foo=1, bar=2}}.fields(), + right = ["foo", "bar"], +}; + assert t.equal{ left = tpl.values{tpl={foo=1, bar=2}}, right = [1, 2], }; +assert t.equal{ + left = tpl.ops{tpl={foo=1, bar=2}}.values(), + right = [1, 2], +}; + assert t.equal{ left = tpl.iter{tpl={foo=1, bar=2}}, right = [["foo", 1], ["bar", 2]], }; +assert t.equal{ + left = tpl.ops{tpl={foo=1, bar=2}}.iter(), + right = [["foo", 1], ["bar", 2]], +}; + assert t.equal{ left = tpl.strip_nulls{tpl={foo="bar", bar=NULL}}, right = {foo="bar"}, diff --git a/std/tuples.ucg b/std/tuples.ucg index 81b7c0a..1ce43b4 100644 --- a/std/tuples.ucg +++ b/std/tuples.ucg @@ -36,6 +36,25 @@ let iter = module{ let result = reduce(func (acc, field, value) => acc + [[field, value]], [], (mod.tpl)); }; +// Wraps a tuple and provides a number of operations on it. +// +// * fields - function returns all the fields in the wrapped tuple as a list. +// +// * values - function returns all the values in the wrapped tuple as a list. +// +// * iter - function returns a list of pairs of [field, value]. +let ops = module{ + tpl = NULL, +} => ({fields=fields, values=values, iter=iter}) { + (mod.tpl != NULL) || fail "tpl must not be null"; + + let super = import "std/tuples.ucg"; + + let fields = func() => super.fields{tpl=mod.tpl}; + let values = func() => super.values{tpl=mod.tpl}; + let iter = func() => super.iter{tpl=mod.tpl}; +}; + // Strip all the null fields from a tuple. let strip_nulls = module{ tpl = NULL,