diff options
Diffstat (limited to 'compiler.lua')
-rw-r--r-- | compiler.lua | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/compiler.lua b/compiler.lua new file mode 100644 index 0000000..d67f9ec --- /dev/null +++ b/compiler.lua @@ -0,0 +1,239 @@ +--[[ + 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, +} |