]> git.lizzy.rs Git - metalua.git/blob - src/compiler/mlp_expr.lua
improved messages clarity, following suggestions by D. Manura
[metalua.git] / src / compiler / mlp_expr.lua
1 ----------------------------------------------------------------------
2 -- Metalua:  $Id: mlp_expr.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
3 --
4 -- Summary: metalua parser, expression parser. This is part of the
5 --   definition of module [mlp].
6 --
7 ----------------------------------------------------------------------
8 --
9 -- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
10 --
11 -- This software is released under the MIT Licence, see licence.txt
12 -- for details.
13 --
14 ----------------------------------------------------------------------
15 -- History:
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.
20 --
21 -- Revision 1.6  2006/11/10 02:11:17  fab13n
22 -- compiler faithfulness to 5.1 improved
23 -- gg.expr extended
24 -- mlp.expr refactored
25 --
26 -- Revision 1.5  2006/11/09 09:39:57  fab13n
27 -- some cleanup
28 --
29 -- Revision 1.4  2006/11/07 21:29:02  fab13n
30 -- improved quasi-quoting
31 --
32 -- Revision 1.3  2006/11/07 04:38:00  fab13n
33 -- first bootstrapping version.
34 --
35 -- Revision 1.2  2006/11/05 15:08:34  fab13n
36 -- updated code generation, to be compliant with 5.1
37 --
38 ----------------------------------------------------------------------
39
40 --------------------------------------------------------------------------------
41 --
42 -- Exported API:
43 -- * [mlp.expr()]
44 -- * [mlp.expr_list()]
45 -- * [mlp.func_val()]
46 --
47 --------------------------------------------------------------------------------
48
49 --require "gg"
50 --require "mlp_misc"
51 --require "mlp_table"
52 --require "mlp_meta"
53
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
62
63 module ("mlp", package.seeall)
64
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 = "," }
70
71 --------------------------------------------------------------------------------
72 -- Helpers for function applications / method applications
73 --------------------------------------------------------------------------------
74 func_args_content = gg.list { 
75    name = "function arguments",
76    _expr, separators = ",", terminators = ")" } 
77
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    default = function(lx) local r = opt_string(lx); return r and {r} or { } end }
84
85 --------------------------------------------------------------------------------
86 -- [func_val] parses a function, from opening parameters parenthese to
87 -- "end" keyword included. Used for anonymous functions as well as
88 -- function declaration statements (both local and global).
89 --
90 -- It's wrapped in a [_func_val] eta expansion, so that when expr
91 -- parser uses the latter, they will notice updates of [func_val]
92 -- definitions.
93 --------------------------------------------------------------------------------
94 func_params_content = gg.list{ name="function parameters",
95    gg.multisequence{ { "...", builder = "Dots" }, default = id },
96    separators  = ",", terminators = {")", "|"} } 
97
98 local _func_params_content = function (lx) return func_params_content(lx) end
99
100 func_val = gg.sequence { name="function body",
101    "(", func_params_content, ")", block, "end", builder = "Function" }
102
103 local _func_val = function (lx) return func_val(lx) end
104
105 --------------------------------------------------------------------------------
106 -- Default parser for primary expressions
107 --------------------------------------------------------------------------------
108 function id_or_literal (lx)
109    local a = lx:next()
110    if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
111       local msg
112       if a.tag=='Eof' then
113          msg = "End of file reached when an expression was expected"
114       elseif a.tag=='Keyword' then
115          msg = "An expression was expected, and `"..a[1]..
116             "' can't start an expression"
117       else
118          msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
119       end
120       gg.parse_error (lx, msg)
121    end
122    return a
123 end
124
125
126 --------------------------------------------------------------------------------
127 -- Builder generator for operators. Wouldn't be worth it if "|x|" notation
128 -- were allowed, but then lua 5.1 wouldn't compile it 
129 --------------------------------------------------------------------------------
130
131 -- opf1 = |op| |_,a| `Op{ op, a }
132 local function opf1 (op) return 
133    function (_,a) return { tag="Op", op, a } end end
134
135 -- opf2 = |op| |a,_,b| `Op{ op, a, b }
136 local function opf2 (op) return 
137    function (a,_,b) return { tag="Op", op, a, b } end end
138
139 -- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
140 local function opf2r (op) return 
141    function (a,_,b) return { tag="Op", op, b, a } end end
142
143 local function op_ne(a, _, b) 
144    -- The first version guarantees to return the same code as Lua,
145    -- but it relies on the non-standard 'ne' operator, which has been
146    -- suppressed from the official AST grammar (although still supported
147    -- in practice by the compiler).
148    -- return { tag="Op", "ne", a, b }
149    return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
150             first = a.lineinfo.first, last = b.lineinfo.last } } }
151 end
152    
153
154 --------------------------------------------------------------------------------
155 --
156 -- complete expression
157 --
158 --------------------------------------------------------------------------------
159
160 -- FIXME: set line number. In [expr] transformers probably
161
162 expr = gg.expr { name = "expression",
163
164    primary = gg.multisequence{ name="expr primary",
165       { "(", _expr, ")",           builder = "Paren" },
166       { "function", _func_val,     builder = fget(1) },
167       { "-{", splice_content, "}", builder = fget(1) },
168       { "+{", quote_content, "}",  builder = fget(1) }, 
169       { "nil",                     builder = "Nil" },
170       { "true",                    builder = "True" },
171       { "false",                   builder = "False" },
172       { "...",                     builder = "Dots" },
173       table,
174       default = id_or_literal },
175
176    infix = { name="expr infix op",
177       { "+",  prec = 60, builder = opf2 "add"  },
178       { "-",  prec = 60, builder = opf2 "sub"  },
179       { "*",  prec = 70, builder = opf2 "mul"  },
180       { "/",  prec = 70, builder = opf2 "div"  },
181       { "%",  prec = 70, builder = opf2 "mod"  },
182       { "^",  prec = 90, builder = opf2 "pow",    assoc = "right" },
183       { "..", prec = 40, builder = opf2 "concat", assoc = "right" },
184       { "==", prec = 30, builder = opf2 "eq"  },
185       { "~=", prec = 30, builder = op_ne  },
186       { "<",  prec = 30, builder = opf2 "lt"  },
187       { "<=", prec = 30, builder = opf2 "le"  },
188       { ">",  prec = 30, builder = opf2r "lt"  },
189       { ">=", prec = 30, builder = opf2r "le"  },
190       { "and",prec = 20, builder = opf2 "and" },
191       { "or", prec = 10, builder = opf2 "or"  } },
192
193    prefix = { name="expr prefix op",
194       { "not", prec = 80, builder = opf1 "not" },
195       { "#",   prec = 80, builder = opf1 "len" },
196       { "-",   prec = 80, builder = opf1 "unm" } },
197
198    suffix = { name="expr suffix op",
199       { "[", _expr, "]", builder = function (tab, idx) 
200          return {tag="Index", tab, idx[1]} end},
201       { ".", id, builder = function (tab, field) 
202          return {tag="Index", tab, id2string(field[1])} end },
203       { "(", func_args_content, ")", builder = function(f, args) 
204          return {tag="Call", f, unpack(args[1])} end },
205       { "{", _table_content, "}", builder = function (f, arg)
206          return {tag="Call", f, arg[1]} end},
207       { ":", id, method_args, builder = function (obj, post)
208          return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
209       { "+{", quote_content, "}", builder = function (f, arg) 
210          return {tag="Call", f,  arg[1] } end },
211       default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg) 
212          return {tag="Call", f, arg } end } } }