Block.st
changeset 1 a27a279701f8
child 2 6526dde5f3ac
equal deleted inserted replaced
0:aa2498ef6470 1:a27a279701f8
       
     1 "
       
     2  COPYRIGHT (c) 1989-93 by Claus Gittinger
       
     3               All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice.   This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person.  No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 Object subclass:#Block
       
    14        instanceVariableNames:'code flags byteCode home nargs
       
    15                               sourcePos initialPC literals
       
    16                               selfValue'
       
    17        classVariableNames:'InvalidNewSignal'
       
    18        poolDictionaries:''
       
    19        category:'Kernel-Methods'
       
    20 !
       
    21 
       
    22 Block comment:'
       
    23 
       
    24 COPYRIGHT (c) 1989-93 by Claus Gittinger
       
    25               All Rights Reserved
       
    26 
       
    27 %W% %E%
       
    28 
       
    29 written spring 89 by claus
       
    30 '!
       
    31 
       
    32 !Block class methodsFor:'documentation'!
       
    33 
       
    34 documentation
       
    35 "
       
    36 Blocks are pieces of executable code which can be evaluated by sending
       
    37 them a value-message (''value'', ''value:'', ''value:value:'' etc).
       
    38 
       
    39 Blocks with arguments need a message of type ''value:arg1 ... value:argn''
       
    40 for evaluation; the number of arguments passed when evaluating must match
       
    41 the number of arguments the block was declared with otherwise an error is
       
    42 raised. Blocks without args need a ''value'' message for evaluation.
       
    43 
       
    44 Blocks keep a reference to the method context where the block was declared -
       
    45 this allows blocks to access the methods arguments and/or variables.
       
    46 This is also true when the method has already returned - since the
       
    47 block keeps this reference, the methods context will NOT die in this case.
       
    48 
       
    49 A return (via ^-statement) out of a block will force a return from the
       
    50 blocks method context (if it is still living) - this make the implementation
       
    51 of long-jumps and control structures possible.
       
    52 (If the method is not alive (i.e. has already returned), a return out of the block 
       
    53 is ignored and a simple return from the block is performed).
       
    54 
       
    55 Long-jump is done by defining a catchBlock as ''[^ self]''
       
    56 somewhere up in the calling-tree. Then, to do the long-jump from out of some 
       
    57 deeply nested method, simply do: ''catchBlock value''.
       
    58 
       
    59 Instance variables:
       
    60 
       
    61 code        <not_an_object>   the function pointer if its a compiled block
       
    62 flags       <SmallInteger>    special flag bits coded in a number
       
    63 byteCode    <ByteArray>       bytecode of home method if its an interpreted block
       
    64 home        <Context>         the context where this block lives
       
    65 nargs       <SmallInteger>    the number of arguments the block expects
       
    66 sourcePos   <SmallInteger>    the character poistion of its source, in chars
       
    67                               relative to methods source beginning
       
    68 initialPC   <SmallInteger>    the start position within the byteCode
       
    69 literals    <Array>           the blocks literal array
       
    70 selfValue   <Object>          value to use for self if its a copying block
       
    71 
       
    72 NOTICE: layout known by runtime system and compiler - do not change
       
    73 "
       
    74 ! !
       
    75 
       
    76 !Block class methodsFor:'initialization' !
       
    77 
       
    78 initialize
       
    79     "setup the signals"
       
    80 
       
    81     InvalidNewSignal := (Signal new).
       
    82     InvalidNewSignal mayProceed:false.
       
    83     InvalidNewSignal notifierString:'blocks are only created by the system'.
       
    84 ! !
       
    85 
       
    86 !Block class methodsFor:'instance creation'!
       
    87 
       
    88 code:codeAddress byteCode:bCode nargs:numArgs sourcePosition:sourcePos initialPC:initialPC literals:literals
       
    89     "create a new cheap (homeless) block.
       
    90      Not for public use - special hook for the compiler."
       
    91 
       
    92     |newBlock|
       
    93 
       
    94     newBlock := super basicNew.
       
    95     newBlock code:codeAddress.
       
    96     newBlock byteCode:bCode.
       
    97     newBlock nargs:numArgs.
       
    98     newBlock sourcePosition:sourcePos. 
       
    99     newBlock initialPC:initialPC. 
       
   100     newBlock literals:literals.
       
   101     ^ newBlock
       
   102 !
       
   103 
       
   104 basicNew
       
   105     "catch creation of blocks - only the system creates blocks"
       
   106 
       
   107     InvalidNewSignal raise.
       
   108     ^ nil
       
   109 !
       
   110 
       
   111 basicNew:size
       
   112     "catch creation of blocks - only the system creates blocks"
       
   113 
       
   114     InvalidNewSignal raise.
       
   115     ^ nil
       
   116 ! !
       
   117 
       
   118 !Block methodsFor:'testing'!
       
   119 
       
   120 isBlock
       
   121     ^ true
       
   122 ! !
       
   123 
       
   124 !Block methodsFor:'accessing'!
       
   125 
       
   126 instVarAt:index
       
   127     "have to catch instVar access to code - since its no object"
       
   128 
       
   129     (index == 1) ifTrue:[^ self code].
       
   130     ^ super instVarAt:index
       
   131 !
       
   132 
       
   133 instVarAt:index put:value
       
   134     "have to catch instVar access to code - since its no object"
       
   135 
       
   136     (index == 1) ifTrue:[^ self code:value].
       
   137     ^ super instVarAt:index put:value
       
   138 !
       
   139 
       
   140 code
       
   141     "return the code field. This is not an object but the address of the machine instructions. 
       
   142      Therefore an integer representing the code-address is returned"
       
   143 
       
   144 %{  /* NOCONTEXT */
       
   145 
       
   146     if (_INST(code) != nil) {
       
   147         RETURN ( _MKSMALLINT((int)(_INST(code))) )
       
   148     }
       
   149 %}
       
   150 .
       
   151     ^ nil
       
   152 !
       
   153 
       
   154 byteCode
       
   155     "return the bytecode (a ByteArray) of the block"
       
   156 
       
   157     ^ byteCode
       
   158 !
       
   159 
       
   160 nargs
       
   161     "return the number of arguments I expect for evaluation"
       
   162 
       
   163     ^ nargs
       
   164 !
       
   165 
       
   166 selfValue
       
   167     "return the copied self"
       
   168 
       
   169     ^ selfValue
       
   170 ! !
       
   171 
       
   172 !Block methodsFor:'private accessing'!
       
   173 
       
   174 code:anAddress
       
   175     "set the code field - danger alert. 
       
   176      This is not an object but the address of the blocks machine instructions.
       
   177      Therefore the argument must be an integer representing for this address.
       
   178      You can crash Smalltalk very badly when playing around here ..."
       
   179 
       
   180 %{  /* NOCONTEXT */
       
   181     if (_isSmallInteger(anAddress))
       
   182         _INST(code) = (OBJ)(_intVal(anAddress));
       
   183 %}
       
   184 !
       
   185 
       
   186 byteCode:aByteArray
       
   187     "set the bytecode field - danger alert"
       
   188 
       
   189     byteCode := aByteArray
       
   190 !
       
   191 
       
   192 nargs:numArgs
       
   193     "set the number of arguments I expect for evaluation - danger alert"
       
   194 
       
   195     nargs := numArgs
       
   196 !
       
   197 
       
   198 sourcePosition:position 
       
   199     "set the position of the source within my method"
       
   200 
       
   201     sourcePos := position
       
   202 !
       
   203 
       
   204 initialPC:initial 
       
   205     "set the initial pc for evaluation - danger alert"
       
   206 
       
   207     initialPC := initial
       
   208 !
       
   209 
       
   210 literals:aLiteralArray 
       
   211     "set the literal array for evaluation - danger alert"
       
   212 
       
   213     literals := aLiteralArray
       
   214 ! !
       
   215 
       
   216 !Block methodsFor:'error handling'!
       
   217 
       
   218 argumentCountError:numberGiven
       
   219     "report that the number of arguments given does not match the number expected"
       
   220 
       
   221     self error:('Block got ' , numberGiven printString ,
       
   222                 ' args while ' , nargs printString , ' where expected')
       
   223 !
       
   224 
       
   225 invalidMethod
       
   226     "this is sent by the bytecode interpreter when the blocks definition is bad.
       
   227      Can only happen when playing around with the blocks instvars
       
   228      or the Compiler/runtime system is buggy"
       
   229 
       
   230     self error:'invalid block - not executable'
       
   231 !
       
   232 
       
   233 invalidByteCode
       
   234     "this is sent by the bytecode interpreter when trying to execute
       
   235      an invalid bytecode.
       
   236      Can only happen when playing around with the blocks instvars
       
   237       or the Compiler/runtime system is buggy"
       
   238 
       
   239     self error:'invalid byteCode in block - not executable'
       
   240 !
       
   241 
       
   242 receiverNotBoolean
       
   243     "this error is triggered when the bytecode-interpreter tries to
       
   244      execute ifTrue:/ifFalse or whileTrue: type of expressions where the
       
   245      receiver is neither true nor false."
       
   246 
       
   247     self error:'if/while on non-boolean receiver'
       
   248 ! !
       
   249 
       
   250 !Block methodsFor:'evaluation'!
       
   251 
       
   252 value
       
   253     "evaluate the receiver with no block args. The receiver must be a block without arguments."
       
   254 
       
   255 %{  /* NOCONTEXT */
       
   256 
       
   257     REGISTER OBJFUNC thecode;
       
   258     OBJ home;
       
   259     extern OBJ interpret();
       
   260 
       
   261     if (_INST(nargs) == _MKSMALLINT(0)) {
       
   262 #if defined(THIS_CONTEXT)
       
   263         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   264             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   265 #endif
       
   266         home = _BlockInstPtr(self)->b_home;
       
   267         thecode = _BlockInstPtr(self)->b_code;
       
   268         if (thecode != (OBJFUNC)nil) {
       
   269             /* compiled machine code */
       
   270             RETURN ( (*thecode)(home COMMA_SND) );
       
   271         }
       
   272         /* interpreted code */
       
   273         RETURN ( interpret(self, 0, nil, home COMMA_SND, nil) );
       
   274     }
       
   275 %}
       
   276 .
       
   277     ^ self argumentCountError:0
       
   278 !
       
   279 
       
   280 value:arg
       
   281     "evaluate the receiver with one argument. The receiver must be a 1-arg block."
       
   282 
       
   283 %{  /* NOCONTEXT */
       
   284 
       
   285     REGISTER OBJFUNC thecode;
       
   286     OBJ home;
       
   287     extern OBJ interpret();
       
   288 
       
   289     if (_INST(nargs) == _MKSMALLINT(1)) {
       
   290 #if defined(THIS_CONTEXT)
       
   291         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   292             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   293 #endif
       
   294         home = _BlockInstPtr(self)->b_home;
       
   295         thecode = _BlockInstPtr(self)->b_code;
       
   296         if (thecode != (OBJFUNC)nil) {
       
   297 #ifdef PASS_ARG_REF
       
   298             RETURN ( (*thecode)(home COMMA_SND, &arg) );
       
   299 #else
       
   300             RETURN ( (*thecode)(home COMMA_SND, arg) );
       
   301 #endif
       
   302         }
       
   303         /* interpreted code */
       
   304 #ifdef PASS_ARG_REF
       
   305         RETURN ( interpret(self, 1, nil, home COMMA_SND, nil, &arg) );
       
   306 #else
       
   307         RETURN ( interpret(self, 1, nil, home COMMA_SND, nil, arg) );
       
   308 #endif
       
   309     }
       
   310 %}
       
   311 .
       
   312     ^ self argumentCountError:1
       
   313 !
       
   314 
       
   315 value:arg1 value:arg2
       
   316     "evaluate the receiver with two arguments. The receiver must be a 2-arg block."
       
   317 
       
   318 %{  /* NOCONTEXT */
       
   319 
       
   320     REGISTER OBJFUNC thecode;
       
   321     OBJ home;
       
   322     extern OBJ interpret();
       
   323 
       
   324     if (_INST(nargs) == _MKSMALLINT(2)) {
       
   325 #if defined(THIS_CONTEXT)
       
   326         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   327             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   328 #endif
       
   329         home = _BlockInstPtr(self)->b_home;
       
   330         thecode = _BlockInstPtr(self)->b_code;
       
   331         if (thecode != (OBJFUNC)nil) {
       
   332 #ifdef PASS_ARG_REF
       
   333             RETURN ( (*thecode)(home COMMA_SND, &arg1) );
       
   334 #else
       
   335             RETURN ( (*thecode)(home COMMA_SND, arg1, arg2) );
       
   336 #endif
       
   337         }
       
   338 #ifdef PASS_ARG_REF
       
   339         RETURN ( interpret(self, 2, nil, home COMMA_SND, nil, &arg1) );
       
   340 #else
       
   341         RETURN ( interpret(self, 2, nil, home COMMA_SND, nil, arg1, arg2) );
       
   342 #endif
       
   343     }
       
   344 %}
       
   345 .
       
   346     ^ self argumentCountError:2
       
   347 !
       
   348 
       
   349 value:arg1 value:arg2 value:arg3
       
   350     "evaluate the receiver with three arguments. The receiver must be a 3-arg block."
       
   351 
       
   352 %{  /* NOCONTEXT */
       
   353 
       
   354     REGISTER OBJFUNC thecode;
       
   355     OBJ home;
       
   356     extern OBJ interpret();
       
   357 
       
   358     if (_INST(nargs) == _MKSMALLINT(3)) {
       
   359 #if defined(THIS_CONTEXT)
       
   360         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   361             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   362 #endif
       
   363         home = _BlockInstPtr(self)->b_home;
       
   364         thecode = _BlockInstPtr(self)->b_code;
       
   365         if (thecode != (OBJFUNC)nil) {
       
   366 #ifdef PASS_ARG_REF
       
   367             RETURN ( (*thecode)(home COMMA_SND, &arg1) );
       
   368 #else
       
   369             RETURN ( (*thecode)(home COMMA_SND, arg1, arg2, arg3) );
       
   370 #endif
       
   371         }
       
   372 #ifdef PASS_ARG_REF
       
   373         RETURN ( interpret(self, 3, nil, home COMMA_SND, nil, &arg1) );
       
   374 #else
       
   375         RETURN ( interpret(self, 3, nil, home COMMA_SND, nil, arg1, arg2, arg3) );
       
   376 #endif
       
   377     }
       
   378 %}
       
   379 .
       
   380     ^ self argumentCountError:3
       
   381 !
       
   382 
       
   383 value:arg1 value:arg2 value:arg3 value:arg4
       
   384     "evaluate the receiver with four arguments. The receiver must be a 4-arg block."
       
   385 
       
   386 %{  /* NOCONTEXT */
       
   387 
       
   388     REGISTER OBJFUNC thecode;
       
   389     OBJ home;
       
   390     extern OBJ interpret();
       
   391 
       
   392     if (_INST(nargs) == _MKSMALLINT(4)) {
       
   393 #if defined(THIS_CONTEXT)
       
   394         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   395             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   396 #endif
       
   397         home = _BlockInstPtr(self)->b_home;
       
   398         thecode = _BlockInstPtr(self)->b_code;
       
   399         if (thecode != (OBJFUNC)nil) {
       
   400 #ifdef PASS_ARG_REF
       
   401             RETURN ( (*thecode)(home COMMA_SND, &arg1) );
       
   402 #else
       
   403             RETURN ( (*thecode)(home COMMA_SND, arg1, arg2, arg3, arg4) );
       
   404 #endif
       
   405         }
       
   406 #ifdef PASS_ARG_REF
       
   407         RETURN ( interpret(self, 4, nil, home COMMA_SND, nil, &arg1) );
       
   408 #else
       
   409         RETURN ( interpret(self, 4, nil, home COMMA_SND, nil, arg1, arg2, arg3, arg4) );
       
   410 #endif
       
   411     }
       
   412 %}
       
   413 .
       
   414     ^ self argumentCountError:4
       
   415 !
       
   416 
       
   417 value:arg1 value:arg2 value:arg3 value:arg4 value:arg5
       
   418     "evaluate the receiver with four arguments. The receiver must be a 5-arg block."
       
   419 
       
   420 %{  /* NOCONTEXT */
       
   421 
       
   422     REGISTER OBJFUNC thecode;
       
   423     OBJ home;
       
   424     extern OBJ interpret();
       
   425 
       
   426     if (_INST(nargs) == _MKSMALLINT(5)) {
       
   427 #if defined(THIS_CONTEXT)
       
   428         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   429             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   430 #endif
       
   431         home = _BlockInstPtr(self)->b_home;
       
   432         thecode = _BlockInstPtr(self)->b_code;
       
   433         if (thecode != (OBJFUNC)nil) {
       
   434 #ifdef PASS_ARG_REF
       
   435             RETURN ( (*thecode)(home COMMA_SND, &arg1) );
       
   436 #else
       
   437             RETURN ( (*thecode)(home COMMA_SND, arg1, arg2, arg3, arg4, arg5) );
       
   438 #endif
       
   439         }
       
   440 #ifdef PASS_ARG_REF
       
   441         RETURN ( interpret(self, 5, nil, home COMMA_SND, nil, &arg1) );
       
   442 #else
       
   443         RETURN ( interpret(self, 5, nil, home COMMA_SND, nil, arg1, arg2, arg3, arg4, arg5) );
       
   444 #endif
       
   445     }
       
   446 %}
       
   447 .
       
   448     ^ self argumentCountError:5
       
   449 !
       
   450 
       
   451 value:arg1 value:arg2 value:arg3 value:arg4 value:arg5 value:arg6
       
   452     "evaluate the receiver with four arguments. The receiver must be a 6-arg block."
       
   453 
       
   454 %{  /* NOCONTEXT */
       
   455 
       
   456     REGISTER OBJFUNC thecode;
       
   457     OBJ home;
       
   458     extern OBJ interpret();
       
   459 
       
   460     if (_INST(nargs) == _MKSMALLINT(6)) {
       
   461 #if defined(THIS_CONTEXT)
       
   462         if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   463             _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   464 #endif
       
   465         home = _BlockInstPtr(self)->b_home;
       
   466         thecode = _BlockInstPtr(self)->b_code;
       
   467         if (thecode != (OBJFUNC)nil) {
       
   468 #ifdef PASS_ARG_REF
       
   469             RETURN ( (*thecode)(home COMMA_SND, &arg1) );
       
   470 #else
       
   471             RETURN ( (*thecode)(home COMMA_SND, arg1, arg2, arg3, arg4, arg5, arg6) );
       
   472 #endif
       
   473         }
       
   474 #ifdef PASS_ARG_REF
       
   475         RETURN ( interpret(self, 6, nil, home COMMA_SND, nil, &arg1) );
       
   476 #else
       
   477         RETURN ( interpret(self, 6, nil, home COMMA_SND, nil, arg1, arg2, arg3, arg4, arg5, arg6) );
       
   478 #endif
       
   479     }
       
   480 %}
       
   481 .
       
   482     ^ self argumentCountError:6
       
   483 !
       
   484 
       
   485 valueWithArguments:argArray
       
   486     "evaluate the receiver with arguments taken from argArray.
       
   487      The size of the argArray must match the number of arguments the receiver expects."
       
   488 
       
   489     |a1 a2 a3 a4 a5 a6 a7|
       
   490 
       
   491     (argArray class == Array) ifFalse:[
       
   492         ^ self error:'argument must be an array'
       
   493     ].
       
   494     (argArray size == nargs) ifFalse:[
       
   495         ^ self argumentCountError:(argArray size)
       
   496     ].
       
   497 %{
       
   498 
       
   499     REGISTER OBJFUNC thecode;
       
   500     OBJ home;
       
   501     extern OBJ interpret();
       
   502 
       
   503 #if defined(THIS_CONTEXT)
       
   504     if (1 /* _intVal(__pilc->ilc_lineNo) > 0 */)
       
   505         _ContextInstPtr(__thisContext)->c_lineno = __pilc->ilc_lineNo;
       
   506 #endif
       
   507     switch (_intVal(_INST(nargs))) {
       
   508         case 7:
       
   509             a7 = _ArrayInstPtr(argArray)->a_element[6];
       
   510         case 6:
       
   511             a6 = _ArrayInstPtr(argArray)->a_element[5];
       
   512         case 5:
       
   513             a5 = _ArrayInstPtr(argArray)->a_element[4];
       
   514         case 4:
       
   515             a4 = _ArrayInstPtr(argArray)->a_element[3];
       
   516         case 3:
       
   517             a3 = _ArrayInstPtr(argArray)->a_element[2];
       
   518         case 2:
       
   519             a2 = _ArrayInstPtr(argArray)->a_element[1];
       
   520         case 1:
       
   521             a1 = _ArrayInstPtr(argArray)->a_element[0];
       
   522         case 0:
       
   523             break;
       
   524     }
       
   525     home = _BlockInstPtr(self)->b_home;
       
   526     thecode = _BlockInstPtr(self)->b_code;
       
   527     if (thecode != (OBJFUNC)nil) {
       
   528 #ifdef PASS_ARG_REF
       
   529         RETURN ( (*thecode)(home COMMA_SND, &a1) );
       
   530 #else
       
   531         RETURN ( (*thecode)(home COMMA_SND, a1, a2, a3, a4, a5, a6, a7) );
       
   532 #endif
       
   533     }
       
   534 #ifdef PASS_ARG_REF
       
   535     RETURN ( interpret(self, _intVal(_INST(nargs)), nil,
       
   536                                     home COMMA_SND, nil, &a1) );
       
   537 #else
       
   538     RETURN ( interpret(self, _intVal(_INST(nargs)), nil,
       
   539                                     home COMMA_SND, nil, a1, a2, a3, a4, a5, a6, a7) );
       
   540 #endif
       
   541 %}
       
   542 !
       
   543 
       
   544 valueNowOrOnUnwindDo:aBlock
       
   545     "evaluate the receiver - after that, or when some method sent within unwinds (i.e. does
       
   546      a long return), evaluate the argument, aBlock.
       
   547      This is used to make certain that cleanup actions (for example closing files etc.) are
       
   548      executed regardless of error actions"
       
   549 
       
   550     |v|
       
   551 
       
   552     v := self value.       "the real logic is in Context"
       
   553     aBlock value.
       
   554     ^ v
       
   555 !
       
   556 
       
   557 valueOnUnwindDo:aBlock
       
   558     "evaluate the receiver - when some method sent within unwinds (i.e. does
       
   559      a long return), evaluate the argument, aBlock.
       
   560      This is used to make certain that cleanup actions (for example closing files etc.) are
       
   561      executed regardless of error actions"
       
   562 
       
   563     ^ self value        "the real logic is in Context"
       
   564 ! !
       
   565 
       
   566 !Block methodsFor:'looping'!
       
   567 
       
   568 whileTrue:aBlock
       
   569     "evaluate the argument, aBlock while the receiver evaluates to true.
       
   570      - open coded by compiler but needed here for #perform and expression evaluation."
       
   571 %{
       
   572     extern OBJ _value;
       
   573     static struct inlineCache bval = _ILC0;
       
   574     static struct inlineCache selfVal = _ILC0;
       
   575 
       
   576     while ((*bval.ilc_func)(self, _value, CON_COMMA nil, &bval) == true) {
       
   577         if (InterruptPending != nil) interrupt(CONARG);
       
   578         (*selfVal.ilc_func)(aBlock, _value, CON_COMMA nil, &selfVal);
       
   579     }
       
   580 %}
       
   581 .
       
   582     ^ nil
       
   583 !
       
   584 
       
   585 whileTrue
       
   586     "evaluate the receiver until it evaluates to false (ST80 compatibility)"
       
   587 
       
   588     ^ self whileTrue:[]
       
   589 !
       
   590 
       
   591 whileFalse:aBlock
       
   592     "evaluate the argument while the receiver evaluates to false.
       
   593      - open coded by compiler but needed here for #perform and expression evaluation."
       
   594 %{
       
   595     extern OBJ _value;
       
   596     static struct inlineCache bval = _ILC0;
       
   597     static struct inlineCache selfVal = _ILC0;
       
   598 
       
   599     while ((*bval.ilc_func)(self, _value, CON_COMMA nil, &bval) == false) {
       
   600         if (InterruptPending != nil) interrupt(CONARG);
       
   601         (*selfVal.ilc_func)(aBlock, _value, CON_COMMA nil, &selfVal);
       
   602     }
       
   603 %}
       
   604 .
       
   605     ^ nil
       
   606 !
       
   607 
       
   608 whileFalse
       
   609     "evaluate the receiver until it evaluates to true (ST80 compatibility)"
       
   610 
       
   611     ^ self whileFalse:[]
       
   612 !
       
   613 
       
   614 doWhile:aBlock
       
   615     "repeat the receiver block until aBlock evaluates to false.
       
   616      The receiver is evaluated at least once."
       
   617 
       
   618     self value.
       
   619     [aBlock value] whileTrue:[
       
   620         self value
       
   621     ]
       
   622 !
       
   623 
       
   624 doUntil:aBlock
       
   625     "repeat the receiver block until aBlock evaluates to true.
       
   626      The receiver is evaluated at least once."
       
   627 
       
   628     self value.
       
   629     [aBlock value] whileFalse:[
       
   630         self value
       
   631     ]
       
   632 !
       
   633 
       
   634 loop
       
   635     "repeat the receiver forever (should contain a return somewhere).
       
   636      Inspired by a corresponding Self method."
       
   637 
       
   638     [true] whileTrue:[self value]
       
   639 
       
   640     "[Transcript showCr:'hello'] loop"  "must be stopped with interrupt"
       
   641 !
       
   642 
       
   643 valueWithExit
       
   644     "the receiver must be a block of one argument.  It is evaluated, and is passed a block,
       
   645      which, if sent a value:-message, will exit the receiver block, returning the parameter of the 
       
   646      value:-message. Used for premature returns to the caller.
       
   647      Taken from a manchester goody (also appears in Self)."
       
   648 
       
   649     ^ self value: [:exitValue | ^exitValue]
       
   650 
       
   651     "[:exit |
       
   652         1 to:10 do:[:i |
       
   653             i == 5 ifTrue:[exit value:'thats it']
       
   654         ].
       
   655         'regular block-value; never returned'
       
   656      ] valueWithExit"
       
   657 !
       
   658 
       
   659 loopWithExit
       
   660     "the receiver must be a block of one argument.  It is evaluated in a loop forever, and is passed a 
       
   661      block, which, if sent a value:-message, will exit the receiver block, returning the parameter of 
       
   662      the value:-message. Used for loops with exit in the middle.
       
   663      Inspired by a corresponding Self method."
       
   664 
       
   665     |exitBlock|
       
   666 
       
   667     exitBlock := [:exitValue | ^ exitValue].
       
   668     [true] whileTrue:[self value:exitBlock]
       
   669 
       
   670     "|i|
       
   671      i := 1.
       
   672      [:exit |
       
   673         i == 5 ifTrue:[exit value:'thats it'].
       
   674         i := i + 1
       
   675      ] loopWithExit"
       
   676 ! !
       
   677 
       
   678 !Block methodsFor:'process creation'!
       
   679 
       
   680 newProcess
       
   681     "create a new (unscheduled) process executing the receiver"
       
   682 
       
   683     |p pBlock startUp|
       
   684 
       
   685     startUp := self.
       
   686     pBlock := [ startUp value. Processor terminate:p ].
       
   687     p := Processor newProcessFor:pBlock.
       
   688     ^ p
       
   689 !
       
   690 
       
   691 fork
       
   692     "create a new process executing the receiver"
       
   693 
       
   694     ^ self newProcess resume
       
   695 !
       
   696 
       
   697 forkWith:argumentArray
       
   698     |b|
       
   699 
       
   700     b := [self valueWithArguments:argumentArray].
       
   701     b fork
       
   702 !
       
   703 
       
   704 forkAt:priority
       
   705     "create a new process executing the receiver"
       
   706 
       
   707     ^ (self newProcess priority:priority) resume
       
   708 ! !
       
   709 
       
   710 !Block methodsFor:'printing'!
       
   711 
       
   712 printString
       
   713     |homeClass|
       
   714 
       
   715     home notNil ifTrue:[
       
   716         ^ '[] in ', home printString
       
   717     ].
       
   718     ^ '[] in ???'
       
   719 !
       
   720 
       
   721 printOn:aStream
       
   722     |homeClass|
       
   723 
       
   724     aStream nextPutAll:'[] in '.
       
   725     homeClass := home containingClass.
       
   726     homeClass notNil ifTrue:[
       
   727         homeClass name printOn:aStream.
       
   728         aStream space.
       
   729         (homeClass selectorForMethod:home) printOn:aStream
       
   730     ] ifFalse:[
       
   731         aStream nextPutAll:' ???'
       
   732     ]
       
   733 ! !