nomsu/core/collections.nom

141 lines
4.1 KiB
Plaintext

#!/usr/bin/env nomsu -V4.10.12.7
#
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 % in {x: 1}: add %] == [{key: "x", value: 1}]
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