Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local args = { ... }
- local test = false
- if args[2] ~= nil then
- if args[2] == "test" then
- print("test")
- test = true
- elseif args[2] == "noTest" then
- else
- error("unknwon first argument: '" .. args[2] .. "'")
- end
- end
- local TYPE_FUNCTION = 1
- local TYPE_VALUE = 2
- local TYPE_VAR = 3
- local TYPE_USER_FUNCTION = 4
- local TYPE_DEFAULT_FUNCTION = 5
- local TYPE_ARR = 6
- local TYPE_ADD = 7
- local TYPE_SUB = 8
- local TYPE_CONSTANT = 9
- local TYPE_DECLARATION = 10
- local TYPE_CMP = 11
- local TYPE_CONTROL_FLOW = 12
- local TYPE_OR = 13
- local TYPE_COMP = 14
- local TYPE_COMP_EQUAL = 1
- local TYPE_CF_WHILE = 1
- local TYPE_CF_IF = 2
- local TYPE_CF_FOR = 3
- local storage
- local defaultFunctions
- local fctSetStorageData
- local initToContinue
- if test then
- local data = require("defaultFunctions")
- data[1](true)
- fctSetStorageData = data[2]
- defaultFunctions = data[3]
- initToContinue = data[4]
- else
- os.loadAPI("lib_defaultFunctions")
- lib_defaultFunctions.setTest(false, { shell = shell, turtle = turtle })
- defaultFunctions = lib_defaultFunctions.getDefaultFunctions()
- fctSetStorageData = lib_defaultFunctions.setStorageData
- initToContinue = lib_defaultFunctions.initToContinue
- end
- function readAll(file)
- local f = assert(io.open(file, "rb"))
- local content = f:read("*all")
- f:close()
- return content
- end
- function splitText(source, letters)
- local parts = {}
- local akt = "";
- local qM1 = 0;
- local qM2 = 0;
- local b1 = 0;
- local b2 = 0;
- local b3 = 0;
- for i = 1, #source do
- local z = string.sub(source, i, i)
- if z == "'" and qM2 == 0 then
- qM1 = 1 - qM1;
- elseif z == "\"" and qM1 == 0 then
- qM2 = 1 - qM2;
- elseif qM1 == 0 and qM2 == 0 then
- if z == "(" then
- b1 = b1 + 1
- elseif z == ")" then
- b1 = b1 - 1
- elseif z == "[" then
- b2 = b2 + 1
- elseif z == "]" then
- b2 = b2 - 1
- elseif z == "{" then
- b3 = b3 + 1
- elseif z == "}" then
- b3 = b3 - 1
- end
- end
- local split = false
- if b1 == 0 and b2 == 0 and b3 == 0 and qM1 == 0 and qM2 == 0 then
- for j = 1, #letters do
- if z == string.sub(letters, j, j) then
- split = true
- break
- end
- end
- end
- if split then
- if akt ~= "" then
- table.insert(parts, akt)
- akt = ""
- end
- else
- akt = akt .. z
- end
- end
- if akt ~= "" then
- table.insert(parts, akt)
- end
- return parts
- end
- function splitTextPattern(source, letters)
- local parts = {}
- local akt = "";
- local qM1 = 0;
- local qM2 = 0;
- local b1 = 0;
- local b2 = 0;
- local b3 = 0;
- local i = 1
- while (i <= #source) do
- local z = string.sub(source, i, i)
- if z == "'" and qM2 == 0 then
- qM1 = 1 - qM1;
- elseif z == "\"" and qM1 == 0 then
- qM2 = 1 - qM2;
- elseif qM1 == 0 and qM2 == 0 then
- if z == "(" then
- b1 = b1 + 1
- elseif z == ")" then
- b1 = b1 - 1
- elseif z == "[" then
- b2 = b2 + 1
- elseif z == "]" then
- b2 = b2 - 1
- elseif z == "{" then
- b3 = b3 + 1
- elseif z == "}" then
- b3 = b3 - 1
- end
- end
- local split = false
- if b1 == 0 and b2 == 0 and b3 == 0 and qM1 == 0 and qM2 == 0 then
- split = true
- for j = 1, #letters do
- if string.sub(source, i + j - 1, i + j - 1) ~= string.sub(letters, j, j) then
- split = false
- break
- end
- end
- end
- if split then
- if akt ~= "" then
- table.insert(parts, akt)
- akt = ""
- i = i + #letters - 1
- end
- else
- akt = akt .. z
- end
- i = i + 1
- end
- if akt ~= "" then
- table.insert(parts, akt)
- end
- return parts
- end
- function removeLetters(source, letters)
- local target = ""
- for i = 1, #source do
- local valid = true
- for j = 1, #letters do
- if string.sub(source, i, i) == string.sub(letters, j, j) then
- valid = false
- end
- end
- if valid then
- target = target .. string.sub(source, i, i)
- end
- end
- return target
- end
- function readFileText(file)
- if test then
- return readAll(file)
- else
- local f = fs.open(file, "r")
- local text = f.readAll()
- f.close()
- return text
- end
- end
- function analyseCommands(source)
- local cmdsSource = splitText(source, ";")
- local cmds = {}
- for i, v in ipairs(cmdsSource) do
- if v ~= "" then
- if string.sub(v, 1, 2) ~= "//" then
- table.insert(cmds, loadCommand(v))
- end
- end
- end
- return cmds
- end
- function nextCloseIndex(source, chOpen, chClose)
- local a = 0;
- local qM1 = 0;
- local qM2 = 0
- for i = 1, #source do
- local z = string.sub(source, i, i)
- if z == "\"" and qM2 == 0 then
- qM1 = 1 - qM1
- elseif z == "'" and qM1 == 0 then
- qM2 = 1 - qM2
- elseif z == chOpen and qM1 == 0 and qM2 == 0 then
- a = a + 1
- elseif z == chClose and qM1 == 0 and qM2 == 0 then
- a = a - 1
- if a == 0 then
- return i
- end
- end
- end
- return -1
- end
- function loadCommand(source)
- if string.find(source, "%(") ~= nil and string.find(source, "){") ~= nil then
- local ind = string.find(source, "%(")
- local name = string.sub(source, 1, ind - 1)
- if name == "while" then
- local ind1 = string.find(source, "){")
- local body = analyseCommands(string.sub(source, ind1 + 2, #source - 1))
- local cmdCondition = loadCommand(string.sub(source, ind + 1, ind1 - 1))
- return { type = TYPE_CONTROL_FLOW, cond = cmdCondition, body = body, id = newCFId(), typeCF = TYPE_CF_WHILE }
- elseif name == "for" then
- local ind1 = string.find(source, "){")
- local body = analyseCommands(string.sub(source, ind1 + 2, #source - 1))
- local headPts = splitText(string.sub(source, ind + 1, ind1 - 1), ";")
- if #headPts ~= 3 then
- error("invalid for-head: " .. string.sub(source, ind + 1, ind1 - 1))
- end
- local firstCommand = loadCommand(headPts[1])
- local secondCondition = loadCommand(headPts[2])
- local thirdCommand = loadCommand(headPts[3])
- return { type = TYPE_CONTROL_FLOW, first = firstCommand, second = secondCondition, third = thirdCommand, body = body, id = newCFId(), typeCF = TYPE_CF_FOR }
- elseif name == "if" then
- local pts = splitText(source, "else")
- local data = { type = TYPE_CONTROL_FLOW, typeCF = TYPE_CF_IF, id = newCFId(), ifCmdBlocks = {} }
- for i = 1, #pts do
- local pt = pts[i]
- local ind = string.find(pt, "%(")
- local ind1 = string.find(pt, "{")
- local body = analyseCommands(string.sub(pt, ind1 + 1, #pt - 1))
- if ind1 == 1 then
- if i ~= #pts then
- error("'else' statement needs to be at end of 'if'-block (source: " .. source .. ")")
- end
- table.insert(data.ifCmdBlocks, { body = body })
- else
- local name = string.sub(pt, 1, ind - 1)
- if name ~= "if" then
- error("invalid keyword: [else]" .. name)
- end
- local cond = loadCommand(string.sub(pt, ind + 1, ind1 - 2))
- table.insert(data.ifCmdBlocks, { body = body, cond = cond })
- end
- end
- return data
- else
- error("unknown keyword '" .. name .. "'")
- end
- end
- local ptsSources = splitTextPattern(source, "||")
- if #ptsSources > 1 then
- local values = {};
- for i = 1, #ptsSources do
- print(ptsSources[i])
- values[i] = loadCommand(ptsSources[i])
- end
- return { type = TYPE_OR, values = values }
- end
- for i, ch in ipairs({ ">=", "<=", "<", ">", "==", "!=" }) do
- local ptsSources = splitTextPattern(source, ch)
- if #ptsSources > 1 then
- if #ptsSources > 2 then
- error("only 2 arguments allowed for '" .. ch .. "'")
- end
- local pts = {}
- for i, v in ipairs(ptsSources) do
- table.insert(pts, loadCommand(v))
- end
- return { type = TYPE_CMP, ch = ch, pts = pts }
- end
- end
- local ptsSources = splitText(source, "=")
- if #ptsSources > 1 then
- local name = ptsSources[1]
- if #ptsSources > 2 then
- error("there is only one '=' allowed in a declaration")
- end
- if string.match(name, "%$[A-Za-z_][A-Za-z0-9_]*%$") == name or
- string.match(name, "[A-Za-z_][A-Za-z0-9_]*") == name then
- return { type = TYPE_DECLARATION, name = name, value = loadCommand(ptsSources[2]) }
- else
- error("invalid declaration variable: " .. name)
- end
- end
- local ptsSources = splitText(source, "+")
- if #ptsSources > 1 then
- local pts = {}
- for i, v in ipairs(ptsSources) do
- table.insert(pts, loadCommand(v))
- end
- return { type = TYPE_ADD, pts = pts }
- end
- local ptsSources = splitText(source, "-")
- if #ptsSources > 1 then
- local pts = {}
- for i, v in ipairs(ptsSources) do
- table.insert(pts, loadCommand(v))
- end
- return { type = TYPE_SUB, pts = pts }
- end
- local i = string.find(source, "%(")
- if i ~= nil and nextCloseIndex(source, "(", ")") == #source then
- local funcName = string.sub(source, 1, i - 1)
- if string.match(funcName, "[a-zA-Z_][a-zA-Z_0-9]*") ~= funcName then
- error("invalid funcName: " .. funcName)
- end
- local pars = {}
- local parSources = splitText(string.sub(source, i + 1, -2), ",")
- for i, par in ipairs(parSources) do
- table.insert(pars, loadCommand(par))
- end
- return { type = TYPE_FUNCTION, name = funcName, pars = pars }
- else
- if tonumber(source) ~= nil then
- return { type = TYPE_VALUE, value = tonumber(source) }
- elseif string.match(source, "%$[A-Za-z_][A-Za-z0-9_]*%$") == source then
- local key = string.sub(source, 2, #source - 1)
- return { type = TYPE_CONSTANT, key = key }
- elseif source == "true" or source == "false" then
- return { type = TYPE_VALUE, value = source == "true" }
- elseif string.match(source, "[A-Za-z_][A-Za-z0-9_]*") == source then
- return { type = TYPE_VAR, name = source }
- elseif string.sub(source, 1, 1) == "[" and string.sub(source, #source) == "]" then
- local parts = splitText(string.sub(source, 2, #source - 1), ",")
- local vars = {}
- for i, v in ipairs(parts) do
- table.insert(vars, loadCommand(v))
- end
- return { type = TYPE_ARR, vars = vars }
- elseif string.sub(source, 1, 1) == "\"" and string.sub(source, #source) == "\"" then
- return { type = TYPE_VALUE, value = string.sub(source, 2, #source - 1) }
- else
- error("unknown value: " .. source)
- end
- end
- return nil
- end
- local currentCFId = 0
- function newCFId()
- local id = currentCFId
- currentCFId = currentCFId + 1
- return id
- end
- function analyseStack(source)
- local values = {}
- for i, v in ipairs(splitText(source, ",")) do
- if v ~= "" then
- table.insert(values, tonumber(v))
- end
- end
- return values
- end
- function combineArr(table1, table2)
- local table = {}
- for i = 1, #table1 do
- table[i] = table1[i]
- end
- for i = 1, #table2 do
- table[i + #table1] = table2[i]
- end
- return table
- end
- function getTableFromSaveText(source)
- local tableSources = splitText(source, ";")
- local tables = {}
- for i = 1, #tableSources do
- table.insert(tables, {})
- end
- for i, v in ipairs(tableSources) do
- local tbl = tables[i]
- getTableFromSaveTextInd(tbl, v, tables)
- end
- return tables[1]
- end
- function getTableFromSaveTextInd(tbl, tblSource, tables)
- if string.sub(tblSource, 1, 1) ~= "{" or string.sub(tblSource, #tblSource) ~= "}" then
- error("invalid source (braces arround table): " .. tblSource)
- end
- local pts = splitText(string.sub(tblSource, 2, #tblSource - 1), ",")
- for i, pt in ipairs(pts) do
- local i = string.find(pt, "=")
- local vKey = getValueFromSaveText(string.sub(pt, 1, i - 1), tables)
- local vValue = getValueFromSaveText(string.sub(pt, i + 1), tables)
- tbl[vKey] = vValue
- end
- end
- function getValueFromSaveText(source, tables)
- if string.sub(source, 1, 1) == "\"" and string.sub(source, #source) == "\"" then
- return string.sub(source, 2, #source - 1)
- elseif tonumber(source) ~= nil then
- return tonumber(source)
- elseif string.sub(source, 1, 4) == "tbl:" then
- return tables[tonumber(string.sub(source, 5))]
- elseif source == "false" then
- return false
- elseif source == "true" then
- return true
- else
- error("invalid source (getValueAnalysis): " .. source)
- end
- end
- function getTableSaveText(sourceTable)
- local alreadyUsed = {}
- local sources = {}
- getTableSaveTextInd(sourceTable, alreadyUsed, sources)
- local txt = ""
- for i, v in pairs(sources) do
- txt = txt .. v .. ";"
- end
- return txt
- end
- function getTableSaveTextInd(sourceTable, alreadyUsed, sources)
- local index
- for i, v in ipairs(alreadyUsed) do
- if v == sourceTable then
- index = i
- break
- end
- end
- if index ~= nil then
- return "tbl:" .. index
- else
- table.insert(alreadyUsed, sourceTable)
- local sourceString = ""
- local ind = #alreadyUsed
- for k, v in pairs(sourceTable) do
- sourceString = sourceString .. getSaveValueString(k, alreadyUsed, sources) .. "=" .. getSaveValueString(v, alreadyUsed, sources) .. ","
- end
- sources[ind] = "{" .. sourceString .. "}"
- return "tbl:" .. ind
- end
- end
- function getSaveValueString(obj, alreadyUsed, sources)
- local t = type(obj)
- if t == "string" then
- return "\"" .. obj .. "\""
- elseif t == "number" then
- return obj
- elseif t == "table" then
- return getTableSaveTextInd(obj, alreadyUsed, sources)
- elseif t == "boolean" then
- if obj then
- return "true"
- else
- return "false"
- end
- else
- error("unknown type: " .. t)
- end
- end
- function finished()
- deleteFile(storage.stackFileName)
- deleteFile(storage.dataFileName)
- end
- function deleteFile(fileName)
- if test then
- os.remove(fileName)
- else
- shell.run("delete", fileName)
- end
- end
- function save()
- if storage.dfData.save then
- local txt = getTableSaveText(storage)
- writeToFile(storage.stackFileName .. "1", txt)
- writeToFile(storage.stackFileName, txt)
- end
- end
- function writeToFile(fileName, data)
- if test then
- local f = io.open(fileName, "w")
- io.output(f)
- io.write(data)
- io.close(f)
- else
- local f = fs.open(fileName, "w")
- f.write(data)
- f.close()
- end
- end
- function fileExists(fileName)
- if test then
- local f = io.open(fileName)
- if f ~= nil then
- io.close(f)
- return true
- end
- return false
- else
- return fs.exists(fileName)
- end
- end
- function tryLoadStorage(fileName, stackFileName, dataFileName, currentFileData)
- print(stackFileName)
- if fileExists(stackFileName) then
- if isSameFileData(currentFileData, readFileText(dataFileName)) then
- print("loading storage")
- local data
- local state, msg = pcall(function()
- data = getTableFromSaveText(readFileText(stackFileName))
- end)
- if state then
- return true, data
- else
- return true, getTableFromSaveText(readFileText(stackFileName .. "1"))
- end
- else
- print("source file has changed, restarting program")
- deleteFile(stackFileName)
- deleteFile(dataFileName)
- end
- end
- return false, {
- stack = nil,
- fileName = fileName,
- stackFileName = stackFileName,
- dataFileName = dataFileName,
- dfData = {save = true},
- diedLast = 0,
- constants = {}
- }
- end
- function isSameFileData(data1, data2)
- local pts1 = getLengthFormatedParts(data1)
- local pts2 = getLengthFormatedParts(data2)
- while #pts1 > 0 do
- local data = pts1[1]
- local success = false
- for j, data2 in ipairs(pts2) do
- if data2 == data then
- table.remove(pts1, 1)
- table.remove(pts2, j)
- success = true
- break
- end
- end
- if not success then
- return false
- end
- end
- return #pts2 == 0
- end
- function getLengthFormatedParts(data)
- local pts = {}
- while #data > 0 do
- local i = string.find(data, "|")
- local len = tonumber(string.sub(data, 1, i - 1))
- data = string.sub(data, i + 1)
- table.insert(pts, string.sub(data, 1, len))
- data = string.sub(data, len + 1)
- end
- return pts
- end
- function loadProgram(file, stackFile, dataFile, cFCount)
- local source = readFileText(file)
- source = string.gsub(source, "/%*[^%*]*%*/", "")
- source = string.gsub(source, "//[^\n]*", "")
- source = removeLetters(source, "\n\r\t ")
- local methods = {}
- for i, v in ipairs(splitText(source, ";")) do
- local m = string.find(v, ":{")
- local name = string.sub(v, 1, m - 1)
- local fct = {}
- fct.pars = {}
- if string.find(name, "%(") ~= nil and string.sub(name, #name, #name) == ")" then
- local i = string.find(name, "%(")
- local parSource = string.sub(name, i + 1, -2)
- name = string.sub(name, 1, i - 1)
- local parNames = splitText(parSource, ",")
- for i, n in ipairs(parNames) do
- if string.match(n, "[A-Za-z_][A-Za-z0-9_]*") ~= n then
- error("invalid parameter-name: " .. n)
- end
- table.insert(fct.pars, n)
- end
- end
- if string.match(name, "[A-Za-z_][A-Za-z0-9_]*") ~= name then
- error("invalid function-name: " .. name)
- end
- local srcCommands = string.sub(v, m + 2, -2)
- fct.cmds = analyseCommands(srcCommands)
- methods[name] = fct
- end
- local validMethods = {}
- for name, fct in pairs(methods) do
- table.insert(validMethods, { type = TYPE_USER_FUNCTION, pars = { #fct.pars }, name = name, fct = fct, cmds = fct.cmds })
- end
- checkMethodValidity(combineArr(validMethods, defaultFunctions))
- if methods["main"] == nil then
- error("function 'main' needs to be defined in commands-source")
- end
- if #methods["main"]["pars"] ~= 0 then
- error("function 'main' doesn't take any arguments (" .. #methods["main"]["pars"] .. " given)")
- end
- local currentFileData = getFileData(methods)
- local success
- success, storage = tryLoadStorage(file, stackFile, dataFile, currentFileData)
- storage.dfData.save = true
- fctSetStorageData(storage.dfData, save)
- if success then
- initToContinue()
- end
- writeToFile(dataFile, currentFileData)
- if storage.stack == nil then
- local stack = {}
- table.insert(stack, { name = "main", offset = 1, executed = false, localVars = { {} }, cFStack = {} })
- if methods["init"] ~= nil then
- if #methods["init"]["pars"] ~= 0 then
- error("function 'init' doesn't take any arguments (" .. #methods["init"]["pars"] .. " given)")
- end
- table.insert(stack, { name = "init", offset = 1, executed = false, localVars = { {} }, cFStack = {} })
- end
- storage.stack = stack
- else
- if methods["onRestart"] ~= nil then
- if #methods["onRestart"]["pars"] ~= 0 then
- error("function 'onRestart' doesn't take any arguments (" .. #methods["onRestart"]["pars"] .. " given)")
- end
- table.insert(storage.stack, { name = "onRestart", offset = 1, executed = false, localVars = { {} }, cFStack = {} })
- end
- end
- save()
- execute(methods, true, cFCount)
- finished()
- end
- function getFileData(methods)
- local data = ""
- for methodName, v in pairs(methods) do
- if countKeys(v) > 2 then
- error("fail")
- end
- local pars = v.pars
- local cmds = v.cmds
- local methodString = methodName .. "("
- for i, par in ipairs(pars) do
- if i ~= 1 then
- methodString = methodString .. ","
- end
- methodString = methodString .. par
- end
- methodString = methodString .. ")|" .. getFileDataCmds(cmds)
- data = data .. #methodString .. "|" .. methodString
- end
- return data
- end
- function getFileDataCmds(cmds)
- local txt = ""
- for i, cmd in ipairs(cmds) do
- if i ~= 1 then
- txt = txt .. ";"
- end
- txt = txt .. getFileDataCmd(cmd)
- end
- return txt
- end
- function getFileDataCmd(cmd)
- if cmd.type == TYPE_VALUE then
- if cmd.value == "nil" then
- return "nil"
- elseif type(cmd.value) == "string" then
- return "\"" .. cmd.value .. "\""
- elseif type(cmd.value) == "boolean" then
- return "\"" .. ((cmd.value and "true") or "false") .. "\""
- else
- return "" .. cmd.value
- end
- --elseif cmd.type == TYPE_DECLARATION then
- elseif cmd.type == TYPE_FUNCTION then
- local txtPars = ""
- for i, par in ipairs(cmd.pars) do
- if i ~= 1 then
- txtPars = txtPars .. ","
- end
- txtPars = txtPars .. getFileDataCmd(par)
- end
- return cmd.name .. "(" .. txtPars .. ")"
- elseif cmd.type == TYPE_CONSTANT then
- return "$" .. cmd.key .. "$"
- elseif cmd.type == TYPE_ARR then
- local txt = ""
- for i, v in ipairs(cmd.vars) do
- if i ~= 1 then
- txt = txt .. ","
- end
- txt = txt .. getFileDataCmd(v)
- end
- return "[" .. txt .. "]"
- elseif cmd.type == TYPE_VAR then
- return cmd.name
- elseif cmd.type == TYPE_ADD then
- local txt = ""
- for i, v in ipairs(cmd.pts) do
- if i ~= 1 then
- txt = txt .. "+"
- end
- txt = txt .. getFileDataCmd(v)
- end
- return txt
- elseif cmd.type == TYPE_SUB then
- local txt = ""
- for i, v in ipairs(cmd.pts) do
- if i ~= 1 then
- txt = txt .. "-"
- end
- if v.type == TYPE_ADD then
- txt = txt .. "(" .. getFileDataCmd(v) .. ")"
- else
- txt = txt .. getFileDataCmd(v)
- end
- end
- return txt
- elseif cmd.type == TYPE_DECLARATION then
- return cmd.name .. "=" .. getFileDataCmd(cmd.value)
- elseif cmd.type == TYPE_CONTROL_FLOW then
- if cmd.typeCF == TYPE_CF_WHILE then
- return "while(" .. getFileDataCmd(cmd.cond) .. "){" .. getFileDataCmds(cmd.body) .. "}"
- elseif cmd.typeCF == TYPE_CF_FOR then
- return "for(" .. getFileDataCmd(cmd.first) .. ";" .. getFileDataCmd(cmd.second) .. ";" .. getFileDataCmd(cmd.third) .. "){" .. getFileDataCmds(cmd.body) .. "}"
- elseif cmd.typeCF == TYPE_CF_IF then
- local txt = "";
- for i, block in pairs(cmd.ifCmdBlocks) do
- if i ~= 1 then
- txt = txt .. "else"
- end
- if block.cond ~= nil then
- txt = txt .. "if(" .. getFileDataCmd(block.cond) .. ")"
- end
- txt = txt .. "{" .. getFileDataCmds(block.body) .. "}"
- end
- return txt
- else
- error("fail: " .. cmd.typeCF)
- end
- elseif cmd.type == TYPE_CMP then
- return getFileDataCmd(cmd.pts[1]) .. cmd.ch .. getFileDataCmd(cmd.pts[2])
- elseif cmd.type == TYPE_OR then
- local txt = ""
- for i = 1, #cmd.values do
- if txt ~= "" then
- txt = txt .. "||"
- end
- txt = txt .. getFileDataCmd(cmd.values[i])
- end
- return txt
- else
- printKeys(cmd)
- error("unknown type: " .. cmd.type)
- end
- end
- function printKeys(t)
- local keys = ""
- local c = 0
- for i, v in pairs(t) do
- keys = keys .. ((c ~= 0 and ",") or "") .. i
- c = 1
- end
- print(keys)
- end
- function countKeys(t)
- local c = 0
- for i, v in pairs(t) do
- c = c + 1
- end
- return c
- end
- function execute(methods, isStartThread, cFCount)
- local methodName = storage.stack[#storage.stack].name
- local methodOffset = storage.stack[#storage.stack].offset
- local methodExecuted = storage.stack[#storage.stack].executed --TODO check pos or anything else when executed=false
- local currentMethod = methods[methodName]
- local cmds = currentMethod.cmds
- local localVars = storage.stack[#storage.stack].localVars
- if methodExecuted then
- storage.stack[#storage.stack].offset = storage.stack[#storage.stack].offset + 1
- end
- executeCommands(storage.stack[#storage.stack], cmds, methods, localVars, cFCount)
- if isStartThread and #storage.stack > 1 then
- table.remove(storage.stack)
- save()
- execute(methods, true, cFCount)
- end
- end
- function executeCommand(cmd, methods, localVars, cFCount)
- if cmd.type == TYPE_FUNCTION then
- local pars = {}
- for i, p in pairs(cmd.pars) do
- table.insert(pars, executeGetValue(p, localVars, methods, cFCount))
- end
- --default function
- for i, f in pairs(defaultFunctions) do
- if f.name == cmd.name then
- return f.fct(pars)
- end
- end
- --user function
- local method = methods[cmd.name]
- local newLocalVars = { {} }
- for i, p in pairs(pars) do
- newLocalVars[1][method.pars[i]] = p
- end
- table.insert(storage.stack, { name = cmd.name, offset = 1, executed = false, localVars = newLocalVars, cFStack = {} })
- save()
- execute(methods, false, cFCount)
- table.remove(storage.stack)
- save()
- elseif cmd.type == TYPE_DECLARATION then
- local name = cmd.name
- if string.sub(name, 1, 1) == "$" then
- local v = executeGetValue(cmd.value, localVars, methods, cFCount)
- name = string.sub(name, 2, #name - 1)
- if storage.constants[name] ~= nil then
- error("constant '" + name + "' is already defined")
- end
- storage.constants[name] = v
- else
- local v = executeGetValue(cmd.value, localVars, methods, cFCount)
- for i = 1, cFCount do
- for n, v1 in pairs(localVars[i]) do
- if n == name then
- localVars[i][name] = v
- return
- end
- end
- end
- if not localVars[cFCount+1] then
- localVars[cFCount+1]={}
- end
- localVars[cFCount+1][name] = v
- end
- elseif cmd.type == TYPE_CONTROL_FLOW then
- if cmd.typeCF == TYPE_CF_IF then
- local id = cmd.id
- local data
- if #storage.stack[#storage.stack].cFStack <= cFCount then
- data = { cmd = cmd, condExecuted = false, offset = 1, ifOffset = 1, executed = false, condResult = false }
- table.insert(localVars, {})
- table.insert(storage.stack[#storage.stack].cFStack, data)
- save()
- else
- data = storage.stack[#storage.stack].cFStack[cFCount + 1]
- if data.cmd.id ~= cmd.id then
- print("fail")
- end
- end
- print(cFCount, #storage.stack[#storage.stack].cFStack)
- for i = data.ifOffset, #cmd.ifCmdBlocks do
- local cond = cmd.ifCmdBlocks[i].cond
- local body = cmd.ifCmdBlocks[i].body
- if not data.condExecuted then
- local v
- if cond ~= nil then
- v = executeGetValue(cond, localVars, methods, cFCount)
- if v == nil or type(v) ~= "boolean" then
- error("type of condition needs to be 'boolean' (type '" .. type(v) .. "' given)")
- end
- else
- v = true
- end
- data.condExecuted = true
- data.condResult = v
- save()
- end
- if data.condResult then
- if data.executed then
- data.offset = data.offset + 1
- end
- save()
- executeCommands(data, body, methods, localVars, cFCount + 1)
- end
- data.ifOffset = i + 1
- data.condExecuted = false
- data.executed = false
- data.offset = 1
- save()
- if data.condResult then
- break
- end
- end
- table.remove(storage.stack[#storage.stack].cFStack)
- table.remove(localVars)
- elseif cmd.typeCF == TYPE_CF_FOR then
- local id = cmd.id
- local data
- if #storage.stack[#storage.stack].cFStack <= cFCount then
- data = { cmd = cmd, firstExecuted = false, offset = 1, condExecuted = false, lastExecuted = false, condResult = false }
- table.insert(localVars, {})
- table.insert(storage.stack[#storage.stack].cFStack, data)
- save()
- else
- data = storage.stack[#storage.stack].cFStack[cFCount + 1]
- if data.cmd.id ~= cmd.id then
- print("fail")
- end
- end
- if not data.firstExecuted then
- executeCommand(data.cmd.first, methods, localVars, cFCount - 1)
- data.firstExecuted = true
- save()
- end
- while true do
- if not data.condExecuted then
- local v = executeGetValue(data.cmd.second, localVars, methods, cFCount)
- if v == nil or type(v) ~= "boolean" then
- error("type of condition needs to be 'boolean' (type '" .. type(v) .. "' given)")
- end
- data.condExecuted = true
- data.condResult = v
- save()
- if not v then
- break
- end
- end
- if data.executed then
- data.offset = data.offset + 1
- save()
- end
- executeCommands(data, data.cmd.body, methods, localVars, cFCount + 1)
- if not data.lastExecuted then
- executeCommand(data.cmd.third, methods, localVars, cFCount)
- data.lastExecuted = true
- save()
- end
- data.lastExecuted = false
- data.condExecuted = false
- data.executed = false
- data.offset = 1
- save()
- end
- table.remove(storage.stack[#storage.stack].cFStack)
- table.remove(localVars)
- elseif cmd.typeCF == TYPE_CF_WHILE then
- local id = cmd.id
- local data
- if #storage.stack[#storage.stack].cFStack <= cFCount then
- data = { cmd = cmd, condExecuted = false, offset = 1, executed = false, condResult = false }
- table.insert(localVars, {})
- table.insert(storage.stack[#storage.stack].cFStack, data)
- save()
- else
- data = storage.stack[#storage.stack].cFStack[cFCount + 1]
- if data.cmd.id ~= cmd.id then
- print("fail")
- end
- end
- while true do
- if not data.condExecuted then
- local v = executeGetValue(data.cmd.cond, localVars, methods, cFCount)
- if v == nil or type(v) ~= "boolean" then
- error("type of condition needs to be 'boolean' (type '" .. type(v) .. "' given)")
- end
- data.condExecuted = true
- data.condResult = v
- save()
- if not v then
- break
- end
- end
- if data.executed then
- data.offset = data.offset + 1
- end
- save()
- executeCommands(data, data.cmd.body, methods, localVars, cFCount + 1)
- data.condExecuted = false
- data.executed = false
- data.offset = 1
- save()
- end
- table.remove(storage.stack[#storage.stack].cFStack)
- table.remove(localVars)
- else
- error("unknown typeCF: " .. cmd.typeCF .. "")
- end
- else
- error("unknown type: " .. cmd.type)
- end
- end
- function executeCommands(data, cmds, methods, localVars, cFCount)
- for i = data.offset, #cmds do
- local cmd = cmds[i]
- data.offset = i
- data.executed = false
- if cmd.type == TYPE_FUNCTION then
- local isDefault = false
- for i, f in pairs(defaultFunctions) do
- if f.name == cmd.name then
- isDefault = true
- end
- end
- data.executed = not isDefault
- end
- --data.executed = cmd.type == TYPE_FUNCTION
- save()
- executeCommand(cmd, methods, localVars, cFCount)
- data.executed = true
- save()
- end
- end
- function executeGetValue(value, localVars, methods, cFCount)
- if value.type == TYPE_VALUE then
- return value.value
- elseif value.type == TYPE_ARR then
- local vars = {}
- for i = 1, #value.vars do
- vars[i] = executeGetValue(value.vars[i], localVars, methods, cFCount);
- end
- return vars
- elseif value.type == TYPE_VAR then
- for i = 1, #localVars do
- for n, v in pairs(localVars[#localVars - i + 1]) do
- if value.name == n then
- return v
- end
- end
- end
- error("var '" .. value.name .. "' isn't defined yet")
- elseif value.type == TYPE_FUNCTION then
- return executeCommand(value, methods, localVars, cFCount)
- elseif value.type == TYPE_ADD then
- local v = executeGetValue(value.pts[1], localVars, methods, cFCount)
- for i = 2, #value.pts do
- local v1 = executeGetValue(value.pts[i], localVars, methods, cFCount)
- if type(v) == "string" or type(v1) == "string" then
- v = v .. v1
- else
- v = v + v1
- end
- end
- return v
- elseif value.type == TYPE_SUB then
- local v = executeGetValue(value.pts[1], localVars, methods, cFCount)
- for i = 2, #value.pts do
- v = v - executeGetValue(value.pts[i], localVars, methods, cFCount)
- end
- return v
- elseif value.type == TYPE_CONSTANT then
- for k, val in pairs(storage.constants) do
- if (k == value.key) then
- return val
- end
- end
- error("constant '" .. value.key .. "' isn't defined yet")
- elseif value.type == TYPE_CMP then
- local v = executeGetValue(value.pts[1], localVars, methods, cFCount)
- local v1 = executeGetValue(value.pts[2], localVars, methods, cFCount)
- if value.ch == ">" then
- return v > v1
- elseif value.ch == "<" then
- return v < v1
- elseif value.ch == ">=" then
- return v >= v1
- elseif value.ch == "<=" then
- return v <= v1
- elseif value.ch == "==" then
- return v == v1
- elseif value.ch == "!=" then
- return v ~= v1
- else
- error("unknown char: '" .. value.ch .. "'")
- end
- elseif value.type == TYPE_OR then
- for i = 1, #value.values do
- if executeGetValue(value.values[i], localVars, methods, cFCount) then
- return true
- end
- end
- return false
- elseif value.type == TYPE_COMP then
- if value.mode == TYPE_COMP_EQUAL then
- printTable(value.values[1])
- return executeGetValue(value.values[1], localVars, methods, cFCount) == executeGetValue(value.values[2], localVars, methods, cFCount)
- else
- error("unsupported mode: " .. value.mode)
- end
- else
- error("unknown type: " .. value.type)
- end
- end
- function checkMethodValidity(methods)
- local definedNames = {}
- for i, v in pairs(methods) do
- definedNames[v.name] = v.pars
- end
- for i, v in pairs(methods) do
- if v.type == TYPE_USER_FUNCTION then
- checkCmdsValidity(v.cmds, definedNames)
- end
- end
- end
- function checkCmdsValidity(cmds, definedNames)
- for i, cmd in pairs(cmds) do
- if cmd.type == TYPE_FUNCTION then
- if definedNames[cmd.name] == nil then
- error("function '" .. cmd.name .. "' isn't defined")
- end
- local args = definedNames[cmd.name]
- local cStart = args[1]
- local cEnd = cStart
- if #args > 1 then
- cEnd = args[2]
- end
- local count = #cmd.pars
- if count < cStart or count > cEnd then
- error("function '" .. cmd.name .. "' takes between " .. cStart .. " and " .. cEnd .. " argument(s) (" .. count .. " given)")
- end
- checkCmdsValidity(cmd.pars, definedNames)
- elseif cmd.type == TYPE_CONTROL_FLOW then
- if cmd.typeCF == TYPE_CF_WHILE then
- checkCmdsValidity(cmd.body, definedNames)
- elseif cmd.typeCF == TYPE_CF_FOR then
- checkCmdsValidity({ cmd.first, cmd.second, cmd.third }, definedNames)
- checkCmdsValidity(cmd.body, definedNames)
- elseif cmd.typeCF == TYPE_CF_IF then
- for i, block in ipairs(cmd.ifCmdBlocks) do
- if cmd.cond ~= nil then
- checkCmdsValidity({ block.cond }, definedNames)
- end
- checkCmdsValidity(block.body, definedNames)
- end
- else
- error("unknown typeCF: " .. cmd.typeCF)
- end
- elseif cmd.type == TYPE_ARR then
- checkCmdsValidity(cmd.vars, definedNames)
- elseif cmd.type == TYPE_ADD or cmd.type == TYPE_SUB then
- checkCmdsValidity(cmd.pts, definedNames)
- elseif cmd.type == TYPE_DECLARATION then
- checkCmdsValidity({ cmd.value }, definedNames)
- elseif cmd.type ~= TYPE_CONSTANT and cmd.type ~= TYPE_VAR and cmd.type ~= TYPE_VALUE and cmd.type ~= TYPE_CMP then
- printKeys(cmd)
- error("unknown type: " .. cmd.type)
- end
- end
- end
- function printTable(tbl)
- printTableIndex(tbl, "", {})
- end
- function printTableIndex(tbl, before, alreadyUsed)
- for i, v in pairs(tbl) do
- if type(v) == "table" then
- if tableContainsValue(alreadyUsed, v) then
- print(before .. i .. ":", "alreadyUsed");
- else
- print(before .. i .. ": [");
- table.insert(alreadyUsed, v)
- printTableIndex(v, before .. "\t", alreadyUsed)
- print(before .. "]")
- end
- else
- print(before .. i .. ":", v);
- end
- end
- end
- function tableContainsValue(table, value)
- for i, v in pairs(table) do
- if v == value then
- return true
- end
- end
- return false
- end
- local fileName = args[1]
- local stackFileName = fileName .. ".stack"
- local dataFileName = fileName .. ".id"
- if args[3] ~= nil then
- if args[3] == "restart" then
- print("restart")
- if test then
- os.remove(stackFileName)
- else
- fs.delete(stackFileName)
- end
- else
- error("unknown second argument: '" .. args[3] .. "'")
- end
- end
- while true do
- local status, err = pcall(loadProgram, fileName, stackFileName, dataFileName, 0)
- if not status then
- if storage ~= nil then
- print(storage.diedLast, os.clock())
- print("err: ", err)
- if err ~= "Terminated" and (storage.diedLast == nil or os.clock() > 300) then
- storage.diedLast = 0
- save()
- os.reboot()
- return
- end
- else
- print("err: ", err)
- end
- return
- else
- return
- end
- end
Add Comment
Please, Sign In to add comment