Skip to content

Commit 535ebec

Browse files
author
hartsantler
committed
coffee backend: fixed variable args and kwargs.
1 parent c3745a6 commit 535ebec

4 files changed

Lines changed: 56 additions & 41 deletions

File tree

README.rst

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ irc freenode::
1515
Introduction
1616
======
1717

18-
PythonJS is a Python to Javascript and Dart translator written in
18+
PythonJS is a Python to Javascript translator written in
1919
Python, created by Amirouche Boubekki and Brett Hartshorn,
2020
currently maintained and developed by Brett. It features:
2121
list comprehensions, classes, multiple inheritance, operator
2222
overloading, function and class decorators, generator functions,
2323
HTML DOM, and easily integrates with JavaScript and external JavaScript
2424
libraries. The generated code works in the Browser and in NodeJS.
25-
Note: the Dart backend is still very experimental.
25+
Note: the Dart and CoffeeScript backends are still very experimental.
2626

2727
Speed
2828
---------------
@@ -335,7 +335,7 @@ Example Output::
335335
Python vs JavaScript Modes
336336
-------------------------
337337

338-
PythonJS has two primary modes you can write code in: "python" and "javascript". The default mode is "python", you can mark sections of your code to use either mode with "pythonjs.configure(javascript=True/False)" or nesting blocks inside "with python:" or "with javascript:". The "javascript" mode can be used for sections of code where performance is a major concern. When in "javascript" mode the literal "[]" syntax will return a JavaScript Array instead of a PythonJS list, and a literal "{}" returns a JavaScript Object instead of a PythonJS dict. In both modes you can directly call external JavaScript functions, its only faster in "javascript" mode because function calls are direct without any wrapping.
338+
PythonJS has two primary modes you can write code in: "python" and "javascript". The default mode is "python", you can mark sections of your code to use either mode with "pythonjs.configure(javascript=True/False)" or nesting blocks inside "with python:" or "with javascript:". The "javascript" mode can be used for sections of code where performance is a major concern. When in "javascript" mode Python dictionaries become JavaScript Objects. In both modes you can directly call external JavaScript functions, its only faster in "javascript" mode because function calls are direct without any wrapping.
339339

340340

341341
Directly Calling JavaScript Functions
@@ -759,7 +759,18 @@ Example::
759759
print f.read()
760760

761761
------------------------------
762+
Regression Tests
763+
================
762764

765+
The best way to see what features are currently supported with each of the backends
766+
is to run the automated regression tests in PythonJS/regtests. To test all the backends
767+
you need to install NodeJS, CoffeeScript, and Dart2JS. You should download the Dart SDK,
768+
and make sure that the executeable "dart2js" is in "~/dart/dart-sdk/bin/"
769+
770+
Run Regression Tests::
771+
772+
cd PythonJS/regtests
773+
./run.py
763774

764775
Test Server
765776
===========

pythonjs/python_to_pythonjs.py

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,7 @@ def visit_Call(self, node):
15771577
else:
15781578
raise SyntaxError
15791579

1580-
elif self._with_js or self._with_dart:
1580+
elif self._with_js or self._with_dart:# or self._with_coffee:
15811581
name = self.visit(node.func)
15821582
args = list( map(self.visit, node.args) )
15831583

@@ -1980,7 +1980,7 @@ def visit_FunctionDef(self, node):
19801980
writer.write( 'def %s( %s ):' % (node.name, ','.join(args)) )
19811981

19821982

1983-
elif self._with_js or javascript or self._with_coffee:
1983+
elif self._with_js or javascript:# or self._with_coffee:
19841984
if node.args.vararg:
19851985
raise SyntaxError( 'pure javascript functions can not take variable arguments (*args)' )
19861986
elif node.args.kwarg:
@@ -2012,8 +2012,8 @@ def visit_FunctionDef(self, node):
20122012
#####################################################################
20132013
if self._with_dart:
20142014
pass
2015-
elif self._with_coffee:
2016-
pass
2015+
#elif self._with_coffee:
2016+
# pass
20172017

20182018
elif self._with_js or javascript:
20192019
if node.args.defaults:
@@ -2057,7 +2057,8 @@ def visit_FunctionDef(self, node):
20572057
# new pythonjs' python function arguments handling
20582058
# create the structure representing the functions arguments
20592059
# first create the defaultkwargs JSObject
2060-
writer.write('var(signature, arguments)')
2060+
if not self._with_coffee:
2061+
writer.write('var(__sig__, __args__)')
20612062

20622063
L = len(node.args.defaults)
20632064
kwargsdefault = map(lambda x: keyword(self.visit(x[0]), x[1]), zip(node.args.args[-L:], node.args.defaults))
@@ -2086,26 +2087,15 @@ def visit_FunctionDef(self, node):
20862087

20872088
# create a JS Object to store the value of each parameter
20882089
signature = ', '.join(map(lambda x: '%s=%s' % (self.visit(x.arg), self.visit(x.value)), keywords))
2089-
writer.write('signature = JSObject(%s)' % signature)
2090-
writer.write('arguments = get_arguments(signature, args, kwargs)')
2090+
writer.write('__sig__ = JSObject(%s)' % signature)
2091+
writer.write('__args__ = get_arguments(__sig__, args, kwargs)')
20912092
# # then for each argument assign its value
20922093
for arg in node.args.args:
2093-
writer.write("""JS("var %s = arguments['%s']")""" % (arg.id, arg.id))
2094+
writer.write("""JS("var %s = __args__['%s']")""" % (arg.id, arg.id))
20942095
if node.args.vararg:
2095-
writer.write("""JS("var %s = arguments['%s']")""" % (node.args.vararg, node.args.vararg))
2096-
2097-
## DEPRECATED
2098-
# turn it into a list
2099-
#expr = '%s = __get__(list, "__call__")(__create_array__(%s), {});'
2100-
#expr = expr % (node.args.vararg, node.args.vararg)
2101-
#writer.write(expr)
2096+
writer.write("""JS("var %s = __args__['%s']")""" % (node.args.vararg, node.args.vararg))
21022097
if node.args.kwarg:
2103-
writer.write("""JS('var %s = arguments["%s"]')""" % (node.args.kwarg, node.args.kwarg))
2104-
2105-
## DEPRECATED
2106-
#expr = '%s = __get__(dict, "__call__")(__create_array__(%s), {});'
2107-
#expr = expr % (node.args.kwarg, node.args.kwarg)
2108-
#writer.write(expr)
2098+
writer.write("""JS('var %s = __args__["%s"]')""" % (node.args.kwarg, node.args.kwarg))
21092099
else:
21102100
log('(function has no arguments)')
21112101

pythonjs/pythonjs.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -250,18 +250,8 @@ def visit_Call(self, node):
250250
return '[]'
251251

252252
elif name == 'JS':
253-
s = node.args[0].s.replace('\n', '\\n').replace('\0', '\\0') ## AttributeError: 'BinOp' object has no attribute 's' - this is caused by bad quotes
254-
if s.strip().startswith('#'): s = '/*%s*/'%s
255-
if '"' in s or "'" in s: ## can not trust direct-replace hacks
256-
pass
257-
else:
258-
if ' or ' in s:
259-
s = s.replace(' or ', ' || ')
260-
if ' not ' in s:
261-
s = s.replace(' not ', ' ! ')
262-
if ' and ' in s:
263-
s = s.replace(' and ', ' && ')
264-
return s
253+
assert len(node.args)==1 and isinstance(node.args[0], ast.Str)
254+
return self._inline_code_helper( node.args[0].s )
265255

266256
elif name == 'dart_import':
267257
if len(node.args) == 1:
@@ -280,6 +270,20 @@ def visit_Call(self, node):
280270
args = ''
281271
return '%s(%s)' % (name, args)
282272

273+
def _inline_code_helper(self, s):
274+
s = s.replace('\n', '\\n').replace('\0', '\\0') ## AttributeError: 'BinOp' object has no attribute 's' - this is caused by bad quotes
275+
if s.strip().startswith('#'): s = '/*%s*/'%s
276+
if '"' in s or "'" in s: ## can not trust direct-replace hacks
277+
pass
278+
else:
279+
if ' or ' in s:
280+
s = s.replace(' or ', ' || ')
281+
if ' not ' in s:
282+
s = s.replace(' not ', ' ! ')
283+
if ' and ' in s:
284+
s = s.replace(' and ', ' && ')
285+
return s
286+
283287
def visit_While(self, node):
284288
body = [ 'while(%s) {' %self.visit(node.test)]
285289
self.push()

pythonjs/pythonjs_to_coffee.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ class CoffeeGenerator( pythonjs.JSGenerator ):
3232
_class_props = dict()
3333
_raw_dict = False
3434

35+
def _inline_code_helper(self, s):
36+
s = s.replace('\n', '\\n').replace('\0', '\\0') ## AttributeError: 'BinOp' object has no attribute 's' - this is caused by bad quotes
37+
if s.strip().startswith('#'): s = '/*%s*/'%s
38+
if '"' in s or "'" in s: ## can not trust direct-replace hacks
39+
pass
40+
else:
41+
if ' or ' in s:
42+
s = s.replace(' or ', ' || ')
43+
if ' not ' in s:
44+
s = s.replace(' not ', ' ! ')
45+
if ' and ' in s:
46+
s = s.replace(' and ', ' && ')
47+
return '`' + s + '`' ## enclose with backticks to inline javascript in coffeescript
48+
3549
def _visit_subscript_ellipsis(self, node):
3650
name = self.visit(node.value)
3751
return '%s.$wrapped' %name
@@ -288,11 +302,7 @@ def visit_Expr(self, node):
288302

289303
def visit_Print(self, node):
290304
args = [self.visit(e) for e in node.values]
291-
if len(args) > 1:
292-
s = 'print([%s]);' % ', '.join(args)
293-
else:
294-
s = 'print(%s);' % ', '.join(args)
295-
return s
305+
return 'console.log(%s)' % ', '.join(args)
296306

297307

298308
def visit_Assign(self, node):

0 commit comments

Comments
 (0)