On Mon, Oct 12, 2009 at 4:21 PM, Greg <g...@kinostudios.com> wrote: > My only concern, and perhaps John could elaborate on this because he > touched on it, would be how are Java nested classes protected from > this? Wouldn't it interfere with them? Or will the delimiters be > restricted to non-alphanumeric characters?
I thought I mentioned that in my previous post. Oh well. The string literal starting $x would have to START with $x. A symbol with an internal $ wouldn't behave differently from now. Nor would the symbol $ (just a dollar sign by itself) other than that you would have to always have whitespace between it and any following parenthesis or other Clojure delimiter. Identifiers of multiple characters starting with a $ are the major backward-compatibility hit, but I think these are (at present) extremely uncommon to nonexistent. One way to add backward compatibility would be to make the $x thing only work inside of (with-verbatim-strings ...) or something similar. Actually, this suggests a way to allow general user-modifiable read tables without the problems everyone's worried about: custom read tables can be defined and associated to a var, but to use them the block of code to which the custom read table would apply would be wrapped in some macro like (with-read-table rt ...). Presumably these could be nested, and as the reader left each of these forms the read table would revert to the previous, using a stack of some sort with the default Clojure read table at the bottom. Custom read tables could be in libraries, e.g. (ns foo (require [package.mysuff :as my])) ... (with-read-table my/fancyrt ...) but would not affect anything unless desired (e.g. (ns foo (use package.mystuff)) won't cause fancyrt to magically take effect without further action). This would require (with-read-table ...) to be a super-special form though, actually evaluated at read time. This would preclude programmatically generating a working (with-read-table ...) form in a macro, though not USING a custom read table in a macro where the read table to use was fixed rather than known only at macroexpansion time (i.e. was not computed from, or supplied directly via, one of the arguments); in that case, just use (with-read-table ...) around the macro or inside it. The (with-read-table ...) should probably become (do ...) rather than be stripped out by the reader, so (if (cond) (with-read-table my-perl-interpreter $#*$&%&# @#*@&$&$%)) will behave as expected, evaluating both perl expressions in the then branch rather than treating them as the then and else branches as would occur if the (with-read-table ...) disappeared entirely from around the wrapped code, or treating the first as a function to call with the second as argument, as would occur if just the with-read-table and the symbol name disappeared. There should also be a function with-read-table in core that errors, to catch cases of macros outputting the thing. The big trickiness here is that the reader will have to have access to certain vars; that is, (defreadtable name ...) would have to be evaluated by the reader, and (ns ...) and (require ...) and the like to discover any read tables. I think a multi-pass compilation becomes required: code is read up to the first (with-read-table ...) and then the reader pauses and macroexpansion and evaluation is done of all completely-read top-level forms. If the symbol's still not bound at this point, it's an error. This adds the restriction that (with-read-table foo ...) only works properly if foo is imported or defined in a previous top-level form, so (let [x 10] (defreadtable foo ...) (with-read-table foo ...) won't work, and redefinitions within a top level form won't take effect until the next one. More sophisticated would be for a (with-read-table ...) to be read initially into a kind of place-holder token as a string. When it had to be evaluated, the token would be lazily read and macroexpanded, and hopefully by then the read table's name has been bound. This would even allow one-off local read tables, e.g. (let [x (read-table ...)] (with-read-table x)), or even (with-read-table (read-table ...) ...). It would also be in the spirit of Clojure, I think, to use laziness in this way. An additional benefit is that (read-table ...) can be a normal macro or even a normal function call, rather than a special form, that returns a suitable data structure. Allowing (with-read-table ...) to be generated by macros is feasible if we go a step further and make (with-read-table ...) a nearly-normal special form with the property that a) it cannot redefine the meaning of parentheses, so everything after the second subform until the matching ) can be read as a string, unambiguously, and the form after reading becomes (with-read-table table-expr "one-big-string-literal"), b) the evaluator of macro output performs the same transformation, and c) when the form is evaluated, it recursively invokes the read-macroexpand-eval chain on its second argument in a context where the first argument is pushed into the readtable stack. Disallowing changing the behavior of whitespace and ( and ) in custom reader macros seems like a good idea anyway, especially if the access is to be through a lispy syntax resembling (with-read-table foo ...) which requires the meaning of that last ) and immediately-preceding whitespace, and of internal parenthesis pairs, to remain normal. On the other hand, doing so would stop the verbatim-string-literal thing being added in that way... --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---