Upload System Image

This commit is contained in:
Bommels05
2025-10-21 00:40:14 +02:00
parent 16da0a1837
commit acf66baf57
56 changed files with 28248 additions and 61 deletions

View File

@@ -0,0 +1,648 @@
------------------------------------------------ LevelOOPer Library 2.2.6 ------------------------------------------------
function _G.pairs(t)
local mt = getmetatable(t)
if mt and type(mt.__pairs) == "function" then
return mt.__pairs(t)
else
return next, t, nil
end
end
local function fread(file)
local f = fs.open(file,"r")
local txt = f.readAll()
f.close()
return txt
end
local env = _ENV
local oop = {}
local classCache = {}
local privCache = {}
local publicCache = {}
local objectCache = {}
local dir = fs.getDir(({...})[1] or shell.getRunningProgram())
local function typeRestriction(index, sType, value)
if not oop.isType(value, sType) then
return false, "cannot convert "..sType.." '"..index.."' to '"..oop.type(value, true).."'"
else
return true
end
end
local function getNumberType(number)
if number%1 == 0 then
return "int"
else
return "double"
end
end
oop.setEnv = function(newEnv)
env = newEnv
end
oop.setDir = function(newDir)
oop.expect(1, newDir, "string")
dir = newDir
end
oop.getDir = function()
return dir
end
local default = {
int = 0,
double = 0,
number = 0,
string = "",
["function"] = function() end,
table = {},
boolean = false,
}
local varTypes = {
int = "int",
double = "double",
num = "number",
str = "string",
func = "function",
tbl = "table",
bool = "boolean",
}
local newVar = {
var = function(name)
local tbl = {name=name}
setmetatable(tbl, {
__call = function(self, value)
self.value = value
return self
end
})
return tbl
end,
obj = function(class)
oop.expect(1, class, "class")
local var = {type=classCache[class].name}
setmetatable(var, {
__call = function(self, name)
self.name = name
setmetatable(var, {
__call = function(self, value)
local ok,err = typeRestriction(name, var.type, value)
if not ok then
error(err, 2)
else
self.value = value
return self
end
end,
})
return self
end,
})
return var
end,
}
local const = function(name)
if type(name) == "function" then
return function(realname)
local var = name(realname)
var.const = true
return var
end
elseif type(name) == "string" then
local var = {name=name, const=true}
setmetatable(var, {
__call = function(self, value)
self.value = value
return self
end,
})
return var
end
end
for k,v in pairs(varTypes) do
newVar[k] = function(name)
local tbl = {name=name, type=varTypes[k]}
setmetatable(tbl, {
__call = function(self, value)
local stat,err = typeRestriction(name, tbl.type, value)
if not stat then
error(err, 2)
else
self.value = value
return self
end
end,
})
return tbl
end
end
oop.injectEnv = function(env)
env.oop = oop
env.class = oop.class
env.const = const
env.import = oop.import
env.type = oop.type
env.getPublicObject = oop.getPublicObject
for k,v in pairs(newVar) do
env[k] = v
end
end
local metamethods = {
["__add"] = true,
["__sub"] = true,
["__mul"] = true,
["__div"] = true,
["__mod"] = true,
["__pow"] = true,
["__unm"] = true,
["__concat"] = true,
["__len"] = true,
["__eq"] = true,
["__lt"] = true,
["__le"] = true,
["__index"] = true,
["__newindex"] = true,
["__call"] = true,
["__tostring"] = true,
["__metatable"] = true,
["__pairs"] = true,
["__ipairs"] = true
}
local function sanitizeArgs(...)
local args = table.pack(...)
for k,v in pairs(args) do
if publicCache[v] then
args[k] = publicCache[v]
end
end
return table.unpack(args, nil, args.n)
end
local function instantiate(orig)
local function deepCopy(o, seen)
seen = seen or {}
if seen[o] then
return seen[o]
end
local copy
if type(o) == 'table' then
copy = {}
seen[o] = copy
for k,v in pairs(o) do
copy[deepCopy(k, seen)] = deepCopy(v, seen)
end
setmetatable(copy, deepCopy(getmetatable(o), seen))
else
copy = o
end
return copy
end
return deepCopy(orig)
end
local function makeClass(name, classTbl, inherit)
local class = {
static = {
},
private = {
},
public = {
},
properties = {
static = {
},
private = {
},
public = {
},
types = {
},
consts = {
},
},
metatable = {
public = {
},
private = {
},
},
name = name,
}
class.metatable.static = {
__index = class.static,
__newindex = function(tbl, k, v)
if class.properties.static[k] then
if class.properties.consts[k] then
error("cannot modify const '"..tostring(k).."'", 2)
elseif class.properties.types[k] then
local stat,err = typeRestriction(k, class.properties.types[k], v)
if not stat then
error(err, 2)
else
class.static[k] = v
end
end
elseif class.properties.private[k] then
error("cannot modify private property '"..tostring(k).."' outside of class", 2)
elseif class.properties.public[k] then
error("cannot modify public property '"..tostring(k).."' outside of object", 2)
end
end,
__call = function(self, ...)
local privObj = {}
local obj = {}
privCache[obj] = privObj
publicCache[privObj] = obj
local properties = {}
local privProperties = {}
setmetatable(properties, {__index=class.public})
setmetatable(privProperties, {
__index=function(t, k)
return properties[k] or class.private[k]
end
})
local mt = {
__index = function(t, k)
local p = properties
if t == privObj then
p = privProperties
end
local v = p[k]
if type(v) == "function" then
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
end
return v
end
}
local inConstructor = false
mt.__pairs = function(tbl)
local loopThroughTables = {properties, class.public, class.static}
if tbl == privObj then
table.insert(loopThroughTables, 2, class.private)
end
local cls = class
while cls.parent do -- this WONT WORK
cls = cls.parent
if tbl == privObj then
table.insert(loopThroughTables, cls.private)
end
table.insert(loopThroughTables, cls.public)
table.insert(loopThroughTables, cls.static)
end
local currentIndex = 1
local had = {}
local function customIterator(_, prevKey)
local key, value
while currentIndex <= #loopThroughTables do
key, value = next(loopThroughTables[currentIndex], prevKey)
while key ~= nil and had[key] do -- skip keys that were already found
key, value = next(loopThroughTables[currentIndex], key)
end
if key ~= nil then
had[key] = true
return key, tbl[key]
else
prevKey = nil
currentIndex = currentIndex + 1
end
end
return nil
end
return customIterator, tbl, nil
end
mt.__newindex = function(tbl, k, v)
if class.properties.consts[k] and not inConstructor then
error("cannot modify const '"..tostring(k).."'", 2)
end
if tbl ~= privObj and class.properties.private[k] then
error("cannot modify private property '"..tostring(k).."' outside of class", 2)
end
if class.properties.types[k] then
local stat,err = typeRestriction(k, class.properties.types[k], v)
if not stat then
error(err, 2)
end
end
if class.properties.static[k] then
-- change in whole class
class.static[k] = v
elseif class.properties.private[k] then
privProperties[k] = v
else
properties[k] = v
end
end
local mt2 = {}
for k,v in pairs(mt) do
mt2[k] = v
end
for k,v in pairs(class.metatable.public) do
mt[k] = function(...)
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
return v(sanitizeArgs(...))
end
end
for k,v in pairs(class.metatable.private) do
mt2[k] = function(...)
local tEnv = {self=privObj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(v, tEnv)
return v(sanitizeArgs(...))
end
end
setmetatable(obj, mt)
setmetatable(privObj, mt2)
local constructors = {class.constructor}
local cls = class
while cls.parent do
cls = cls.parent
if cls.constructor then
table.insert(constructors, 1, cls.constructor)
end
end
for t=1,#constructors do
inConstructor = true
local tEnv = {self=privCache[obj] or obj}
oop.injectEnv(tEnv)
setmetatable(tEnv, {__index=env})
setfenv(constructors[t], tEnv)
local status,tObj = pcall(constructors[t],sanitizeArgs(...))
if not status then
error(tObj, 2)
end
if tObj == false then
return false
elseif tObj then
obj = publicCache[tObj] or tObj
end
inConstructor = false
end
objectCache[obj] = class
objectCache[privObj] = class
for k,v in pairs(privObj) do
if type(v) == "table" and v == class.private[k] then
privObj[k] = instantiate(v)
end
end
return obj
end,
}
local iClass
if inherit then
iClass = classCache[inherit]
class.parent = iClass
setmetatable(class.static, {__index=iClass.static})
setmetatable(class.public, {
__index = function(tbl, key)
if iClass.public[key] ~= nil then
return iClass.public[key]
else
return class.static[key]
end
end,
})
setmetatable(class.private, {
__index = function(tbl, key)
if iClass.private[key] ~= nil then
return iClass.private[key]
else
return class.public[key]
end
end,
})
for k,v in pairs(class.properties) do
setmetatable(v, {__index=iClass.properties[k]})
end
setmetatable(class, {__index=iClass})
else
setmetatable(class.public, {__index=class.static})
setmetatable(class.private, {__index=class.public})
end
loopThrough = {"static","private","public"}
for i,l in ipairs(loopThrough) do
if classTbl[l] then
for k,v in pairs(classTbl[l]) do
if type(k) == "number" then
if type(v) == "table" and v.name then
if v.const then
class.properties.consts[v.name] = true
end
if v.type then
class.properties.types[v.name] = v.type
end
if v.value or v.type then
class[l][v.name] = v.value or default[v.type]
end
class.properties[l][v.name] = true -- now values can be generic typed starting with nil but still recognized
elseif type(v) == "string" then
class.properties[l][v] = true
end
elseif type(k) == "string" then
if l == "public" and k == name then -- constructor
if type(v) ~= "function" then
error("invalid constructor: expected function, got "..type(v),2)
end
class.constructor = v
elseif metamethods[k] then
class.metatable[l][k] = v
else
class[l][k] = v
class.properties[l][k] = true
end
end
end
end
end
local classObj = {}
classCache[classObj] = class
class.obj = classObj
setmetatable(classObj, class.metatable.static)
env[name] = classObj
end
function oop.class(name)
return function(class)
if classCache[class] then -- a class object was passed meaning we're gonna inherit
return function(realclass)
makeClass(name, realclass, class)
end
else
makeClass(name, class)
end
end
end
local oType = type
function oop.type(value, numberType)
if oType(value) == "table" then
if objectCache[value] then
return objectCache[value].name
elseif classCache[value] then
return "class"
else
return "table"
end
elseif numberType and oType(value) == "number" then
return getNumberType(value)
else
return oType(value)
end
end
function oop.getClassName(class)
oop.expect(1, class, "class")
return classCache[class].name
end
function oop.isType(value, ...)
local types = {oop.type(value), oType(value), oop.type(value, true)}
if types[1] ~= types[2] and types[3] ~= "class" then
types[3] = "object"
end
local allowedTypes = {...}
for i,t in ipairs(types) do
for i=1, #allowedTypes do
if allowedTypes[i] == t or (allowedTypes[i] == "double" and t == "number") then
return true
end
end
end
return false
end
function oop.expect(index, value, ...)
local level = 3
local allowedTypes = {...}
if type(allowedTypes[1]) == "number" then
level = allowedTypes[1]
table.remove(allowedTypes, 1)
end
if type(allowedTypes[1]) ~= "string" then
error("bad argument #3: expected string", 2)
end
if oop.isType(value, ...) then
return value
end
local expectlist
local numbertype = false
for t=1,#allowedTypes do
if allowedTypes[t] == "int" then
numbertype = true
end
end
if #allowedTypes > 1 then
local lastType = allowedTypes[#allowedTypes]
allowedTypes[#allowedTypes] = nil
expectlist = table.concat(allowedTypes, ", ").." or "..lastType
else
expectlist = allowedTypes[1]
end
local t = oop.type(value, numbertype)
error("bad argument #"..index..": expected "..expectlist.." got "..t.." ("..tostring(value)..")", level)
end
function oop.getPublicObject(privateObject)
return publicCache[privateObject] or privateObject
end
function oop.import(filepath)
oop.expect(1, filepath, "string")
local makePackage = require("cc.require")
local tEnv = setmetatable({shell=shell, multishell=multishell},{__index=env})
tEnv.require, tEnv.package = makePackage.make(tEnv, dir)
tEnv.oop = oop
oop.injectEnv(tEnv)
local pathlog = filepath
local filepath2 = filepath..".lua"
pathlog = pathlog.."\n"..filepath2
if filepath:sub(1,1) ~= "/" then
pathlog = pathlog.."\n"..fs.combine(dir, filepath)
pathlog = pathlog.."\n"..fs.combine(dir, filepath2)
if fs.exists(fs.combine(dir, filepath)) then
filepath = fs.combine(dir, filepath)
elseif fs.exists(fs.combine(dir, filepath2)) then
filepath = fs.combine(dir, filepath2)
end
end
if fs.exists(filepath2) and not fs.exists(filepath) then
filepath = filepath2
end
if not fs.exists(filepath) then
error("Could not find file:"..pathlog,2)
end
local f = fread(filepath)
local func, err = load(f, "@"..filepath, nil, tEnv)
if not func then
error(err, 2)
else
local ok,err = pcall(func)
if not ok then
error(err, 2)
end
end
end
return oop

View File

@@ -0,0 +1,723 @@
local tokens = {
whitespace = {
["\t"] = true,
[" "] = true,
["\n"] = true,
[","] = true,
},
line = {
["\n"] = true,
[","] = true,
},
label = {
[":"] = true,
},
indexVar = {
["%"] = true,
},
operator = {},
op = {
add = {
["+"] = true,
},
subtract = {
["-"] = true,
},
multiply = {
["*"] = true,
},
modulo = {
["%"] = true,
},
power = {
["^"] = true,
},
divide = {
["/"] = true,
},
},
assign = {
["="] = true,
},
comparison = {},
comp = {
equals = {
["=="] = true,
},
notEquals = {
["~="] = true,
},
bigger = {
[">"] = true,
},
biggerOrEquals = {
[">="] = true,
},
smaller = {
["<"] = true,
},
smallerOrEquals = {
["<="] = true,
},
},
logic = {},
logicAnd = {
["and"] = true,
["&&"] = true,
},
logicOr = {
["or"] = true,
["||"] = true,
},
logicNot = {
["not"] = true,
["!"] = true,
},
keyword = {},
ifStatement = {
["if"] = true,
},
whileStatement = {
["while"] = true,
},
forStatement = {
["for"] = true,
},
elseStatement = {
["else"] = true,
},
localStatement = {
["local"] = true,
},
eof = {
["end"] = true,
["exit"] = true,
},
boolean = {},
boolTrue = {
["true"] = true,
},
boolFalse = {
["false"] = true,
},
ident = {
["_"] = true,
},
digits = {
},
string = {
["\""] = true,
["'"] = true,
},
symbol = {
["("] = true,
[")"] = true,
},
escape = {
["\\"] = true,
}
}
for c=("a"):byte(), ("z"):byte() do
tokens.ident[string.char(c)] = true
tokens.ident[string.char(c):upper()] = true
end
for c=("0"):byte(), ("9"):byte() do
tokens.ident[string.char(c)] = true
tokens.digits[string.char(c)] = true
end
local function addTo(root, ...)
if not root then error("invalid argument #1: expected table, got nil",2) end
local tbls = {...}
for i,t in ipairs(tbls) do
for k,v in pairs(t) do
root[k] = v
end
end
end
for k,v in pairs(tokens.comp) do
addTo(tokens.comparison, v)
end
for k,v in pairs(tokens.op) do
addTo(tokens.operator, v)
end
addTo(tokens.logic, tokens.logicAnd, tokens.logicOr, tokens.logicNot)
addTo(tokens.keyword, tokens.logic, tokens.ifStatement, tokens.whileStatement, tokens.forStatement, tokens.elseStatement, tokens.localStatement, tokens.eof)
addTo(tokens.boolean, tokens.boolTrue, tokens.boolFalse)
local statementValues = {
["string"] = true,
["number"] = true,
["variable"] = true,
["arg"] = true,
["value"] = true,
}
local validVarTypes = {
["function"] = true,
["arg"] = true,
["variable"] = true,
["escape"] = true,
}
local function lex(text)
local char = 1
local function get(p)
local tPos = p or char
return text:sub(tPos,tPos)
end
local beginline = true
local inStatement = false
local isLabel = false
local data = {{}}
local line = data[1]
local posOffset = 0
local function newline()
posOffset = char
table.insert(data,{})
line = data[#data]
end
local function addData(txt,type)
if not txt then error("no txt",2) end
if line[#line] and line[#line].type == type then
line[#line].data = line[#line].data..txt
line[#line].posLast = line[#line].posLast+#txt
else
table.insert(line,{data=txt,posFirst=(char-posOffset),posLast=(char-posOffset)+(#txt-1),type=type})
end
end
local function readWhitespace(acceptNewline)
local txt = get()
local oldchar = char
while tokens.whitespace[txt] and (acceptNewline or not tokens.line[txt]) do
char = char + 1
addData(txt,"whitespace")
isLabel = false
txt = get()
end
if oldchar == char then
return false
else
return true
end
end
while char <= #text do
local txt = get()
if tokens.whitespace[txt] and not tokens.line[txt] then
addData(txt,"whitespace")
isLabel = false
elseif tokens.escape[txt] then
addData(txt..text:sub(char+1,char+1),"escape")
char = char+1
if tokens.whitespace[get(char+1)] then
isLabel = false
beginline = false
end
elseif tokens.string[txt] then
local bchar = txt
local echar = bchar
local stype = "string"
if isLabel then
stype = "label"
elseif beginline then
stype = "function"
end
isLabel = false
beginline = false
addData(txt,stype)
char = char+1
while char <= #text do
local c = text:sub(char,char)
if tokens.escape[c] then
addData(c..get(char+1),"escape")
char = char+1
if tokens.digits[get()] then
char = char+1
for i=1,2 do
if tokens.digits[get()] then
addData(get(),"escape")
char = char+1
else
break
end
end
else
char = char+1
end
elseif tokens.indexVar[c] then
local b2,e2 = text:find("^%%[A-Za-z0-9_]+%%", char)
if b2 then
addData(text:sub(b2,e2), "variable")
char = e2
else
local b3,e3 = text:find("^%%[0-9]+", char)
if not b3 then
b3,e3 = text:find("^%%~[0-9]+", char)
end
if b3 then
addData(text:sub(b3,e3), "arg")
char = e3
else
addData(c, stype)
end
end
char = char+1
elseif c == echar then
addData(c, stype)
break
else
if c == "\n" then
newline()
else
addData(c, stype)
end
char = char+1
end
end
elseif tokens.indexVar[txt] then
if inStatement == 1 and line[#line] and line[#line].type == "whitespace" and line[#line-1] and statementValues[line[#line-1].type] then
inStatement = false
beginline = true
end
local b2,e2 = text:find("^%%[A-Za-z0-9_]+%%", char)
if b2 then
if isLabel and beginline then
addData(text:sub(b2,e2), "unidentified")
else
addData(text:sub(b2,e2), "variable")
end
char = e2
else
local b3,e3 = text:find("^%%[0-9]+", char)
if not b3 then
b3,e3 = text:find("^%%~[0-9]+", char)
end
if b3 then
if isLabel and beginline then
addData(text:sub(b3,e3), "unidentified")
else
addData(text:sub(b3,e3), "arg")
end
char = e3
elseif isLabel then
addData(txt, "label")
elseif beginline then
addData(txt, "function")
elseif not inStatement then
addData(txt, "string")
elseif tokens.operator[txt] then
addData(txt, "operator")
else
addData(txt, "unidentified")
end
end
if tokens.whitespace[get(char+1)] then
beginline = false
end
elseif tokens.ident[txt] or (not inStatement and not (tokens.line[txt] or tokens.label[txt] or tokens.assign[txt] or tokens.symbol[txt])) then
local b,e
if inStatement then
b,e = text:find("^[A-Za-z0-9_.]+", char)
else
b,e = char,char+1
local c = get(e)
while e <= #text and not (tokens.line[c] or tokens.label[c] or tokens.assign[c] or tokens.indexVar[c] or tokens.whitespace[c] or tokens.symbol[c] or tokens.escape[c]) do
e = e + 1
c = get(e)
end
e = e - 1
end
local token = text:sub(b,e)
local ltoken = token:lower()
local statementValue = false
if inStatement then
if line[#line] and line[#line].type == "whitespace" and line[#line-1] and statementValues[line[#line-1].type] then
if inStatement == 1 then
inStatement = 0
beginline = true
end
statementValue = true
end
end
char = e
if isLabel then
addData(token, "label")
if tokens.whitespace[get(char+1)] then
isLabel = false
beginline = false
end
elseif tokens.localStatement[ltoken] and not inStatement then
if not beginline then
addData(token, "string")
else
addData(token, "keyword")
end
elseif tokens.eof[ltoken] and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
elseif (tokens.ifStatement[ltoken] or tokens.whileStatement[ltoken]) and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
inStatement = 1
elseif (tokens.elseStatement[ltoken] or tokens.eof[ltoken]) and (inStatement == 0 or not inStatement) then
addData(token, "keyword")
elseif (tokens.logicAnd[ltoken] or tokens.logicOr[ltoken]) and statementValue then
addData(token, "logic")
if inStatement == 0 then
inStatement = 1
end
elseif tokens.logicNot[ltoken] and inStatement and not statementValue then
addData(token, "logic")
if inStatement == 0 then
inStatement = 1
end
elseif tokens.forStatement[ltoken] and (inStatement == 0 or not inStatement) then
-- other handling
elseif tokens.boolean[ltoken] and inStatement and not statementValue then
addData(token, "value")
elseif beginline and (inStatement == 0 or not inStatement) then
addData(token, "function")
if tokens.whitespace[get(char+1)] then
beginline = false
end
elseif tonumber(token) then
addData(token, "number")
if tokens.whitespace[get(char+1)] then
beginline = false
end
else
addData(token, "string")
end
if inStatement == 0 then
inStatement = false
end
elseif tokens.label[txt] then
if char+1 > #text or tokens.whitespace[get(char+1)] then
addData(txt, "string")
else
addData(txt, "label")
isLabel = true
end
elseif tokens.line[txt] then
beginline = true
inStatement = false
if txt ~= "\n" then
addData(txt, "symbol")
end
elseif tokens.symbol[txt] then
addData(txt, "symbol")
elseif txt:find("%p") then
local b,e = text:find("^%p+", char)
local token = text:sub(b,e)
char = e
if inStatement then
if tokens.operator[token] then
addData(token, "operator")
elseif tokens.comparison[token] then
addData(token, "comparison")
elseif tokens.logic[token] then
addData(token, "logic")
else
addData(token, "string")
end
else
if tokens.assign[token] then
local v = line[#line]
if v and v.type == "whitespace" then
v = line[#line-1]
end
if v and (validVarTypes[v.type]) then
local it = #line-1
while v and (validVarTypes[v.type]) do
if v.type == "function" then
v.type = "variable"
end
it = it-1
v = line[it]
end
addData(token, "assign")
inStatement = true
elseif beginline then
addData(token, "unidentified")
else
addData(token, "string")
end
elseif beginline then
addData(token, "unidentified")
else
addData(token, "string")
end
end
elseif txt ~= "\n" then
addData(txt, "unidentified")
end
if txt == "\n" then
newline()
end
char = char+1
end
return data
end
local function parse(data, filename)
filename = filename or "latch"
if type(data) == "string" then
data = lex(data)
end
local function err(lineNum, txt, txtafter)
local err = filename..": "..txt.." on line "..lineNum
if txtafter then
err = err.." ("..txtafter..")"
end
error(err, 0)
end
local function unexpectedToken(line, token, ...)
_G.debugtoken = token
local exp = {...}
local expstr
if #exp > 0 then
expstr = "expected "..table.concat(exp, ", ")
end
err(line, "unexpected token '"..tostring(token.data).."' ("..tostring(token.type)..")", expstr)
end
local function locateEntry(tbl, value)
for k,v in pairs(tbl) do
if v == value then
return true
end
end
return false
end
local function parseToken(line, i, allowed, stopAt)
local token = line[i]
local data = {}
stopAt = stopAt or {"whitespace"}
while true do
if locateEntry(allowed, token.type) then
if token.type == "number" then
table.insert(data, {type="number", data=token.data})
elseif token.type == "operator" then
table.insert(data, {type="operator", data=token.data})
elseif token.type == "variable" and token.data:sub(1,1) == "%" then
table.insert(data, {type="variable", data=token.data:sub(2,#token.data-1)})
elseif token.type == "variable" then
table.insert(data, {type="string", data=token.data})
elseif token.type == "arg" then
table.insert(data, {type="argument", data=token.data:sub(2)})
elseif token.type == "label" then
if tokens.string[token.data:sub(2,2)] then
table.insert(data, {type="label", data=token.data:sub(2):gsub(token.data:sub(2,2),"")})
else
table.insert(data, {type="label", data=token.data:sub(2)})
end
elseif tokens.string[token.data:sub(1,1)] then
table.insert(data, {type="string", data=token.data:gsub(token.data:sub(1,1),"")})
else
table.insert(data, {type="string", data=token.data})
end
elseif locateEntry(stopAt, token.type) then
i = i - 1
break
else
local expected = {}
addTo(expected, stopAt)
addTo(expected, allowed)
unexpectedToken(ln, token, unpack(expected))
end
i = i + 1
token = line[i]
if not token then break end
end
return data, i
end
local function parseExpression(line, i, whitespaceConcat) -- this is all wrong FUCK, value (x+5) > comparison (x+5 == 8) > expression(x+5 == 8 and %potato%)
-- expression structure
local token = line[i]
local conditions = {
{
{} -- current condition (value)
-- more AND conditions
}
-- more OR conditions
}
local condition = conditions[1][1]
local isValid = false
while true do
token = line[i]
if not token then break end
if token.type == "whitespace" then -- optional token
elseif token.type == "logic" and tokens.logicNot[token.data] then -- optional token
table.insert(condition, token)
isValid = false
elseif statementValues[token.type] then -- REQUIRED token, expression is invalid without it
table.insert(condition, token)
isValid = true
i = i + 1
token = line[i]
if not token then break end
if token.type == "whitespace" then
i = i + 1
token = line[i]
end
if not token then break end
if token.type == "logic" and tokens.logicAnd[token.data] then
condition = {}
table.insert(conditions[#conditions], condition)
isValid = false
elseif token.type == "logic" and tokens.logicOr[token.data] then
condition = {}
table.insert(conditions, {})
table.insert(conditions[#conditions], condition)
isValid = false
elseif token.type == "operator" then
table.insert(condition, token)
elseif whitespaceConcat then
i = i - 1
else
i = i - 1
break -- end of statement
end
else
unexpectedToken(i, token, "expression")
end
i = i + 1
end
if not isValid then
err(i, "invalid statement")
else
return conditions, i
end
end
local program = {
arguments = {},
env = {},
commands = {},
labels = {},
code = {},
}
local scope = program.code
for ln,line in ipairs(data) do
local token
local i = 1
local beginline = true
local function nextToken(includeWhitespace)
if line[i+1] and (includeWhitespace or line[i+1].type ~= "whitespace") then
return line[i+1]
elseif line[i+2] then
return line[i+2]
end
end
local function nextTokenType(includeWhitespace)
local nt = nextToken(includeWhitespace)
if nt then
return nt.type
end
end
while i <= #line do
token = line[i]
if beginline then
if token.type == "function" or token.type == "variable" or token.type == "arg" then
local data
data, i = parseToken(line, i, {"function", "variable", "arg", "escape"}, {"whitespace", "symbol", "assign"})
local l
if nextTokenType() == "assign" then
l = {type="assign", data=data, value={}}
while nextTokenType() == "assign" do
i = i + 1
end
i = i + 1
l.value, i = parseExpression(line, i, true)
else
l = {type="command", data=data, line=ln, params={}}
beginline = false
end
table.insert(scope, l)
elseif token.type == "label" then
program.labels[token.data] = {scope=scope, commandNum=#scope+1}
elseif token.type ~= "whitespace" then
--unexpectedToken(ln, token, "whitespace", "function", "variable", "arg")
end
else
if token.type == "label" then
if scope[#scope].type == "command" then
local data
data, i = parseToken(line, i, {"label", "variable", "arg", "escape"}, {"whitespace", "symbol"})
table.insert(scope[#scope].params, data)
else
unexpectedToken(ln, token)
end
elseif token.type == "string" or token.type == "number" then
if scope[#scope].type == "command" then
local data
data, i = parseToken(line, i, {"string", "number", "variable", "arg", "escape"}, {"whitespace", "symbol"})
table.insert(scope[#scope].params, data)
end
elseif token.type ~= "whitespace" then
end
end
i = i + 1
end
end
return program
end
return {lex=lex,parse=parse}

View File

@@ -0,0 +1 @@
{{{"Ÿ€"," b ","b ",},{"ƒ","bb9"," 9 ",},{"€€€"," "," ",},},}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{{{"‡‹"," 0","00 ",},{"ƒ‡","000"," ",},},}

View File

@@ -0,0 +1 @@
{{{"ƒ€€","1 ","444",},{"—Œ”","499","944",},{"€€€"," "," ",},},}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{{{"—‹"," 0","00 ",},{"Š…","000"," ",},},}

View File

@@ -0,0 +1 @@
{{{"Ÿˆ"," b","bb ",},{"€‚•"," 0b","bb ",},{"‚ƒ€","bb "," ",},},}

View File

@@ -0,0 +1,172 @@
local tArgs = {...}
if type(tArgs[1]) == "string" and fs.exists(tArgs[1]) then
lOS.execute(table.concat(tArgs," "))
return
end
if LevelOS then LevelOS.self.window.icon = {"\3","b"} end
local lex = "LevelOS/modules/lex.lua"
local docs = "Program_Files/Slime_Text/highlight/lua/docs.json"
local docstable
if not fs.exists(lex) then
-- oh no
end
if not fs.exists(docs) then
local webres = http.get("http://tweaked.cc/index.json")
if webres then
docstable = textutils.unserializeJSON(webres.readAll())
end
--[[if webres then
lUtils.fwrite(docs,webres.readAll())
end]]
end
if fs.exists(docs) then
docstable = textutils.unserializeJSON(lUtils.fread(docs))
end
local pretty = require "cc.pretty"
local tCommandHistory = {}
local hCur = 0
local bRunning = true
local tEnv = {
["exit"] = setmetatable({}, {
__tostring = function() return "Call exit() to exit." end,
__call = function() bRunning = false end,
__type = "function",
}),
["_echo"] = function(...)
return ...
end,
}
setmetatable(tEnv, { __index = _ENV })
term.setTextColor(colors.yellow)
print("LevelOS interactive Lua prompt.\nCall exit() to exit.")
term.setTextColor(colors.white)
while bRunning do
hCur = #tCommandHistory+1
write("lua> ")
local w,h = term.getSize()
local x,y = term.getCursorPos()
local self = lUtils.input(x,y,w,y)
self.opt.cursorColor = colors.white
self.opt.overflowY = "scroll"
self.scrollY = 0
self.opt.syntax = {
type="lua",
keyword=colors.yellow,
comment=colors.green,
string=colors.red,
number=colors.purple,
symbol=colors.white,
operator=colors.lightGray,
value=colors.purple,
ident=colors.white,
["function"]=colors.cyan,
nfunction=colors.lime,
arg=colors.orange,
lexer=lex,
whitespace=colors.lightGray,
}
self.opt.complete = {
docs = docstable,
env = tEnv,
overlay = true,
LevelOS = LevelOS,
}
self.opt.selectColor=colors.gray
self.opt.overflowY="stretch"
self.opt.overflowX="scroll"
_G.debugeditor = self
while true do
tCommandHistory[hCur] = self.txt
self.state = true
local doUpdate = true
local e = {os.pullEvent()}
if e[1] == "term_resize" then
local w,h = term.getSize()
self.x2 = w
elseif e[1] == "key" and (e[2] == keys.up or e[2] == keys.down) and not self.opt.complete.list then
doUpdate = false
local o = 1
if e[2] == keys.up then
o = -1
end
if tCommandHistory[hCur+o] then
hCur = hCur+o
self.txt = tCommandHistory[hCur]
self.cursor.x = #self.txt+1
self.cursor.a = #self.txt+1
end
self.update("term_resize")
elseif e[1] == "key" and e[2] == keys.enter and not lUtils.isHolding(keys.leftShift) then
if hCur < #tCommandHistory then
hCur = #tCommandHistory
tCommandHistory[hCur] = self.txt
end
doUpdate = false
term.setCursorBlink(false)
LevelOS.overlay = nil
print("")
local s = self.txt
local nForcePrint = 0
local func, e = load(s, "=lua", "t", tEnv)
local func2 = load("return _echo(" .. s .. ");", "=lua", "t", tEnv)
if not func then
if func2 then
func = func2
e = nil
nForcePrint = 1
end
else
if func2 then
func = func2
end
end
if func then
local tResults = table.pack(pcall(func))
if tResults[1] then
local n = 1
while n < tResults.n or n <= nForcePrint do
local value = tResults[n + 1]
local ok, serialised = pcall(pretty.pretty, value, {
function_args = settings.get("lua.function_args"),
function_source = settings.get("lua.function_source"),
})
if ok then
pretty.print(serialised)
else
print(tostring(value))
end
n = n + 1
end
else
printError(tResults[2])
end
else
printError(e)
end
break
elseif e[1] == "key" or e[1] == "char" or e[1] == "paste" then
if hCur < #tCommandHistory then
hCur = #tCommandHistory
tCommandHistory[hCur] = self.txt
end
end
if doUpdate then
self.update(unpack(e))
end
local w,h = term.getSize()
while self.y2 > h do
if self.y1 > 1 then
term.scroll(1)
self.y2 = self.y2-1
self.y1 = self.y1-1
else
self.y1 = 1
self.y2 = h
self.opt.overflowY = "scroll"
end
end
self.render()
end
end

View File

@@ -0,0 +1 @@
{{{"Ÿœ’"," 00","0 ",},{"‚","000"," ",},},}

View File

@@ -0,0 +1 @@
{{{"ŸŸ€"," ","77 ",},{"•","888","77 ",},{"ˆŒ•","778","88 ",},},}

View File

@@ -0,0 +1,273 @@
local tArgs = {...}
local tFilepath = ""
if tArgs[1] ~= nil then
tFilepath = tArgs[1]
end
local isReadOnly = false
if tArgs[2] ~= nil and tArgs[2] == "true" then
isReadOnly = true
end
local tCol = {bg=colors.white,txt=colors.black,misc=colors.lightGray,misc2=colors.gray}
local btns = {{"File",{{"New","New window","Open...","Save","Save as..."},"Print","Quit"}},{"Edit",{"Undo",{"Search","Replace"},{"Time"}}},{"View",{"Dark Mode"}}}
local function topbar()
local w,h = term.getSize()
theline = ""
for t=1,w-1 do
theline = theline.."\131"
end
term.setCursorPos(1,1)
term.setBackgroundColor(tCol.bg)
term.setTextColor(tCol.misc)
term.clearLine()
term.setCursorPos(1,2)
term.write(theline)
term.setCursorPos(1,1)
term.setTextColor(tCol.txt)
for t=1,#btns do
btns[t].x = ({term.getCursorPos()})[1]
btns[t].w = string.len(btns[t][1])+2
term.write(" "..btns[t][1].." ")
end
end
local w,h = term.getSize()
local a = {}
local function txt()
a = {{width=w-1,height=h-4,sTable={},filepath="",lines={""},changed=false},0,0,1,1}
if tFilepath ~= "" then
if fs.exists(tFilepath) == true then
local openfile = fs.open(tFilepath,"r")
a[1].lines = {}
for line in openfile.readLine do
a[1].lines[#a[1].lines+1] = line
end
openfile.close()
if a[1].lines[1] == nil then
a[1].lines[1] = ""
end
end
end
while true do
local w,h = term.getSize()
a[1].width = w-1
a[1].height = h-4
a[1].sTable = {background={tCol.bg},text={tCol.txt},cursor={colors.red}}
term.setCursorPos(1,5)
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
--print("I am present.")
local changesAllowed = true
if isReadOnly == true or (tFilepath ~= "" and fs.isReadOnly(tFilepath) == true) then
changesAllowed = false
end
a = {lUtils.drawEditBox(a[1],1,3,a[2],a[3],a[4],a[5],true,true,nil,changesAllowed)}
--term.setCursorPos(1,3)
--term.clearLine()
--term.write("HIII: ")
--term.write(textutils.serialize(a))
os.sleep(0)
end
end
_G.thetxtfunction = txt
local function save()
if tFilepath == "" then
while true do
local i = {lUtils.inputbox("Filepath","Please enter a new filepath:",29,10,{"Done","Cancel"})}
if i[2] == false or i[4] == "Cancel" then
return false
end
if fs.exists(i[1]) == true then
lUtils.popup("Error","This path already exists!",29,9,{"OK"})
else
tFilepath = i[1]
break
end
end
end
local savefile = fs.open(tFilepath,"w")
for t=1,#a[1].lines do
savefile.writeLine(a[1].lines[t])
end
savefile.close()
return true
end
function uwansave()
local name = ""
if tFilepath == "" then
name = "Untitled"
else
name = fs.getName(tFilepath)
end
local c = {lUtils.popup("Notepad","Do you want to save your changes in "..name.."?",30,8,{"Save","Don't save","Cancel"})}
if c[1] == false then return false
elseif c[3] == "Save" then
if tFilepath == "" then
-- select file path with explorer asap
return false
end
local ayyy = fs.open(tFilepath,"w")
for t=1,#a[1].lines do
ayyy.writeLine(a[1].lines[t])
end
end
if c[3] ~= "Cancel" then
return true
end
end
local function scrollbars()
local w,h = term.getSize()
term.setCursorPos(1,h-1)
term.setBackgroundColor(tCol.misc)
term.setTextColor(tCol.misc2)
term.clearLine()
term.setCursorPos(1,h-1)
term.write("\17")
term.setCursorPos(w-1,h-1)
term.write("\16")
for t=2,h-2 do
term.setCursorPos(w,t)
if t == 3 then
term.write("\30")
elseif t == h-2 then
term.write("\31")
else
term.write(" ")
end
end
term.setCursorPos(1,h)
for t=1,w do
term.write("\131")
end
end
function LevelOS.close()
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
return
else
regevents()
end
end
function regevents()
scrollbars()
local txtcor = coroutine.create(txt)
topbar()
coroutine.resume(txtcor)
while true do
e = {os.pullEvent()}
scrollbars()
if not ((e[1] == "mouse_click" or e[1] == "mouse_up") and e[4] == 1) then
coroutine.resume(txtcor,table.unpack(e))
end
--term.setCursorPos(1,3)
--term.setBackgroundColor(colors.white)
--term.setTextColor(colors.black)
--term.clearLine()
--term.setCursorPos(1,3)
--term.write(coroutine.status(txtcor).." "..textutils.serialize(a[1]))
if e[1] == "term_resize" then
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
elseif e[1] == "mouse_click" then
if e[4] == 1 then
topbar()
term.setCursorBlink(false)
local oldcursorpos = {term.getCursorPos()}
for t=1,#btns do
if e[3] >= btns[t].x and e[3] <= btns[t].x+btns[t].w-1 then
-- open menu and color button light blue
term.setCursorPos(btns[t].x,1)
term.setBackgroundColor(colors.blue)
term.write(" "..btns[t][1].." ")
local disabled = {}
if btns[t][1] == "File" then
if a[1].changed == false then
disabled = {"Save","Save as..."}
end
end
local b = {lUtils.clickmenu(btns[t].x,2,20,btns[t][2],true,disabled)}
if b[1] ~= false then
if b[3] == "New" then
local d = true
if a[1].changed == true then
d = uwansave()
end
if d == true then
tFilepath = ""
txtcor = coroutine.create(txt)
os.startTimer(0.1)
end
elseif b[3] == "New window" then
lOS.execute(LevelOS.path)
elseif b[3] == "Open..." then
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
local d = {lUtils.explorer("/","SelFile false")}
if d[1] ~= nil then
if fs.exists(d[1]) == true then
a = {}
txtcor = coroutine.create(txt)
coroutine.resume(txtcor)
tFilepath = d[1]
local openfile = fs.open(tFilepath,"r")
a[1].lines = {}
for line in openfile.readLine do
a[1].lines[#a[1].lines+1] = line
end
openfile.close()
if a[1].lines[1] == nil then
a[1].lines[1] = ""
end
end
end
end
elseif b[3] == "Save" then
if save() == true then
a[1].changed = false
end
elseif b[3] == "Save as..." then
local oldF = tFilepath
tFilepath = ""
if save() == false then
tFilepath = oldF
else
a[1].changed = false
end
elseif b[3] == "Quit" then
local u = true
if a[1].changed == true then
u = uwansave()
end
if u == true then
return
end
elseif b[3] == "Dark Mode" then
tCol = {bg=colors.black,txt=colors.white,misc=colors.gray,misc2=colors.lightGray}
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
btns[3][2][1] = "Light Mode"
elseif b[3] == "Light Mode" then
tCol = {bg=colors.white,txt=colors.black,misc=colors.lightGray,misc2=colors.gray}
topbar()
scrollbars()
coroutine.resume(txtcor,"mouse_click",1,1,1)
btns[3][2][1] = "Dark Mode"
end
end
end
end
topbar()
term.setCursorPos(table.unpack(oldcursorpos))
term.setTextColor(colors.red)
term.setCursorBlink(true)
end
end
end
end
regevents()

View File

@@ -0,0 +1 @@
{{{"•ƒ•"," 0","00 ",},{"Š…","000"," ",},},}

View File

@@ -0,0 +1 @@
{{{"‡Œ‹"," ","999",},{"€Š€"," 9 ","909",},{"","999"," ",},},}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{{{"—Œ”"," 0","00 ",},{"Š…","000"," ",},},}