Permalink
Browse files

defer(splat...) now works. knock off some todo items

  • Loading branch information...
1 parent 0c2b467 commit 0e87d4cd10b971999ebda682623def11bec6c3fa @maxtaco committed Dec 12, 2011
Showing with 85 additions and 28 deletions.
  1. +0 −2 TODO-tame.md
  2. +27 −12 lib/coffee-script/nodes.js
  3. +43 −13 src/nodes.coffee
  4. +15 −1 test/tame.coffee
View
@@ -3,5 +3,3 @@ Todos
* `await` returns a value?
* continuations must therefore return a value
* tamed `for`, `while` and others return a value
- * splats in defer
- * Autocb?
Oops, something went wrong.
View
@@ -1583,6 +1583,9 @@ exports.Splat = class Splat extends Base
unwrap: -> @name
+ toSlot: () ->
+ new Slot(new Value(@name), null, true)
+
# Utility function that converts an arbitrary number of elements, mixed with
# splats, to a proper array.
@compileSplattedArray: (o, list, apply) ->
@@ -1878,18 +1881,18 @@ exports.In = class In extends Base
#### Slot
exports.Slot = class Slot extends Base
- constructor : (value, suffix) ->
+ constructor : (value, suffix, splat) ->
@value = value
@suffix = suffix
+ @splat = splat
children : [ 'value', 'suffix' ]
#### Defer
exports.Defer = class Defer extends Base
constructor : (args) ->
- @slots = for a in args
- a.toSlot()
+ @slots = (a.toSlot() for a in args)
@params = []
@vars = []
@@ -1902,27 +1905,54 @@ exports.Defer = class Defer extends Base
@params.push v.copy()
v
+ #
+ # makeAssignFn
+ # - Implement C++-style pass-by-reference in Coffee
+ #
+ # the 'assign_fn' returned by here will set all parameters to defer()
+ # to have the appropriate values after the defer is fulfilled. The
+ # four cases to consider are listed in the following call:
+ #
+ # defer(x, a.b, c.d[i], rest...)
+ #
+ # Case 1 -- defer(x) -- Regular assignment to a local variable
+ # Case 2 -- defer(a.b) -- Assignment to an object; must capture
+ # object when defer() is called
+ # Case 3 -- defer(c.d[i]) -- Assignment to an array slot; must capture
+ # array and slot index with defer() is called
+ # Case 4 -- defer(rest...) -- rest is an array, assign it to all
+ # leftover arguments.
+ #
makeAssignFn : (o) ->
return null if @slots.length == 0
assignments = []
args = []
i = 0
for s in @slots
a = new Value new Literal "arguments"
- a.add new Index new Value new Literal i
- if not s.suffix
+ i_lit = new Value new Literal i
+ if s.splat # case 4
+ func = new Value new Literal(utility 'slice')
+ func.add new Access new Value new Literal 'call'
+ call = new Call func, [ a, i_lit ]
slot = s.value
@vars.push slot
+ assign = new Assign slot, call
else
- args.push s.value
- slot = @newParam()
- if s.suffix instanceof Index
- prop = new Index @newParam()
- args.push s.suffix.index
+ a.add new Index i_lit
+ if not s.suffix # case 1
+ slot = s.value
+ @vars.push slot
else
- prop = s.suffix
- slot.add prop
- assign = new Assign slot, a
+ args.push s.value
+ slot = @newParam()
+ if s.suffix instanceof Index # case 3
+ prop = new Index @newParam()
+ args.push s.suffix.index
+ else # case 2
+ prop = s.suffix
+ slot.add prop
+ assign = new Assign slot, a
assignments.push assign
i++
block = new Block assignments
View
@@ -33,7 +33,21 @@ atest "basic tame set structs", (cb) ->
field = "bar" # change the field to make sure that we captured "yo"
cb(obj.cat.yo == i, {})
-atest "continue / brek test" , (cb) ->
+multi = (cb, arr) ->
+ await delay defer()
+ cb.apply(null, arr)
+
+atest "defer splats", (cb) ->
+ v = [ 1, 2, 3, 4]
+ obj = { x : 0 }
+ await multi(defer(obj.x, out...), v)
+ out.unshift obj.x
+ ok = true
+ for i in [0..v.length-1]
+ ok = false if v[i] != out[i]
+ cb(ok, {})
+
+atest "continue / break test" , (cb) ->
tot = 0
for i in [0..100]
await delay defer()

0 comments on commit 0e87d4c

Please sign in to comment.