]> git.lizzy.rs Git - metalua.git/blob - src/compiler/mlp_meta.lua
Merge remote branch 'origin/master'
[metalua.git] / src / compiler / mlp_meta.lua
1 ----------------------------------------------------------------------
2 -- Metalua:  $Id: mlp_meta.lua,v 1.4 2006/11/15 09:07:50 fab13n Exp $
3 --
4 -- Summary: Meta-operations: AST quasi-quoting and splicing
5 --
6 ----------------------------------------------------------------------
7 --
8 -- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
9 --
10 -- This software is released under the MIT Licence, see licence.txt
11 -- for details.
12 --
13 ----------------------------------------------------------------------
14
15
16 --------------------------------------------------------------------------------
17 --
18 -- Exported API:
19 -- * [mlp.splice_content()]
20 -- * [mlp.quote_content()]
21 --
22 --------------------------------------------------------------------------------
23
24 module ("mlp", package.seeall)
25
26 --------------------------------------------------------------------------------
27 -- External splicing: compile an AST into a chunk, load and evaluate
28 -- that chunk, and replace the chunk by its result (which must also be
29 -- an AST).
30 --------------------------------------------------------------------------------
31
32 function splice (ast)
33    local f = mlc.function_of_ast(ast, '=splice')
34    local result=f()
35    return result
36 end
37
38 --------------------------------------------------------------------------------
39 -- Going from an AST to an AST representing that AST
40 -- the only key being lifted in this version is ["tag"]
41 --------------------------------------------------------------------------------
42 function quote (t)
43    --print("QUOTING:", _G.table.tostring(t, 60))
44    local cases = { }
45    function cases.table (t)
46       local mt = { tag = "Table" }
47       --_G.table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
48       if t.tag == "Splice" then
49          assert (#t==1, "Invalid splice")
50          local sp = t[1]
51          return sp
52       elseif t.tag then
53          _G.table.insert (mt, { tag = "Pair", quote "tag", quote (t.tag) })
54       end
55       for _, v in ipairs (t) do
56          _G.table.insert (mt, quote(v))
57       end
58       return mt
59    end
60    function cases.number (t) return { tag = "Number", t, quote = true } end
61    function cases.string (t) return { tag = "String", t, quote = true } end
62    return cases [ type (t) ] (t)
63 end
64
65 --------------------------------------------------------------------------------
66 -- when this variable is false, code inside [-{...}] is compiled and
67 -- avaluated immediately. When it's true (supposedly when we're
68 -- parsing data inside a quasiquote), [-{foo}] is replaced by
69 -- [`Splice{foo}], which will be unpacked by [quote()].
70 --------------------------------------------------------------------------------
71 in_a_quote = false
72
73 --------------------------------------------------------------------------------
74 -- Parse the inside of a "-{ ... }"
75 --------------------------------------------------------------------------------
76 function splice_content (lx)
77    local parser_name = "expr"
78    if lx:is_keyword (lx:peek(2), ":") then
79       local a = lx:next()
80       lx:next() -- skip ":"
81       assert (a.tag=="Id", "Invalid splice parser name")
82       parser_name = a[1]
83    end
84    local ast = mlp[parser_name](lx)
85    if in_a_quote then
86       --printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
87       return { tag="Splice", ast }
88    else
89       if parser_name == "expr" then ast = { { tag="Return", ast } }
90       elseif parser_name == "stat"  then ast = { ast }
91       elseif parser_name ~= "block" then
92          error ("splice content must be an expr, stat or block") end
93       --printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
94       return splice (ast)
95    end
96 end
97
98 --------------------------------------------------------------------------------
99 -- Parse the inside of a "+{ ... }"
100 --------------------------------------------------------------------------------
101 function quote_content (lx)
102    local parser 
103    if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
104       parser = mlp[id(lx)[1]]
105       lx:next()
106    else -- +{ content }
107       parser = mlp.expr
108    end
109
110    local prev_iq = in_a_quote
111    in_a_quote = true
112    --print("IN_A_QUOTE")
113    local content = parser (lx)
114    local q_content = quote (content)
115    in_a_quote = prev_iq
116    return q_content
117 end
118