metapensiero / metapensiero.pj

Javascript for refined palates: a Python 3 to ES6 Javascript translator
Other
901 stars 73 forks source link

Support calling python list functions on variable without wrapping it in list() call #69

Closed ktbytechibong closed 2 years ago

ktbytechibong commented 2 years ago

Currently, this does not work:

a = []
a.append(1) # transpiles to JS as `a.append(1)`, which doesn't work because append is not a JS array function

We need to wrap the variable in a list() call:

a = []
list(a).append(1) # trasnpiles to JS correctly as `a.push(1)`

What do you think about creating a JS array subclass to support native python list functions (append, remove, clear, count....)? Then we can have the JSList node generate code to create instance of the subclass instead of native JS arrays. I can work on a PR if you are ok with this approach.

azazel75 commented 2 years ago

Hi @ktbytechibong! What you propose is what Transcrypt does, with an extensive "runtime library" that wraps JS objects in Python APIs. This comes with several pros and cons. It makes the transpiler much more compatible with "in the field" Python code but to replicate all the features and quirks of Python API and semantics this runtime will grow larger, in the end probably making those "wrapped subclasses" incompatible with the JS APIs ( so you wll throw away interoperability with JS). Another factor to take into consideration is that once started creating this "emulation API" it's very difficult to draw a line and say "I will offer this API and no more"...

Another approach could be to extend the transpiler to be "pluggable" so that the developer can add its own transpilation code and maybe distribute it as a library... That's not very difficoult really, but the consideration on the runtime library are the same....

One more modern approach could be to integrate a library that is able to do an analysis a-la Mypy and ask it: "given that source code, what's the expected type of the object referenced by "a" at line 2?" and then consult a much more richer and capable transpilation library....

Unfortunately I don't have the time to implement neither of these options as of now, because at the moment I'm not using Javascripthon because I'm doing much less client code lately, so I think that the best option for you it's just to write

a = []
a.push(1)
ktbytechibong commented 2 years ago

Another factor to take into consideration is that once started creating this "emulation API" it's very difficult to draw a line and say "I will offer this API and no more"...

Ok, that's a good point. I have requirement to emulate only a subset of the Python syntax as accurately as possible, but I understand that's not everyone's goal.

Another approach could be to extend the transpiler to be "pluggable" so that the developer can add its own transpilation code and maybe distribute it as a library..

I am actually doing something like that locally already. I changed the api.trasnlate() function to take in a custom transformer to transform the output of ast.parse(dedented). I'll just stick to that approach then. Thanks.