| ------------------------------------------------------------------------------- |
| -- Copyright (c) 2006-2013 Fabien Fleutot and others. |
| -- |
| -- All rights reserved. |
| -- |
| -- This program and the accompanying materials are made available |
| -- under the terms of the Eclipse Public License v1.0 which |
| -- accompanies this distribution, and is available at |
| -- http://www.eclipse.org/legal/epl-v10.html |
| -- |
| -- This program and the accompanying materials are also made available |
| -- under the terms of the MIT public license which accompanies this |
| -- distribution, and is available at http://www.lua.org/license.html |
| -- |
| -- Contributors: |
| -- Fabien Fleutot - API and implementation |
| -- |
| ------------------------------------------------------------------------------- |
| |
| -------------------------------------------------------------------------------- |
| -- |
| -- Non-Lua syntax extensions |
| -- |
| -------------------------------------------------------------------------------- |
| |
| local gg = require 'metalua.grammar.generator' |
| |
| return function(M) |
| |
| local _M = gg.future(M) |
| |
| --------------------------------------------------------------------------- |
| -- Algebraic Datatypes |
| ---------------------------------------------------------------------------- |
| local function adt (lx) |
| local node = _M.id (lx) |
| local tagval = node[1] |
| -- tagkey = `Pair{ `String "key", `String{ -{tagval} } } |
| local tagkey = { tag="Pair", {tag="String", "tag"}, {tag="String", tagval} } |
| if lx:peek().tag == "String" or lx:peek().tag == "Number" then |
| -- TODO support boolean litterals |
| return { tag="Table", tagkey, lx:next() } |
| elseif lx:is_keyword (lx:peek(), "{") then |
| local x = M.table.table (lx) |
| table.insert (x, 1, tagkey) |
| return x |
| else return { tag="Table", tagkey } end |
| end |
| |
| M.adt = gg.sequence{ "`", adt, builder = unpack } |
| |
| M.expr.primary :add(M.adt) |
| |
| ---------------------------------------------------------------------------- |
| -- Anonymous lambda |
| ---------------------------------------------------------------------------- |
| M.lambda_expr = gg.sequence{ |
| "|", _M.func_params_content, "|", _M.expr, |
| builder = function (x) |
| local li = x[2].lineinfo |
| return { tag="Function", x[1], |
| { {tag="Return", x[2], lineinfo=li }, lineinfo=li } } |
| end } |
| |
| M.expr.primary :add (M.lambda_expr) |
| |
| -------------------------------------------------------------------------------- |
| -- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell. |
| -------------------------------------------------------------------------------- |
| function M.expr_in_backquotes (lx) return M.expr(lx, 35) end -- 35=limited precedence |
| M.expr.infix :add{ name = "infix function", |
| "`", _M.expr_in_backquotes, "`", prec = 35, assoc="left", |
| builder = function(a, op, b) return {tag="Call", op[1], a, b} end } |
| |
| -------------------------------------------------------------------------------- |
| -- C-style op+assignments |
| -- TODO: no protection against side-effects in LHS vars. |
| -------------------------------------------------------------------------------- |
| local function op_assign(kw, op) |
| local function rhs(a, b) return { tag="Op", op, a, b } end |
| local function f(a,b) |
| if #a ~= #b then gg.parse_error "assymetric operator+assignment" end |
| local right = { } |
| local r = { tag="Set", a, right } |
| for i=1, #a do right[i] = { tag="Op", op, a[i], b[i] } end |
| return r |
| end |
| M.lexer :add (kw) |
| M.assignments[kw] = f |
| end |
| |
| local ops = { add='+='; sub='-='; mul='*='; div='/=' } |
| for ast_op_name, keyword in pairs(ops) do op_assign(keyword, ast_op_name) end |
| |
| return M |
| end |