--[[ 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 . --]] --[[ 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, }