Add stuff that doesn't work
This commit is contained in:
parent
e5e6533401
commit
af3acfbb80
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
until inotifywait -e modify compiler.lua testc.lua; do
|
||||||
|
date '+%s'
|
||||||
|
lua testc.lua
|
||||||
|
done
|
|
@ -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,
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
--[[
|
||||||
|
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 code is highly experimental and not very good
|
||||||
|
|
||||||
|
local parser = require "parser"
|
||||||
|
local luatokens = require "luatokens"
|
||||||
|
local compiler = require "compiler"
|
||||||
|
|
||||||
|
local CRATERA_SEED = nil -- TODO
|
||||||
|
|
||||||
|
local function cratera_load(reader)
|
||||||
|
local f, s, i = parser.stream(luatokens.defs, reader)
|
||||||
|
local nl = 1
|
||||||
|
local otherstate = {}
|
||||||
|
local f, s, i = parser.stream(compiler.defs, function()
|
||||||
|
local tokens
|
||||||
|
repeat
|
||||||
|
local pos, state, transemsg, etoken, estate = f(s, i)
|
||||||
|
otherstate.line = state.line
|
||||||
|
i = pos
|
||||||
|
if not i then return nil end
|
||||||
|
if not state then error(transemsg) end
|
||||||
|
tokens = {}
|
||||||
|
for i,v in ipairs(state) do
|
||||||
|
state[i] = nil
|
||||||
|
tokens[i] = v
|
||||||
|
end
|
||||||
|
until #tokens > 0 or not transemsg
|
||||||
|
return tokens
|
||||||
|
end, otherstate)
|
||||||
|
local function fn()
|
||||||
|
function fn()
|
||||||
|
local tokens
|
||||||
|
repeat
|
||||||
|
local pos, state, transemsg, etoken, estate, est = f(s, i)
|
||||||
|
i = pos
|
||||||
|
if not i then return nil end
|
||||||
|
if not state then error(transemsg .. " " .. tostring(etoken)) end
|
||||||
|
tokens = {""}
|
||||||
|
for i,v in ipairs(state) do
|
||||||
|
state[i] = nil
|
||||||
|
tokens[i+1] = v
|
||||||
|
end
|
||||||
|
until #tokens > 1 or not transemsg
|
||||||
|
return table.concat(tokens, " ")
|
||||||
|
end
|
||||||
|
local ret = fn()
|
||||||
|
return string.sub(ret, 2)
|
||||||
|
end
|
||||||
|
return load(function()
|
||||||
|
return fn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {load = cratera_load, CRATERA_SEED = CRATERA_SEED}
|
|
@ -272,7 +272,7 @@ do local tstring = selfify({})
|
||||||
end
|
end
|
||||||
return "string"
|
return "string"
|
||||||
end
|
end
|
||||||
tsescapes.digitc = setmetatable(selfify({[""] = tsescapes.digit, string = tstring}, "digitc"), {__index=tstring})
|
tsescapes.digitc = setmetatable(selfify({[parser.FALLBACK] = tsescapes.digit, string = tstring}, "digitc"), {__index=tstring})
|
||||||
tsescapes.digitc[1]=function(state, token, rule)
|
tsescapes.digitc[1]=function(state, token, rule)
|
||||||
if rule == nil then
|
if rule == nil then
|
||||||
collect_fallback(state, string.char(state.in_digit))
|
collect_fallback(state, string.char(state.in_digit))
|
||||||
|
@ -346,7 +346,7 @@ do local tstring = selfify({})
|
||||||
do local tseskipwhitespace = selfify(mknewline({
|
do local tseskipwhitespace = selfify(mknewline({
|
||||||
string = defs.string,
|
string = defs.string,
|
||||||
whitespace = "self",
|
whitespace = "self",
|
||||||
[""] = "string",
|
[parser.FALLBACK] = "string",
|
||||||
[1] = collect_fallback,
|
[1] = collect_fallback,
|
||||||
}, 2))
|
}, 2))
|
||||||
--tseskipwhitespace["\n"] = setmetatable({[2] = countline, ["\r"] = setmetatable({}, {__index=tseskipwhitespace})}, {__index=tseskipwhitespace})
|
--tseskipwhitespace["\n"] = setmetatable({[2] = countline, ["\r"] = setmetatable({}, {__index=tseskipwhitespace})}, {__index=tseskipwhitespace})
|
||||||
|
@ -366,7 +366,7 @@ do local tstring = selfify({})
|
||||||
tstring['\n'] = false
|
tstring['\n'] = false
|
||||||
tstring['\r'] = false
|
tstring['\r'] = false
|
||||||
|
|
||||||
tstring[""] = "self"
|
tstring[parser.FALLBACK] = "self"
|
||||||
|
|
||||||
tstring[1] = collect_fallback
|
tstring[1] = collect_fallback
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ end
|
||||||
|
|
||||||
do local tlongstring = {}
|
do local tlongstring = {}
|
||||||
defs.longstring = tlongstring
|
defs.longstring = tlongstring
|
||||||
do local tllongstring_proper = selfify({[""] = "self", ["]"] = function(state, token) state.longstring_close = 0 return "maybe_end" end})
|
do local tllongstring_proper = selfify({[parser.FALLBACK] = "self", ["]"] = function(state, token) state.longstring_close = 0 return "maybe_end" end})
|
||||||
tllongstring_proper[1] = false -- placeholder for newline handling
|
tllongstring_proper[1] = false -- placeholder for newline handling
|
||||||
tllongstring_proper[2] = collect_fallback
|
tllongstring_proper[2] = collect_fallback
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ do local tlongstring = {}
|
||||||
return "maybe_end"
|
return "maybe_end"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
tllmaybe_end[""] = "longstring_proper"
|
tllmaybe_end[parser.FALLBACK] = "longstring_proper"
|
||||||
tllmaybe_end[1] = collect_fallback
|
tllmaybe_end[1] = collect_fallback
|
||||||
tllmaybe_end[-1] = function(state, token, rule)
|
tllmaybe_end[-1] = function(state, token, rule)
|
||||||
if not rule then
|
if not rule then
|
||||||
|
@ -473,6 +473,7 @@ mknewline(defs, 1)
|
||||||
defs["-"] = "maybe_comment"
|
defs["-"] = "maybe_comment"
|
||||||
do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs})
|
do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs})
|
||||||
defs.maybe_comment = tmaybe_comment
|
defs.maybe_comment = tmaybe_comment
|
||||||
|
tmaybe_comment[parser.EOZ] = "self" -- defs
|
||||||
tmaybe_comment[-1] = function(state, token, rule)
|
tmaybe_comment[-1] = function(state, token, rule)
|
||||||
if rule ~= "comment" then
|
if rule ~= "comment" then
|
||||||
state[#state+1] = "-"
|
state[#state+1] = "-"
|
||||||
|
@ -480,12 +481,12 @@ do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs})
|
||||||
end
|
end
|
||||||
do local tmcomment = {comment_proper = selfify({})}
|
do local tmcomment = {comment_proper = selfify({})}
|
||||||
tmaybe_comment.comment = tmcomment
|
tmaybe_comment.comment = tmcomment
|
||||||
tmcomment[""] = "comment_proper"
|
tmcomment[parser.FALLBACK] = "comment_proper"
|
||||||
tmcomment["["] = "maybe_longcomment"
|
tmcomment["["] = "maybe_longcomment"
|
||||||
mknewline(tmcomment, 1, defs)
|
mknewline(tmcomment, 1, defs)
|
||||||
mknewline(tmcomment.comment_proper, 1, defs)
|
mknewline(tmcomment.comment_proper, 1, defs)
|
||||||
tmcomment.comment_proper[""] = "self"
|
tmcomment.comment_proper[parser.FALLBACK] = "self"
|
||||||
do local tllongcomment_proper = selfify({[""] = "self", ["]"] = function(state, token) state.longcomment_close = 0 return "maybe_end" end})
|
do local tllongcomment_proper = selfify({[parser.FALLBACK] = "self", ["]"] = function(state, token) state.longcomment_close = 0 return "maybe_end" end})
|
||||||
tmcomment.longcomment = tllongcomment_proper
|
tmcomment.longcomment = tllongcomment_proper
|
||||||
do local tllmaybe_end = selfify({defs = defs}, "maybe_end")
|
do local tllmaybe_end = selfify({defs = defs}, "maybe_end")
|
||||||
tllongcomment_proper.maybe_end = tllmaybe_end
|
tllongcomment_proper.maybe_end = tllmaybe_end
|
||||||
|
@ -504,7 +505,7 @@ do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs})
|
||||||
return "maybe_end"
|
return "maybe_end"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
tllmaybe_end[""] = "longcomment_proper"
|
tllmaybe_end[parser.FALLBACK] = "longcomment_proper"
|
||||||
tllmaybe_end[-1] = function(state, token, rule)
|
tllmaybe_end[-1] = function(state, token, rule)
|
||||||
if not rule then
|
if not rule then
|
||||||
state.longcomment_close = nil
|
state.longcomment_close = nil
|
||||||
|
@ -543,6 +544,7 @@ end
|
||||||
local STATE = parser.STATE
|
local STATE = parser.STATE
|
||||||
|
|
||||||
defs.multitokens = setmetatable({
|
defs.multitokens = setmetatable({
|
||||||
|
[parser.EOZ] = "self",
|
||||||
[-1] = function(state, token, rule)
|
[-1] = function(state, token, rule)
|
||||||
if not state[STATE].multitoken[token] then
|
if not state[STATE].multitoken[token] then
|
||||||
state[#state+1] = state[STATE].first
|
state[#state+1] = state[STATE].first
|
||||||
|
@ -736,18 +738,23 @@ function defs.string_open(state, token)
|
||||||
assert("this shouldn't happen")
|
assert("this shouldn't happen")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local tokens = {
|
||||||
|
TK_AND = TK_AND, TK_BREAK = TK_BREAK,
|
||||||
|
TK_DO = TK_DO, TK_ELSE = TK_ELSE, TK_ELSEIF = TK_ELSEIF, TK_END = TK_END, TK_FALSE = TK_FALSE, TK_FOR = TK_FOR, TK_FUNCTION = TK_FUNCTION,
|
||||||
|
TK_GOTO = TK_GOTO, TK_IF = TK_IF, TK_IN = TK_IN, TK_LOCAL = TK_LOCAL, TK_NIL = TK_NIL, TK_NOT = TK_NOT, TK_OR = TK_OR, TK_REPEAT = TK_REPEAT,
|
||||||
|
TK_RETURN = TK_RETURN, TK_THEN = TK_THEN, TK_TRUE = TK_TRUE, TK_UNTIL = TK_UNTIL, TK_WHILE = TK_WHILE,
|
||||||
|
TK_IDIV = TK_IDIV, TK_CONCAT = TK_CONCAT, TK_DOTS = TK_DOTS, TK_EQ = TK_EQ, TK_GE = TK_GE, TK_LE = TK_LE, TK_NE = TK_NE,
|
||||||
|
TK_SHL = TK_SHL, TK_SHR = TK_SHR,
|
||||||
|
TK_DBCOLON = TK_DBCOLON, TK_EOS = TK_EOS,
|
||||||
|
TK_FLT = TK_FLT, TK_INT = TK_INT, TK_NAME = TK_NAME, TK_STRING = TK_STRING
|
||||||
|
}
|
||||||
|
for k,v in pairs(tokens) do
|
||||||
|
setmetatable(v, {__name=k, __tostring=function(self) return getmetatable(self).__name end})
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
defs = defs,
|
defs = defs,
|
||||||
tokens = {
|
tokens = tokens,
|
||||||
TK_AND = TK_AND, TK_BREAK = TK_BREAK,
|
|
||||||
TK_DO = TK_DO, TK_ELSE = TK_ELSE, TK_ELSEIF = TK_ELSEIF, TK_END = TK_END, TK_FALSE = TK_FALSE, TK_FOR = TK_FOR, TK_FUNCTION = TK_FUNCTION,
|
|
||||||
TK_GOTO = TK_GOTO, TK_IF = TK_IF, TK_IN = TK_IN, TK_LOCAL = TK_LOCAL, TK_NIL = TK_NIL, TK_NOT = TK_NOT, TK_OR = TK_OR, TK_REPEAT = TK_REPEAT,
|
|
||||||
TK_RETURN = TK_RETURN, TK_THEN = TK_THEN, TK_TRUE = TK_TRUE, TK_UNTIL = TK_UNTIL, TK_WHILE = TK_WHILE,
|
|
||||||
TK_IDIV = TK_IDIV, TK_CONCAT = TK_CONCAT, TK_DOTS = TK_DOTS, TK_EQ = TK_EQ, TK_GE = TK_GE, TK_LE = TK_LE, TK_NE = TK_NE,
|
|
||||||
TK_SHL = TK_SHL, TK_SHR = TK_SHR,
|
|
||||||
TK_DBCOLON = TK_DBCOLON, TK_EOS = TK_EOS,
|
|
||||||
TK_FLT = TK_FLT, TK_INT = TK_INT, TK_NAME = TK_NAME, TK_STRING = TK_STRING
|
|
||||||
},
|
|
||||||
reverse_keywords = reverse_keywords,
|
reverse_keywords = reverse_keywords,
|
||||||
reverse_tokens = {
|
reverse_tokens = {
|
||||||
[TK_IDIV] = "//", [TK_CONCAT] = "..", [TK_DOTS] = "...", [TK_EQ] = "==", [TK_GE] = ">=", [TK_LE] = "<=", [TK_NE] = "~=",
|
[TK_IDIV] = "//", [TK_CONCAT] = "..", [TK_DOTS] = "...", [TK_EQ] = "==", [TK_GE] = ">=", [TK_LE] = "<=", [TK_NE] = "~=",
|
||||||
|
|
51
parser.lua
51
parser.lua
|
@ -16,34 +16,43 @@
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
|
local function ts(self) return getmetatable(self).__name end
|
||||||
|
|
||||||
-- key for STATE
|
-- key for STATE
|
||||||
local STATE = {}
|
local STATE = setmetatable({}, {__name="STATE", __tostring=ts})
|
||||||
-- key for DATA
|
-- key for DATA
|
||||||
local DATA = {}
|
local DATA = setmetatable({}, {__name="DATA", __tostring=ts})
|
||||||
-- key for GENERATOR
|
-- key for GENERATOR
|
||||||
local GEN = {}
|
local GEN = setmetatable({}, {__name="GEN", __tostring=ts})
|
||||||
-- key for DATA OFFSET
|
-- key for DATA OFFSET
|
||||||
local OFFDATA = {}
|
local OFFDATA = setmetatable({}, {__name="OFFDATA", __tostring=ts})
|
||||||
-- key for End of Stream
|
-- key for End of Stream
|
||||||
local EOZ = {}
|
local EOZ = setmetatable({}, {__name="EOZ", __tostring=ts})
|
||||||
|
-- key for number rules (prevent conflict with hooks)
|
||||||
|
local NUMBER = setmetatable({}, {__name="NUMBER", __tostring=ts})
|
||||||
|
-- key for fallback rules (prevent conflict with empty string)
|
||||||
|
local FALLBACK = setmetatable({}, {__name="FALLBACK", __tostring=ts})
|
||||||
|
|
||||||
local optimize_lookups = {}
|
local optimize_lookups = {}
|
||||||
for i=0, 255 do
|
for i=0, 255 do
|
||||||
optimize_lookups[i] = string.char(i)
|
optimize_lookups[i] = string.char(i)
|
||||||
end
|
end
|
||||||
|
|
||||||
local type, tostring
|
local type, tostring, string_byte
|
||||||
= type, tostring
|
= type, tostring, string.byte
|
||||||
|
|
||||||
local function get_next_common(state, in_pos, token)
|
local function get_next_common(state, in_pos, token)
|
||||||
-- note: must preserve "token" - do not call recursively with a different token
|
-- note: must preserve "token" - do not call recursively with a different token
|
||||||
local transition
|
local transition, retry
|
||||||
if state[STATE] then
|
local st = state[STATE]
|
||||||
local st = state[STATE]
|
if st then
|
||||||
local rule = st[token]
|
local rule = st[token]
|
||||||
if not rule and token == EOZ then
|
if not rule and token == EOZ then
|
||||||
return in_pos, state
|
return in_pos, state
|
||||||
end
|
end
|
||||||
|
if type(token) == "number" then
|
||||||
|
rule = st[NUMBER]
|
||||||
|
end
|
||||||
do -- pre-hooks
|
do -- pre-hooks
|
||||||
local pos = -1
|
local pos = -1
|
||||||
local hook = st[pos]
|
local hook = st[pos]
|
||||||
|
@ -57,7 +66,7 @@ local function get_next_common(state, in_pos, token)
|
||||||
end
|
end
|
||||||
transition = rule
|
transition = rule
|
||||||
if transition == nil then
|
if transition == nil then
|
||||||
transition = st[""]
|
transition = st[FALLBACK]
|
||||||
end
|
end
|
||||||
local recheck = true
|
local recheck = true
|
||||||
while recheck do
|
while recheck do
|
||||||
|
@ -67,7 +76,10 @@ local function get_next_common(state, in_pos, token)
|
||||||
transition = st[transition]
|
transition = st[transition]
|
||||||
recheck = true
|
recheck = true
|
||||||
elseif tytrans == "function" then
|
elseif tytrans == "function" then
|
||||||
transition = transition(state, token)
|
transition, retry = transition(state, token)
|
||||||
|
recheck = true
|
||||||
|
elseif tytrans == "table" and st[transition] ~= nil then
|
||||||
|
transition = st[transition]
|
||||||
recheck = true
|
recheck = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -88,8 +100,9 @@ local function get_next_common(state, in_pos, token)
|
||||||
if not state[STATE] then
|
if not state[STATE] then
|
||||||
-- unexpected token. stream consumer may attempt to recover,
|
-- unexpected token. stream consumer may attempt to recover,
|
||||||
-- but we do this mostly to differentiate it from "end of stream" condition.
|
-- but we do this mostly to differentiate it from "end of stream" condition.
|
||||||
return in_pos - 1, nil, "unexpected token", token, state
|
return in_pos - 1, nil, "unexpected token", token, state, st
|
||||||
end
|
end
|
||||||
|
if retry then in_pos = in_pos - 1 end
|
||||||
return in_pos, state, transition -- TODO is this what we should be returning?
|
return in_pos, state, transition -- TODO is this what we should be returning?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,7 +133,7 @@ local function get_next_string(state, in_pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
in_pos = in_pos + 1
|
in_pos = in_pos + 1
|
||||||
local token = optimize_lookups[string.byte(state[DATA], in_pos - state[OFFDATA], in_pos - state[OFFDATA])]
|
local token = optimize_lookups[string_byte(state[DATA], in_pos - state[OFFDATA], in_pos - state[OFFDATA])]
|
||||||
if token == nil then
|
if token == nil then
|
||||||
state[OFFDATA] = in_pos - 1
|
state[OFFDATA] = in_pos - 1
|
||||||
state[DATA] = state[GEN]()
|
state[DATA] = state[GEN]()
|
||||||
|
@ -129,8 +142,8 @@ local function get_next_string(state, in_pos)
|
||||||
return get_next_common(state, in_pos, token)
|
return get_next_common(state, in_pos, token)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function stream(defs, data)
|
local function stream(defs, data, state)
|
||||||
local state = {}
|
local state = state or {}
|
||||||
local fn
|
local fn
|
||||||
state[STATE] = defs
|
state[STATE] = defs
|
||||||
if type(data) == "function" then
|
if type(data) == "function" then
|
||||||
|
@ -145,8 +158,8 @@ local function stream(defs, data)
|
||||||
return fn, state, state[OFFDATA]
|
return fn, state, state[OFFDATA]
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parse(defs, data)
|
local function parse(defs, data, state)
|
||||||
for pos, state, transemsg, etoken, estate in stream(defs, data) do
|
for pos, state, transemsg, etoken, estate in stream(defs, data, state) do
|
||||||
if not state then
|
if not state then
|
||||||
-- parse error
|
-- parse error
|
||||||
return nil, transemsg, etoken, estate
|
return nil, transemsg, etoken, estate
|
||||||
|
@ -165,6 +178,8 @@ return {
|
||||||
STATE = STATE,
|
STATE = STATE,
|
||||||
COLLECT = COLLECT,
|
COLLECT = COLLECT,
|
||||||
EOZ = EOZ,
|
EOZ = EOZ,
|
||||||
|
FALLBACK = FALLBACK,
|
||||||
|
NUMBER = NUMBER,
|
||||||
stream = stream,
|
stream = stream,
|
||||||
parse = parse,
|
parse = parse,
|
||||||
-- common utility function
|
-- common utility function
|
||||||
|
|
|
@ -28,7 +28,7 @@ defs['-'] = function(state, token)
|
||||||
state.file = io.stdin
|
state.file = io.stdin
|
||||||
return "self"
|
return "self"
|
||||||
end
|
end
|
||||||
defs[""] = function(state, token)
|
defs[parser.FALLBACK] = function(state, token)
|
||||||
if state.filename then
|
if state.filename then
|
||||||
error("Must specify only one filename")
|
error("Must specify only one filename")
|
||||||
end
|
end
|
||||||
|
@ -47,7 +47,7 @@ defs[-1] = function(state, token, rule)
|
||||||
error("Unknown option: " .. token)
|
error("Unknown option: " .. token)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
defs['--'] = parser.selfify({[""] = defs[""], [parser.EOZ] = defs[parser.EOZ]})
|
defs['--'] = parser.selfify({[parser.FALLBACK] = defs[parser.FALLBACK], [parser.EOZ] = defs[parser.EOZ]})
|
||||||
|
|
||||||
local state = parser.parse(defs, arg)
|
local state = parser.parse(defs, arg)
|
||||||
local luatokens = require "luatokens"
|
local luatokens = require "luatokens"
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
local function printr(...)
|
||||||
|
print(...)
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
|
||||||
|
local realload = load
|
||||||
|
load = function(target, ...)
|
||||||
|
if type(target) == "function" then
|
||||||
|
return realload(function() return printr(target()) end, ...)
|
||||||
|
else
|
||||||
|
return realload(printr(target), ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local cratera = require "cratera"
|
||||||
|
|
||||||
|
assert(printr(cratera.load("")))()
|
|
@ -42,7 +42,7 @@ do -- trim left spaces
|
||||||
defs['\f'] = "whitespace"
|
defs['\f'] = "whitespace"
|
||||||
defs['\v'] = "whitespace"
|
defs['\v'] = "whitespace"
|
||||||
defs.whitespace = "self"
|
defs.whitespace = "self"
|
||||||
defs[''] = function(state, token)
|
defs[parser.FALLBACK] = function(state, token)
|
||||||
state[#state + 1] = token
|
state[#state + 1] = token
|
||||||
if #state > 20 then
|
if #state > 20 then
|
||||||
state[1] = table.concat(state)
|
state[1] = table.concat(state)
|
||||||
|
@ -54,7 +54,7 @@ do -- trim left spaces
|
||||||
end
|
end
|
||||||
defs.start = {}
|
defs.start = {}
|
||||||
defs.start.self = defs.start
|
defs.start.self = defs.start
|
||||||
defs.start[''] = function(state, token)
|
defs.start[parser.FALLBACK] = function(state, token)
|
||||||
state[#state + 1] = token
|
state[#state + 1] = token
|
||||||
if #state > 20 then
|
if #state > 20 then
|
||||||
state[1] = table.concat(state)
|
state[1] = table.concat(state)
|
Loading…
Reference in New Issue