summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler.lua769
-rw-r--r--cratera.lua84
-rw-r--r--cratera/compiler.lua (renamed from dirtycompiler.lua)6
-rw-r--r--cratera/init.lua (renamed from dirtycratera.lua)11
-rw-r--r--cratera/luatokens.lua (renamed from luatokens.lua)4
-rw-r--r--cratera/parser.lua (renamed from parser.lua)2
-rw-r--r--printtokens.lua6
-rw-r--r--testc.lua4
-rw-r--r--testp.lua34
9 files changed, 33 insertions, 887 deletions
diff --git a/compiler.lua b/compiler.lua
deleted file mode 100644
index 0e852c0..0000000
--- a/compiler.lua
+++ /dev/null
@@ -1,769 +0,0 @@
---[[
-    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.
-******************************************************************************/
---]]
-
--- this is basically just a straight translation of the lparser.c
--- main difference is we don't care about lua_State *L
-
-local parser = require "parser"
-local selfify = parser.selfify
-local STATE = parser.STATE
-local TK = require "luatokens".TK
-local error, assert = error, assert
--- try to avoid making too many locals because Lua has a limit to how many locals you can have
-local coroutine = {create = coroutine.create,
-                   resume = coroutine.resume,
-                   yield  = coroutine.yield}
-local math = {huge  = math.huge,
-              floor = math.floor}
-local string = {format = string.format}
-
-local luaX = {} -- lexer
-local luaK = {} -- code generator
-
-luaK.ret = function() end -- FIXME
-
-luaX.next = (function()
-    local extra_tokens = {[TK.NAME] = true, [TK.INT] = true, [TK.FLT] = true, [TK.STRING] = true}
-    return function(ls)
-        ls.lastline = ls.linenumber
-        if ls.lookahead_token then
-            ls.t_token = ls.lookahead_token
-            ls.lookahead_token = nil
-            ls.t_seminfo = ls.lookahead_seminfo
-        end
-        local token = coroutine.yield()
-        ls.t_token = token
-        if extra_tokens[token] then
-            ls.t_seminfo = coroutine.yield()
-        end
-    end
-end)()
-
-local function save_token(ls)
-    local tk = ls.t_token
-    local seminfo = ls.t_seminfo
-    local c = ls[parser.COLLECT] or ls
-    if tk == TK.FLOAT then
-        local token = seminfo
-        local extra, num, den = 1, token, 1
-        assert(token == token and token >= 0, "NYI") -- the tokenizer should never output NaNs or negative values
-        if token == math.huge then
-            num, den = 1, 0
-        else
-            while num ~= math.floor(num) do
-                num = num * 2 -- always safe (I think)
-                local oldden = den
-                den = den * 2
-                if den == math.huge then -- subnormals or something?
-                    extra = oldden
-                    den = 2
-                end
-            end
-        end
-        c[#c+1] = string.format('((%d/%d)/%d)', num, den, extra)
-    elseif tk == TK.INT then
-        c[#c+1] = string.format('%d', seminfo)
-    elseif tk == TK.STRING then
-        c[#c+1] = string.format('%q', seminfo)
-    elseif tk == TK.NAME then
-        c[#c+1] = seminfo
-    else
-        c[#c+1] = tostring(tk)
-    end
-end
-
-function luaX.syntaxerror(ls, msg)
-    error("NYI")
-end
-
--- maximum number of local variables per function (must be smaller
--- than 250, due to the bytecode format)
-local MAXVARS = 200
-
--- hasmultret TODO
--- eqstr TODO
-
--- prototypes for recursive non-terminal functions
-local statement, expr
-
--- semantic error
-local function semerror(ls, msg)
-    ls.t_token = nil -- remove "near <token>" from final message
-    luaX.syntaxerror(ls, msg)
-end
-
-local function error_expected(ls, token)
-    luaX.syntaxerror(ls, string.format("%s expected", tostring(token)))
-end
-
--- errorlimit TODO
--- checklimit TODO
-
-local function testnext(ls, c)
-    if ls.t_token == c then
-        save_token(ls)
-        luaX.next(ls)
-        return true
-    end
-    return false
-end
-
-local function check(ls, c)
-    if ls.t_token ~= c then
-        error_expected(ls, c)
-    end
-end
-
-local function checknext(ls, c)
-    check(ls, c)
-    save_token(ls)
-    luaX.next(ls)
-end
-
-local function check_condition(ls, c, msg) if not c then luaX.syntaxerror(ls, msg) end end
-
-local function check_match(ls, what, who, where)
-    if not testnext(ls, what) then
-        if where == ls.linenumber then
-            error_expected(ls, what)
-        else
-            luaX.syntaxerror(ls, string.format("%s expected (to close %s at line %d)", tostring(what), tostring(who), where))
-        end
-    end
-end
-
-local function str_checkname(ls)
-    check(ls, TK.NAME)
-    local ts = ls.t_seminfo
-    save_token(ls)
-    luaX.next(ls)
-    return ts
-end
-
-local function init_exp(expdesc, expkind, i)
-    expdesc.t = NO_JUMP
-    expdesc.f = expdesc.t
-    expdesc.k = expkind
-    expdesc.val = i
-end
-
-local function codestring(ls, e, s)
-    init_exp(e, VK, luaK.stringK(ls.fs, s))
-end
-
--- checkname TODO
--- registerlocalvar TODO
--- new_localvar TODO
--- new_localvarliteral_ TODO
--- new_localvarliteral TODO
--- getlocvar TODO
--- adjustlocalvars TODO
--- removevars TODO
--- searchupvalue TODO
--- newupvalue TODO
--- searchvar TODO
--- markupval TODO
--- singlevaraux TODO
--- singlevar TODO
--- adjust_assign TODO
-
-local function enterlevel(ls)
-    -- don't bother
-    --local L = ls.L
-    --L.nCcalls = L.nCcalls + 1
-    --checklimit(ls.fs, L.nCcalls, LUAI_MAXCCALLS, "C levels")
-end
-
-local function leavelevel(ls)
-    --ls.L.nCcalls = ls.L.nCcalls - 1
-end
-
--- closegoto TODO
--- findlabel TODO
--- newlabelentry TODO
--- findgotos TODO
--- movegotosout TODO
-
-local function enterblock(fs, bl, isloop)
-    bl.isloop = isloop
-    bl.nactvar = fs.nactvar
-    bl.firstlabel = #fs.ls.dyd.label
-    bl.firstgoto = #fs.ls.dyd.gt
-    bl.upval = 0
-    bl.previous = fs.bl
-    fs.bl = bl
-    --lua_assert(fs.freereg == fs.nactvar)
-end
-
--- breaklabel TODO
--- undefgoto TODO
-
-local function leaveblock(fs)
-    local bl = fs.bl
-    local ls = fs.ls
-    if bl.previous and bl.upval then
-        -- create a 'jump to here' to close upvalues
-        local j = luaK.jump(fs)
-        luaK.patchclose(fs, j, bl.nactvar)
-        luaK.patchtohere(fs, j)
-    end
-    if bl.isloop then
-        breaklabel(ls) -- close pending breaks
-    end
-    fs.bl = bl.previous
-    removevars(fs, bl.nactvar)
-    --lua_assert(bl.nactvar == fs.nactvar)
-    fs.freereg = fs.nactvar -- free registers
-    for i=bl.firstlabel,#ls.dyd.label do ls.dyd.label[i]=nil end -- remove local labels
-    if bl.previous then
-        movegotosout(fs, bl)
-    elseif bl.firstgoto < #ls.dyd.gt then
-        undefgoto(ls, ls.dyd.gt[bl.firstgoto])
-    end
-end
-
--- addprototype TODO
-
--- codes instruction to create new closure in parent function.
--- The OP_CLOSURe instruction must use the last available register,
--- so that, if it invokes the GC, the GC knows which registers
--- are in use at that time.
-local function codeclosure(ls, v)
-    local fs = ls.fs.prev
-    init_exp(v, VRELOCABLE, luaK.codeABx(fs, OP_CLOSURE, 0, #fs.f.p - 1))
-    luaK.exp2nextreg(fs, v) -- fix it at the last register
-end
-
-local function open_func(ls, fs, bl)
-    fs.prev = ls.fs
-    fs.ls = ls
-    ls.fs = fs
-    fs.pc = 0
-    fs.lasttarget = 0
-    fs.jpc = NO_JUMP
-    fs.freereg = 0
-    fs.nactvar = 0
-    fs.firstlocal = #ls.dyd.actvar
-    fs.bl = nil
-    local f = fs.f
-    f.source = ls.source
-    f.maxstacksize = 2 -- registers 0/1 are always valid
-    enterblock(fs, bl, false)
-end
-
-local function close_func(ls)
-    local fs = ls.fs
-    local f = fs.f
-    luaK.ret(fs, 0, 0) -- final return
-    leaveblock(fs)
-    -- don't need to worry about reallocating vectors
-    --lua_assert(fs.bl == nil)
-    ls.fs = fs.prev
-end
-
-local block_follow = (function()
-    local tokens = {[TK.ELSE] = true, [TK.ELSEIF] = true, [TK.END] = true, [parser.EOZ] = true}
-    return function(ls, withuntil)
-        local tk = ls.t_token
-        return tokens[tk] or (withuntil and tk == TK.UNTIL)
-    end
-end)()
-
-local function statlist(ls)
-    -- statlist -> { stat [';'] }
-    while not block_follow(ls, true) do
-        if ls.t_token == TK_RETURN then
-            statement(ls)
-            return -- 'return' must be last statement
-        end
-        statement(ls)
-    end
-end
-
--- fieldsel TODO
-
-local function yindex(ls, v)
-    -- index -> '[' expr ']'
-    save_token(ls)
-    luaX.next(ls) -- skip the '['
-    expr(ls, v)
-    luaK.exp2val(ls.fs, v)
-    checknext(ls, ']')
-end
-
--- recfield TODO
--- closelistfield TODO
--- lastlistfield TODO
--- listfield TODO
--- field TODO
--- constructor TODO
--- parlist TODO
-
-local function body(ls, e, ismethod, line)
-    -- body -> '(' parlist ')' block END
-    -- TODO
-    error("NYI")
-end
-
-local function explist(ls, v)
-    -- explist -> expr { ',' expr }
-    local n = 1 -- at least one expression
-    expr(ls, v)
-    while testnext(ls, ',') do
-        luaK.exp2nextreg(ls.fs, v)
-        expr(ls, v)
-        n = n + 1
-    end
-    return n
-end
-
-local function funcargs(ls, f, line)
-    local fs = ls.fs
-    local args = {}
-    local base, nparams
-    local tk = ls.t_token
-    if tk == '(' then -- funcargs -> '(' [ explist ] ')'
-        save_token(ls)
-        luaX.next(ls)
-        if ls.t_token == ')' then -- arg list is empty?
-            args.k = VVOID
-        else
-            explist(ls, args)
-            luaK.setmultret(fs, args)
-        end
-        check_match(ls, ')', '(', line)
-    elseif tk == '{' then -- funcargs -> constructor
-        constructor(ls, args)
-    elseif tk == TK.STRING then -- funcargs -> STRING
-        codestring(ls, args, ls.t_seminfo)
-        save_token(ls)
-        luaX.next(ls) -- must use 'seminfo' before 'next'
-    else
-        luaX.syntaxerror(ls, "function arguments expected")
-    end
-    --lua_assert(f.k == VNONRELOC)
-    base = f.val -- base register for call
-    if hasmultret(args.k) then
-        nparams = LUA_MULTRET -- open call
-    else
-        if args.k ~= VVOID then
-            luaK.exp2nextreg(fs, args) -- close last argument
-        end
-        nparams = fs.freereg - (base+1)
-    end
-    init_exp(f, VCALL, luaK.codeABC(fs, OP_CALL, base, nparams+1, 2))
-    luaK.fixline(fs, line)
-    fs.freereg = base+1 -- call remove function and arguments and leaves
-                        -- (unless changed) one result
-end
-
-local suffixedexp -- hm.
-
-;(function() -- avoid issues with 200 locals or w/e
-    local function primaryexp(ls, v)
-        local tk = ls.t_token
-        if tk == '(' then
-            local line = ls.linenumber
-            save_token(ls)
-            luaX.next(ls)
-            expr(ls, v)
-            check_match(ls, ')', '(', line)
-            luaK.dischargevars(ls.fs, v)
-        elseif tk == TK.NAME then
-            singlevar(ls, v)
-        else
-            luaX.syntaxerror(ls, "unexpected symbol")
-        end
-    end
-
-    function suffixedexp(ls, v)
-        -- suffixedexp ->
-        --   primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
-        local fs = ls.fs
-        local line = ls.linenumber
-        primaryexp(ls, v)
-        repeat
-            local tk = ls.t_token
-            if tk == '.' then -- fieldsel
-                fieldsel(ls, v)
-            elseif tk == '[' then -- '[' exp1 ']'
-                local key = {}
-                luaK.exp2anyregup(fs, v)
-                yindex(ls, key)
-                luaK.indexed(fs, v, key)
-            elseif tk == ':' then -- ':' NAME funcargs
-                local key = {}
-                save_token(ls)
-                luaX.next(ls)
-                checkname(ls, key)
-                luaK.self(fs, v, key)
-                funcargs(ls, v, line)
-            elseif tk == '(' or tk == TK.STRING or tk == '{' then -- funcargs
-                luaK.exp2nextreg(fs, v)
-                funcargs(ls, v, line)
-            else
-                return
-            end
-        until nil
-    end
-
-    local function simpleexp(ls, v)
-        -- simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |
-        --              constructor | FUNCTION body | suffixedexp
-        local tk = ls.t_token
-        if tk == TK.FLT then
-            init_exp(v, VKFLT, 0)
-            v.val = ls.t_seminfo
-        elseif tk == TK.INT then
-            init_exp(v, VKINT, 0)
-            v.val = ls.t_seminfo
-        elseif tk == TK.STRING then
-            codestring(ls, v, ls.t_seminfo)
-        elseif tk == TK.NIL then
-            init_exp(v, VNIL, 0)
-        elseif tk == TK.TRUE then
-            init_exp(v, VTRUE, 0)
-        elseif tk == TK.FALSE then
-            init_exp(v, VFALSE, 0)
-        elseif tk == TK.DOTS then -- vararg
-            local fs = ls.fs
-            check_condition(ls, fs.f.is_vararg,
-                            "cannot use '...' outside a vararg function")
-            init_exp(v, VVARARG, luaK.codeABC(fs, OP.VARARG, 0, 1, 0))
-        elseif tk == '{' then
-            constructor(ls, v)
-        elseif tk == TK.FUNCTION then
-            save_token(ls)
-            luaX.next(ls)
-            body(ls, v, 0, ls.linenumber)
-        else
-            suffixedexp(ls, v)
-        end
-        save_token(ls)
-        luaX.next(ls)
-    end
-
-    local function getunopr(op)
-        if op == TK.NOT or
-           op == '-' or
-           op == '~' or
-           op == '#' then
-            return op
-        end
-    end
-
-    -- order intentionally swapped
-    local priority = {
-        ['+'] =       {left=10, right=10},
-        ['-'] =       {left=10, right=10},
-        ['*'] =       {left=11, right=11},
-        ['%'] =       {left=11, right=11},
-        ['^'] =       {left=14, right=13},
-        ['/'] =       {left=11, right=11},
-        [TK.IDIV] =   {left=11, right=11},
-        ['&'] =       {left=6,  right=6},
-        ['|'] =       {left=4,  right=4},
-        ['~'] =       {left=5,  right=5},
-        [TK.SHL] =    {left=7,  right=7},
-        [TK.SHR] =    {left=7,  right=7},
-        [TK.CONCAT] = {left=9,  right=8},
-        [TK.EQ] =     {left=3,  right=3},
-        ['<'] =       {left=3,  right=3},
-        [TK.LE] =     {left=3,  right=3},
-        [TK.NE] =     {left=3,  right=3},
-        ['>'] =       {left=3,  right=3},
-        [TK.GE] =     {left=3,  right=3},
-        [TK.AND] =    {left=2,  right=2},
-        [TK.OR] =     {left=1,  right=1},
-    }
-
-    -- order intentionally swapped
-    local function getbinopr(op)
-        if priority[op] then
-            return op
-        end
-    end
-
-    local UNARY_PRIORITY = 12
-
-    -- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
-    -- where 'binop' is any binary operator with a priority higher than 'limit'
-    local function subexpr(ls, v, limit)
-        enterlevel(ls)
-        local uop = getunopr(ls.t_token)
-        if uop then
-            local line = ls.linenumber
-            save_token(ls)
-            luaX.next(ls)
-            subexpr(ls, v, UNARY_PRIORITY)
-            luaK.prefix(ls.fs, uop, v, line)
-        else
-            simpleexp(ls, v)
-        end
-        -- expand while operators have priorities higher than 'limit'
-        local op = getbinopr(ls.t_token)
-        while op and priority[op].left > limit do
-            local line = ls.linenumber
-            save_token(ls)
-            luaX.next(ls)
-            luaK.infix(ls.fs, op, v)
-            -- read sub-expression with higher priority
-            local nextop = subexpr(ls, v2, priority[op].right)
-            luaK_posfix(ls.fs, op, v, v2, line)
-            op = nextop
-        end
-        leavelevel(ls)
-        return op -- return first untreated operator
-    end
-
-    function expr(ls, v)
-        subexpr(ls, v, 0)
-    end
-end)()
-
-;(function() -- avoid issues with 200 locals or w/e
-    -- block TODO
-    -- check_conflict TODO
-    -- assignment TODO
-    -- cond TODO
-
-    local function gotostat(ls, pc)
-        local line = ls.linenumber
-        local label
-        if testnext(ls, TK.GOTO) then
-            label = str_checkname(ls)
-        else
-            save_token(ls)
-            luaX.next(ls) -- skip break
-            label = "break" -- ?
-        end
-        local g = newlabelentry(ls, ls.dyd.gt, label, line, pc)
-        findlabel(ls, g) -- close it if label already defined
-    end
-
-    -- checkrepeated TODO
-
-    local function skipnoopstat(ls)
-        while ls.t_token == ';' or ls.t_token == TK.DBCOLON do
-            statement(ls)
-        end
-    end
-
-    -- labelstat TODO
-    -- whilestat TODO
-    -- repeatstat TODO
-    -- exp1 TODO
-    -- forbody TODO
-    -- fornum TODO
-    -- forlist TODO
-    -- forstat TODO
-    -- test_then_block TODO
-    -- ifstat TODO
-    -- localfunc TODO
-    -- localstat TODO
-    -- funcname TODO
-    -- funcstat TODO
-    -- exprstat TODO
-
-    local function retstat(ls)
-        local fs = ls.fs
-        local e = {}
-        local first, nret
-        if block_follow(ls, true) or ls.t_token == ';' then
-            first, nret = 0, 0
-        else
-            nret = explist(ls, e)
-            if hasmultret(e.k) then
-                luaK.setmultret(fs, e)
-                if e.k == VCALL and nret == 1 then -- tail call?
-                    --SET_OPCODE(getinstruction(fs,e), OP_TAILCALL)
-                    --lua_assert(GETARG_A(getinstruction(fs,e)) == fs.nactvar)
-                end
-                first = fs.nactvar
-                nret = LUA_MULTRET
-            else
-                if nret == 1 then
-                    first = luaK.exp2anyreg(fs, e)
-                else
-                    luaK.exp2nextreg(fs, e)
-                    first = fs.nactvar
-                    --lua_assert(nret == fs.freereg - first)
-                end
-            end
-        end
-        luaK.ret(fs, first, nret)
-        testnext(ls, ';') -- skip optional semicolon
-    end
-
-    function statement(ls)
-        local line = ls.linenumber
-        enterlevel(ls)
-        local tk = ls.t_token
-        if tk == ';' then -- stat -> ';' (empty statement)
-            save_token(ls)
-            luaX.next(ls) -- skip ';'
-        elseif tk == TK.IF then -- stat -> ifstat
-            ifstat(ls, line)
-        elseif tk == TK.WHILE then -- stat -> whilestat
-            whilestat(ls, line)
-        elseif tk == TK.DO then --> stat -> DO block END
-            save_token(ls)
-            luaX.next(ls) -- skip DO
-            block(ls)
-            check_match(ls, TK_END, TK_DO, line)
-        elseif tk == TK.FOR then -- stat -> forstat
-            forstat(ls, line)
-        elseif tk == TK.REPEAT then -- stat -> repeatstat
-            repeatstat(ls, line)
-        elseif tk == TK.FUNCTION then -- stat -> funcstat
-            funcstat(ls, line)
-        elseif tk == TK.LOCAL then -- stat -> localstat
-            save_token(ls)
-            luaX.next(ls) -- skip LOCAL
-            if testnext(ls, TK.FUNCTION) then -- local function?
-                localfunc(ls)
-            else
-                localstat(ls)
-            end
-        elseif tk == TK.DBCOLON then -- stat -> label
-            save_token(ls)
-            luaX.next(ls) -- skip double colon
-            labelstat(ls, str_checkname(ls), line)
-        elseif tk == TK.RETURN then -- stat -> retstat
-            save_token(ls)
-            luaX.next(ls) -- skip RETURN
-            retstat(ls)
-        elseif tk == TK.BREAK     -- stat -> breakstat
-            or tk == TK.GOTO then -- stat -> 'goto' NAME
-            gotostat(ls, luaK.jump(ls.fs))
-        else
-            exprstat(ls)
-        end
-        --lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
-        --           ls.fs.freereg >= ls.fs.nactvar)
-        ls.fs.freereg = ls.fs.nactvar -- free registers
-        leavelevel(ls)
-    end
-end)()
-
-local function mainfunc(ls, fs)
-    local bl = {}
-    open_func(ls, fs, bl)
-    fs.f.is_vararg = true
-    -- we don't worry about these:
-    --local v = {}
-    --init_exp(v, VLOCAL, 0)
-    --newupvalue(fs, ls.envn, &v)
-    luaX.next(ls)
-    statlist(ls)
-    check(ls, parser.EOZ)
-    close_func(ls)
-end
-
-local function worst_cratera_parser(ls) -- luaY.parser
-    local lexstate, funcstate, cl
-    lexstate = ls
-    funcstate = {}
-    cl = {}
-    lexstate.h = {}
-    cl.p = {}
-    funcstate.f = cl.p
-    funcstate.f.source = lexstate.source
-    --lua_assert(iswhite(funcstate.f))
-    --lexstate.buff = {} -- ???
-    lexstate.dyd = {actvar = {}, gt = {}, label = {}} -- ???
-    if not lexstate.linenumber then lexstate.linenumber = 1 end -- not managed by us
-    lexstate.lastline = 1
-    mainfunc(lexstate, funcstate)
-    --lua_assert(!funcstate.prev and funcstate.nups == 1 and !lexstate.fs)
-    --lua_assert(#dyd.actvar == 0 and #dyd.gt == 0 and #dyd.label == 0)
-    return cl -- close enough
-end
-
-local defs = selfify({})
-defs[parser.EOZ] = parser.FALLBACK
-defs[parser.FALLBACK] = function(state, token)
-    local coro = state.coro
-    if not coro then
-        coro = coroutine.create(worst_cratera_parser)
-        state.coro = coro
-        state.t = {} -- token
-        assert(coroutine.resume(coro, state))
-    end
-    local _, override = assert(coroutine.resume(coro, token))
-    if override then return override end
-    return "self"
-end
-
-return {
-    defs = defs,
-}
diff --git a/cratera.lua b/cratera.lua
deleted file mode 100644
index 46894c5..0000000
--- a/cratera.lua
+++ /dev/null
@@ -1,84 +0,0 @@
---[[
-    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 LUA_SIGNATURE = string.dump(function() end):sub(1,1)
-
-local function cratera_load(reader, ...)
-    local chunkname, mode, env = ...
-    if type(reader) == "string" and reader:sub(1,1) == LUA_SIGNATURE then
-        -- bytecode
-        return (loadstring or load)(reader, ...)
-    end
-    local f, s, i = parser.stream(luatokens.defs, reader)
-    if type(s[parser.DATA]) == "string" and s[parser.DATA]:sub(1,1) == LUA_SIGNATURE then
-        -- bytecode
-        local function fn()
-            fn = reader
-            return s[parser.DATA]
-        end
-        return (loadstring or load)(function() return fn() end, ...)
-    end
-    local nl = 1
-    local otherstate = {source=chunkname} -- FIXME
-    local f, s, i = parser.stream(compiler.defs, function()
-        local tokens
-        repeat
-            local pos, state, transemsg, etoken, estate = f(s, i)
-            otherstate.linenumber = 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/dirtycompiler.lua b/cratera/compiler.lua
index 779a691..2f4a998 100644
--- a/dirtycompiler.lua
+++ b/cratera/compiler.lua
@@ -1,5 +1,5 @@
 --[[
-    This file is part of cratera.lua - pure-Lua Cratera-to-Lua transpiler
+    This file is part of Cratera Compiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
@@ -21,10 +21,10 @@
 -- need to run this first
 local is51 = (function() local _ENV = {hasenv = true} return not hasenv end)()
 
-local parser = require "parser"
+local parser = require "cratera.parser"
 local selfify = parser.selfify
 local STATE = parser.STATE
-local luatokens = require "luatokens"
+local luatokens = require "cratera.luatokens"
 local reverse_keywords, reverse_tokens = luatokens.reverse_keywords, luatokens.reverse_tokens
 local TK = luatokens.TK
 local error, assert, ipairs, tostring, type = error, assert, ipairs, tostring, type
diff --git a/dirtycratera.lua b/cratera/init.lua
index 1a45709..ab76be4 100644
--- a/dirtycratera.lua
+++ b/cratera/init.lua
@@ -1,5 +1,5 @@
 --[[
-    cratera.lua - pure-Lua Cratera-to-Lua transpiler
+    Cratera Compiler - pure-Lua Cratera-to-Lua transpiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
@@ -18,14 +18,13 @@
 
 -- This code is highly experimental and not very good
 
-local parser = require "parser"
-local luatokens = require "luatokens"
-local compiler = require "dirtycompiler"
+local parser = require "cratera.parser"
+local luatokens = require "cratera.luatokens"
+local compiler = require "cratera.compiler"
 
 local LUA_SIGNATURE = string.dump(function() end):sub(1,1)
 
 local function cratera_load(reader, ...)
-    local chunkname, mode, env = ...
     if type(reader) == "string" and reader:sub(1,1) == LUA_SIGNATURE then
         -- bytecode
         return (loadstring or load)(reader, ...)
@@ -40,7 +39,7 @@ local function cratera_load(reader, ...)
         return (loadstring or load)(function() return fn() end, ...)
     end
     local nl = 1
-    local otherstate = {source=chunkname} -- FIXME
+    local otherstate = {} -- needed to match linenumbers
     local f, s, i = parser.stream(compiler.defs, function()
         local tokens
         repeat
diff --git a/luatokens.lua b/cratera/luatokens.lua
index 12fbd24..90d0c61 100644
--- a/luatokens.lua
+++ b/cratera/luatokens.lua
@@ -1,5 +1,5 @@
 --[[
-    luatokens.lua - pure-Lua Lua tokenizer
+    This file is part of Cratera Compiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
@@ -71,7 +71,7 @@
 --]]
 
 -- we need some stuff from here
-local parser = require "parser"
+local parser = require "cratera.parser"
 local selfify = parser.selfify
 local EOF = parser.EOF
 local COLLECT = parser.COLLECT
diff --git a/parser.lua b/cratera/parser.lua
index fdc2041..ade568c 100644
--- a/parser.lua
+++ b/cratera/parser.lua
@@ -1,5 +1,5 @@
 --[[
-    parser.lua - table based parsing
+    This file is part of Cratera Compiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
diff --git a/printtokens.lua b/printtokens.lua
index 62e8fd9..2cc6125 100644
--- a/printtokens.lua
+++ b/printtokens.lua
@@ -1,5 +1,5 @@
 --[[
-    This file is part of luatokens.lua - pure-Lua Lua tokenizer
+    This file is part of Cratera Compiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 --]]
 
-local parser = require "parser"
+local parser = require "cratera.parser"
 
 -- CLI argument rules
 local defs = parser.selfify({})
@@ -50,7 +50,7 @@ end
 defs['--'] = parser.selfify({[parser.FALLBACK] = defs[parser.FALLBACK], [parser.EOZ] = defs[parser.EOZ]})
 
 local state = parser.parse(defs, arg)
-local luatokens = require "luatokens"
+local luatokens = require "cratera.luatokens"
 local file = state.file
 local tokens = luatokens.defs
 local state, err, etoken, estate = parser.parse(tokens, function() return file:read(8192) end)
diff --git a/testc.lua b/testc.lua
index eb864e1..e9a793c 100644
--- a/testc.lua
+++ b/testc.lua
@@ -21,13 +21,13 @@ load = function(target, ...)
     end
 end
 
-local cratera = require "dirtycratera"
+local cratera = require "cratera"
 
 -- first test: does it handle empty files properly?
 assert(printr(cratera.load("")))()
 
 -- second test: does it handle lua code properly?
-assert(printr(cratera.load(io.open("dirtycompiler.lua"):read("*a"))))()
+assert(printr(cratera.load(io.open("cratera/compiler.lua"):read("*a"))))()
 
 print("-----------------------------------------------------------------------------------------------------------------------")
 print(table.concat(collect))
diff --git a/testp.lua b/testp.lua
index 44bd5a3..4b6434a 100644
--- a/testp.lua
+++ b/testp.lua
@@ -1,5 +1,5 @@
 --[[
-    This file is part of parser.lua - table based parsing
+    This file is part of Cratera Compiler
     Copyright (C) 2019  Soni L.
 
     This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 --]]
 
-local parser = require "parser"
+local parser = require "cratera.parser"
 
 local caseno = 0
 local function case()
@@ -76,7 +76,7 @@ do -- trim left spaces
 end -- trim left spaces
 
 do -- lua tokens
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [["hello world"]])
     local case = case()
@@ -96,7 +96,7 @@ do -- lua tokens
 end -- lua tokens
 
 do -- more lua tokens
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [["\a\b\f\n\r\t\v\\\"\'\z        \x41\65\
 "]])
@@ -117,7 +117,7 @@ do -- more lua tokens
 end -- lua tokens
 
 do -- even more lua tokens
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [["\u{000000000000000000000000000000000000000000000000000000000000041}"]])
     local case = case()
@@ -137,7 +137,7 @@ do -- even more lua tokens
 end -- lua tokens
 
 do -- even more lua tokens
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [["\u{7F}""\u{80}""\u{7FF}""\u{800}""\u{FFFF}""\u{10000}""\u{1FFFFF}""\u{200000}""\u{3FFFFFF}""\u{4000000}""\u{7FFFFFFF}"]])
     local case = case()
@@ -177,7 +177,7 @@ do -- even more lua tokens
 end -- lua tokens
 
 do -- simple lua tokens
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [[[""]])
     local case = case()
@@ -198,7 +198,7 @@ do -- simple lua tokens
 end -- lua tokens
 
 do -- simple long string
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [=[[[]]]=])
     local case = case()
@@ -218,7 +218,7 @@ do -- simple long string
 end -- long string
 
 do -- long string with depth 1
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [==[[=[]=]]==])
     local case = case()
@@ -238,7 +238,7 @@ do -- long string with depth 1
 end -- long string
 
 do -- long string with "nested" long string
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [==[[=[[[]]]=]]==])
     local case = case()
@@ -258,7 +258,7 @@ do -- long string with "nested" long string
 end -- long string
 
 do -- long string edge cases
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, "[==[]=]==][==[]]==][=[] ]=][[\n]][[\n ]]")
     local case = case()
@@ -286,7 +286,7 @@ do -- long string edge cases
 end -- long string
 
 do -- keywords
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [[
      and       break     do        else      elseif    end
@@ -330,7 +330,7 @@ do -- keywords
 end -- keywords
 
 do -- "other tokens"
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [[
      +     -     *     /     %     ^     #
@@ -386,7 +386,7 @@ do -- "other tokens"
 end -- "other tokens"
 
 do -- long comments
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [==[--[[
       
@@ -406,7 +406,7 @@ do -- long comments
 end -- long comments
 
 do -- numbers
-    local luatokens = require "luatokens"
+    local luatokens = require "cratera.luatokens"
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, [[
      3   345   0xff   0xBEBADA
@@ -453,8 +453,8 @@ do -- numbers
 end -- numbers
 
 do -- FUCK
-    local luatokens = require "luatokens"
-    local luatokens_file = io.open("./luatokens.lua", "r")
+    local luatokens = require "cratera.luatokens"
+    local luatokens_file = io.open("./cratera/luatokens.lua", "r")
     local tokens = luatokens.defs
     local state, err, etoken, estate = parser.parse(tokens, function() return luatokens_file:read(8192) end)
     local case = case()