1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
require "lib/metaprogramming.nom"
require "lib/control_flow.nom"
require "lib/operators.nom"
# List/dict functions:
# Indexing
macro [..]
%list's %index, %index st in %list, %index nd in %list, %index rd in %list
%index th in %list, %index in %list, %list -> %index
..=:
".."|\%list as lua\[\%index as lua\]
".."|\%list as lua\[\%index as lua\]
macro [..]
%index st to last in %list, %index nd to last in %list, %index rd to last in %list
%index th to last in %list
..=:
".."|compiler.utils.nth_to_last(\%list as lua\, \%index as lua\)
macro [first in %list, first %list] =:
".."|\%list as lua\[1]
macro [last in %list, last %list] =:
".."|compiler.utils.nth_to_last(\%list as lua\, 1)
# Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ...
macro block [for %key -> %value in %dict %body] =:
assert ((%key's "type") == "Var") ".."
|For loop has the wrong type for the key variable. Expected Var, but got: \%key's "type"\
assert ((%value's "type") == "Var") ".."
|For loop has the wrong type for the value variable. Expected Var, but got: \%value's "type"\
".."
|do
| local vars = setmetatable({}, {__index=vars})
| for k, v in pairs(\%dict as lua\) do
| \%key as lua\, \%value as lua\ = k, v
| \%body as lua\
| end
|end
# Membership testing
rule [%item is in %list, %list contains %item, %list has %item] =:
for %key -> %value in %list:
if (%key == %item): return (yes)
return (no)
macro [%list has key %index, %list has index %index] =: ".."
|(\%list as lua\[\%index as lua\] ~= nil)
rule [..]
%item isn't in %list, %item is not in %list
%list doesn't contain %item, %list does not contain %item
%list doesn't have %item, %list does not have %item
..=:
for %key -> %value in %list:
if (%key == %item): return (no)
return (yes)
macro [..]
%list doesn't have key %index, %list does not have key %index
%list doesn't have index %index, %list does not have index %index
..=: ".."|(\%list as lua\[\%index as lua\] ~= nil)
macro [length of %list, size of %list, number of %list, len %list] =:
".."|#(\%list as lua\)
# Chained lookup
macro [%list ->* %indices] =:
assert ((%indices's "type") == "List") ".."
|Expected List for chained lookup, not \%indices's "type"\
%ret =: ".."|(\%list as lua\)
for %index in (%indices's "value"):
%ret join=: ".."|[\%index as lua\]
".."|(\%ret\)
# Assignment
macro block [..]
%list's %index = %new_value, %index st in %list = %new_value, %index nd in %list = %new_value
%index rd in %list = %new_value, %index th in %list = %new_value, %index in %list = %new_value
%list -> %index = %new_value
..=:
assert ((%new_value's "type") == "Thunk") ".."
|Dict assignment operation has the wrong type for the right hand side.
|Expected Thunk, but got \%new_value's "type"\.
|Maybe you used "=" instead of "=:"?
assert ((size of (%new_value ->*["value","value"])) == 1) ".."
|Dict assignment operation has the wrong number of values on the right hand side.
|Expected 1 value, but got \repr %new_value\
%new_value =: %new_value ->*["value","value",1]
if ((%new_value's "type") == "Statement"): %new_value =: %new_value's "value"
".."|\%list as lua\[\%index as lua\] = \%new_value as lua\
macro [append %item to %list, add %item to %list] =:
".."|table.insert(\%list as lua\, \%item as lua\)
rule [flatten %lists] =:
%flat =: []
for %list in %lists:
for %item in %list:
add %item to %flat
%flat
rule [dict %items] =:
%dict =: []
for %pair in %items:
%dict -> (first in %pair) =: last in %pair
%dict
rule [entries in %dict] =:
lua block ".."
|local items = {}
|for k,v in pairs(vars.dict) do
| table.insert(items, {key=k,value=v})
|end
|return items
rule [keys in %dict] =:
lua block ".."
|local items = {}
|for k,v in pairs(vars.dict) do
| table.insert(items, k)
|end
|return items
rule [values in %dict] =:
lua block ".."
|local items = {}
|for k,v in pairs(vars.dict) do
| table.insert(items, v)
|end
|return items
# List Comprehension
macro [%expression for %var in %iterable] =:
assert ((%var's "type") == "Var") ".."
|List comprehension has the wrong type for the loop variable. Expected Var, but got: \%var's "type"\
".."
|(function(game, vars)
| local comprehension = {}
| for i,value in ipairs(\%iterable as lua\) do
| \%var as lua\ = value
| comprehension[i] = \%expression as lua\
| end
| return comprehension
|end)(game, setmetatable({}, {__index=vars}))
macro [%expression for all %iterable] =:
".."|(function(game, vars)
| local comprehension = {}
| for i,value in ipairs(\%iterable as lua\) do
| vars.it = value
| comprehension[i] = \%expression as lua\
| end
| return comprehension
|end)(game, setmetatable({}, {__index=vars}))
# TODO: maybe make a generator/coroutine?
#.. Dict comprehensions can be accomplished okay by doing:
dict ([new_key using (%it's "key"), new_value using (%it's "value")] for all (entries in %dict))
or something similar
# TODO: fix compiler bugs
pass
|