(236 lines)
1 #!/usr/bin/env nomsu -V7.0.02 ###3 This file contains code that supports manipulating and using collections like lists4 and dictionaries.6 use "core/metaprogramming"7 use "core/control_flow"8 use "core/operators"10 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~12 ### List functionality:13 test:14 $list = [1, 2, 3, 4, 5]15 $visited = {}16 for ($i = $x) in $list:17 $visited.$i = (yes)18 assume ($visited == {.1, .2, .3, .4, .5})19 $visited = {}20 for $x in $list:21 $visited.$x = (yes)22 assume ($visited == {.1, .2, .3, .4, .5})23 assume (($list, 2 nd to last) == 4)24 assume (($list, first) == 1)25 assume ($list, has 3)26 assume (($list, index of 3) == 3)27 assume (#$list == 5)28 $list, add 629 assume (($list, last) == 6)30 $list, pop31 assume (($list, last) == 5)32 $list, remove index 133 assume (($list, first) == 2)34 assume (([1, 2] + [3, 4]) == [1, 2, 3, 4])36 ### Dict functionality37 test:38 $dict = {.x = 1, .y = 2, .z = 3}39 assume #$dict == 340 assume [: for ($k = $v) in {.x = 1}: add {.key = $k, .value = $v}] ==41 [{.key = "x", .value = 1}]42 assume ({.x = 1, .y = 1} + {.y = 10, .z = 10}) == {.x = 1, .y = 11, .z = 10}43 assume ({.x = 1, .y = 1} - {.y = 10, .z = 10}) == {.x = 1, .y = -9, .z = -10}44 assume ({.x = 1, .y = 1} | {.y = 10, .z = 10}) == {.x = 1, .y = 1, .z = 10}45 assume ({.x = 1, .y = 1} & {.y = 10, .z = 10}) == {.y = 1}46 assume ({.x = 1, .y = 1} ~ {.y = 10, .z = 10}) == {.x = 1, .z = 10}48 ### Set compliments:49 assume (~{.x}).y50 assume ((~{.x}).x == (nil))51 $sc = ~{.x, .y}52 $sc.y = 9954 ### For now, whether $sc.y == 99 or $sc.y == (yes) is unspecified,55 (but the actual behavior is (yes))56 assume ($sc.y and (not $sc.x))57 assume ($sc == (~{.x, .y} | {.y = 99}))59 ### Both sets:60 assume (({.x, .y} & {.y, .z}) == {.y})61 assume (({.x, .y} | {.y, .z}) == {.x, .y, .z})62 assume (({.x, .y} ~ {.y, .z}) == {.z, .x})64 ### Mixed:65 assume (({.x, .y} & ~{.y, .z}) == {.x})66 assume (({.x, .y} | ~{.y, .z}) == ~{.z})67 assume (({.x, .y} ~ ~{.y, .z}) == ~{.x})69 ### Mixed reversed:70 assume ((~{.y, .z} & {.x, .y}) == {.x})71 assume ((~{.y, .z} | {.x, .y}) == ~{.z})72 assume ((~{.y, .z} ~ {.x, .y}) == ~{.x})74 ### Both set compliments:75 assume ((~{.x, .y} & ~{.y, .z}) == ~{.x, .y, .z})76 assume ((~{.x, .y} | ~{.y, .z}) == ~{.y})77 assume ((~{.x, .y} ~ ~{.y, .z}) == {.x, .z})79 test:80 assume ((entries in {.x = 1}) == [{.key = "x", .value = 1}])82 (entries in $dict) parses as83 [: for ($k = $v) in $dict: add {.key = $k, .value = $v}]85 test:86 assume ((keys in {.x = 1}) == ["x"])88 [keys in $dict, keys of $dict] all parse as [: for ($k = $v) in $dict: add $k]89 test:90 assume ((values in {.x = 1}) == [1])92 [values in $dict, values of $dict] all parse as93 [: for ($k = $v) in $dict: add $v]95 ### Metatable stuff96 test:97 $t = {}98 set $t's metatable to {.__tostring = ($ -> "XXX")}99 assume ("\$t" == "XXX")101 (set $dict's metatable to $metatable) compiles to102 "setmetatable(\($dict as lua expr), \($metatable as lua expr));"104 [$'s metatable, $'metatable] all compile to "getmetatable(\($ as lua expr))"105 test:106 assume (({} with fallback $ -> ($ + 1)).10 == 11)108 ($dict with fallback $key -> $value) compiles to ("109 (function(d)110 local mt = {}111 for k,v in pairs(getmetatable(d) or {}) do mt[k] = v end112 mt.__index = function(self, \($key as lua expr))113 local value = \($value as lua expr)114 self[\($key as lua expr)] = value115 return value116 end117 return setmetatable(d, mt)118 end)(\($dict as lua expr))119 ")121 ### Sorting122 test:123 $x = [3, 1, 2]124 sort $x125 assume ($x == [1, 2, 3])126 sort $x by $ = -$127 assume ($x == [3, 2, 1])128 $keys = {.1 = 999, .2 = 0, .3 = 50}129 sort $x by $ = $keys.$130 assume ($x == [2, 3, 1])131 (sort $items) compiles to "table.sort(\($items as lua expr));"132 [sort $items by $item = $key_expr, sort $items by $item -> $key_expr]133 ..all parse as134 do:135 $keys = ({} with fallback $item -> $key_expr)136 lua> "table.sort(\$items, function(x,y) return \$keys[x] < \$keys[y] end)"138 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~140 external:141 test:142 assume ((sorted [3, 1, 2]) == [1, 2, 3])144 [$items sorted, sorted $items] all mean:145 $copy = [: for $ in $items: add $]146 sort $copy147 return $copy149 [$items sorted by $item = $key, $items sorted by $item -> $key] all parse as150 result of:151 $copy = [: for $ in $items: add $]152 sort $copy by $item = $key153 return $copy155 test:156 assume ((unique [1, 2, 1, 3, 2, 3]) == [1, 2, 3])158 (unique $items) means:159 $unique = []160 $seen = {}161 for $ in $items:162 unless $seen.$:163 $unique, add $164 $seen.$ = (yes)166 return $unique168 ### Ranges:169 test:170 $r = (3 to 5)171 assume ($r.2 == 4)172 assume ($r is "a Range")173 assume ((1 to 10, backwards) == (10 to 1 by -1))174 assume (#(1 to 10 by 2) == 5)175 $visited = []176 for $ in (1 to 10 by 2):177 $visited, add $178 assume ($visited == [1, 3, 5, 7, 9])179 $r = (1 to 10 by 2)180 $visited = []181 for $ in $r:182 $visited, add $183 assume ($visited == [1, 3, 5, 7, 9])185 $range_mt = {186 .__type = "a Range"187 .__index =188 for ($self's $key):189 if ($key is "a Number"):190 if (($key % 1) != 0):191 return (nil)192 $i = ($self.first + ($key - 1) * $self.step)193 if ($self.step > 0):194 if ($i > $self.last):195 return (nil)196 ..else:197 if ($i < $self.last):198 return (nil)200 return $i201 return $range_mt.$key203 .__len =204 for $self:205 $len = (($self.last - $self.first) / $self.step + 1)206 if ($len < 0):207 $len = 0208 return ($len, rounded down)210 .__eq =211 for ($self == $other)212 (($self's metatable) == ($other's metatable)) and213 ($self.first == $other.first) and214 ($self.last == $other.last) and ($self.step == $other.step)216 .backwards = (for $self ($self.last to $self.first by -$self.step))217 .__inext = $(inext), .__next = $(inext)218 .as_text =219 for $self:220 if ($self.step == 1):221 return "(\($self.first) to \($self.last))"222 ..else:223 return "(\($self.first) to \($self.last) by \($self.step))"224 }226 $range_mt.reversed = $range_mt.backwards227 $range_mt.__unm = $range_mt.backwards228 $range_mt.__tostring = $range_mt.as_text229 $range_mt.as_nomsu = $range_mt.as_text230 set $range_mt's metatable to (nil)231 external:232 ($first to $last by $step) means233 setmetatable {.first = $first, .last = $last, .step = $step} $range_mt235 ($first to $last) means236 setmetatable {.first = $first, .last = $last, .step = 1} $range_mt