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

Daniel Gackle danielgackle at gmail.com
Tue Dec 7 01:01:14 UTC 2010


Thank you for these examples, and sorry for the delay in replying. They are
invaluable in figuring out what you've done with BLOCK and RETURN-FROM.

In example #5, the following line:

  err['ps-return-value'];

fails to actually return anything. Presumably it should be:

  return err['ps-return-value'];

Daniel


On Sun, Nov 14, 2010 at 5:44 PM, Vladimir Sedach <vsedach at gmail.com> wrote:

> Dammit, I was counting on being the lazy one.
>
> There's 6 different situations that block and return-from can be involved
> in:
>
> 1. implicit nil block in iteration forms (do/dolist etc.) in lexical
> extent:
>
> (ps (dolist (x '(1 2 3)) (when (= x 1) (return))))
>
> =>
>
> for (var x = null, _js_arrvar2 = [1, 2, 3], _js_idx1 = 0; _js_idx1 <
> _js_arrvar2.length; _js_idx1 += 1) {
>    x = _js_arrvar2[_js_idx1];
>    if (x === 1) {
>        break;
>    };
> };
>
> 2. explicit nil or named block in lexical extent (we have to assign a
> name to the nil block):
>
> (ps (block nil (return) (+ 1 2)))
>
> =>
>
> nilblock: {
>    break nilblock;
>    1 + 2;
> };
>
> 3. implicit named block established by defun, flet, and labels with
> lexical extent:
>
> (defun foo ()  (return-from foo))
>
> =>
>
> function foo() {
>    return null;
> };
>
> 4. implicit named block established by defun, flet, and labels with
> dynamic extent:
>
> (defun foo ()  ((lambda () (return-from foo))))
>
> =>
>
> function foo() {
>    try {
>        return (function () {
>            throw { 'ps-block-tag' : 'foo', 'ps-return-value' : null };
>        })();
>    } catch (err) {
>        if (err && 'foo' === err['ps-block-tag']) {
>            err['ps-return-value'];
>        } else {
>            throw err;
>        };
>    };
> };
>
> 5. explicit named block with dynamic extent:
>
> (block nil ((lambda () (return))) (+ 1 2))
>
> =>
>
> nilblock: {
>    try {
>        (function () {
>            throw { 'ps-block-tag' : 'nilblock', 'ps-return-value' : null };
>        })();
>        1 + 2;
>    } catch (err) {
>        if (err && 'nilblock' === err['ps-block-tag']) {
>            err['ps-return-value'];
>        } else {
>            throw err;
>        };
>    };
> };
>
> 6. implicit nil block in iteration forms with dynamic extent return
>
> (ps (dolist (x '(1 2 3)) ((lambda (x) (when (= x 1) (return))) x)))
>
> =>
>
> Which is currently not implemented
>
> Vladimir
>
> 2010/11/13 Daniel Gackle <danielgackle at gmail.com>:
> > Sorry for being lazy, but can you post an example or two? This is a
> feature
> > I will definitely try out. One of the unwanted weaknesses of my code on
> the
> > JS side is the inability to get out of a top level function from inside a
> > lambda.
> >
> > On Sat, Nov 13, 2010 at 2:11 PM, Vladimir Sedach <vsedach at gmail.com>
> wrote:
> >>
> >> I just pushed a patch that tries to do the right thing with both
> >> lexical and dynamic-extent BLOCK (including implicit BLOCK forms) and
> >> RETURN-FROM. It's also supposed to provide backwards-compatibility
> >> with the old-style RETURN behavior (although that does issue a
> >> warning).
> >>
> >> The big thing is that right now in most of the interesting cases it
> >> does the control jump, but does not return a value. That will be fixed
> >> in future patches.
> >>
> >> I haven't really tested it, so try it out and let me know what breaks.
> >>
> >> Vladimir
> >>
> >> 2010/8/18 Daniel Gackle <danielgackle at gmail.com>:
> >> > I like your suggestion of emitting TRY/CATCH only in the cases where
> >> > it's necessary, i.e. only when trying to escape out of more than one
> >> > level of function nesting, seems like a good way to go. Then you're
> >> > only paying for the ugliness when you need it. It's in keeping with
> >> > PS's philosophy of staying close to what one would write by hand.
> >> >
> >> > On Wed, Aug 18, 2010 at 6: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
> >> >> >
> >> >>
> >> >> _______________________________________________
> >> >> 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
> >> >
> >> >
> >>
> >> _______________________________________________
> >> 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
> >
> >
>
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/parenscript-devel/attachments/20101206/aec0e0e4/attachment.html>


More information about the parenscript-devel mailing list