summary refs log tree commit diff stats
path: root/cratera/compiler.lua
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2024-05-27 00:11:26 -0300
committerSoniEx2 <endermoneymod@gmail.com>2024-05-27 00:11:26 -0300
commite62ec5ac36188cb12411a8c720daebce77ecf645 (patch)
treeb1a2ce8e95ffc6e92ee31c1e271b0fcafe8a0b2f /cratera/compiler.lua
parent9dea1c26b487ae723d99ba1e5e5887b09aec87dd (diff)
Set up a "build system"
Diffstat (limited to 'cratera/compiler.lua')
-rw-r--r--cratera/compiler.lua463
1 files changed, 0 insertions, 463 deletions
diff --git a/cratera/compiler.lua b/cratera/compiler.lua
deleted file mode 100644
index 2f4a998..0000000
--- a/cratera/compiler.lua
+++ /dev/null
@@ -1,463 +0,0 @@
---[[
-    This file is part of Cratera Compiler
-    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/>.
---]]
-
--- slow af but works
-
--- need to run this first
-local is51 = (function() local _ENV = {hasenv = true} return not hasenv end)()
-
-local parser = require "cratera.parser"
-local selfify = parser.selfify
-local STATE = parser.STATE
-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
--- try to avoid making too many locals because Lua has a limit to how many locals you can have
-local math = {huge=math.huge, floor=math.floor}
-local string = {format=string.format, byte=string.byte, gsub=string.gsub}
-local table = {insert=table.insert, remove=table.remove}
-
--- marker for use with selfify()
-local SELF = {}
--- other markers
-local FINISH = {}
-local START_OF_STMT = {}
-local END_OF_STMT = {}
-local END_OF_CRATERA = {}
-
--- implementation of myobj:[mytrait].myfunction(...)
-local CRATERA_FUNCTION = "function(myobj, mytrait, myfunction, ...) return myobj[mytrait][myfunction](myobj, ...) end"
-
-local EXTRA_DATA = {[TK.NAME] = true, [TK.INT] = true, [TK.FLT] = true, [TK.STRING] = true, [END_OF_STMT] = true}
-
-local function is_tk(results, i, tk)
-    -- needed to prevent accidentally processing string literals as tokens
-    -- (note: it's generally safe, and faster, to do results[i] == tk,
-    -- if tk is one of the values in the TK.* table.)
-    return not EXTRA_DATA[results[i-1]] and results[i] == tk
-end
-
-local function ignore_newlines(results, i)
-    -- skip '\n' and return the new i
-    while is_tk(results, i, '\n') do -- ignore newlines
-        i = i - 1
-    end
-    return i
-end
-
--- -- --
-
-local defs = selfify({}, SELF)
-
-local finish = selfify({}, SELF)
-finish[parser.EOZ] = function(state, token)
-    local results = state.results
-    local tk = table.remove(results)
-    if tk == TK.FLT then
-        local token = table.remove(results)
-        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 -- the tokenizer *can* output math.huge tho
-            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
-        table.insert(state, string.format('((%d/%d)/%d)', num, den, extra))
-    elseif tk == TK.INT then
-        local v = table.remove(results)
-        if v == math.mininteger then
-            -- corner case ( https://github.com/lua/lua/commit/707b0ba6e2dbfd58cf1167dae0e17975904b18aa )
-            table.insert(state, string.format('0x%x', v))
-        else
-            table.insert(state, string.format('(%d)', v)) -- may be negative (overflow)
-        end
-    elseif tk == TK.STRING then
-        -- lua tends to use a backslash and a newline but we already do newline processing,
-        -- so we need to replace the escaped newline ("\\\n") with a newline escape ("\\n").
-        -- additionally lua 5.1 doesn't handle control characters other than '\0' and '\r' so we need to escape them as well
-        local fmted = string.format('%q', table.remove(results))
-        fmted = string.gsub(fmted, '\n', 'n')
-        if is51 then
-            fmted = string.gsub(fmted, "%c", function(c) return string.format("\\%03d", string.byte(c)) end)
-        end
-        table.insert(state, fmted)
-    elseif tk == TK.NAME then
-        table.insert(state, table.remove(results))
-    elseif type(tk) == "string" then
-        table.insert(state, tk)
-    elseif tk then
-        -- START_OF_STMT and END_OF_STMT are neither keywords nor tokens; this should error in that case.
-        table.insert(state, assert(reverse_keywords[tk] or reverse_tokens[tk]))
-    else
-        return {}
-    end
-    return SELF
-end
-defs[FINISH] = finish
-
-defs[parser.EOZ] = function(state, token)
-    local results = state.results
-    if not results then return {} end -- empty, don't waste time processing unnecessary things
-    -- flip results around
-    local len = results.n
-    for i=1, len do
-        local j = len-i+1
-        if i >= j then
-            break
-        end
-        results[i], results[j] = results[j], results[i]
-    end
-    return FINISH
-end
-defs[parser.FALLBACK] = function(state, token)
-    local results = state.results or (function() state.results = {} return state.results end)()
-
-    do -- handle newlines. this allows error messages to correctly map between lua and cratera
-        local oldline = state.oldline or 1
-        local linenumber = state.linenumber or 1
-        if linenumber > oldline then
-            local count = linenumber-oldline
-            local len = (results.n or 0)
-            for i=1, count do
-                results[len+i] = '\n'
-            end
-            results.n = len + count
-            if EXTRA_DATA[results[len]] then -- we're in the middle of a token with extra data. fix it up.
-                results[len], results[results.n] = results[results.n], results[len]
-            end
-        end
-        state.oldline = state.linenumber
-    end
-
-    results.n = (results.n or 0) + 1
-    results[results.n] = token
-    if not results.skip then -- don't process string literals as tokens
-        if token == ':' then
-            -- figure out whether we're in funcname
-            local i = results.n - 1 -- skip the ':'
-            local find_statement = true
-            i = ignore_newlines(results, i)
-            while results[i-1] == TK.NAME do
-                i = ignore_newlines(results, i-2) + 2
-                if is_tk(results, i-2, '.') then
-                    -- keep going
-                    i = i - 3
-                elseif results[i-2] == TK.FUNCTION then -- we're in funcname
-                    find_statement = false -- don't even bother with : handling
-                    break
-                else
-                    -- found start of statement
-                    find_statement = false
-                    -- mark start
-                    i = i - 1
-                    table.insert(results, i, START_OF_STMT)
-                    results.n = results.n + 1
-                    -- no need to fix existing END_OF_STMT because this code
-                    -- only detects patterns of the form Name {'.' Name} ':',
-                    -- which do not contain subexpressions.
-                    -- mark end
-                    table.insert(results, results.n + 1, END_OF_STMT)
-                    table.insert(results, results.n + 2, i)
-                    results.n = results.n + 2
-                    break
-                end
-            end
-            if find_statement then
-                while true do
-                    i = ignore_newlines(results, i)
-                    if is_tk(results, i, ')') then
-                        -- (prefixexp) or (funcargs)
-                        -- find matching '('
-                        local depth = 1
-                        repeat
-                            i = i - 1
-                            if is_tk(results, i, '(') then
-                                depth = depth - 1
-                            elseif is_tk(results, i, ')') then
-                                depth = depth + 1
-                            elseif not results[i] then
-                                error("syntax error (unbalanced '()')")
-                            end
-                        until depth == 0
-                    elseif is_tk(results, i, ']') then
-                        -- [indexing]
-                        -- find matching '['
-                        local depth = 1
-                        repeat
-                            i = i - 1
-                            if is_tk(results, i, '[') then
-                                depth = depth - 1
-                            elseif is_tk(results, i, ']') then
-                                depth = depth + 1
-                            elseif not results[i] then
-                                error("syntax error (unbalanced '[]')")
-                            end
-                        until depth == 0
-                    elseif results[i-1] == TK.NAME then
-                        -- Name or '.' Name
-                        i = i - 2
-                        i = ignore_newlines(results, i)
-                        if is_tk(results, i, '.') then
-                            -- skip '.'
-                            i = i - 1
-                        else
-                            -- found start of statement
-                            break
-                        end
-                    elseif is_tk(results, i, '}') then
-                        -- prefixexp '{' table '}'
-                        local newi = i
-                        local depth = 1
-                        repeat
-                            newi = newi - 1
-                            if is_tk(results, newi, '[') then
-                                depth = depth - 1
-                            elseif is_tk(results, newi, ']') then
-                                depth = depth + 1
-                            elseif not results[i] then
-                                error("syntax error (unbalanced '{}')")
-                            end
-                        until depth == 0
-                        local checki = ignore_newlines(results, newi-1)
-                        -- do I need these checks?
-                        if is_tk(results, checki, ']') or
-                            is_tk(results, checki, '}') or
-                            is_tk(results, checki, ')') or
-                            results[checki-1] == TK.NAME or
-                            results[checki-1] == TK.STRING then
-                            i = newi
-                        else
-                            -- syntax error?
-                            error("syntax error")
-                        end
-                    elseif results[i-1] == TK.STRING then
-                        -- prefixexp "string"
-                        -- prefixexp 'string'
-                        -- prefixexp [[string]]
-                        local newi = i-1
-                        local checki = ignore_newlines(results, newi-1)
-                        -- do I need these checks?
-                        if is_tk(results, checki, ']') or
-                            is_tk(results, checki, '}') or
-                            is_tk(results, checki, ')') or
-                            results[checki-1] == TK.NAME or
-                            results[checki-1] == TK.STRING then
-                            i = newi
-                        else
-                            -- syntax error?
-                            error("syntax error")
-                        end
-                    else
-                        -- found start of statement
-                        break
-                    end
-                    i = i - 1
-                end
-                -- mark start
-                i = i + 1
-                table.insert(results, i, START_OF_STMT)
-                results.n = results.n + 1
-                -- fix existing END_OF_STMT
-                for k=i, #results do
-                    if results[k] == END_OF_STMT then
-                        local v = results[k+1]
-                        if v > i then -- this should always be true?
-                            results[k+1] = v + 1
-                        end
-                    end
-                end
-                -- mark end
-                table.insert(results, results.n + 1, END_OF_STMT)
-                table.insert(results, results.n + 2, i)
-                results.n = results.n + 2
-            end
-        elseif token == '(' or token == '{' or token == TK.STRING then
-            local i = results.n - 1 -- skip the '(' / '{' / TK_STRING
-            i = ignore_newlines(results, i)
-            -- possible patterns:
-            -- ':' Name '(' -- plain Lua thing, ignore
-            -- ':' Name '.' Name '(' -- cratera string traits
-            -- ':' '[' exp ']' '.' Name '(' -- cratera object traits
-            -- ':' '[' exp ']' '(' -- supported in lua 5.3 cratera patch but no reason to support it here.
-            if results[i-1] == TK.NAME then
-                local tk_myfunction = i-1
-                -- maybe cratera
-                i = ignore_newlines(results, i-2)
-                if results[i-1] == END_OF_STMT then
-                    -- lua, but we need to fix it up
-                    -- we could just replace them with dummies, but
-                    local pos = results[i]
-                    table.remove(results, i) -- remove END_OF_STMT's value
-                    table.remove(results, i-1) -- remove END_OF_STMT
-                    table.remove(results, pos) -- remove START_OF_STMT
-                    results.n = results.n - 3 -- adjust length
-                    assert(results[i-3] == ':')
-                elseif is_tk(results, i, '.') then
-                    -- maybe cratera
-                    local tk_dot = i
-                    local inject_cratera = false
-                    i = ignore_newlines(results, i-1)
-                    if results[i-1] == TK.NAME then
-                        local tk_mytrait = i-1
-                        i = ignore_newlines(results, i-2)
-                        if results[i-1] == END_OF_STMT then
-                            -- definitely cratera (stmt ':' Name '.' Name '(')
-                            -- convert into '(' stmt ',' String ',' String
-                            -- convert names into strings
-                            results[tk_mytrait] = TK.STRING
-                            inject_cratera = true
-                        end -- else not cratera
-                    elseif is_tk(results, i, ']') then
-                        local tk_right = i
-                        local depth = 1
-                        repeat
-                            i = i - 1
-                            if is_tk(results, i, '[') then
-                                depth = depth - 1
-                            elseif is_tk(results, i, ']') then
-                                depth = depth + 1
-                            elseif not results[i] then
-                                error("syntax error (unbalanced '[]')")
-                            end
-                        until depth == 0
-                        local tk_left = i
-                        i = ignore_newlines(results, i-1)
-                        if results[i-1] == END_OF_STMT then
-                            -- definitely cratera (stmt ':' '[' exp ']' '.' Name '(')
-                            -- convert into '(' stmt ',' '(' exp ')' ',' String
-                            -- replace '[' and ']'
-                            results[tk_right] = ')'
-                            results[tk_left] = '('
-                            inject_cratera = true
-                        end -- else not cratera
-                    end
-                    if inject_cratera then
-                        --assert(token == '(', "unimplemented")
-                        -- convert name into string
-                        results[tk_myfunction] = TK.STRING
-                        -- replace '.' with ','
-                        results[tk_dot] = ','
-                        local pos = results[i]
-                        -- remove END_OF_STMT
-                        table.remove(results, i-1)
-                        table.remove(results, i-1)
-                        results.n = results.n - 2
-                        -- replace ':' with ','
-                        results[ignore_newlines(results, i-2)] = ','
-                        -- replace START_OF_STMT with '('
-                        results[pos] = '('
-                        if token == '(' then
-                            -- replace '(' with ','
-                            results[results.n] = ','
-                        else
-                            -- insert ',' before argument
-                            table.insert(results, results.n, ',')
-                            results.n = results.n + 1
-                        end
-                        -- inject cratera
-                        table.insert(results, pos, ')')
-                        table.insert(results, pos, CRATERA_FUNCTION)
-                        table.insert(results, pos, '(')
-                        -- check for potential prefixexp and correct for it
-                        if is_tk(results, pos-1, ']') or
-                            is_tk(results, pos-1, '}') or
-                            is_tk(results, pos-1, ')') or
-                            results[pos-2] == TK.NAME or
-                            results[pos-2] == TK.STRING then
-                            table.insert(results, pos, ';')
-                            results.n = results.n + 1
-                        end
-                        results.n = results.n + 3
-                        -- tag it so we know to insert a ')' to close our '('
-                        -- and to handle '(' ')' (no argument) calls
-                        -- we add the tag before TK.STRING/'{'/','
-                        table.insert(results, results.n, END_OF_CRATERA)
-                        results.n = results.n + 1
-                    end
-                end -- else not cratera
-            end
-        elseif token == '}' then
-            local i = results.n -- we'll be subtracting anyway, see below
-            local depth = 1
-            repeat
-                i = i - 1
-                if is_tk(results, i, '{') then
-                    depth = depth - 1
-                elseif is_tk(results, i, '}') then
-                    depth = depth + 1
-                elseif not results[i] then
-                    error("syntax error (unbalanced '{}')")
-                end
-            until depth == 0
-            assert(is_tk(results, i, '{'))
-            if results[i-1] == END_OF_CRATERA then
-                -- need to add ')' to close our '('
-                table.remove(results, i-1)
-                results[results.n] = ')'
-            end
-        elseif token == ')' then
-            local i = results.n - 1 -- skip the ')'
-            i = ignore_newlines(results, i)
-            if results[i] == ',' and results[i-1] == END_OF_CRATERA then
-                -- '(' CRATERA_FUNCTION ')' '(' something END_OF_CRATERA ',' ')'
-                -- need to fix it up into 
-                -- '(' CRATERA_FUNCTION ')' '(' something ')'
-                table.remove(results, i-1)
-                table.remove(results, i-1)
-                results.n = results.n - 2
-            else
-                -- still might need to remove an END_OF_CRATERA somewhere
-                i = i + 1
-                local depth = 1
-                repeat
-                    i = i - 1
-                    if is_tk(results, i, '(') then
-                        depth = depth - 1
-                    elseif is_tk(results, i, ')') then
-                        depth = depth + 1
-                    elseif results[i] == END_OF_CRATERA then
-                        table.remove(results, i)
-                        results.n = results.n - 1
-                        break
-                    elseif not results[i] then
-                        error("syntax error (unbalanced '()')")
-                    end
-                until depth == 0
-            end
-        end
-    else -- we skipped a string literal
-        if results[results.n-1] == TK.STRING and results[results.n-2] == END_OF_CRATERA then
-            -- need to add ')' to close our '('
-            table.remove(results, results.n-2)
-            results[results.n] = ')'
-        end
-    end
-    results.skip = EXTRA_DATA[token]
-    return SELF
-end
-
-return {defs = defs}