[parenscript-devel] Keyword arguments and quoted symbols in Parenscript

Red Daly reddaly at gmail.com
Sun Apr 26 17:38:04 UTC 2009


On Sun, Apr 26, 2009 at 8:03 AM, Vladimir Sedach <vsedach at gmail.com> wrote:

> Hi Red,
>
> > I have modified the behavior of keywords found in Parenscript source to
> be
> > parsed into (PS-QUOTE keyword) instead of (JS-VARIABLE keyword).
>
> The current behavior is (ps::compile-parenscript-form :baz) => :baz
> (there's no quoting involved). The printer then outputs keyword
> symbols as strings, since this is the closest analogue (a
> self-evaluating object) to keywords among the native JavaScript
> objects.


It appears that I had an old version.  I was using the darcs repo instead of
the git repo.  There must have been a lot of changes as of August! (ps:ps
:foo) used to output a variable reference to foo.

Nonetheless, here is a bug with the current implementation:

CL-USER>
(setf (ps:PS-PACKAGE-PREFIX :cl-user) "CL_USER_")
CL-USER>
(ps:ps

           (let* ((some-prop
'foo-sym)

                  (my-object (ps:create 'foo-sym
"value!")))

             (slot-value my-object
'foo-sym)))


"var CL_USER_someProp =
'foo-sym';

var CL_USER_myObject = { 'foo-sym' : 'value!'
};

CL_USER_myObject.CL_USER_fooSym;"

The expected behavior would be for the (create ...) form to reference the
same value as the (slot-value ...) form.

If there were any sort of Parenscript runtime, it would be easy to make a
data structure for symbols.  For example, the above code could translate to
something like...

function Symbol(string, prefix) {
  this.string = string;
  this.prefix = prefix;
  // .. add to symbol table, etc.
}
Symbol.prototype.toString = function() { if (this.prefix) return this.prefix
+ "::" + this.string; else return this.string; }
var someProp_symbol = new Symbol("someProp", "CL_USER");

var CL_USER_someProp =
someProp_symbol;

var CL_USER_myObject = { someProp_symbol : 'value!'
};

CL_USER_myObject[someProp_symbol];

This would differentiate symbols and strings, and it would result in pointer
comparisons between symbols, just as in lisp.

I understand the current approach is to avoid any runtime, but the runtime
solution does seem like less of a hack in the end.

> This seems
> to make more sense because in Lisp, evaluating a keyword yields the
keyword
> itself rather than the value bound to it.  As a result, the ability to
paass
> keyword arguments to functions is now restored.
>
> CL-USER> (ps:ps (foo "bar" :quix "quo" :etc "etc..."))
> "foo('bar', { quix : 'quo', etc : 'etc...' });"
>
> Whereas this used to yield foo('bar', quix, 'quo', etc, 'etc...')

This is actually a fix to keyword argument handling: previously the PS
> lambda-list handling code assumed that whenever it encountered a
> keyword in the arglist of a function, it was the beginning of the
> keyword portion of the lambda list, and started making the object at
> that point. This of course may not be the case if you are trying to
> use keywords as arguments to a function. With keywords compiled to
> strings, you get self-evaluating objects and can do keyword handling
> in the function body at runtime (which is what the current code does).


I see the latest implementation now processes keyword arguments differently,
eliminating the old hash table approach.  This seems like an okay solution,
but I suspect it adds a a little overhead for each call to a function with
keyword arguments.

I also noticed a bug that resulted in improper handling of the following
case:
(ps:ps

           (defun hello-world (&key ((my-name-key
my-name)))
             (print "hello, " +
my-name))

           (hello-world 'my-name-key "fred"))


"function CL_USER_helloWorld()
{

    var
CL_USER_myName;

    var _js54 =
arguments.length;

    for (var n52 = 0; n52 < _js54; n52 += 2)
{

        switch (arguments[n52])
{

        case
CL_USER_myNameKey:


{

                CL_USER_myName = arguments[n52 +
1];


};


};


};

    if (CL_USER_myName === undefined)
{

        CL_USER_myName =
null;


};

    print('hello, ', plus,
CL_USER_myName);

};

CL_USER_helloWorld('my-name-key', 'fred');"

the javascript should really use the following case:  case 'myNameKey'
instead of case CL_USER_myNameKey.  a patch is attached


All the best,
Red


>
> Thanks,
> Vladimir
>
> > In general, symbols occupy a strange place in Parenscript.  Javascript
> has
> > no analogue of Lisp symbols, so there is no sensible translation of
> symbols
> > that works for everyone.  Nonetheless, quoted symbols are used in many
> > Parenscript macros to fake having real symbols in javascript.  We could
> > build in the ability to translate symbols to some javascript form, e.g.
> >
> > (ps:ps (make-instance 'animal)) =>  makeInstance( symbolTable["ANIMAL"] )
> >
> > The latter part of this post is just food for thought.  I will go ahead
> and
> > commit the patch for the former part of this post unless someone objects.
> >
> > Red
> >
> > _______________________________________________
> > 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/20090426/749cb1e0/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: paren-keyword-args-patch.diff
Type: application/octet-stream
Size: 3099 bytes
Desc: not available
URL: <https://mailman.common-lisp.net/pipermail/parenscript-devel/attachments/20090426/749cb1e0/attachment.obj>


More information about the parenscript-devel mailing list