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 <[email protected]> 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 <[email protected]> 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 <[email protected]>: >>> 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 >>> [email protected] >>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel >>> >>> >> >> _______________________________________________ >> parenscript-devel mailing list >> [email protected] >> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel >> > _______________________________________________ parenscript-devel mailing list [email protected] http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
