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

                     
                                       
                               
                     












                                           









                                                
                                         




                                                           




















                                                      

                                              



                                             















                                         
                                 
                                         























                                                                  
               
                                 
                                         























                                                                  
               
                                 
                                         























                                                                  
               
                                 
                                         













                                                                  
               






                                                                  
            

                                                  











                                               
local chupacabra = {}

-- Parse a string into a list of tokens
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 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.run(str, context)
    local tokens = chupacabra.tokenize(str)
    return chupacabra.evaluate(tokens, context)
end

return chupacabra