#!/usr/bin/env nomsu -V4.12.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 % 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