Tcl Library Source Code

Changes On Branch bug-td-coroutine
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch bug-td-coroutine Excluding Merge-Ins

This is equivalent to a diff from 7bed475cb2 to 5f50c249bd

2014-04-11
20:26
Ticket [c21b57e4fc]. Fixed version number mismatch for "coroutine". See also Ticket [ac8d016077] whose fix (revision [7bed475cb2]) introduced the problem. check-in: 51083f878a user: andreask tags: trunk
2014-03-26
17:29
In coroutine and coro_auto: 'read' must correctly emulate Tcl's built-in read and not close the chan at EOF. Add command expansion in 'global', which looks like it never worked. Took the opportunity to fix how 'global' stores coro-global values so that we don't tramp on Frame #1's local variables (no compatibility break as 'global' never worked). Bumped versions. Adding tests. Work-in-progress. Leaf check-in: 5f50c249bd user: twylite tags: bug-td-coroutine
2014-03-24
18:24
Ticket [ac8d016077]. Package coroutine and coroutine::auto. Fixed missing variable "result" in various ok code paths. Bumped versions to 1.1.1 and 1.1.2 respectively. check-in: 7bed475cb2 user: andreask tags: trunk
18:03
Ticket 874dedb816 - struct::matrix - Fixed documentation buglet. check-in: ed580c5543 user: andreask tags: trunk

Changes to modules/coroutine/ChangeLog.














1
2
3
4
5
6
7













2013-05-31  Andreas Kupries  <[email protected]>

	* coroutine.tcl: Added Colin Macleod and http://wiki/21555
	* coro_auto.tcl: to the set of acknowledged contributors
	  and references for the module.

2013-05-15  Andreas Kupries  <[email protected]>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2014-03-24  Trevor Davel  <[email protected]>

	* coroutine.tcl: Stopped 'read' closing the channel at EOF, which is 
	* coro_auto.tcl: not the behaviour's of Tcl's built-in read.  Bumped
	  versions to 1.1.3.        
	* pkgIndex.tcl: Updated version numbers.

2014-03-24  Andreas Kupries  <[email protected]>

	* coroutine.tcl: Fixed missing variable "result" in various ok code
	* coro_auto.tcl: paths. Bumped versions to 1.1.1 and 1.1.2 
	  respectively

2013-05-31  Andreas Kupries  <[email protected]>

	* coroutine.tcl: Added Colin Macleod and http://wiki/21555
	* coro_auto.tcl: to the set of acknowledged contributors
	  and references for the module.

2013-05-15  Andreas Kupries  <[email protected]>

Changes to modules/coroutine/coro_auto.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
## -- Tcl Module -- -*- tcl -*-
# # ## ### ##### ######## #############

# @@ Meta Begin
# Package coroutine::auto 1.1.2
# Meta platform        tcl
# Meta require         {Tcl 8.6}
# Meta require         {coroutine 1.1}
# Meta license         BSD
# Meta as::author      {Andreas Kupries}
# Meta as::origin      http://wiki.tcl.tk/21555
# Meta summary         Coroutine Event and Channel Support




|







1
2
3
4
5
6
7
8
9
10
11
12
## -- Tcl Module -- -*- tcl -*-
# # ## ### ##### ######## #############

# @@ Meta Begin
# Package coroutine::auto 1.1.3
# Meta platform        tcl
# Meta require         {Tcl 8.6}
# Meta require         {coroutine 1.1}
# Meta license         BSD
# Meta as::author      {Andreas Kupries}
# Meta as::origin      http://wiki.tcl.tk/21555
# Meta summary         Coroutine Event and Channel Support
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
		yield
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result

		if {[::chan eof $chan]} {
		    ::chan close $chan
		    break
		}
	    }
	}
    } else {
	# Loop until total characters have been read, or eof found,
	# whichever is first.







<







222
223
224
225
226
227
228

229
230
231
232
233
234
235
		yield
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result

		if {[::chan eof $chan]} {

		    break
		}
	    }
	}
    } else {
	# Loop until total characters have been read, or eof found,
	# whichever is first.
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result
		incr   left -[string length $result]

		if {[::chan eof $chan]} {
		    ::chan close $chan
		    break
		} elseif {!$left} {
		    break
		}
	    }
	}
    }







<







252
253
254
255
256
257
258

259
260
261
262
263
264
265
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result
		incr   left -[string length $result]

		if {[::chan eof $chan]} {

		    break
		} elseif {!$left} {
		    break
		}
	    }
	}
    }
306
307
308
309
310
311
312
313
314

    return
} ::coroutine::auto}

# # ## ### ##### ######## #############
## Ready

package provide coroutine::auto 1.1.2
return







|

304
305
306
307
308
309
310
311
312

    return
} ::coroutine::auto}

# # ## ### ##### ######## #############
## Ready

package provide coroutine::auto 1.1.3
return

Changes to modules/coroutine/coroutine.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
## -- Tcl Module -- -*- tcl -*-
# # ## ### ##### ######## #############

# @@ Meta Begin
# Package coroutine 1.1.1
# Meta platform        tcl
# Meta require         {Tcl 8.6}
# Meta license         BSD
# Meta as::author      {Andreas Kupries}
# Meta as::author      {Colin Macleod}
# Meta as::author      {Colin McCormack}
# Meta as::author      {Donal Fellows}




|







1
2
3
4
5
6
7
8
9
10
11
12
## -- Tcl Module -- -*- tcl -*-
# # ## ### ##### ######## #############

# @@ Meta Begin
# Package coroutine 1.1.3
# Meta platform        tcl
# Meta require         {Tcl 8.6}
# Meta license         BSD
# Meta as::author      {Andreas Kupries}
# Meta as::author      {Colin Macleod}
# Meta as::author      {Colin McCormack}
# Meta as::author      {Donal Fellows}
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
proc ::coroutine::util::global {args} {
    # Frame #1 is the coroutine-specific stack frame at its
    # bottom. Variables there are out of view of the main code, and
    # can be made visible in the entire coroutine underneath.

    set cmd [list upvar "#1"]
    foreach var $args {
	lappend cmd $var $var 
    }
    tailcall $cmd
}

# - -- --- ----- -------- -------------

proc ::coroutine::util::after {delay} {
    ::after $delay [info coroutine]
    yield







|

|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
proc ::coroutine::util::global {args} {
    # Frame #1 is the coroutine-specific stack frame at its
    # bottom. Variables there are out of view of the main code, and
    # can be made visible in the entire coroutine underneath.

    set cmd [list upvar "#1"]
    foreach var $args {
	lappend cmd COROGLOBAL($var) $var 
    }
    tailcall {*}$cmd
}

# - -- --- ----- -------- -------------

proc ::coroutine::util::after {delay} {
    ::after $delay [info coroutine]
    yield
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
		yield
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result

		if {[::chan eof $chan]} {
		    ::chan close $chan
		    break
		}
	    }
	}
    } else {
	# Loop until total characters have been read, or eof found,
	# whichever is first.







<







259
260
261
262
263
264
265

266
267
268
269
270
271
272
		yield
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result

		if {[::chan eof $chan]} {

		    break
		}
	    }
	}
    } else {
	# Loop until total characters have been read, or eof found,
	# whichever is first.
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result
		incr   left -[string length $result]

		if {[::chan eof $chan]} {
		    ::chan close $chan
		    break
		} elseif {!$left} {
		    break
		}
	    }
	}
    }







<







289
290
291
292
293
294
295

296
297
298
299
300
301
302
		::chan event $chan readable {}
	    } else {
		::chan configure $chan -blocking $blocking
		append buf $result
		incr   left -[string length $result]

		if {[::chan eof $chan]} {

		    break
		} elseif {!$left} {
		    break
		}
	    }
	}
    }
369
370
371
372
373
374
375
376
377
namespace eval ::coroutine::util {
    #checker exclude warnShadowVar
    variable counter 0
}

# # ## ### ##### ######## #############
## Ready
package provide coroutine 1.1.1
return







|

367
368
369
370
371
372
373
374
375
namespace eval ::coroutine::util {
    #checker exclude warnShadowVar
    variable counter 0
}

# # ## ### ##### ######## #############
## Ready
package provide coroutine 1.1.3
return

Added modules/coroutine/coroutine.test.

















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# coroutine.test
#
# Tests for the coroutine package
#
# Copyright (C) 2014 Trevor Davel <[email protected]>
# -------------------------------------------------------------------------
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# -------------------------------------------------------------------------

package require tcltest

source [file join \
    [file dirname [file dirname [file join [pwd] [info script]]]] \
    devtools testutilities.tcl]

testsNeedTcl     8.6
testsNeedTcltest 2.3

testing {
    useLocal coroutine.tcl coroutine ::coroutine::util
}


# ----- Helpers ----------------------------------------------------------------

  
  # Resume a coroutine in a tight loop and collect its output as a list.  When
  # the coroutine terminates return the list. 
  proc Test_collect {coro} {
    set coro [uplevel 1 [list namespace which -command $coro]]
    set result {}
    while { [info commands $coro] ne {} } {
      lappend result [$coro] 
    }
    set result
  }
  

# ----- coroutine::util::create ------------------------------------------------

  # coroutine::util::create should create a coroutine with a unique name

  test coroutine-1.1 {coroutine::util::create} -body {
    set coroid [namespace eval ::coroutine::util {
      create apply {{} {
        yield [info coroutine]
        yield "alpha"
        return "beta"
      }}
    }]
    Test_collect $coroid
  } -result {alpha beta}
  

# ----- coroutine::util::global ------------------------------------------------

  # coroutine::util::global should link to a coro-global variable, not an
  # interp-global variable.  It should work at all stack levels _including
  # the first frame of the coroutine_, should not tramp on the first frame's
  # local vars, and should be auto-created if necessary by commands like 
  # [incr]/[append] (from any stack level).  [global] can be called with
  # multiple variable names.

  proc ::coroutine::util::Test_global {} {
    global myglobal
    incr myglobal
    yield $::myglobal 
    yield $myglobal
    return [apply [list {} {
      global strglobal myglobal
      incr myglobal
      yield $::myglobal 
      yield $myglobal
      return [append strglobal "ghi"]      
    } [namespace current]]] 
  }
  
  test coroutine-2.1 {coroutine::util::global} -body {
    set myglobal 10
    set strglobal "abc"

    set coroid [namespace eval ::coroutine::util {
      create apply [list {} {
        yield [info coroutine]
        global myglobal
        incr myglobal            ;# Create coro-global that doesn't exist yet
        yield $::myglobal        ;# Dereference interp/real global
        yield $myglobal          ;# Dereference coro-global 
        return [apply [list {} { ;# Push another stack frame
          global myglobal strglobal
          incr myglobal
          append strglobal "def"
          yield $::myglobal
          yield $myglobal
          yield $::strglobal
          yield $strglobal
          return [Test_global]   ;# And another two stack frames, one is named
        } [namespace current]]]  ;# All the coro's stack frames must have access
      } [namespace current]]     ;# to the overridden [global] command
    }]
    Test_collect $coroid
  } -result {10 1 10 2 abc def 10 3 10 4 defghi}

  catch { unset myglobal }


# ----- coroutine::util::after -------------------------------------------------


  # Work in progress
  # - coroutine::util::global functionality has been slightly modified in 
  #   order to work correctly at frame #1.  This may need to be reviewed.
  #   The new approach prevents tramping on frame #1's local variables.
  #   If trampling is intended then we may need a workaround to detect use of
  #   'global' in frame #1 and make it a noop. 
  # - Run tests with: %TCLSH% sak.tcl test run coroutine

testsuiteCleanup
return

Changes to modules/coroutine/pkgIndex.tcl.

1
2
3
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
package ifneeded coroutine       1.1   [list source [file join $dir coroutine.tcl]]
package ifneeded coroutine::auto 1.1.1 [list source [file join $dir coro_auto.tcl]]

|
|
1
2
3
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
package ifneeded coroutine       1.1.3 [list source [file join $dir coroutine.tcl]]
package ifneeded coroutine::auto 1.1.3 [list source [file join $dir coro_auto.tcl]]