about summary refs log blame commit diff stats
path: root/lua/chupacabra/chupacabra.lua
blob: 27cd8b5bd05b42d5e164e46b6355519739d3703b (plain) (tree)
1
2
3
4

                     
                               
                     












                                           









                                                
                                         




                                                           




















                                                      

                                              




                                         




                                         
                                                                                                                 









                                                      



                                             















                                         
                                 
                                         























                                                                  
               
                                 
                                         























                                                                  
               
                                 
                                         























                                                                  
               
                                 
                                         













                                                                  
               






                                                                  
            

                                                  





                              











                                      




                                               
                 
local chupacabra = {}

function chupacabra.tokenize(s)
    local tokens = {}
    local array = nil
    for token in s:gmatch("%S+") do
        if array then
            array = array .. " " .. token
            if token:find("]$") then
                table.insert(tokens, array)
                array = nil
            end
        elseif token:find("^%[") then
            array = token
        else
            table.insert(tokens, token)
        end
    end
    return tokens
end

function chupacabra.evaluate(tokens, context)
    local stack = {}

    for _, token in ipairs(tokens) do
        if tonumber(token) then
            table.insert(stack, tonumber(token))
        elseif token:match("^%b[]$") then
            local array = {}
            for number in token:sub(2, -2):gmatch("%S+") do
                table.insert(array, tonumber(number))
            end
            table.insert(stack, array)
        elseif token == ".." then
            local array = {}
            for i = 1, #stack do
                table.insert(array, stack[i])
            end
            table.insert(stack, array)
        elseif token == "@.." then
            local result = {}
            for i = 1, #stack do
                local value = stack[i]
                if type(value) == "table" then
                    for j = 1, #value do
                        table.insert(result, value[j])
                    end
                else
                    table.insert(result, value)
                end
            end
            table.insert(stack, result)    
        elseif token == "." then
            table.remove(stack)
        elseif token == ":" then 
            table.insert(stack, stack[#stack])
        elseif token == "?" then
            local a = table.remove(stack)
            local b = table.remove(stack)
            table.insert(stack, a)
            table.insert(stack, b)
        elseif token == "=" then
            local b = table.remove(stack)
            local a = table.remove(stack)
            table.insert(stack, a == b)
        elseif token == "@=" then
            -- checks if the values of 2 equal length arrays are equal, and returns a bit mask of the differences
            local b = table.remove(stack)
            local a = table.remove(stack)
            if #a ~= #b then
                error("Arrays must have equal length")
            end
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] == b[i])
            end
            table.insert(stack, result)
        elseif token == "@" then
            local index = table.remove(stack)
            local array = table.remove(stack)
            table.insert(stack, array[index])
        elseif token == "+" then
            local b = table.remove(stack)
            local a = table.remove(stack)
            table.insert(stack, a + b)
        elseif token == "-" then
            local b = table.remove(stack)
            local a = table.remove(stack)
            table.insert(stack, a - b)
        elseif token == "*" then
            local b = table.remove(stack)
            local a = table.remove(stack)
            table.insert(stack, a * b)
        elseif token == "/" then
            local b = table.remove(stack)
            local a = table.remove(stack)
            table.insert(stack, a / b)
        elseif token == "@+" then
            local a = table.remove(stack)
            local b = table.remove(stack)
            if type(a) == "table" and type(b) == "table" then
            if #a ~= #b then
                error("Arrays must have equal length")
            end
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] + b[i])
            end
            table.insert(stack, result)
            elseif type(a) == "table" and type(b) == "number" then
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] + b)
            end
            table.insert(stack, result)
            elseif type(a) == "number" and type(b) == "table" then
            local result = {}
            for i = 1, #b do
                table.insert(result, a + b[i])
            end
            table.insert(stack, result)
            else
            error("Invalid operands for addition")
            end
        elseif token == "@*" then
            local a = table.remove(stack)
            local b = table.remove(stack)
            if type(a) == "table" and type(b) == "table" then
            if #a ~= #b then
                error("Arrays must have equal length")
            end
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] * b[i])
            end
            table.insert(stack, result)
            elseif type(a) == "table" and type(b) == "number" then
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] * b)
            end
            table.insert(stack, result)
            elseif type(a) == "number" and type(b) == "table" then
            local result = {}
            for i = 1, #b do
                table.insert(result, a * b[i])
            end
            table.insert(stack, result)
            else
            error("Invalid operands for multiplication")
            end
        elseif token == "@-" then
            local a = table.remove(stack)
            local b = table.remove(stack)
            if type(a) == "table" and type(b) == "table" then
            if #a ~= #b then
                error("Arrays must have equal length")
            end
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] - b[i])
            end
            table.insert(stack, result)
            elseif type(a) == "table" and type(b) == "number" then
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] - b)
            end
            table.insert(stack, result)
            elseif type(a) == "number" and type(b) == "table" then
            local result = {}
            for i = 1, #b do
                table.insert(result, a - b[i])
            end
            table.insert(stack, result)
            else
            error("Invalid operands for subtraction")
            end
        elseif token == "@/" then
            local a = table.remove(stack)
            local b = table.remove(stack)
            if type(a) == "table" and type(b) == "table" then
            if #a ~= #b then
                error("Arrays must have equal length")
            end
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] / b[i])
            end
            table.insert(stack, result)
            elseif type(a) == "table" and type(b) == "number" then
            local result = {}
            for i = 1, #a do
                table.insert(result, a[i] / b)
            end
            table.insert(stack, result)
            elseif type(a) == "number" and type(b) == "table" then
            local result = {}
            for i = 1, #b do
                table.insert(result, a / b[i])
            end
            table.insert(stack, result)
        else
            error("Invalid operands for division")
            end
        end
    end

    return table.remove(stack)
end

function chupacabra.table_to_string(t)
    local str = "["
    for i, v in ipairs(t) do
        if i > 1 then
            str = str .. " "
        end
        str = str .. tostring(v)
    end
    str = str .. "]"
    return str
end

function chupacabra.run(str, context)
    local tokens = chupacabra.tokenize(str)
    return chupacabra.evaluate(tokens, context)
end

return chupacabra