code / nomsu

Lines6.6K Lua5.1K PEG1.3K make117
2 others 83
Markdown60 Bourne Again Shell23
(236 lines)
1 #!/usr/bin/env nomsu -V7.0.0
2 ###
3 This file contains code that supports manipulating and using collections like lists
4 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 6
29 assume (($list, last) == 6)
30 $list, pop
31 assume (($list, last) == 5)
32 $list, remove index 1
33 assume (($list, first) == 2)
34 assume (([1, 2] + [3, 4]) == [1, 2, 3, 4])
36 ### Dict functionality
37 test:
38 $dict = {.x = 1, .y = 2, .z = 3}
39 assume #$dict == 3
40 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}).y
50 assume ((~{.x}).x == (nil))
51 $sc = ~{.x, .y}
52 $sc.y = 99
54 ### 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 as
83 [: 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 as
93 [: for ($k = $v) in $dict: add $v]
95 ### Metatable stuff
96 test:
97 $t = {}
98 set $t's metatable to {.__tostring = ($ -> "XXX")}
99 assume ("\$t" == "XXX")
101 (set $dict's metatable to $metatable) compiles to
102 "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 end
112 mt.__index = function(self, \($key as lua expr))
113 local value = \($value as lua expr)
114 self[\($key as lua expr)] = value
115 return value
116 end
117 return setmetatable(d, mt)
118 end)(\($dict as lua expr))
121 ### Sorting
122 test:
123 $x = [3, 1, 2]
124 sort $x
125 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 as
134 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 $copy
147 return $copy
149 [$items sorted by $item = $key, $items sorted by $item -> $key] all parse as
150 result of:
151 $copy = [: for $ in $items: add $]
152 sort $copy by $item = $key
153 return $copy
155 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 $unique
168 ### 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 $i
201 return $range_mt.$key
203 .__len =
204 for $self:
205 $len = (($self.last - $self.first) / $self.step + 1)
206 if ($len < 0):
207 $len = 0
208 return ($len, rounded down)
210 .__eq =
211 for ($self == $other)
212 (($self's metatable) == ($other's metatable)) and
213 ($self.first == $other.first) and
214 ($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))"
226 $range_mt.reversed = $range_mt.backwards
227 $range_mt.__unm = $range_mt.backwards
228 $range_mt.__tostring = $range_mt.as_text
229 $range_mt.as_nomsu = $range_mt.as_text
230 set $range_mt's metatable to (nil)
231 external:
232 ($first to $last by $step) means
233 setmetatable {.first = $first, .last = $last, .step = $step} $range_mt
235 ($first to $last) means
236 setmetatable {.first = $first, .last = $last, .step = 1} $range_mt