1 ----------------------------------------------------------------------
\r
2 -- Metalua samples: $Id$
\r
4 -- Summary: Lists by comprehension
\r
6 ----------------------------------------------------------------------
\r
8 -- Copyright (c) 2006-2007, Fabien Fleutot <metalua@gmail.com>.
\r
10 -- This software is released under the MIT Licence, see licence.txt
\r
13 --------------------------------------------------------------------------------
\r
15 -- This extension implements list comprehensions, similar to Haskell and
\r
16 -- Python syntax, to easily describe lists.
\r
18 --------------------------------------------------------------------------------
\r
20 -{ extension "match" }
\r
22 local function dots_builder (x) return `Dots{ x } end
\r
24 local function for_builder (x, h)
\r
26 | `Comp{ _, acc } -> table.insert (acc, h[1]); return x
\r
27 | `Pair{ _, _ } -> error "No explicit key in a for list generator"
\r
28 | _ -> return `Comp{ x, {h[1]} }
\r
32 local function if_builder (x, p)
\r
34 | `Comp{ _, acc } -> table.insert (acc, `If{ p[1] }); return x
\r
35 | `Pair{ _, _ } -> error "No explicit key in a list guard"
\r
36 | _ -> return `Comp{ x, p[1] }
\r
40 local function comp_builder(core, list, no_unpack)
\r
41 -- [ti] = temp var holding table.insert
\r
42 -- [v] = variable holding the table being built
\r
43 -- [r] = the core of the list being built
\r
44 local ti, v, r = mlp.gensym "table_insert", mlp.gensym "table"
\r
46 -----------------------------------------------------------------------------
\r
47 -- 1 - Build the loop's core: if it has suffix "...", every elements of the
\r
48 -- multi-return must be inserted, hence the extra [for] loop.
\r
49 -----------------------------------------------------------------------------
\r
52 local w = mlp.gensym()
\r
53 r = +{stat: for -{w} in values( -{x} ) do -{ `Call{ ti, v, w } } end }
\r
55 r = `Set{ { `Index{ v, k } }, { w } }
\r
56 | x -> r = `Call{ ti, v, x }
\r
59 -----------------------------------------------------------------------------
\r
60 -- 2 - Stack the if and for control structures, from outside to inside.
\r
61 -- This is done in a destructive way for the elements of [list].
\r
62 -----------------------------------------------------------------------------
\r
63 for i = #list, 1, -1 do
\r
64 table.insert (list[i], {r})
\r
68 return `Stat{ { `Local{ {ti, v}, { +{table.insert}, `Table} }, r }, v }
\r
70 return +{ function()
\r
71 local -{ti}, -{v} = table.insert, { }
\r
72 -{r}; return unpack(-{v})
\r
77 local function table_content_builder (list)
\r
79 | { `Comp{ y, acc } } -> return comp_builder( y, acc, "no unpack")
\r
81 local tables = { `Table }
\r
82 local ctable = tables[1]
\r
83 local function flush() ctable=`Table; table.insert(tables, ctable) end
\r
84 for x in values(list) do
\r
86 | `Comp{ y, acc } -> table.insert(ctable, comp_builder(y, acc)); flush()
\r
87 | `Dots{ y } -> table.insert(ctable, y); flush()
\r
88 | _ -> table.insert (ctable, x);
\r
92 | { x } | { x, { } } -> return x
\r
94 if #tables[#tables]==0 then table.remove(tables) end --suppress empty table
\r
95 return `Call{ +{table.cat}, unpack(tables) }
\r
100 mlp.table_field = gg.expr{ name="table cell",
\r
101 primary = mlp.table_field,
\r
102 suffix = { name="table cell suffix",
\r
103 { "...", builder = dots_builder },
\r
104 { "for", mlp.for_header, builder = for_builder },
\r
105 { "if", mlp.expr, builder = if_builder } } }
\r
107 mlp.table_content.builder = table_content_builder
\r
110 mlp.stat:add{ "for", gg.expr {
\r
111 primary = for_header,
\r
113 { "for", mlp.for_header, builder = for_builder },
\r
114 { "if", mlp.expr, builder = if_builder } } },
\r
115 "do", mlp.block, "end", builder = for_stat_builder }
\r
118 local function index_builder(a, suffix)
\r
119 match suffix[1] with
\r
120 | { { e, false } } -> return `Index{ a, e }
\r
122 local r = `Call{ +{table.isub}, a }
\r
123 local function acc(x,y) table.insert(r,x); table.insert(r,y) end
\r
124 for seq in values(ranges) do
\r
126 | { e, false } -> acc(e,e)
\r
127 | { e, f } -> acc(e,f)
\r
134 mlp.expr.suffix:del '['
\r
135 mlp.expr.suffix:add{ name="table index/range",
\r
137 gg.sequence { mlp.expr, gg.onkeyword{ "...", mlp.expr } } ,
\r
138 separators = { ",", ";" } },
\r
139 "]", builder = index_builder }
\r