240 lines
9.9 KiB
Lua
240 lines
9.9 KiB
Lua
--[[
|
|
This file is part of cratera.lua - pure-Lua Cratera-to-Lua transpiler
|
|
Copyright (C) 2019 Soni L.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
--]]
|
|
|
|
--[[
|
|
This software is based on Lua 5.1 and Lua 5.3
|
|
|
|
Lua 5.1 license:
|
|
|
|
/******************************************************************************
|
|
* Copyright (C) 1994-2012 Lua.org, PUC-Rio. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
Lua 5.3 license:
|
|
|
|
/******************************************************************************
|
|
* Copyright (C) 1994-2018 Lua.org, PUC-Rio.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
******************************************************************************/
|
|
--]]
|
|
|
|
-- a parser.lua-based cratera compiler
|
|
-- a few notes:
|
|
-- * all "next" should be tables. as well as all "super" (which should be "next").
|
|
-- (it wouldn't work properly without this)
|
|
-- * when calling into a deeper level, remember to use the second return value "retry"
|
|
-- (i.e. set it to true)
|
|
|
|
local parser = require "parser"
|
|
local selfify = parser.selfify
|
|
local STATE = parser.STATE
|
|
local l = require "luatokens".tokens
|
|
local assert, type, setmetatable = assert, type, setmetatable
|
|
|
|
local function tostring__name(self)
|
|
return getmetatable(self).__name
|
|
end
|
|
|
|
local function Upvaldesc() return {
|
|
name = nil, -- TString -- upvalue name (for debug information)
|
|
instack = false, -- lu_byte -- whether it is in stack (register)
|
|
idx = 0, -- lu_byte -- index of upvalue (in stack or in outer function's list)
|
|
} end
|
|
local function LocVar() return {
|
|
varname = nil, -- TString
|
|
startpc = 0, -- int -- first point where variable is active
|
|
endpc = 0, -- int -- first point where variable is dead
|
|
} end
|
|
local function Proto() return { -- is a GC object
|
|
numparams = 0, -- lu_byte -- number of fixed parameters
|
|
is_vararg = false, -- lu_byte but boolean
|
|
maxstacksize = 0, -- lu_byte -- number of registers needed by this function
|
|
k = {}, -- TValue * -- constants used by the function
|
|
code = {}, -- Instruction * -- opcodes
|
|
p = {}, -- Proto ** -- functions defined inside the function
|
|
lineinfo = {}, -- int * -- map from opcodes to source lines (debug information)
|
|
locvars = {}, -- LocVar * -- information about local variables (debug information)
|
|
uvalues = {}, -- Upvaldesc * -- upvalue information
|
|
} end
|
|
local function FuncState() return {
|
|
f = nil, -- Proto -- current function header
|
|
prev = nil, -- FuncState -- enclosing function
|
|
ls = nil, -- LexState -- lexical state
|
|
bl = nil, -- BlockCnt -- chain of current blocks
|
|
pc = 0, -- int -- next position to code (equivalent to 'ncode')
|
|
lasttarget = 0, -- int -- 'label' of last 'jump label'
|
|
jpc = 0, -- int -- number of pending jumps to 'pc'
|
|
--nk = 0, -- int -- number of elements in 'k'
|
|
--np = 0, -- int -- number of elements in 'p'
|
|
firstlocal = 0, -- int -- index of first local var (in Dyndata array)
|
|
nlocvars = 0, -- short -- number of elements in 'f->locvars'
|
|
nactvar = 0, -- lu_byte -- number of active local variables
|
|
nups = 0, -- lu_byte -- number of upvalues
|
|
freereg = 0, -- lu_byte -- first free register
|
|
} end
|
|
local function Labeldesc() return {
|
|
name = nil, -- TString -- label identifier
|
|
pc = nil, -- int -- position in code
|
|
line = nil, -- int -- line where it appeared
|
|
nactvar = nil, -- lu_byte -- local level where it appears in current block
|
|
} end
|
|
local function Dyndata() return {
|
|
actvar = {}, -- ArrayList of Vardesc (short) -- list of active local variables
|
|
gt = {}, -- Labellist (ArrayList of Labeldesc) -- list of pending gotos
|
|
label = {}, -- Labellist (ArrayList of Labeldesc) -- list of active labels
|
|
} end
|
|
local function ParserState() return { -- LexState
|
|
fs = nil, -- FuncState *
|
|
dyd = nil, -- Dyndata *
|
|
} end
|
|
|
|
local gotostatname = {[parser.EOZ] = false}
|
|
local gotostatnamemt = {__index=gotostatname, __name="gotostatname", __tostring=tostring__name}
|
|
gotostatname[parser.FALLBACK] = function(state, token)
|
|
assert(type(token) == "string")
|
|
state[#state+1] = "goto"
|
|
state[#state+1] = token
|
|
return state[STATE].next
|
|
end
|
|
|
|
local gotostat = {[parser.EOZ] = false}
|
|
local gotostatmt = {__index=gotostat, __name="gotostat", __tostring=tostring__name}
|
|
gotostat[l.TK_NAME] = function(state, token)
|
|
return setmetatable({next = state[STATE].next}, gotostatnamemt)
|
|
end
|
|
|
|
local singlevar = {[parser.EOZ] = false}
|
|
local singlevarmt = {__index=singlevar, __name="singlevar", __tostring=tostring__name}
|
|
singlevar[parser.FALLBACK] = function(state, token)
|
|
assert(type(token) == "string")
|
|
state[#state+1] = token
|
|
return state[STATE].next
|
|
end
|
|
|
|
local primaryexp = {[parser.EOZ] = false}
|
|
local primaryexpmt = {__name="primaryexp", __tostring=tostring__name}
|
|
primaryexp['('] = function(state, token) end
|
|
primaryexp[l.TK_NAME] = function(state, token)
|
|
return setmetatable({next=state[STATE].next}, singlevarmt)
|
|
end
|
|
|
|
local suffixedexp = {}
|
|
local suffixedexpmt = {__name="suffixedexp", __tostring=tostring__name}
|
|
suffixedexp.next = function() end
|
|
|
|
local exprstat = {}
|
|
local exprstatmt = {__index=exprstat, __name="exprstat", __tostring=tostring__name}
|
|
exprstat.next = {}
|
|
|
|
local statementt = {[parser.EOZ] = false}
|
|
local statementmt = {__index=statementt, __name="statement", __tostring=tostring__name}
|
|
local function statement(state, token)
|
|
local cur = state[STATE]
|
|
return setmetatable({next = cur.next}, statementmt), true
|
|
end
|
|
statementt[";"] = function(state, token)
|
|
state[#state+1] = token
|
|
return "next"
|
|
end
|
|
statementt[l.TK_IF] = function(state, token) end
|
|
statementt[l.TK_WHILE] = function(state, token) end
|
|
statementt[l.TK_DO] = function(state, token) end
|
|
statementt[l.TK_FOR] = function(state, token) end
|
|
statementt[l.TK_REPEAT] = function(state, token) end
|
|
statementt[l.TK_FUNCTION] = function(state, token) end
|
|
statementt[l.TK_LOCAL] = function(state, token) end
|
|
statementt[l.TK_DBCOLON] = function(state, token) end
|
|
statementt[l.TK_RETURN] = function(state, token) end
|
|
statementt[l.TK_BREAK] = function(state, token)
|
|
state[#state+1] = "break"
|
|
return "next"
|
|
end
|
|
statementt[l.TK_GOTO] = function(state, token)
|
|
return setmetatable({next = state[STATE].next}, gotostatmt)
|
|
end
|
|
statementt[parser.FALLBACK] = function(state, token)
|
|
return setmetatable({super = state[STATE].next}, exprstatmt), true
|
|
end
|
|
|
|
local statlistt = {}
|
|
local statlistmt = {__index=statlistt, __name="statlist", __tostring=tostring__name}
|
|
local function statlist(state, token)
|
|
local cur = state[STATE]
|
|
return setmetatable(selfify({super = cur.next, withuntil = cur.withuntil}, "next"), statlistmt), true
|
|
end
|
|
statlistt[l.TK_ELSE] = function() return "super", true end
|
|
statlistt[l.TK_ELSEIF] = function() return "super", true end
|
|
statlistt[l.TK_END] = function() return "super", true end
|
|
statlistt[parser.EOZ] = function() return "super", true end
|
|
statlistt[l.TK_UNTIL] = function() return "withuntil", true end
|
|
statlistt[parser.FALLBACK] = statement
|
|
|
|
local mainfunc = setmetatable({}, {__name="mainfunc", __tostring=tostring__name})
|
|
mainfunc.withuntil = "super"
|
|
mainfunc[parser.EOZ] = parser.FALLBACK
|
|
mainfunc[parser.FALLBACK] = statlist
|
|
mainfunc.next = {
|
|
[parser.EOZ] = {}
|
|
}
|
|
|
|
local defs = setmetatable({}, {__name="defs", __tostring=tostring__name})
|
|
defs[parser.EOZ] = parser.FALLBACK
|
|
defs[parser.FALLBACK] = function(state, token) return mainfunc, true end
|
|
|
|
|
|
return {
|
|
defs = defs,
|
|
}
|