forked from jashkenas/coffeescript
-
Notifications
You must be signed in to change notification settings - Fork 58
/
tame.coffee
143 lines (114 loc) · 3.07 KB
/
tame.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# =======================================================================
# Compile Time!
#
exports.transform = (x) ->
x.tameTransform()
exports.const =
k : "__tame_k"
param : "__tame_p_"
ns: "tame"
Deferrals : "Deferrals"
deferrals : "__tame_deferrals"
fulfill : "_fulfill"
b_while : "_break"
t_while : "_while"
c_while : "_continue"
n_while : "_next"
n_arg : "__tame_next_arg"
defer_method : "defer"
slot : "__slot"
assign_fn : "assign_fn"
runtime : "tamerun"
autocb : "autocb"
retslot : "ret"
#=======================================================================
# runtime
makeDeferReturn = (obj, defer_args, id) ->
ret = (inner_args...) ->
defer_args?.assign_fn?.apply(null, inner_args)
obj._fulfill id
if defer_args
ret.__tame_trace = {}
for k in [ "parent_cb", "file", "line", "func_name" ]
ret.__tame_trace[k] = defer_args[k]
ret
#-----------------------------------------------------------------------
#
# Tick Counter --
# count off every mod processor ticks
#
__c = 0
tickCounter = (mod) ->
__c++
if (__c % mod) == 0
__c = 0
true
else
false
#-----------------------------------------------------------------------
# Deferrals
#
# A collection of Deferrals; this is a better version than the one
# that's inline; it allows for tame tracing
#
class Deferrals
constructor: (k) ->
@continuation = k
@count = 1
@ret = null
_fulfill : ->
if --@count == 0
if tickCounter 500
process.nextTick (=> @continuation @ret)
else
@continuation @ret
defer : (args) ->
@count++
self = this
return makeDeferReturn self, args, null
#=======================================================================
class Rendezvous
constructor: ->
@completed = []
@waiters = []
@defer_id = 0
# This is a hack to work with the desugaring of
# 'defer' output by the coffee compiler.
@[exports.const.deferrals] = this
#-----------------------------------------
class RvId
constructor: (@rv,@id)->
defer: (defer_args) ->
@rv._deferWithId @id, defer_args
#-----------------------------------------
#
# The public interface has 3 methods --- wait, defer and id
wait: (cb) ->
if @completed.length
x = @completed.shift()
cb(x)
else
@waiters.push cb
#-----------------------------------------
defer: (defer_args) ->
id = @defer_id++
@deferWithId id, defer_args
#-----------------------------------------
id: (i) ->
ret = {}
ret[exports.const.deferrals] = new RvId(this, i)
ret
#-----------------------------------------
_fulfill: (id) ->
if @waiters.length
cb = @waiters.shift()
cb(id)
else
@completed.push id
#-----------------------------------------
_deferWithId: (id, defer_args) ->
@count++
makeDeferReturn this, defer_args, id
#=======================================================================
exports.runtime = { Deferrals, Rendezvous }
#=======================================================================