]> git.lizzy.rs Git - metalua.git/blob - metalua/compiler/parser/ext.lua
Merge branch 'master' of ssh://git.eclipse.org/gitroot/koneki/org.eclipse.koneki...
[metalua.git] / metalua / compiler / parser / ext.lua
1 -------------------------------------------------------------------------------
2 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
3 --
4 -- All rights reserved.
5 --
6 -- This program and the accompanying materials are made available
7 -- under the terms of the Eclipse Public License v1.0 which
8 -- accompanies this distribution, and is available at
9 -- http://www.eclipse.org/legal/epl-v10.html
10 --
11 -- This program and the accompanying materials are also made available
12 -- under the terms of the MIT public license which accompanies this
13 -- distribution, and is available at http://www.lua.org/license.html
14 --
15 -- Contributors:
16 --     Fabien Fleutot - API and implementation
17 --
18 -------------------------------------------------------------------------------
19
20 --------------------------------------------------------------------------------
21 --
22 -- Non-Lua syntax extensions
23 --
24 --------------------------------------------------------------------------------
25
26 local gg        = require 'metalua.grammar.generator'
27
28 return function(M)
29
30     local _M = gg.future(M)
31
32     ---------------------------------------------------------------------------
33     -- Algebraic Datatypes
34     ----------------------------------------------------------------------------
35     local function adt (lx)
36         local node = _M.id (lx)
37         local tagval = node[1]
38         -- tagkey = `Pair{ `String "key", `String{ -{tagval} } }
39         local tagkey = { tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
40         if lx:peek().tag == "String" or lx:peek().tag == "Number" then
41             -- TODO support boolean litterals
42             return { tag="Table", tagkey, lx:next() }
43         elseif lx:is_keyword (lx:peek(), "{") then
44             local x = M.table.table (lx)
45             table.insert (x, 1, tagkey)
46             return x
47         else return { tag="Table", tagkey } end
48     end
49
50     M.adt = gg.sequence{ "`", adt, builder = unpack }
51
52     M.expr.primary :add(M.adt)
53
54     ----------------------------------------------------------------------------
55     -- Anonymous lambda
56     ----------------------------------------------------------------------------
57     M.lambda_expr = gg.sequence{
58         "|", _M.func_params_content, "|", _M.expr,
59         builder = function (x)
60             local li = x[2].lineinfo
61             return { tag="Function", x[1],
62                      { {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
63         end }
64
65     M.expr.primary :add (M.lambda_expr)
66
67     --------------------------------------------------------------------------------
68     -- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
69     --------------------------------------------------------------------------------
70     function M.expr_in_backquotes (lx) return M.expr(lx, 35) end -- 35=limited precedence
71     M.expr.infix :add{ name = "infix function",
72         "`", _M.expr_in_backquotes, "`", prec = 35, assoc="left",
73         builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
74
75     --------------------------------------------------------------------------------
76     -- C-style op+assignments
77     -- TODO: no protection against side-effects in LHS vars.
78     --------------------------------------------------------------------------------
79     local function op_assign(kw, op)
80         local function rhs(a, b) return { tag="Op", op, a, b } end
81         local function f(a,b)
82             if #a ~= #b then gg.parse_error "assymetric operator+assignment" end
83             local right = { }
84             local r = { tag="Set", a, right }
85             for i=1, #a do right[i] = { tag="Op", op, a[i], b[i] } end
86             return r
87         end
88         M.lexer :add (kw)
89         M.assignments[kw] = f
90     end
91
92     local ops = { add='+='; sub='-='; mul='*='; div='/=' }
93     for ast_op_name, keyword in pairs(ops) do op_assign(keyword, ast_op_name) end
94
95     return M
96 end