erase the old version
This commit is contained in:
260
src/machine.lua
Normal file
260
src/machine.lua
Normal file
@@ -0,0 +1,260 @@
|
||||
-- The boot-up code of the Lua architecture.
|
||||
-- Extremely bad.
|
||||
-- Do not use in a serious context, you will be hacked.
|
||||
-- There is no sandboxing here.
|
||||
|
||||
|
||||
local sysyieldobj = {}
|
||||
|
||||
local function sysyield()
|
||||
coroutine.yield(sysyieldobj)
|
||||
end
|
||||
|
||||
local resume = coroutine.resume
|
||||
|
||||
function coroutine.resume(co, ...)
|
||||
while true do
|
||||
local t = {resume(co, ...)}
|
||||
if t[1] and rawequal(t[2], sysyieldobj) then
|
||||
coroutine.yield(sysyieldobj)
|
||||
else
|
||||
return table.unpack(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function coroutine.wrap(f)
|
||||
local co = coroutine.create(f)
|
||||
return function(...)
|
||||
local t = {coroutine.resume(co, ...)}
|
||||
if t[1] then
|
||||
return table.unpack(t, 2)
|
||||
end
|
||||
error(t[2], 2)
|
||||
end
|
||||
end
|
||||
|
||||
local clist, cinvoke, computer, component, print, unicode = component.list, component.invoke, computer, component, print, unicode
|
||||
debug.print = print
|
||||
debug.sysyield = sysyield
|
||||
|
||||
function component.list(ctype, exact)
|
||||
local list = clist()
|
||||
local desired = {}
|
||||
|
||||
for addr, type in pairs(list) do
|
||||
if ctype then
|
||||
if exact then
|
||||
if ctype == type then desired[addr] = type end
|
||||
else
|
||||
if string.find(type, ctype) then desired[addr] = type end
|
||||
end
|
||||
else
|
||||
desired[addr] = type
|
||||
end
|
||||
end
|
||||
|
||||
local key = nil
|
||||
setmetatable(desired, {__call = function()
|
||||
local val
|
||||
key, val = next(desired, key)
|
||||
return key, val
|
||||
end})
|
||||
return desired
|
||||
end
|
||||
|
||||
function component.invoke(address, method, ...)
|
||||
local t = {pcall(cinvoke, address, method, ...)}
|
||||
if computer.energy() <= 0 then sysyield() end -- out of power
|
||||
if computer.isOverused() then sysyield() end -- overused
|
||||
if computer.isIdle() then sysyield() end -- machine idle
|
||||
|
||||
if t[1] then
|
||||
return table.unpack(t, 2)
|
||||
end
|
||||
return nil, t[2]
|
||||
end
|
||||
|
||||
local componentCallback = {
|
||||
__call = function(self, ...)
|
||||
return component.invoke(self.address, self.name, ...)
|
||||
end,
|
||||
__tostring = function(self)
|
||||
return component.doc(self.address, self.name) or "function"
|
||||
end,
|
||||
}
|
||||
|
||||
local componentProxy = {
|
||||
__index = function(self, key)
|
||||
if self.fields[key] and self.fields[key].getter then
|
||||
return component.invoke(self.address, key)
|
||||
end
|
||||
return rawget(self, key)
|
||||
end,
|
||||
__newindex = function(self, key, value)
|
||||
if self.fields[key] and self.fields[key].setter then
|
||||
return component.invoke(self.address, key, value)
|
||||
end
|
||||
rawset(self, key, value)
|
||||
end,
|
||||
__pairs = function(self)
|
||||
local reachedFields = false
|
||||
local key, val
|
||||
return function()
|
||||
if not reachedFields then
|
||||
key, val = next(self, key)
|
||||
if key == nil then reachedFields = true end
|
||||
end
|
||||
if reachedFields then
|
||||
key = next(self.fields, key)
|
||||
val = self[key]
|
||||
end
|
||||
return key, val
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
local proxyCache = setmetatable({}, {__mode = "v"})
|
||||
|
||||
function component.proxy(address)
|
||||
if proxyCache[address] then return proxyCache[address] end
|
||||
|
||||
local t, err = component.type(address)
|
||||
if not t then return nil, err end
|
||||
local slot, err = component.slot(address)
|
||||
if not slot then return nil, err end
|
||||
|
||||
local proxy = {address = address, type = t, slot = slot}
|
||||
proxy.fields, err = component.fields(address)
|
||||
if not proxy.fields then return nil, err end
|
||||
|
||||
local methods = component.methods(address)
|
||||
for name in pairs(methods) do
|
||||
proxy[name] = setmetatable({address=address,name=name}, componentCallback)
|
||||
end
|
||||
|
||||
setmetatable(proxy, componentProxy)
|
||||
proxyCache[address] = proxy
|
||||
return proxy
|
||||
end
|
||||
|
||||
function computer.getProgramLocations()
|
||||
return {}
|
||||
end
|
||||
|
||||
local shutdown, setArch = computer.shutdown, computer.setArchitecture
|
||||
|
||||
function computer.shutdown(...)
|
||||
shutdown(...)
|
||||
sysyield()
|
||||
end
|
||||
|
||||
function computer.setArchitecture(arch)
|
||||
if arch == computer.getArchitecture() then return end
|
||||
local ok, err = setArch(arch)
|
||||
sysyield()
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function computer.pullSignal(timeout)
|
||||
timeout = timeout or math.huge
|
||||
local deadline = computer.uptime() + timeout
|
||||
while true do
|
||||
if computer.uptime() >= deadline then return end
|
||||
local t = {computer.popSignal()}
|
||||
if #t == 0 then
|
||||
sysyield()
|
||||
else
|
||||
return table.unpack(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unicode.upper, unicode.lower = string.upper, string.lower
|
||||
|
||||
unicode.isWide = function(s)
|
||||
local c = unicode.sub(s, 1, 1)
|
||||
return unicode.wlen(c) > unicode.len(c)
|
||||
end
|
||||
|
||||
unicode.wtrunc = function(str,space)
|
||||
space = space - 1
|
||||
return unicode.sub(str, 1, space)
|
||||
end
|
||||
|
||||
unicode.reverse = string.reverse
|
||||
|
||||
unicode.charWidth = function(s)
|
||||
return 1
|
||||
end
|
||||
|
||||
unicode.sub = function(str, a, b)
|
||||
if not b then b = utf8.len(str) end
|
||||
if not a then a = 1 end
|
||||
-- a = math.max(a,1)
|
||||
if a < 0 then
|
||||
-- negative
|
||||
a = utf8.len(str) + a + 1
|
||||
end
|
||||
if b < 0 then
|
||||
b = utf8.len(str) + b + 1
|
||||
end
|
||||
if a > b then return "" end
|
||||
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
|
||||
if a > utf8.len(str) then return "" end
|
||||
a = utf8.offset(str,a)
|
||||
return str:sub(a,b)
|
||||
-- return str:sub(a, b)
|
||||
end
|
||||
|
||||
function checkArg(arg, val, ...)
|
||||
local t = {...}
|
||||
for i=1,#t do
|
||||
if type(val) == t[i] then return end
|
||||
end
|
||||
error("bad argument #" .. arg .. " (" .. table.concat(t, ", ") .. ") expected", 2)
|
||||
end
|
||||
|
||||
if os.getenv("NN_REPL") == "1" then
|
||||
while true do
|
||||
io.write("\x1b[34mlua>\x1b[0m ")
|
||||
io.flush()
|
||||
local l = io.read("l")
|
||||
if not l then break end
|
||||
local f, err = load("return " .. l, "=repl")
|
||||
if f then
|
||||
print(f())
|
||||
else
|
||||
f, err = load(l, "=repl")
|
||||
if f then f() else print(err) end
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
io.write("\n")
|
||||
print("exiting repl")
|
||||
end
|
||||
|
||||
-- Save on just a tiny smudgeon of RAM
|
||||
io = nil
|
||||
package = nil
|
||||
|
||||
local eeprom = component.list("eeprom", true)()
|
||||
assert(eeprom, "missing firmware")
|
||||
|
||||
-- this would automatically reboot us if it needs to be a different architecture
|
||||
local arch = component.invoke(eeprom, "getArchitecture")
|
||||
if arch then computer.setArchitecture(arch) end
|
||||
|
||||
local code = assert(component.invoke(eeprom, "get"))
|
||||
local f = assert(load(code, "=bios"))
|
||||
local thread = coroutine.create(f)
|
||||
|
||||
while true do
|
||||
collectgarbage("collect")
|
||||
local ok, err = resume(thread)
|
||||
if not ok then
|
||||
print(debug.traceback(thread, err))
|
||||
end
|
||||
if coroutine.status(thread) == "dead" then break end
|
||||
coroutine.yield()
|
||||
end
|
||||
Reference in New Issue
Block a user