[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