Skip to content
Permalink
Browse files
Merge branch 'better-events'
  • Loading branch information
James King committed Oct 10, 2013
2 parents 198a631 + 9acb04e commit 42c33ec
Show file tree
Hide file tree
Showing 33 changed files with 431 additions and 118 deletions.
@@ -50,7 +50,7 @@ function errorHandler(err)
if term.isColor() then
term.setTextColor(colors.red)
end
print(see.formatTraceback(err, see.traceback(err, 3, true), 10))
print(formatTraceback(err, traceback(err, 2, true), 10))
if term.isColor() then
term.setTextColor(colors.white)
end
@@ -178,25 +178,31 @@ function SeeVM.new(natives, seePath)
setmetatable(self, SeeVM)
self.seePath = seePath

self.threads = { }
self.threadFilters = { }

self.standardGlobals = { }
for k, v in pairs(StandardGlobals) do
self.standardGlobals[k] = function(...) return StandardGlobals[k](self, ...) end
end

self.base = { }
self.rt = { }
self.event = { }
self.classes = { }
self.natives = natives
self.natives.error = error
self.archives = { }
self.classPaths = { }
self.base.Object = self:loadClassFromAny("see.base.Object")
self.rt = self:loadClassFromAny("see.rt.Class")
self.rt.Class = self:loadClassFromAny("see.rt.Class")
self.base.Exception = self:loadClassFromAny("see.base.Exception")
self.base.System = self:loadClassFromAny("see.base.System")
self.base.Iterators = self:loadClassFromAny("see.base.Iterators")
self.base.Array = self:loadClassFromAny("see.base.Array")
self.base.String = self:loadClassFromAny("see.base.String")
self.event.Events = self:loadClassFromAny("see.event.Events")
self.event.UnknownEvent = self:loadClassFromAny("see.event.impl.UnknownEvent")
return self
end

@@ -257,6 +263,91 @@ function getAnnotations(code)
return annotations
end

function SeeVM:spawnThread(func)
local thread = coroutine.create(function() xpcall(func, errorHandler) end)
table.insert(self.threads, thread)
self.threadFilters[#self.threads] = { coroutine.resume(thread) }
return thread
end

function SeeVM:start(mainClass, ...)
local Events = self.event.Events
local UnknownEvent = self.event.UnknownEvent
local args = self.base.Array.new(...)
local threads = self.threads
threads[1] = coroutine.create(function() xpcall(function() mainClass.main(args) end, errorHandler) end)
local threadFilters = self.threadFilters
local event

threadFilters[1] = { coroutine.resume(threads[1], args) }
local cycle = 1
while true do
local threadDeaths = { }
for i = 1, #threads do
if coroutine.status(threads[i]) == "dead" then
table.insert(threadDeaths, i)
elseif event then
if event.ident == "terminate" then
error("terminate")
end

local passEvent = false

if #threadFilters[i] == 1 then
passEvent = true
else
for j = 2, #threadFilters[i] do
if threadFilters[i][j] == event.ident then
passEvent = true
break
end
end
end

if passEvent then
local threadData = { coroutine.resume(threads[i], event) }

if not threadData[1] then
error(threadData[2], 2)
table.insert(threadDeaths, i)
end

threadFilters[i] = threadData
end

if coroutine.status(threads[i]) == "dead" then
table.insert(threadDeaths, i)
end
end
end

for i = #threadDeaths, 1, -1 do
table.remove(threads, threadDeaths[i])
table.remove(threadFilters, threadDeaths[i])
end

if #threads == 0 then break end

local eventData = { coroutine.yield() }
local eventParams = { }

for i = 2, #eventData do
eventParams[i - 1] = eventData[i]
end

if type(eventData[2]) == "table" and eventData[2].__type then
event = eventData[2]
else
local EventClass = Events.getEventClass(eventData[1])
if EventClass == UnknownEvent then
xpcall(function() event = EventClass.new(unpack(eventData)) end, errorHandler)
else
xpcall(function() event = EventClass.new(unpack(eventParams)) end, errorHandler)
end
end
end
end

--[[
Loads a class by trying the standard library first, then from class paths.
@param string:name
@@ -301,6 +392,11 @@ end
]]
function SeeVM:executeAnnotation(env, class, annotation)
local pindex = annotation:find("%s")

if not pindex then
error("Failed to execute annotation for class " .. class.__name .. ".")
end

local aname = annotation:sub(1, pindex - 1)

if aname == "import" then
@@ -310,6 +406,12 @@ function SeeVM:executeAnnotation(env, class, annotation)
env[getPackageName(name)] = class
elseif aname == "native" then
local name = annotation:sub(pindex + 1):gsub("%s", "")

if name == "__rt" then
env.__rt = self
return
end

local keys = getPackageComponents(name)
local lk
local v = self.natives
@@ -417,6 +519,9 @@ function SeeVM:loadClass(def, annotations, name)
env[k] = class
end

-- Import Events class for convenience.
env["Events"] = self.event.Events

-- Setup class environment.
env[className] = class
setfenv(def, env)
@@ -1,5 +1,8 @@
--@native coroutine
--@native sleep
--@native __rt
--@native os.startTimer

--@import see.event.Events

Thread.SUSPENDED = "suspended"
Thread.RUNNING = "running"
@@ -19,22 +22,23 @@ end
@param number:s Seconds.
]]
function Thread.sleep(s)
sleep(s)
local id = os.startTimer(s)
while id ~= Events.pull("timer").id do end
end

--[[
Constructs a new Thread.
@param function:func The function to run in a new thread.
]]
function Thread:init(func)
self.co = coroutine.create(func)
self.func = func
end

--[[
Resumes a suspended coroutine.
Add thread to the event dispatcher.
]]
function Thread:resume()
coroutine.resume(self.co)
function Thread:start()
self.co = __rt:spawnThread(self.func)
end

--[[
@@ -51,4 +55,8 @@ end
]]
function Thread:isRunning()
return coroutine.running(self.co)
end

function Thread:isAlive()
return self:status() ~= Thread.DEAD
end

This file was deleted.

@@ -0,0 +1,3 @@
function Event:init(ident)
self.ident = ident
end
@@ -0,0 +1,73 @@
--@native os.queueEvent

--@import see.concurrent.Thread

--@import see.event.impl.CharEvent
--@import see.event.impl.KeyPressEvent
--@import see.event.impl.TimerEvent
--@import see.event.impl.AlarmEvent
--@import see.event.impl.RedstoneEvent
--@import see.event.impl.TerminateEvent
--@import see.event.impl.DiskInsertEvent
--@import see.event.impl.DiskEjectEvent
--@import see.event.impl.PeripheralAttachEvent
--@import see.event.impl.PeripheralDetachEvent
--@import see.event.impl.RednetMessageEvent
--@import see.event.impl.ModemMessageEvent
--@import see.event.impl.HttpSuccessEvent
--@import see.event.impl.HttpFailureEvent
--@import see.event.impl.MousePressEvent
--@import see.event.impl.MouseScrollEvent
--@import see.event.impl.MouseDragEvent
--@import see.event.impl.MonitorTouchEvent
--@import see.event.impl.MonitorResizeEvent
--@import see.event.impl.TurtleInventoryEvent
--@import see.event.impl.UnknownEvent

local registeredEvents

function Events.__static()
registeredEvents = { }

Events.register("char", CharEvent)
Events.register("key", KeyPressEvent)
Events.register("timer", TimerEvent)
Events.register("alarm", AlarmEvent)
Events.register("redstone", RedstoneEvent)
Events.register("terminate", TerminateEvent)
Events.register("disk", DiskInsertEvent)
Events.register("disk_eject", DiskEjectEvent)
Events.register("peripheral", PeripheralAttachEvent)
Events.register("peripheral_detach", PeripheralDetachEvent)
Events.register("rednet_message", RednetMessageEvent)
Events.register("modem_message", ModemMessageEvent)
Events.register("http_success", HttpSuccessEvent)
Events.register("http_failure", HttpFailureEvent)
Events.register("mouse_click", MousePressEvent)
Events.register("mouse_scroll", MouseScrollEvent)
Events.register("mouse_drag", MouseDragEvent)
Events.register("monitor_touch", MonitorTouchEvent)
Events.register("monitor_resize", MonitorResizeEvent)
Events.register("turtle_inventory", TurtleInventoryEvent)
end

function Events.register(ident, eventClass)
registeredEvents[cast(ident, "string")] = eventClass
end

function Events.getEventClass(ident)
return registeredEvents[cast(ident, "string")] or UnknownEvent
end

function Events.queue(event)
os.queueEvent(cast(event.ident, "string"), event)
end

function Events.pull(...)
local args = Array.new(...)
local casted = Array.new()
for arg in args:iAll() do
casted:add(cast(arg, "string"))
end
return Thread.yield(casted:unpack())
end
@@ -0,0 +1,8 @@
--@import see.event.Event

--@extends see.event.Event

function AlarmEvent:init(id)
Event.init(self, "alarm")
self.id = id
end
@@ -0,0 +1,8 @@
--@import see.event.Event

--@extends see.event.Event

function CharEvent:init(char)
Event.init(self, "char")
self.char = char
end
@@ -0,0 +1,8 @@
--@import see.event.Event

--@extends see.event.Event

function DiskEjectEvent:init(side)
Event.init(self, "disk_eject")
self.side = side
end

0 comments on commit 42c33ec

Please sign in to comment.