1 ----------------------------------------------------------------------
2 -- Metalua: $Id: mlp_expr.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
4 -- Summary: metalua parser, expression parser. This is part of the
5 -- definition of module [mlp].
7 ----------------------------------------------------------------------
9 -- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
11 -- This software is released under the MIT Licence, see licence.txt
14 ----------------------------------------------------------------------
16 -- $Log: mlp_expr.lua,v $
17 -- Revision 1.7 2006/11/15 09:07:50 fab13n
18 -- debugged meta operators.
19 -- Added command line options handling.
21 -- Revision 1.6 2006/11/10 02:11:17 fab13n
22 -- compiler faithfulness to 5.1 improved
24 -- mlp.expr refactored
26 -- Revision 1.5 2006/11/09 09:39:57 fab13n
29 -- Revision 1.4 2006/11/07 21:29:02 fab13n
30 -- improved quasi-quoting
32 -- Revision 1.3 2006/11/07 04:38:00 fab13n
33 -- first bootstrapping version.
35 -- Revision 1.2 2006/11/05 15:08:34 fab13n
36 -- updated code generation, to be compliant with 5.1
38 ----------------------------------------------------------------------
40 --------------------------------------------------------------------------------
44 -- * [mlp.expr_list()]
47 --------------------------------------------------------------------------------
54 --------------------------------------------------------------------------------
55 -- These function wrappers (eta-expansions ctually) are just here to break
56 -- some circular dependencies between mlp_xxx.lua files.
57 --------------------------------------------------------------------------------
58 local function _expr (lx) return mlp.expr (lx) end
59 local function _table_content (lx) return mlp.table_content (lx) end
60 local function block (lx) return mlp.block (lx) end
61 local function stat (lx) return mlp.stat (lx) end
63 module ("mlp", package.seeall)
65 --------------------------------------------------------------------------------
66 -- Non-empty expression list. Actually, this isn't used here, but that's
67 -- handy to give to users.
68 --------------------------------------------------------------------------------
69 expr_list = gg.list{ _expr, separators = "," }
71 --------------------------------------------------------------------------------
72 -- Helpers for function applications / method applications
73 --------------------------------------------------------------------------------
74 func_args_content = gg.list {
75 name = "function arguments",
76 _expr, separators = ",", terminators = ")" }
78 -- Used to parse methods
79 method_args = gg.multisequence{
80 name = "function argument(s)",
81 { "{", table_content, "}" },
82 { "(", func_args_content, ")", builder = fget(1) },
83 { "+{", quote_content, "}" },
84 function(lx) local r = opt_string(lx); return r and {r} or { } end }
86 --------------------------------------------------------------------------------
87 -- [func_val] parses a function, from opening parameters parenthese to
88 -- "end" keyword included. Used for anonymous functions as well as
89 -- function declaration statements (both local and global).
91 -- It's wrapped in a [_func_val] eta expansion, so that when expr
92 -- parser uses the latter, they will notice updates of [func_val]
94 --------------------------------------------------------------------------------
95 func_params_content = gg.list{ name="function parameters",
96 gg.multisequence{ { "...", builder = "Dots" }, id },
97 separators = ",", terminators = {")", "|"} }
99 local _func_params_content = function (lx) return func_params_content(lx) end
101 func_val = gg.sequence { name="function body",
102 "(", func_params_content, ")", block, "end", builder = "Function" }
104 local _func_val = function (lx) return func_val(lx) end
106 --------------------------------------------------------------------------------
107 -- Default parser for primary expressions
108 --------------------------------------------------------------------------------
109 function id_or_literal (lx)
111 if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
114 msg = "End of file reached when an expression was expected"
115 elseif a.tag=='Keyword' then
116 msg = "An expression was expected, and `"..a[1]..
117 "' can't start an expression"
119 msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
121 gg.parse_error (lx, msg)
127 --------------------------------------------------------------------------------
128 -- Builder generator for operators. Wouldn't be worth it if "|x|" notation
129 -- were allowed, but then lua 5.1 wouldn't compile it
130 --------------------------------------------------------------------------------
132 -- opf1 = |op| |_,a| `Op{ op, a }
133 local function opf1 (op) return
134 function (_,a) return { tag="Op", op, a } end end
136 -- opf2 = |op| |a,_,b| `Op{ op, a, b }
137 local function opf2 (op) return
138 function (a,_,b) return { tag="Op", op, a, b } end end
140 -- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
141 local function opf2r (op) return
142 function (a,_,b) return { tag="Op", op, b, a } end end
144 local function op_ne(a, _, b)
145 -- The first version guarantees to return the same code as Lua,
146 -- but it relies on the non-standard 'ne' operator, which has been
147 -- suppressed from the official AST grammar (although still supported
148 -- in practice by the compiler).
149 -- return { tag="Op", "ne", a, b }
150 return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
151 first = a.lineinfo.first, last = b.lineinfo.last } } }
155 --------------------------------------------------------------------------------
157 -- complete expression
159 --------------------------------------------------------------------------------
161 -- FIXME: set line number. In [expr] transformers probably
163 expr = gg.expr { name = "expression",
165 primary = gg.multisequence{ name="expr primary",
166 { "(", _expr, ")", builder = "Paren" },
167 { "function", _func_val, builder = fget(1) },
168 { "-{", splice_content, "}", builder = fget(1) },
169 { "+{", quote_content, "}", builder = fget(1) },
170 { "nil", builder = "Nil" },
171 { "true", builder = "True" },
172 { "false", builder = "False" },
173 { "...", builder = "Dots" },
177 infix = { name="expr infix op",
178 { "+", prec = 60, builder = opf2 "add" },
179 { "-", prec = 60, builder = opf2 "sub" },
180 { "*", prec = 70, builder = opf2 "mul" },
181 { "/", prec = 70, builder = opf2 "div" },
182 { "%", prec = 70, builder = opf2 "mod" },
183 { "^", prec = 90, builder = opf2 "pow", assoc = "right" },
184 { "..", prec = 40, builder = opf2 "concat", assoc = "right" },
185 { "==", prec = 30, builder = opf2 "eq" },
186 { "~=", prec = 30, builder = op_ne },
187 { "<", prec = 30, builder = opf2 "lt" },
188 { "<=", prec = 30, builder = opf2 "le" },
189 { ">", prec = 30, builder = opf2r "lt" },
190 { ">=", prec = 30, builder = opf2r "le" },
191 { "and",prec = 20, builder = opf2 "and" },
192 { "or", prec = 10, builder = opf2 "or" } },
194 prefix = { name="expr prefix op",
195 { "not", prec = 80, builder = opf1 "not" },
196 { "#", prec = 80, builder = opf1 "len" },
197 { "-", prec = 80, builder = opf1 "unm" } },
199 suffix = { name="expr suffix op",
200 { "[", _expr, "]", builder = function (tab, idx)
201 return {tag="Index", tab, idx[1]} end},
202 { ".", id, builder = function (tab, field)
203 return {tag="Index", tab, id2string(field[1])} end },
204 { "(", func_args_content, ")", builder = function(f, args)
205 return {tag="Call", f, unpack(args[1])} end },
206 { "{", _table_content, "}", builder = function (f, arg)
207 return {tag="Call", f, arg[1]} end},
208 { ":", id, method_args, builder = function (obj, post)
209 return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
210 { "+{", quote_content, "}", builder = function (f, arg)
211 return {tag="Call", f, arg[1] } end },
212 default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg)
213 return {tag="Call", f, arg } end } } }