aboutsummaryrefslogtreecommitdiff
path: root/lib/collections.nom
blob: d0d1f028464ed86d29489a960a8c63cfcc267aae (plain)
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#..
    This file contains code that supports manipulating and using collections like lists
    and dictionaries.

use "lib/metaprogramming.nom"
use "lib/control_flow.nom"
use "lib/operators.nom"

# List/dict functions:

# Indexing
parse [..]
    %index st in %list, %index nd in %list, %index rd in %list
    %index th in %list, %index in %list
..as: %list -> %index
compile [..]
    %index st to last in %list, %index nd to last in %list, %index rd to last in %list
    %index th to last in %list
..to: "utils.nth_to_last(\(%list as lua), \(%index as lua))"

parse [first in %list, first %list] as: 1 st in %list
parse [last in %list, last %list] as: 1 st to last in %list

# Membership testing
action [%item is in %list, %list contains %item, %list has %item]:
    for %key = %value in %list:
        if (%key is %item): return (yes)
    return (no)

action [..]
    %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 is %item): return (no)
    return (yes)

compile [%list has key %index, %list has index %index] to: ".."
    ((\(%list as lua))[\(%index as lua)] ~= nil)

compile [..]
    %list doesn't have key %index, %list does not have key %index
    %list doesn't have index %index, %list does not have index %index
..to: "((\(%list as lua))[\(%index as lua)] ~= nil)"

compile [length of %list, size of %list, size %list, number of %list, len %list] to:
    "utils.size(\(%list as lua))"

# Chained lookup
compile [%list ->* %indices] to:
    assume ((%indices's "type") is "List") or barf ".."
        Expected List for chained lookup, not \(%indices's "type")
    set %ret = "\(%list as lua)"
    for %index in (%indices's "value"):
        %ret join= "[\(%index as lua)]"
    return "\%ret"

# Assignment
compile [..]
    %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
..to code:
    "(\(%list as lua))[\(%index as lua)] = \(%new_value as lua);"

compile [append %item to %list, add %item to %list] to:
    "table.insert(\(%list as lua), \(%item as lua))"

compile [pop from %list, remove last from %list] to:
    "table.remove(\(%list as lua))"

compile [remove index %index from %list] to:
    "table.remove(\(%list as lua), \(%index as lua))"


action [flatten %lists]:
    set %flat = []
    for %list in %lists:
        for %item in %list:
            add %item to %flat
    return %flat

action [dict %items]:
    {(%->1)=(%->2) for all %items}

action [entries in %dict]:
    [{key=%k, value=%v} for %k=%v in %dict]

action [keys in %dict]:
    [%k for %k=%v in %dict]

action [values in %dict]:
    [%v for %k=%v in %dict]

# List Comprehension
immediately:
    compile [%expression for %item in %iterable] to:
        assume ((%item's "type") is "Var") or barf ".."
            List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type")
        return ".."
            (function()
                local comprehension = {};
                for i,\(%item as lua) in ipairs(\(%iterable as lua)) do
                    comprehension[i] = \(%expression as lua);
                end
                return comprehension;
            end)()
    parse [%expression for all %iterable] as: %expression for % in %iterable

    compile [%expression for %key = %value in %iterable] to:
        assume ((%key's "type") is "Var") or barf ".."
            List comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%key's "type")
        assume ((%value's "type") is "Var") or barf ".."
            List comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%value's "type")
        return ".."
            (function()
                local comprehension = {};
                for \(%key as lua), \(%value as lua) in pairs(\(%iterable as lua)) do
                    comprehension[i] = \(%expression as lua)
                end
                return comprehension;
            end)()

# Dict comprehensions
immediately:
    compile [%key = %value for %item in %iterable] to:
        assume ((%item's "type") is "Var") or barf ".."
            Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type")
        return ".."
            (function()
                local comprehension = {};
                for i,\(%item as lua) in ipairs(\(%iterable as lua)) do
                    comprehension[\(%key as lua)] = \(%value as lua)
                end
                return comprehension;
            end)()
    parse [%key = %value for all %iterable] as: %key = %value for % in %iterable

    compile [%key = %value for %src_key = %src_value in %iterable] to:
        assume ((%src_key's "type") is "Var") or barf ".."
            Dict comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%src_key's "type")
        assume ((%src_value's "type") is "Var") or barf ".."
            Dict comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%src_value's "type")
        return ".."
            (function()
                local comprehension = {};
                for \(%src_key as lua), \(%src_value as lua) in pairs(\(%iterable as lua)) do
                    comprehension[\(%key as lua)] = \(%value as lua);
                end
                return comprehension;
            end)()

# Sorting:
compile [sort %items] to: "table.sort(\(%items as lua))"
compile [sort %items by %key_expr] to: ".."
    utils.sort(\(%items as lua), function(\(\% as lua))
        return \(%key_expr as lua);
    end)

action [%items sorted]:
    %copy = (% for all %items)
    sort %copy
    return %copy
action [%items sorted by %key]:
    %copy = (% for all %items)
    sort %copy by %key
    return %copy

action [unique %items]:
    [%k for %k=%v in {%=(yes) for all %items}]

# Metatable stuff
compile [counter] to: "setmetatable({}, {__index=function() return 0; end})"
compile [default dict] to: ".."
    setmetatable({}, {__index=function(self, key)
        t = {};
        self[key] = t;
        return t;
    end})"
action [chain %dict to %fallback]:
    when (type of %fallback) is ?:
        * "table":
            =lua "setmetatable(\%dict, \%fallback)"
        * "function":
            =lua "setmetatable(\%dict, {__index=function(self, key) return (\%fallback)(nomsu, {['']=key, self=self}); end})"
        * else:
            =lua "setmetatable(\%dict, {__index=function(self, key) return (\%fallback); end})"


# TODO: maybe make a generator/coroutine?