6 ----------------------------------------------------------------------
8 ----------------------------------------------------------------------
10 -- Parse additional elements in a loop
11 loop_element = gg.multisequence{
12 { 'while', mlp.expr, builder = |x| `Until{ `Op{ 'not', x[1] } } },
13 { 'until', mlp.expr, builder = |x| `Until{ x[1] } },
14 { 'if', mlp.expr, builder = |x| `If{ x[1] } },
15 { 'unless', mlp.expr, builder = |x| `If{ `Op{ 'not', x[1] } } },
16 { 'for', mlp.for_header, builder = |x| x[1] } }
19 function xloop_builder(x)
20 local first, elements, body = unpack(x)
22 -------------------------------------------------------------------
23 -- If it's a regular loop, don't bloat the code
24 -------------------------------------------------------------------
25 if not next(elements) then
26 table.insert(first, body)
30 -------------------------------------------------------------------
31 -- There's no reason to treat the first element in a special way
32 -------------------------------------------------------------------
33 table.insert(elements, 1, first)
35 -------------------------------------------------------------------
36 -- if a header or a break must be able to exit the loops, ti will
37 -- set exit_label and use it (a regular break wouldn't be enough,
38 -- as it couldn't escape several nested loops.)
39 -------------------------------------------------------------------
42 if not exit_label then exit_label = mlp.gensym 'break' [1] end
43 return `Goto{ exit_label }
46 -------------------------------------------------------------------
47 -- Compile all headers elements, from last to first
48 -------------------------------------------------------------------
49 for i = #elements, 1, -1 do
53 body = `If{ cond, {body} }
55 body = +{stat: if -{cond} then -{exit()} else -{body} end }
56 | `Forin{ ... } | `Fornum{ ... } ->
57 table.insert (e, {body}); body=e
61 -------------------------------------------------------------------
62 -- Change breaks into gotos that escape all loops at once.
63 -------------------------------------------------------------------
64 local cfg = { stat = { }, expr = { } }
65 function cfg.stat.down(x)
67 | `Break -> x <- exit()
68 | `Forin{ ... } | `Fornum{ ... } | `While{ ... } | `Repeat{ ... } ->
73 function cfg.expr.down(x) if x.tag=='Function' then return 'break' end end
76 if exit_label then body = { body, `Label{ exit_label } } end
80 ----------------------------------------------------------------------
82 ----------------------------------------------------------------------
84 mlp.lexer:add 'unless'
88 loop_element_list = gg.list{ loop_element, terminators='do' }
91 'for', mlp.for_header, loop_element_list, 'do', mlp.block, 'end',
92 builder = xloop_builder }
95 'while', mlp.expr, loop_element_list, 'do', mlp.block, 'end',
96 builder = |x| xloop_builder{ `While{x[1]}, x[2], x[3] } }
99 'unless', mlp.expr, 'then', mlp.block, 'end',
100 builder = |x| +{stat: if not -{x[1]} then -{x[2]} end} }