aboutsummaryrefslogtreecommitdiff
path: root/lib/collections.nom
blob: 3751d27b76e5f72c71a94b1c04e34f24c01f5fbf (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
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 expr\[\%index as lua expr\]
    ".."|\%list as lua expr\[\%index as lua expr\]
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 expr\, \%index as lua expr\)

macro [first in %list, first %list] =:
    ".."|\%list as lua expr\[1]
macro [last in %list, last %list] =:
    ".."|compiler.utils.nth_to_last(\%list as lua expr\, 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 expr\) do
        |        \%key as lua expr\, \%value as lua expr\ = k, v
        |        \%body as lua block\
        |    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 expr\[\%index as lua expr\] ~= 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 expr\[\%index as lua expr\] ~= nil)

macro [length of %list, size of %list, number of %list, len %list] =:
    ".."|#(\%list as lua expr\)

# Chained lookup
macro [%list ->* %indices] =:
    %ret =: %list as lua expr
    for %index in %indices:
        %ret join=: ".."|[\%index as lua expr\]
    %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 "=:"?
    if ((size of (%new_value ->*["value","value"])) > 1):
        error ".."|Dict assignment operation has too many values on the right hand side.
    ".."|\%list as lua expr\[\%index as lua expr\] = \(%new_value ->*["value","value",1]) as lua expr\

macro [append %item to %list, add %item to %list] =:
    ".."|table.insert(\%list as lua expr\, \%item as lua expr\)

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:
        lua block "vars.dict[vars.pair[1]] = vars.pair[2]"
    return %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

# 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 expr\) do
        |        \%var as lua expr\ = value
        |        comprehension[i] = \%expression as lua expr\
        |    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 expr\) do
        |        vars.it = value
        |        comprehension[i] = \%expression as lua expr\
        |    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