mirror of
https://github.com/g012/l65.git
synced 2024-06-02 12:41:28 +00:00
96 lines
3.8 KiB
Lua
96 lines
3.8 KiB
Lua
-------------------------------------------------------------------------------
|
|
-- 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 |