]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/extension/continue.mlua
Merge remote branch 'origin/master'
[metalua.git] / src / lib / metalua / extension / continue.mlua
1 require "metalua.walk"
2
3 ----------------------------------------------------------------------
4 -- * [loop_tags] are the tags of statements which support continue.
5 -- * [loop_keywords] are the initial keywords which trigger the parsing
6 --   of these statements: they're indeed indexed by keyword in [mlp.stat].
7 ----------------------------------------------------------------------
8
9 local loop_tags = table.transpose{ "Forin", "Fornum", "While", "Repeat" }
10 local loop_keywords = { "for", "while", "repeat" }
11
12 ----------------------------------------------------------------------
13 -- This function takes the AST of a continue-enabled loop, parse
14 -- its body to find all instances of [`Continue]. If any of them
15 -- is found ([label~=nil]), they're transformed in [`Goto{...}], and
16 -- the corresponding label is added at the end of the loop's body.
17 --
18 -- Caveat: if a [continue] appears in the non-body part of a loop
19 -- (and therefore is relative to some enclosing loop), it isn't
20 -- handled, and therefore causes a compilation error. This could
21 -- only happen due in a [`Stat{ }], however, since [`Function{ }]
22 -- cuts the search for [`Continue].
23 ----------------------------------------------------------------------
24 local function loop_transformer (ast)
25    local label
26    local cfg = { stat = { }; expr = { } }
27
28    function cfg.stat.down (x)
29       if loop_tags[x.tag] then return 'break'
30       elseif x.tag=='Continue' then
31          if not label then label = mlp.gensym 'continue' end
32          x <- `Goto{ label }
33       end
34    end
35
36    function cfg.expr.down (x)
37       return x.tag=='Function' and 'break'
38    end
39
40    local loop_body = ast.tag=="Repeat" and ast[1] or ast[#ast]
41    walk.block (cfg, loop_body)
42    if label then table.insert (loop_body, `Label{ label }) end
43 end
44
45 ----------------------------------------------------------------------
46 -- Register the transformer for each kind of loop:
47 ----------------------------------------------------------------------
48 for keyword in values (loop_keywords) do
49    mlp.stat:get(keyword).transformers:add (loop_transformer)
50 end
51
52 mlp.lexer:add "continue"
53 mlp.stat:add{ "continue", builder = ||`Continue }