Skip to content

Commit b5e7569

Browse files
committed
Use coroutine with @stateful
1 parent ba9ecd8 commit b5e7569

21 files changed

Lines changed: 324 additions & 158 deletions

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ os:
33
- linux
44
- osx
55
julia:
6-
- 0.5
76
- nightly
87
notifications:
98
email: false

REQUIRE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
julia 0.5
1+
julia 0.6
22
DataStructures
3-
Compat

appveyor.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
environment:
22
matrix:
3-
- JULIAVERSION: "julialang/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
4-
- JULIAVERSION: "julialang/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
53
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
64
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
75

src/SimJulia.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ module SimJulia
1717
export succeed, fail
1818
export Operator
1919
export (&), (|)
20+
export FiniteStateMachine, @stateful, @yield
2021
export Process, @Process
21-
export yield, interrupt
22+
export interrupt
2223
export Simulation, StopSimulation
2324
export run, now, active_process
2425
export Container, Resource, Store
25-
export Put, Get, Request, Release, cancel, capacity
26+
export Put, Get, Request, Release, cancel, capacity, @Request
2627

2728
include("base.jl")
2829
include("events.jl")
2930
include("operators.jl")
31+
include("coroutine/utils.jl")
32+
include("coroutine/transforms.jl")
33+
include("coroutine/macro.jl")
3034
include("process.jl")
3135
include("time.jl")
3236
include("simulation.jl")

src/base.jl

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using Compat
2-
3-
@compat abstract type Environment end
1+
abstract type Environment end
42

53
"""
64
The parent type for all events.
@@ -17,46 +15,34 @@ Once the events is scheduled, it has a value.
1715
1816
An event has also a list of callbacks. A callback can be any function as long as it accepts an instance of a subtype of `AbstractEvent` as its first argument. Once an event gets triggered, all callbacks will be invoked. Callbacks can do further processing with the value it has produced.
1917
"""
20-
@compat abstract type AbstractEvent{E<:Environment} end
18+
abstract type AbstractEvent{E<:Environment} end
2119

2220
@enum EVENT_STATE idle=0 scheduled=1 triggered=2
2321

24-
immutable EventTriggered{E<:Environment} <: Exception
22+
struct EventTriggered{E<:Environment} <: Exception
2523
ev :: AbstractEvent{E}
2624
end
2725

28-
immutable EventNotIdle{E<:Environment} <: Exception
26+
struct EventNotIdle{E<:Environment} <: Exception
2927
ev :: AbstractEvent{E}
3028
end
3129

32-
type BaseEvent{E<:Environment}
30+
mutable struct BaseEvent{E<:Environment}
3331
env :: E
3432
id :: UInt
3533
cid :: UInt
3634
callbacks :: DataStructures.PriorityQueue{Function, UInt}
3735
state :: EVENT_STATE
3836
value :: Any
39-
function BaseEvent(env::E)
37+
function BaseEvent{E}(env::E) where E<:Environment
4038
new(env, env.eid+=one(UInt), zero(UInt), DataStructures.PriorityQueue(Function, UInt), idle, nothing)
4139
end
4240
end
4341

44-
function BaseEvent{E<:Environment}(env::E) :: BaseEvent
42+
function BaseEvent{E<:Environment}(env::E)
4543
BaseEvent{E}(env)
4644
end
4745

48-
# type BaseEvent{E<:Environment}
49-
# env :: E
50-
# id :: UInt
51-
# cid :: UInt
52-
# callbacks :: DataStructures.PriorityQueue{Function, UInt}
53-
# state :: EVENT_STATE
54-
# value :: Any
55-
# function BaseEvent{E}(env::E) where E<:Environment
56-
# new(env, env.eid+=one(UInt), zero(UInt), DataStructures.PriorityQueue(Function, UInt), idle, nothing)
57-
# end
58-
# end
59-
6046
function show(io::IO, ev::AbstractEvent)
6147
print(io, "$(typeof(ev)) $(ev.bev.id)")
6248
end

src/coroutine/macro.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
macro yield(val)
2+
:($(esc(val)))
3+
end
4+
5+
abstract type FiniteStateMachine end
6+
7+
iscoroutinedone(fsm::FiniteStateMachine) = fsm._state == 0xff
8+
9+
macro stateful(expr::Expr)
10+
expr.head != :function && error("Not a function definition!")
11+
args = getArguments(expr)
12+
func_name = shift!(args)
13+
type_name = gensym()
14+
slots = getSlots(expr, func_name)
15+
type_expr = :(
16+
type $type_name <: FiniteStateMachine
17+
_state :: UInt8
18+
$((:($slotname :: $(slottype == Union{} ? Any : :($slottype))) for (slotname, slottype) in slots)...)
19+
function $type_name($((:($arg::$(slots[:($arg)])) for arg in args)...))
20+
fsm = new()
21+
fsm._state = 0x00
22+
$((:(fsm.$arg = $arg) for arg in args)...)
23+
fsm
24+
end
25+
end
26+
)
27+
new_expr = deepcopy(expr.args[2])
28+
transformVars!(new_expr, keys(slots))
29+
n = transformYield!(new_expr)
30+
func_expr = :(
31+
function (_fsm::$type_name)(_ret::Any=nothing)
32+
_fsm._state == 0x00 && @goto _STATE_0
33+
$((:(_fsm._state == $i && @goto $(Symbol("_STATE_",:($i)))) for i in 0x01:n)...)
34+
error("Iterator has stopped!")
35+
@label _STATE_0
36+
_fsm._state = 0xff
37+
$((:($arg) for arg in new_expr.args)...)
38+
end
39+
)
40+
if expr.args[1].head == Symbol("::")
41+
func_expr.args[1] = Expr(Symbol("::"), func_expr.args[1], expr.args[1].args[2])
42+
end
43+
call_expr = deepcopy(expr)
44+
if call_expr.args[1].head == Symbol("::")
45+
call_expr.args[1] = call_expr.args[1].args[1]
46+
end
47+
call_expr.head = Symbol("=")
48+
call_expr.args[2] = :($type_name($((:($arg) for arg in args)...)))
49+
esc(quote
50+
$type_expr
51+
$func_expr
52+
$call_expr
53+
end)
54+
end

src/coroutine/transforms.jl

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
function transformVars!(expr::Expr, symbols::Base.KeyIterator{Dict{Symbol,Type}})
2+
for i in 1:length(expr.args)
3+
if expr.head == :kw && i == 1
4+
5+
elseif expr.head == Symbol(".") && i == 2
6+
7+
elseif isa(expr.args[i], Symbol) && in(expr.args[i], symbols)
8+
expr.args[i] = :(_fsm.$(expr.args[i]))
9+
elseif isa(expr.args[i], Expr)
10+
transformVars!(expr.args[i], symbols)
11+
end
12+
end
13+
end
14+
15+
function transformTry!(expr::Expr, n::UInt8=0x00, super::Expr=:(), line_no::Int=0, super_try::Expr=:(), line_try::Int=0) :: UInt8
16+
for (i, arg) in enumerate(expr.args)
17+
if isa(arg, Expr)
18+
if arg.head == :line
19+
line_no = i+1
20+
super = expr
21+
elseif arg.head == :macrocall && arg.args[1] == Symbol("@yield")
22+
n += one(UInt8)
23+
if expr == super
24+
expr.args[i] = :(isa(_ret, Exception) && throw(_ret))
25+
else
26+
expr.args[i] = :(_ret)
27+
insert!(super.args, line_no+1, :(isa(_ret, Exception) && throw(_ret)))
28+
end
29+
insert!(super.args, line_no, :(_fsm._state = 0xff))
30+
insert!(super.args, line_no, arg.args[2])
31+
insert!(super.args, line_no, :(_fsm._state = $n))
32+
insert!(super_try.args, line_try, :(@label $(Symbol("_STATE_",:($n)))))
33+
insert!(super_try.args, line_try, deepcopy(super_try.args[line_try+1]))
34+
for j in length(super_try.args[line_try].args[1].args):-1:line_no+2
35+
deleteat!(super_try.args[line_try].args[1].args, j)
36+
end
37+
for j in 1:line_no+1
38+
deleteat!(super_try.args[line_try+2].args[1].args, 1)
39+
end
40+
break
41+
else
42+
m = transformTry!(arg, n, super, line_no, super_try, line_try)
43+
if m > n
44+
n=m
45+
break
46+
end
47+
end
48+
end
49+
end
50+
n
51+
end
52+
53+
function transformYield!(expr::Expr, n::UInt8=0x00, super::Expr=:(), line_no::Int=0) :: UInt8
54+
for (i, arg) in enumerate(expr.args)
55+
if isa(arg, Expr)
56+
if arg.head == :try
57+
n = transformTry!(arg.args[1], n, super, line_no, expr, i)
58+
println("hi")
59+
elseif arg.head == :line
60+
line_no = i+1
61+
super = expr
62+
elseif arg.head == :macrocall && arg.args[1] == Symbol("@yield")
63+
n += one(UInt8)
64+
if expr == super
65+
expr.args[i] = :(_fsm._state = 0xff)
66+
else
67+
expr.args[i] = :(_ret)
68+
insert!(super.args, line_no, :(_fsm._state = 0xff))
69+
end
70+
insert!(super.args, line_no, :(@label $(Symbol("_STATE_",:($n)))))
71+
insert!(super.args, line_no, arg.args[2])
72+
insert!(super.args, line_no, :(_fsm._state = $n))
73+
else
74+
n = transformYield!(arg, n, super, line_no)
75+
end
76+
end
77+
end
78+
n
79+
end

src/coroutine/utils.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
function getArguments(expr) :: Vector{Symbol}
2+
args = Symbol[]
3+
kws = Symbol[]
4+
params = Symbol[]
5+
if expr.args[1].head == :call
6+
expr_args = expr.args[1].args
7+
else
8+
expr_args = expr.args[1].args[1].args
9+
end
10+
for arg in expr_args
11+
if isa(arg, Symbol)
12+
push!(args, arg)
13+
elseif arg.head == Symbol("::")
14+
push!(args, arg.args[1])
15+
elseif arg.head == :kw
16+
if isa(arg.args[1], Symbol)
17+
push!(kws, arg.args[1])
18+
else
19+
push!(kws, arg.args[1].args[1])
20+
end
21+
elseif arg.head == :parameters
22+
for arg2 in arg.args
23+
if isa(arg2.args[1], Symbol)
24+
push!(params, arg2.args[1])
25+
else
26+
push!(params, arg2.args[1].args[1])
27+
end
28+
end
29+
end
30+
end
31+
[args; kws; params]
32+
end
33+
34+
function getSlots(expr::Expr, name::Symbol) :: Dict{Symbol, Type}
35+
slots = Dict{Symbol, Type}()
36+
eval(expr)
37+
code_data_infos = @eval code_typed($name)
38+
for (code_info, data_type) in code_data_infos
39+
for i in 2:length(code_info.slotnames)
40+
slots[code_info.slotnames[i]] = code_info.slottypes[i]
41+
end
42+
end
43+
delete!(slots, Symbol("#temp#"))
44+
delete!(slots, Symbol("#unused#"))
45+
slots
46+
end

src/events.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
type Event{E<:Environment} <: AbstractEvent{E}
1+
struct Event{E<:Environment} <: AbstractEvent{E}
22
bev :: BaseEvent{E}
3-
function Event(env::E)
3+
function Event{E}(env::E) where E<:Environment
44
new(BaseEvent(env))
55
end
66
end
77

8-
function Event{E<:Environment}(env::E) :: Event{E}
8+
function Event{E<:Environment}(env::E)
99
Event{E}(env)
1010
end
1111

@@ -41,9 +41,9 @@ Timeout{E<:Environment} <: AbstractEvent{E}
4141
- Timeout{E<:Environment}(env::E, delay::Number=0; priority::Bool=false, value::Any=nothing)
4242
"""
4343

44-
type Timeout{E<:Environment} <: AbstractEvent{E}
44+
struct Timeout{E<:Environment} <: AbstractEvent{E}
4545
bev :: BaseEvent{E}
46-
function Timeout(env::E, delay::Union{Period, Number}, priority::Bool, value::Any)
46+
function Timeout{E}(env::E, delay::Union{Period, Number}, priority::Bool, value::Any) where E<:Environment
4747
ev = new(BaseEvent(env))
4848
schedule(ev.bev, delay, priority=priority, value=value)
4949
return ev

src/operators.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
immutable StateValue
1+
struct StateValue
22
state :: EVENT_STATE
33
value :: Any
44
function StateValue(state::EVENT_STATE, value::Any=nothing)
55
new(state, value)
66
end
77
end
88

9-
type Operator{E<:Environment} <: AbstractEvent{E}
9+
struct Operator{E<:Environment} <: AbstractEvent{E}
1010
bev :: BaseEvent
1111
eval :: Function
12-
function Operator(eval::Function, fev::AbstractEvent{E}, events::AbstractEvent{E}...)
12+
function Operator{E}(eval::Function, fev::AbstractEvent{E}, events::AbstractEvent{E}...) where E<:Environment
1313
env = environment(fev)
1414
op = new(BaseEvent(env), eval)
1515
event_state_values = Dict{AbstractEvent{E}, StateValue}()
@@ -21,7 +21,7 @@ type Operator{E<:Environment} <: AbstractEvent{E}
2121
end
2222
end
2323

24-
function Operator{E<:Environment}(eval::Function, fev::AbstractEvent{E}, events::AbstractEvent{E}...) :: Operator{E}
24+
function Operator{E<:Environment}(eval::Function, fev::AbstractEvent{E}, events::AbstractEvent{E}...)
2525
Operator{E}(eval, fev, events...)
2626
end
2727

0 commit comments

Comments
 (0)