aboutsummaryrefslogtreecommitdiff
path: root/lib/control_flow.nom
blob: 460d4dc531ee75c7767da86131a730b835c3a81a (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
require "lib/metaprogramming.nom"
require "lib/operators.nom"
require "lib/utils.nom"

# Conditionals
parse (if %condition %if_body) as lua code ".."
    |if \(%condition) then
    |    \(lua expr "vars.if_body.value")
    |end

parse (if %condition %if_body else %else_body) as lua code ".."
    |if \(%condition) then
    |    \(lua expr "vars.if_body.value")
    |else
    |    \(lua expr "vars.else_body.value")
    |end

# Return
parse (return) as lua code "do return end"
parse (return %return-value) as lua code "do return \(%return-value)"
parse (do %action) as lua expr ".."
    |(\(%action))(nomsu, setmetatable({}, {__index=vars}))


# GOTOs
parse (-> %label) as lua code ".."
    |::label_\(nomsu "var_to_lua_identifier" [%label])::
parse (go to %label) as lua code ".."
    |goto label_\(nomsu "var_to_lua_identifier" [%label])

# Loop control flow
parse (stop; stop loop; break) as lua code "break"
parse (stop for; stop for-loop; break for) as lua code "goto break_for"
parse (stop repeat; stop repeat-loop; break repeat) as lua code "goto break_repeat"
parse (stop %var; break %var) as lua code ".."
    |goto break_\(nomsu "var_to_lua_identifier" [%var])

parse (continue; continue loop) as lua code "continue"
parse (continue for; continue for-loop) as lua code "goto continue_for"
parse (continue repeat; continue repeat-loop) as lua code "goto continue_repeat"
parse (continue %var; go to next %var; on to the next %var) as lua code ".."
    |goto continue_\(nomsu "var_to_lua_identifier" [%var])

# While loops
parse (repeat %body) as lua block ".."
    |while true do
    |    \(lua expr "vars.body.value")
    |    ::continue_repeat::
    |end
    |::break_repeat::
parse (repeat while %condition %body) as lua block ".."
    |while \(%condition) do
    |    \(lua expr "vars.body.value")
    |    ::continue_repeat::
    |end
    |::break_repeat::
parse (repeat until %condition %body) as lua block ".."
    |while not (\(%condition)) do
    |    \(lua expr "vars.body.value")
    |    ::continue_repeat::
    |end
    |::break_repeat::

# Numeric range for loops
parse:
    for %var from %start to %stop by %step %body
    for %var from %start to %stop via %step %body
..as lua block ".."
    |for i=\(%start),\(%stop),\(%step) do
    # This trashes the loop variables, just like in Python.
    |    \(%var) = i
    |    \(lua expr "vars.body.value")
    |    ::continue_for::
    |    ::continue_\(nomsu "var_to_lua_identifier" [%var])::
    |end
    |::break_for::
    |::break_\(nomsu "var_to_lua_identifier" [%var])::
parse (for %var from %start to %stop %body) as: for %var from %start to %stop via 1 %body
parse:
    for all %start to %stop by %step %body
    for all %start to %stop via %step %body
..as: for % from %start to %stop via %step %body
parse (for all %start to %stop %body) as: for all %start to %stop via 1 %body

parse (for %var in %iterable %body) as lua block ".."
    |for i,value in ipairs(\(%iterable)) do
    # This trashes the loop variables, just like in Python.
    |    \(%var) = value
    |    \(lua expr "vars.body.value")
    |    ::continue_for::
    |    ::continue_\(nomsu "var_to_lua_identifier" [%var])::
    |end
    |::break_for::
    |::break_\(nomsu "var_to_lua_identifier" [%var])::
parse (for all %iterable %body) as: for % in %iterable %body

# Switch statement/multi-branch if
parse (when %body) as lua block:
    %result =: ""
    %fallthroughs =: []
    for %statement in (lua expr "vars.body.value.value"):
        %func-call =: lua expr "vars.statement.value"
        assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".."
            |Invalid format for 'when' statement. Only '*' blocks are allowed.
        %tokens =: lua expr "vars['func-call'].value"

        %star =: lua expr "vars.tokens[1]"
        assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".."
            |Invalid format for 'when' statement. Lines must begin with '*'

        %condition =: lua expr "vars.tokens[2]"
        assert %condition ".."
            |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"

        %thunk =: lua expr "vars.tokens[3]"
        if (%thunk == (nil)):
            lua block "table.insert(vars.fallthroughs, vars.condition)"
            go to next %statement

        if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
            %result join=: ".."
                |
                |do
        ..else:
            %condition =: %condition as lua
            for all %fallthroughs: %condition join= " or \(%)"
            %result join=: ".."
                |
                |if \(%condition) then
        %result join=: ".."
            |
            |    \(lua expr "vars.thunk.value")
            |    goto finished_when
            |end

        %fallthroughs =: []

    %result join=: "\n::finished_when::"
    %result

# Switch statement
parse (when %branch-value == ? %body) as lua block:
    %result =: "local branch_value = \(%branch-value)"
    %fallthroughs =: []
    for %statement in (lua expr "vars.body.value.value"):
        %func-call =: lua expr "vars.statement.value"
        assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".."
            |Invalid format for 'when' statement. Only '*' blocks are allowed.
        %tokens =: lua expr "vars['func-call'].value"

        %star =: lua expr "vars.tokens[1]"
        assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".."
            |Invalid format for 'when' statement. Lines must begin with '*'

        %condition =: lua expr "vars.tokens[2]"
        assert %condition ".."
            |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"

        %thunk =: lua expr "vars.tokens[3]"
        if (%thunk == (nil)):
            lua block "table.insert(vars.fallthroughs, vars.condition)"
            go to next %statement

        if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
            %result join=: ".."
                |
                |do
        ..else:
            %condition =: "branch_value == (\(%condition))"
            for all %fallthroughs: %condition join= " or (branch_value == \(%))"
            %result join=: ".."
                |
                |if \%condition\ then
        %result join=: ".."
            |
            |    \((lua expr "vars.thunk.value"))
            |    goto finished_when
            |end

        %fallthroughs =: []

    %result join=: "\n::finished_when::"
    %result