diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71bfb3c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.stfolder diff --git a/halyde/apps/lua.lua b/halyde/apps/lua.lua index 251f1ee..9fc9d64 100644 --- a/halyde/apps/lua.lua +++ b/halyde/apps/lua.lua @@ -1,10 +1,10 @@ print("\27[44m".._VERSION.."\27[0m shell") print('Type "exit" to exit.') -termlib.readHistory["lua"] = {""} +terminal.readHistory["lua"] = {""} local fs = require("filesystem") local loadedLibraries = "" -local libList = fs.list("halyde/lib") +local libList = fs.list("/lib/") for _, lib in pairs(libList) do if lib:match("(.+)%.lua") then loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n' @@ -12,7 +12,7 @@ for _, lib in pairs(libList) do end while true do - local command = read("lua", "\27[44mlua>\27[0m ") + local command = terminal.read("lua", "\27[44mlua>\27[0m ") if command == "exit" then return else diff --git a/halyde/kernel/boot.lua b/halyde/kernel/boot.lua index 27c5c41..cf36067 100644 --- a/halyde/kernel/boot.lua +++ b/halyde/kernel/boot.lua @@ -3,7 +3,6 @@ local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile)) _G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file _G._OSLOGO = "" _G._PUBLIC = {} -local ocelot = component.proxy(component.list("ocelot")()) local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil repeat @@ -16,7 +15,6 @@ _G.package = {["preloaded"] = {}} loadfile("/halyde/kernel/modules/datatools.lua")() function _G.require(module, ...) - ocelot.log("Requiring " .. module) local args = table.pack(...) if package.preloaded[module] then return package.preloaded[module] @@ -50,7 +48,7 @@ function _G.package.preload(module) _G[module] = nil end -require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. +require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. TODO: When VFS is implemented, make the pre-VFS loading of filesystem load a more basic version. And remove this. require("/halyde/kernel/modload.lua") package.preload("component") diff --git a/halyde/kernel/evmgr.lua b/halyde/kernel/evmgr.lua index 861cfa1..b5525d3 100644 --- a/halyde/kernel/evmgr.lua +++ b/halyde/kernel/evmgr.lua @@ -30,7 +30,7 @@ while true do if print then print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.") end - tsched.tasks[#tsched.tasks] = nil + table.remove(tsched.tasks, #tsched.tasks) end elseif args[2] == "key_up" then local keycode = args[5] diff --git a/halyde/kernel/modload.lua b/halyde/kernel/modload.lua index 6aa7dfa..9cab079 100644 --- a/halyde/kernel/modload.lua +++ b/halyde/kernel/modload.lua @@ -1,19 +1,16 @@ local fs = require("filesystem") -local ocelot = require("component").ocelot local modulePath = "/halyde/kernel/modules" -local modules = fs.list(modulePath) +local modules = assert(fs.list(modulePath)) local moduleTypes = {} local function loadModule(modName) - ocelot.log("Checking module " .. modName) - local moduleData = require(fs.concat(modulePath, modName)) + local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on table.remove(modules, table.find(modules, modName)) if not moduleData.check() then return end - ocelot.log("Loading module " .. modName) if moduleData.dependencies then for _, dependency in pairs(moduleData.dependencies) do if table.find(modules, dependency) then @@ -37,7 +34,7 @@ local function loadModule(modName) end for _, modName in pairs(modules) do -- Get all the module types - local moduleData = require(fs.concat(modulePath, modName)) + local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on if moduleData.type then --print(moduleData.type) moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key @@ -49,5 +46,3 @@ while modules[1] do loadModule(modules[1]) end end - -ocelot.log("Finished loading modules!") diff --git a/halyde/kernel/modules/ipc.lua b/halyde/kernel/modules/ipc.lua index fbdbec7..13e7e7e 100644 --- a/halyde/kernel/modules/ipc.lua +++ b/halyde/kernel/modules/ipc.lua @@ -1,15 +1,125 @@ local module = {} function module.check() - return true -- This module should always be loaded + return true -- IPC should always be loaded end function module.init() + _G.ipc = {} + _G.ipc.shared = {} + _PUBLIC.ipc = {} + function _PUBLIC.ipc.shareWithAll() + local shareTable = {} + setmetatable(shareTable, {["__newindex"] = function(_, key, value) + local currentPID = _PUBLIC.tsched.getCurrentTask().id + if not _G.ipc.shared[currentPID] then + _G.ipc.shared[currentPID] = {} -- TODO: Add some kind of cleanup routine since these IPC shares can just keep piling up + end + local globalTable + for _, tab in pairs(_G.ipc.shared[currentPID]) do + if tab.sharedWith == "all" then + globalTable = tab + end + end + if not globalTable then + globalTable = {["sharedWith"] = "all"} + table.insert(_G.ipc.shared[currentPID], globalTable) + end + if not globalTable.vars then + globalTable.vars = {} + end + globalTable.vars[key] = value + end, ["__index"] = function(_, key) + local currentPID = _PUBLIC.tsched.getCurrentTask().id + if not _G.ipc.shared[currentPID] then + return nil + end + local globalTable + for _, tab in pairs(_G.ipc.shared[currentPID]) do + if tab.sharedWith == "all" then + globalTable = tab + end + end + if not globalTable then + return nil + end + if not globalTable.vars then + return nil + end + return globalTable.vars[key] + end}) + return shareTable + end + + function _PUBLIC.ipc.shareWith(pid) + checkArg(1, pid, "number") + local shareTable = {} + setmetatable(shareTable, {["__newindex"] = function(_, key, value) + local currentPID = _PUBLIC.tsched.getCurrentTask().id + if not _G.ipc.shared[currentPID] then + _G.ipc.shared[currentPID] = {} -- TODO: Add some kind of cleanup routine since these IPC shares can just keep piling up + end + local globalTable + for _, tab in pairs(_G.ipc.shared[currentPID]) do + if tab.sharedWith == "all" then + globalTable = tab + end + end + if not globalTable then + globalTable = {["sharedWith"] = pid} + table.insert(_G.ipc.shared[currentPID], globalTable) + end + if not globalTable.vars then + globalTable.vars = {} + end + globalTable.vars[key] = value + end, ["__index"] = function(_, key) + local currentPID = _PUBLIC.tsched.getCurrentTask().id + if not _G.ipc.shared[currentPID] then + return nil + end + local globalTable + for _, tab in pairs(_G.ipc.shared[currentPID]) do + if tab.sharedWith == pid then + globalTable = tab + end + end + if not globalTable then + return nil + end + if not globalTable.vars then + return nil + end + return globalTable.vars[key] + end}) + return shareTable + end + + _PUBLIC.ipc.shared = {} + setmetatable(_PUBLIC.ipc.shared, {["__index"] = function(_, pid) + local currentPID = _PUBLIC.tsched.getCurrentTask().id + local returnTable = {} + for _, shareTable in pairs(ipc.shared[pid] or {}) do + if shareTable.sharedWith == currentPID then + for key, value in pairs(shareTable.vars) do + returnTable[key] = table.copy(value) + end + elseif shareTable.sharedWith == "all" then + for key, value in pairs(shareTable.vars) do + if not returnTable[key] then + returnTable[key] = table.copy(value) + end + end + end + end + return returnTable + end}) end function module.exit() - + _G.ipc = nil + _PUBLIC.ipc = nil end return module diff --git a/halyde/kernel/tsched.lua b/halyde/kernel/tsched.lua index 865a1eb..1a341b4 100644 --- a/halyde/kernel/tsched.lua +++ b/halyde/kernel/tsched.lua @@ -1,3 +1,5 @@ +local idCounter = 1 + _G._PUBLIC.tsched = {} _G.tsched = {} _G.tsched.tasks = {} @@ -9,8 +11,6 @@ local computer = require("computer") local filesystem = require("filesystem") local json = require("json") local gpu = component.gpu -local ocelot = component.ocelot - function _G._PUBLIC.tsched.runAsTask(path,...) local args = {...} local function taskFunction() @@ -48,15 +48,21 @@ function _G._PUBLIC.tsched.runAsTask(path,...) end function _G._PUBLIC.tsched.addTask(func, name) - ocelot.log("Added task " .. name) local task = coroutine.create(func) - table.insert(tsched.tasks, {["task"] = task, ["name"] = name}) + table.insert(tsched.tasks, {["task"] = task, ["name"] = name, ["id"] = idCounter}) + idCounter = idCounter + 1 return task end function _G._PUBLIC.tsched.removeTask(id) -- TODO: Check for user permissions before running - table.remove(_G.tsched.tasks, id) + for index, task in pairs(tsched.tasks) do + if task.id == id then + table.remove(tsched.tasks, index) + return true + end + end + return false end function handleError(errormsg) @@ -76,7 +82,7 @@ local function runTasks() handleError(errorMessage) end if coroutine.status(tsched.tasks[i].task) == "dead" then - _PUBLIC.tsched.removeTask(i) + _PUBLIC.tsched.removeTask(tsched.tasks[i].id) --ocelot.log("Removed coroutine") i = i - 1 end diff --git a/halyde/shell/shell.lua b/halyde/shell/shell.lua index efc5937..38cb3f9 100644 --- a/halyde/shell/shell.lua +++ b/halyde/shell/shell.lua @@ -17,11 +17,21 @@ _G.shell.aliases = shellcfg["aliases"] local function runAsTask(path, ...) --ocelot.log("running " .. path .. " as coroutine") tsched.runAsTask(path, ...) - local corIndex = #tsched.getTasks() - local task = tsched.getTasks()[#tsched.getTasks()] - repeat - coroutine.yield() - until tsched.getTasks()[corIndex] ~= task + local pid = tsched.getTasks()[#tsched.getTasks()].id + while true do + local foundTask = false + for _, task in pairs(tsched.getTasks()) do + if task.id == pid then + foundTask = true + break + end + end + if foundTask then + coroutine.yield() + else + break + end + end end function _G.shell.run(command) diff --git a/home/test.lua b/home/test.lua index c6f637f..0e36f56 100644 --- a/home/test.lua +++ b/home/test.lua @@ -1,7 +1,6 @@ -local cor = coroutine.create(function() - print("Hello World!") -end) - -print(coroutine.status(cor)) -coroutine.resume(cor) -print(coroutine.status(cor)) +local pid = tsched.getCurrentTask().id +local shareTable = ipc.shareWith(pid) +shareTable.gabbagool = "Pigeon Pizza! Wow!" +print(shareTable.gabbagool) +print(pid) +print(ipc.shared[pid].gabbagool) diff --git a/init.lua b/init.lua index 463f850..0beefd2 100644 --- a/init.lua +++ b/init.lua @@ -1,25 +1,6 @@ local gpu = component.proxy(component.list("gpu")()) local resX, resY = gpu.getResolution() --- Architecture check -local foundArchitecture = false -for _, arch in pairs(computer.getArchitectures()) do - if arch == "Lua 5.3" then - foundArchitecture = true - break - end -end - -if foundArchitecture then - computer.setArchitecture("Lua 5.3") -else - gpu.set(1, 1, "Required architecture (Lua 5.3) is not supported.") - gpu.set(1, 2, "Halting.") - while true do - computer.pullSignal() - end -end - local function loadfile(file) checkArg(1, file, "string") local handle = component.invoke(computer.getBootAddress(), "open", file, "r") @@ -37,6 +18,26 @@ local function handleError(errorMessage) end function loadBoot() + local foundArchitecture = false + for _, arch in pairs(computer.getArchitectures()) do + if arch == "Lua 5.3" then + foundArchitecture = true + break + end + end + + if foundArchitecture then + local _, errorMesage = computer.setArchitecture("Lua 5.3") + if errorMessage then + error(errorMessage) + end + else + gpu.set(1, 1, "Required architecture (Lua 5.3) is not supported.") + gpu.set(1, 2, "Halting.") + while true do + computer.pullSignal() + end + end loadfile("/halyde/kernel/boot.lua")(loadfile) end @@ -45,28 +46,43 @@ gpu.fill(1, 1, resX, resY, " ") -- Copying low-level functions in case of post-preload failure local pullSignal = computer.pullSignal -local shutdown = computer.shutdown +local beep = computer.beep local result, reason = xpcall(loadBoot, handleError) if not result then - gpu.setBackground(0x000000) - gpu.fill(1, 1, resX, resY, " ") - gpu.setBackground(0x800000) - gpu.setForeground(0xFFFFFF) - gpu.set(2,2,"A critical error has occurred.") - local i = 4 - reason = tostring(reason):gsub("\t", " ") - for line in string.gmatch(reason or "unknown error", "([^\n]*)\n?") do - gpu.set(2,i,line) - i = i + 1 + local bgColor + if gpu.getDepth() == 1 then + bgColor = 0x000000 + else + bgColor = 0x000080 end - gpu.set(2,i+1, "Press any key to restart.") - local evname - repeat - evname = pullSignal() - until evname == "key_down" - shutdown(true) - while true do - coroutine.yield() + gpu.setBackground(bgColor) + gpu.fill(1, 1, resX, resY, " ") + local function render() + gpu.setForeground(0xFFFFFF) + local i = 2 + reason = "A fatal error has occurred.\nHalyde cannot continue.\n \n" .. tostring(reason or "unknown error"):gsub("\t", " ") + for line in string.gmatch(reason, "([^\n]*)\n?") do + gpu.set(2, i, line) + i = i + 1 + end + gpu.set(1, resY - 1, string.rep("─", resX)) + gpu.setForeground(bgColor) + gpu.setBackground(0xFFFFFF) + gpu.set(2, resY, "🠅 🠄 🠇 🠆") + gpu.setForeground(0xFFFFFF) + gpu.setBackground(bgColor) + gpu.set(4, resY, " / ") + gpu.set(9, resY, " / ") + gpu.set(14, resY, " / ") + gpu.set(20, resY, "Scroll" .. string.rep(" ", resX - 21)) + end + render() + beep(440, 0.2) + beep(465, 0.2) + beep(440, 0.2) + beep(370, 0.5) + while true do -- TODO: Make this scrollable + pullSignal() end end