[parenscript-devel] Patch: added JS label/break to PS

Red Daly reddaly at gmail.com
Wed Aug 18 12:14:28 UTC 2010


Sorry, I forgot the link.  See
http://github.com/gonzojive/parenscript/commit/d8ebace1bcd60a57470d7a8cf0d4e351b7645e8e
for the commit that adds this.

My Parenscript branch is now pretty much in sync with the main branch,
with only 2 mostly cosmetic test failures

Red

On Wed, Aug 18, 2010 at 5:12 AM, Red Daly <reddaly at gmail.com> wrote:
> I added RETURN-FROM and BLOCK without too much effort using the
> implicit return functionality and try/catch. In my view this is the
> most reasonable way to implement this in the general case, since
> BLOCK/RETURN-FROM require non-local exit much in the same way that
> lisp's TRY/CATCH do.
>
> The alternative to this approach is to exit from each function in the
> call stack via a Javascript `return' statement.  Unfortunately, the
> call stack can contain many functions code over which the Parenscript
> compiler exerts little control, requiring throw as the control
> transfer mechanism.  Thus, in the general case of unknown code on the
> call stack, there is no means to exit without a throw.  I do not view
> throwing as an ugly solution at all, since try/catch was designed for
> non-local exits of all sorts.
>
> Nonetheless, using try/catch to implement Parenscript features
> deserves some attention.  Programs will need to ensure that they do
> not use try/catch in a way that interferes with the Parenscript
> convention.  Generally, try/catch blocks should only catch specific
> exceptions and re-throw PS's exceptions.   I'm happy to also implement
> a safe TRY/CATCH wrapper that re-throws Parenscript errors and catches
> everything else, too.  However, we may want to make an official
> interface change to try/catch if any lisp-style non-local exit code
> becomes part of the language.
>
> I present an example of why try/catch is unavoidable inline below:
>
> On Fri, Apr 9, 2010 at 3:42 PM, Vladimir Sedach <vsedach at gmail.com> wrote:
>> Makes sense to me. I'll add this to my todo list (which I'll publish
>> in an email as soon as I'm done my current work on the PS compiler).
>>
>> Vladimir
>>
>> 2010/4/9 Daniel Gackle <danielgackle at gmail.com>:
>>> I just pushed a patch (authored by Scott) to implement JS's LABEL and BREAK
>>> in PS. (Note that this patch deprecates LABELED-FOR since you can get the
>>> same effect by combining LABEL and FOR. Was anybody using LABELED-FOR?)
>>> Here's an example:
>>> (label scope
>>>     (foo)
>>>     (when (bar)
>>>       (break scope))
>>>     (blee))
>>> =>
>>> scope: {
>>>     foo();
>>>     if (bar()) {
>>>         break scope;
>>>     };
>>>     blee();
>>> };
>>> I was astonished to discover recently that JS has supported this ability all
>>> along in the form of labeled statements and labeled breaks. I'd always
>>> assumed that to get explicit returns from an arbitrary scope, you'd have to
>>> resort to the ugly hack of muscling TRY/CATCH to do it, thinking that this
>>> was the closest JS counterpart.
>>> (See http://news.ycombinator.com/item?id=793092 for a thread in which
>>> several people believe this.) But it appears we were all wrong.
>>> What's not clear yet is how far this can be taken. Can you use it inside a
>>> nested local function to return immediately from the top-level function?
>>> That is one thing I've wanted for a long time.
>>> In the ideal case, LABEL/BREAK could be used as a base for implementing a
>>> proper BLOCK and RETURN-FROM in PS, something which we'd long believed to be
>>> impossible. One challenge is that in CL, RETURN-FROM can take a value, which
>>> becomes the value of BLOCK. In other words, BLOCK in CL is an expression
>>> while LABEL in JS is not. It seems, though, that most of this challenge has
>>> already been conquered with the development of implicit return in PS. The
>>> only thing you'd need to add is detecting when BLOCK is being used as an
>>> expression, declaring a gensymed variable and assigning whatever is
>>> happening inside BLOCK to that variable (much like implicit return already
>>> does with e.g. CASE), then put the variable in the expression position that
>>> BLOCK was in. It seems like this ought to work. It would also make things
>>> like this possible in PS:
>>> (1+ (case foo
>>>         (:eleven 11)
>>>         (:twelve 12)))
>>> Vladimir (and everybody), is the above clear? What do you think of it?
>
> As stated above, I think try/catch is the way to go.  There is no
> other way to exit a stack of functions in the general case otherwise.
>
> For example, I can write a Javascript function that calls its argument
> infinity times and never returns.
>
> function mapForever(fn) {
> while(true) fn();
> }
>
> Now consider some parenscript:
>
> (block non-local
>  (map-forever
>    (lambda ()
>      (return-from non-local "we got out!"))))
>
> To extricate itself from map-forever, there is no alternative but JS's
> throw statement.
>
> Even if we had the ability to alter every function in the system, it
> would be necessary to inspect nearly every function call's return
> values to properly unwind the stack to the appropriate BLOCK.
>
> Having said all that, there are cases when try/catch is not necessary
> for BLOCK/RETURN-FROM, as you have described.  BLOCK should emit code
> according to the contexts in which RETURN-FROM appears.  If there is a
> RETURN-FROM inside the same function, BLOCK can use a label for a
> local exit.  If RETURN-FROM appears inside a lambda, try/catch is
> necessary (except in cases where you want to optimize this away by
> inspecting how that lambda gets passed around).  If there are no
> return-froms, just emit a PROGN.
>
> My solution does not do the local optimization, but it does refrain
> from putting try/catches around code with no return-froms.
>
>
>
> Red
>
>>> Daniel
>>> _______________________________________________
>>> parenscript-devel mailing list
>>> parenscript-devel at common-lisp.net
>>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>>>
>>>
>>
>> _______________________________________________
>> parenscript-devel mailing list
>> parenscript-devel at common-lisp.net
>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>>
>




More information about the parenscript-devel mailing list