nomsu/core/collections.nom
Bruce Hill b6d3cbd61c Misc changes, including text indented interpolations are now indented
relative to the text, not the opening '("', code objects can now remove
all free vars, the REPL uses global vars. Error API is changing a bit.
2019-01-01 15:07:10 -08:00

144 lines
4.1 KiB
Plaintext

#!/usr/bin/env nomsu -V6.13.12.8
#
This file contains code that supports manipulating and using collections like lists
and dictionaries.
use "core/metaprogramming.nom"
use "core/control_flow.nom"
use "core/operators.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# List functionality:
test:
$list = [1, 2, 3, 4, 5]
$visited = {}
for $i = $x in $list:
$visited.$i = (yes)
assume ($visited == {.1, .2, .3, .4, .5})
$visited = {}
for $x in $list:
$visited.$x = (yes)
assume ($visited == {.1, .2, .3, .4, .5})
assume (($list, 2 nd to last) == 4)
assume (($list, first) == 1)
assume ($list, has 3)
assume (($list, index of 3) == 3)
assume ((size of $list) == 5)
$list, add 6
assume (($list, last) == 6)
$list, pop
assume (($list, last) == 5)
$list, remove index 1
assume (($list, first) == 2)
assume (([1, 2] + [3, 4]) == [1, 2, 3, 4])
# Dict functionality
test:
$dict = {.x = 1, .y = 2, .z = 3}
assume (size of $dict) == 3
assume [: for $k = $v in {.x = 1}: add {.key = $k, .value = $v}] ==
[{.key = "x", .value = 1}]
assume ({.x = 1, .y = 1} + {.y = 10, .z = 10}) == {.x = 1, .y = 11, .z = 10}
assume ({.x = 1, .y = 1} | {.y = 10, .z = 10}) == {.x = 1, .y = 1, .z = 10}
assume ({.x = 1, .y = 1} & {.y = 10, .z = 10}) == {.y = 1}
assume ({.x = 1, .y = 1} ~ {.y = 10, .z = 10}) == {.x = 1, .z = 10}
test:
assume (([[1, 2], [3, 4]] flattened) == [1, 2, 3, 4])
externally ($lists flattened) means:
$flat = []
for $item in recursive $lists:
if ($item is a "List"):
for $ in $item:
recurse $item on $
..else:
$flat, add $item
return $flat
test:
assume ((entries in {.x = 1}) == [{.key = "x", .value = 1}])
(entries in $dict) parses as
[: for $k = $v in $dict: add {.key = $k, .value = $v}]
test:
assume ((keys in {.x = 1}) == ["x"])
[keys in $dict, keys of $dict] all parse as [: for $k = $v in $dict: add $k]
test:
assume ((values in {.x = 1}) == [1])
[values in $dict, values of $dict] all parse as [: for $k = $v in $dict: add $v]
# Metatable stuff
test:
$t = {}
set $t's metatable to {.__tostring = ($ -> "XXX")}
assume ("\$t" == "XXX")
(set $dict's metatable to $metatable) compiles to
"setmetatable(\($dict as lua expr), \($metatable as lua expr));"
[$'s metatable, $'metatable] all compile to "getmetatable(\($ as lua expr))"
test:
assume (({} with fallback $ -> ($ + 1)).10 == 11)
($dict with fallback $key -> $value) compiles to ("
(function(d)
local mt = {}
for k,v in pairs(getmetatable(d) or {}) do mt[k] = v end
mt.__index = function(self, \($key as lua expr))
local value = \($value as lua expr)
self[\($key as lua expr)] = value
return value
end
return setmetatable(d, mt)
end)(\($dict as lua expr))
")
# Sorting
test:
$x = [3, 1, 2]
sort $x
assume ($x == [1, 2, 3])
sort $x by $ = (- $)
assume ($x == [3, 2, 1])
$keys = {.1 = 999, .2 = 0, .3 = 50}
sort $x by $ = $keys.$
assume ($x == [2, 3, 1])
(sort $items) compiles to "table.sort(\($items as lua expr));"
[sort $items by $item = $key_expr, sort $items by $item -> $key_expr]
..all parse as
do:
$keys = ({} with fallback $item -> $key_expr)
lua> "table.sort(\$items, function(x,y) return \$keys[x] < \$keys[y] end)"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
assume ((sorted [3, 1, 2]) == [1, 2, 3])
externally [$items sorted, sorted $items] all mean:
$copy = [: for $ in $items: add $]
sort $copy
return $copy
[$items sorted by $item = $key, $items sorted by $item -> $key] all parse as
result of:
$copy = [: for $ in $items: add $]
sort $copy by $item = $key
return $copy
test:
assume ((unique [1, 2, 1, 3, 2, 3]) == [1, 2, 3])
externally (unique $items) means:
$unique = []
$seen = {}
for $ in $items:
unless $seen.$:
$unique, add $
$seen.$ = (yes)
return $unique