diff --git a/autotest.sh b/autotest.sh new file mode 100755 index 0000000..54b998c --- /dev/null +++ b/autotest.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +until inotifywait -e modify compiler.lua testc.lua; do + date '+%s' + lua testc.lua +done 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 . +--]] + +--[[ + 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, +} diff --git a/cratera.lua b/cratera.lua new file mode 100644 index 0000000..fabb371 --- /dev/null +++ b/cratera.lua @@ -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 . +--]] + +-- 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} diff --git a/luatokens.lua b/luatokens.lua index ecc3b6d..9ca19ac 100644 --- a/luatokens.lua +++ b/luatokens.lua @@ -272,7 +272,7 @@ do local tstring = selfify({}) end return "string" 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) if rule == nil then collect_fallback(state, string.char(state.in_digit)) @@ -346,7 +346,7 @@ do local tstring = selfify({}) do local tseskipwhitespace = selfify(mknewline({ string = defs.string, whitespace = "self", - [""] = "string", + [parser.FALLBACK] = "string", [1] = collect_fallback, }, 2)) --tseskipwhitespace["\n"] = setmetatable({[2] = countline, ["\r"] = setmetatable({}, {__index=tseskipwhitespace})}, {__index=tseskipwhitespace}) @@ -366,7 +366,7 @@ do local tstring = selfify({}) tstring['\n'] = false tstring['\r'] = false - tstring[""] = "self" + tstring[parser.FALLBACK] = "self" tstring[1] = collect_fallback @@ -385,7 +385,7 @@ end do local 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[2] = collect_fallback @@ -412,7 +412,7 @@ do local tlongstring = {} return "maybe_end" end end - tllmaybe_end[""] = "longstring_proper" + tllmaybe_end[parser.FALLBACK] = "longstring_proper" tllmaybe_end[1] = collect_fallback tllmaybe_end[-1] = function(state, token, rule) if not rule then @@ -473,6 +473,7 @@ mknewline(defs, 1) defs["-"] = "maybe_comment" do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs}) defs.maybe_comment = tmaybe_comment + tmaybe_comment[parser.EOZ] = "self" -- defs tmaybe_comment[-1] = function(state, token, rule) if rule ~= "comment" then state[#state+1] = "-" @@ -480,12 +481,12 @@ do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs}) end do local tmcomment = {comment_proper = selfify({})} tmaybe_comment.comment = tmcomment - tmcomment[""] = "comment_proper" + tmcomment[parser.FALLBACK] = "comment_proper" tmcomment["["] = "maybe_longcomment" mknewline(tmcomment, 1, defs) mknewline(tmcomment.comment_proper, 1, defs) - tmcomment.comment_proper[""] = "self" - do local tllongcomment_proper = selfify({[""] = "self", ["]"] = function(state, token) state.longcomment_close = 0 return "maybe_end" end}) + tmcomment.comment_proper[parser.FALLBACK] = "self" + do local tllongcomment_proper = selfify({[parser.FALLBACK] = "self", ["]"] = function(state, token) state.longcomment_close = 0 return "maybe_end" end}) tmcomment.longcomment = tllongcomment_proper do local tllmaybe_end = selfify({defs = defs}, "maybe_end") tllongcomment_proper.maybe_end = tllmaybe_end @@ -504,7 +505,7 @@ do local tmaybe_comment = setmetatable({["-"] = "comment"}, {__index=defs}) return "maybe_end" end end - tllmaybe_end[""] = "longcomment_proper" + tllmaybe_end[parser.FALLBACK] = "longcomment_proper" tllmaybe_end[-1] = function(state, token, rule) if not rule then state.longcomment_close = nil @@ -543,6 +544,7 @@ end local STATE = parser.STATE defs.multitokens = setmetatable({ + [parser.EOZ] = "self", [-1] = function(state, token, rule) if not state[STATE].multitoken[token] then state[#state+1] = state[STATE].first @@ -736,18 +738,23 @@ function defs.string_open(state, token) assert("this shouldn't happen") 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 { defs = defs, - 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 - }, + tokens = tokens, reverse_keywords = reverse_keywords, reverse_tokens = { [TK_IDIV] = "//", [TK_CONCAT] = "..", [TK_DOTS] = "...", [TK_EQ] = "==", [TK_GE] = ">=", [TK_LE] = "<=", [TK_NE] = "~=", diff --git a/parser.lua b/parser.lua index 7410571..34bfce2 100644 --- a/parser.lua +++ b/parser.lua @@ -16,34 +16,43 @@ along with this program. If not, see . --]] +local function ts(self) return getmetatable(self).__name end + -- key for STATE -local STATE = {} +local STATE = setmetatable({}, {__name="STATE", __tostring=ts}) -- key for DATA -local DATA = {} +local DATA = setmetatable({}, {__name="DATA", __tostring=ts}) -- key for GENERATOR -local GEN = {} +local GEN = setmetatable({}, {__name="GEN", __tostring=ts}) -- key for DATA OFFSET -local OFFDATA = {} +local OFFDATA = setmetatable({}, {__name="OFFDATA", __tostring=ts}) -- 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 = {} for i=0, 255 do optimize_lookups[i] = string.char(i) end -local type, tostring - = type, tostring +local type, tostring, string_byte + = type, tostring, string.byte local function get_next_common(state, in_pos, token) -- note: must preserve "token" - do not call recursively with a different token - local transition - if state[STATE] then - local st = state[STATE] + local transition, retry + local st = state[STATE] + if st then local rule = st[token] if not rule and token == EOZ then return in_pos, state end + if type(token) == "number" then + rule = st[NUMBER] + end do -- pre-hooks local pos = -1 local hook = st[pos] @@ -57,7 +66,7 @@ local function get_next_common(state, in_pos, token) end transition = rule if transition == nil then - transition = st[""] + transition = st[FALLBACK] end local recheck = true while recheck do @@ -67,7 +76,10 @@ local function get_next_common(state, in_pos, token) transition = st[transition] recheck = true 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 end end @@ -88,8 +100,9 @@ local function get_next_common(state, in_pos, token) if not state[STATE] then -- unexpected token. stream consumer may attempt to recover, -- 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 + if retry then in_pos = in_pos - 1 end return in_pos, state, transition -- TODO is this what we should be returning? end @@ -120,7 +133,7 @@ local function get_next_string(state, in_pos) end end 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 state[OFFDATA] = in_pos - 1 state[DATA] = state[GEN]() @@ -129,8 +142,8 @@ local function get_next_string(state, in_pos) return get_next_common(state, in_pos, token) end -local function stream(defs, data) - local state = {} +local function stream(defs, data, state) + local state = state or {} local fn state[STATE] = defs if type(data) == "function" then @@ -145,8 +158,8 @@ local function stream(defs, data) return fn, state, state[OFFDATA] end -local function parse(defs, data) - for pos, state, transemsg, etoken, estate in stream(defs, data) do +local function parse(defs, data, state) + for pos, state, transemsg, etoken, estate in stream(defs, data, state) do if not state then -- parse error return nil, transemsg, etoken, estate @@ -165,6 +178,8 @@ return { STATE = STATE, COLLECT = COLLECT, EOZ = EOZ, + FALLBACK = FALLBACK, + NUMBER = NUMBER, stream = stream, parse = parse, -- common utility function diff --git a/printtokens.lua b/printtokens.lua index 0b3b5b5..62e8fd9 100644 --- a/printtokens.lua +++ b/printtokens.lua @@ -28,7 +28,7 @@ defs['-'] = function(state, token) state.file = io.stdin return "self" end -defs[""] = function(state, token) +defs[parser.FALLBACK] = function(state, token) if state.filename then error("Must specify only one filename") end @@ -47,7 +47,7 @@ defs[-1] = function(state, token, rule) error("Unknown option: " .. token) 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 luatokens = require "luatokens" diff --git a/testc.lua b/testc.lua new file mode 100644 index 0000000..1c8f572 --- /dev/null +++ b/testc.lua @@ -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("")))() diff --git a/test.lua b/testp.lua similarity index 99% rename from test.lua rename to testp.lua index 9ad6aa0..44bd5a3 100644 --- a/test.lua +++ b/testp.lua @@ -42,7 +42,7 @@ do -- trim left spaces defs['\f'] = "whitespace" defs['\v'] = "whitespace" defs.whitespace = "self" - defs[''] = function(state, token) + defs[parser.FALLBACK] = function(state, token) state[#state + 1] = token if #state > 20 then state[1] = table.concat(state) @@ -54,7 +54,7 @@ do -- trim left spaces end defs.start = {} defs.start.self = defs.start - defs.start[''] = function(state, token) + defs.start[parser.FALLBACK] = function(state, token) state[#state + 1] = token if #state > 20 then state[1] = table.concat(state)