PageRenderTime 80ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/pyjs/pyjs.py

http://pyjamas.googlecode.com/
Python | 1125 lines | 1094 code | 16 blank | 15 comment | 10 complexity | 7e2ee59463fdad3863d512565a344f55 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. #!/usr/bin/env python
  2. from types import StringType
  3. # Copyright 2006 James Tauber and contributors
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. import compiler
  17. from compiler import ast
  18. import os
  19. import copy
  20. # this is the python function used to wrap native javascript
  21. NATIVE_JS_FUNC_NAME = "JS"
  22. class Klass:
  23. klasses = {}
  24. def __init__(self, name):
  25. self.name = name
  26. self.klasses[name] = self
  27. self.functions = set()
  28. def set_base(self, base_name):
  29. self.base = self.klasses.get(base_name)
  30. def add_function(self, function_name):
  31. self.functions.add(function_name)
  32. class TranslationError(Exception):
  33. def __init__(self, message, node):
  34. self.message = "line %s:\n%s\n%s" % (node.lineno, message, node)
  35. def __str__(self):
  36. return self.message
  37. class Translator:
  38. def __init__(self, module_name, mod, output):
  39. if module_name:
  40. self.module_prefix = module_name + "_"
  41. else:
  42. self.module_prefix = ""
  43. self.imported_modules = set()
  44. self.imported_js = set()
  45. self.top_level_functions = set()
  46. self.top_level_classes = set()
  47. self.top_level_vars = set()
  48. self.output = output
  49. self.imported_classes = {}
  50. self.method_imported_globals = set()
  51. self.method_self = None
  52. for child in mod.node:
  53. if isinstance(child, ast.Function):
  54. self.top_level_functions.add(child.name)
  55. elif isinstance(child, ast.Class):
  56. self.top_level_classes.add(child.name)
  57. for child in mod.node:
  58. if isinstance(child, ast.Function):
  59. self._function(child, False)
  60. elif isinstance(child, ast.Class):
  61. self._class(child)
  62. elif isinstance(child, ast.Import):
  63. importName = child.names[0][0]
  64. if importName == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter
  65. pass
  66. elif importName.endswith('.js'):
  67. self.imported_js.add(importName)
  68. else:
  69. self.imported_modules.add(importName)
  70. elif isinstance(child, ast.From):
  71. if child.modname == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter
  72. pass
  73. else:
  74. self.imported_modules.add(child.modname)
  75. self._from(child)
  76. elif isinstance(child, ast.Discard):
  77. self._discard(child, None)
  78. elif isinstance(child, ast.Assign):
  79. self._assign(child, None, True)
  80. else:
  81. raise TranslationError("unsupported type (in __init__)", child)
  82. # Initialize all classes for this module
  83. for className in self.top_level_classes:
  84. print >> self.output, "__"+self.module_prefix+className+"_initialize();"
  85. def _default_args_handler(self, node, arg_names, current_klass):
  86. if len(node.defaults):
  87. default_pos = len(arg_names) - len(node.defaults)
  88. if arg_names and arg_names[0] == self.method_self:
  89. default_pos -= 1
  90. for default_node in node.defaults:
  91. if isinstance(default_node, ast.Const):
  92. default_value = self._const(default_node)
  93. elif isinstance(default_node, ast.Name):
  94. default_value = self._name(default_node)
  95. elif isinstance(default_node, ast.UnarySub):
  96. default_value = self._unarysub(default_node, current_klass)
  97. else:
  98. raise TranslationError("unsupported type (in _method)", default_node)
  99. default_name = arg_names[default_pos]
  100. default_pos += 1
  101. print >>self.output, " if (typeof %s == 'undefined') %s=%s;" % (default_name, default_name, default_value)
  102. def _varargs_handler(self, node, varargname, arg_names, current_klass):
  103. print >>self.output, " var", varargname, '= new pyjslib_List([]);'
  104. print >>self.output, " for(var __va_arg="+str(len(arg_names))+"; __va_arg < arguments.length; __va_arg++) {"
  105. print >>self.output, " var __arg = arguments[__va_arg];"
  106. print >>self.output, " "+varargname+".append(__arg);"
  107. print >>self.output, " }"
  108. def _kwargs_parser(self, node, function_name, arg_names, current_klass):
  109. if len(node.defaults) or node.kwargs:
  110. default_pos = len(arg_names) - len(node.defaults)
  111. if arg_names and arg_names[0] == self.method_self:
  112. default_pos -= 1
  113. print >>self.output, function_name+'.parse_kwargs = function (', ", ".join(["__kwargs"]+arg_names), ") {"
  114. for default_node in node.defaults:
  115. default_value = self.expr(default_node, current_klass)
  116. # if isinstance(default_node, ast.Const):
  117. # default_value = self._const(default_node)
  118. # elif isinstance(default_node, ast.Name):
  119. # default_value = self._name(default_node)
  120. # elif isinstance(default_node, ast.UnarySub):
  121. # default_value = self._unarysub(default_node, current_klass)
  122. # else:
  123. # raise TranslationError("unsupported type (in _method)", default_node)
  124. default_name = arg_names[default_pos]
  125. print >>self.output, " if (typeof %s == 'undefined')"%(default_name)
  126. print >>self.output, " %s=__kwargs.%s;"% (default_name, default_name)
  127. default_pos += 1
  128. #self._default_args_handler(node, arg_names, current_klass)
  129. if node.kwargs: arg_names += ["pyjslib_Dict(__kwargs)"]
  130. print >>self.output, " var __r = "+"".join(["[", ", ".join(arg_names), "]"])+";"
  131. if node.varargs:
  132. self._varargs_handler(node, "__args", arg_names, current_klass)
  133. print >>self.output, " __r.push.apply(__r, __args.getArray())"
  134. print >>self.output, " return __r;"
  135. print >>self.output, "};"
  136. def _function(self, node, local=False):
  137. if local: function_name = node.name
  138. else: function_name = self.module_prefix + node.name
  139. arg_names = list(node.argnames)
  140. normal_arg_names = list(arg_names)
  141. if node.kwargs: kwargname = normal_arg_names.pop()
  142. if node.varargs: varargname = normal_arg_names.pop()
  143. declared_arg_names = list(normal_arg_names)
  144. if node.kwargs: declared_arg_names.append(kwargname)
  145. function_args = "(" + ", ".join(declared_arg_names) + ")"
  146. print >>self.output, "function %s%s {" % (function_name, function_args)
  147. self._default_args_handler(node, normal_arg_names, None)
  148. if node.varargs:
  149. self._varargs_handler(node, varargname, declared_arg_names, None)
  150. for child in node.code:
  151. self._stmt(child, None)
  152. print >>self.output, "}"
  153. print >>self.output, "\n"
  154. self._kwargs_parser(node, function_name, normal_arg_names, None)
  155. def _return(self, node, current_klass):
  156. expr = self.expr(node.value, current_klass)
  157. if expr != "null":
  158. print >>self.output, " return " + expr + ";"
  159. else:
  160. print >>self.output, " return;"
  161. def _break(self, node, current_klass):
  162. print >>self.output, " break;"
  163. def _continue(self, node, current_klass):
  164. print >>self.output, " continue;"
  165. def _callfunc(self, v, current_klass):
  166. if isinstance(v.node, ast.Name):
  167. if v.node.name in self.top_level_functions:
  168. call_name = self.module_prefix + v.node.name
  169. elif v.node.name in self.top_level_classes:
  170. call_name = self.module_prefix + v.node.name
  171. elif self.imported_classes.has_key(v.node.name):
  172. call_name = self.imported_classes[v.node.name] + '_' + v.node.name
  173. elif v.node.name == "callable":
  174. call_name = "pyjslib_isFunction"
  175. elif v.node.name == "map":
  176. call_name = "pyjslib_map"
  177. elif v.node.name == "filter":
  178. call_name = "pyjslib_filter"
  179. elif v.node.name == "dir":
  180. call_name = "pyjslib_dir"
  181. elif v.node.name == "getattr":
  182. call_name = "pyjslib_getattr"
  183. elif v.node.name == "hasattr":
  184. call_name = "pyjslib_hasattr"
  185. elif v.node.name == "int":
  186. call_name = "pyjslib_int"
  187. elif v.node.name == "str":
  188. call_name = "pyjslib_str"
  189. elif v.node.name == "range":
  190. call_name = "pyjslib_range"
  191. elif v.node.name == "len":
  192. call_name = "pyjslib_len"
  193. elif v.node.name == "hash":
  194. call_name = "pyjslib_hash"
  195. elif v.node.name == "abs":
  196. call_name = "pyjslib_abs"
  197. else:
  198. call_name = v.node.name
  199. call_args = []
  200. elif isinstance(v.node, ast.Getattr):
  201. attr_name = v.node.attrname
  202. if isinstance(v.node.expr, ast.Name):
  203. call_name = self._name2(v.node.expr, current_klass, attr_name)
  204. call_args = []
  205. elif isinstance(v.node.expr, ast.Getattr):
  206. call_name = self._getattr2(v.node.expr, current_klass, attr_name)
  207. call_args = []
  208. elif isinstance(v.node.expr, ast.CallFunc):
  209. call_name = self._callfunc(v.node.expr, current_klass) + "." + v.node.attrname
  210. call_args = []
  211. elif isinstance(v.node.expr, ast.Subscript):
  212. call_name = self._subscript(v.node.expr, current_klass) + "." + v.node.attrname
  213. call_args = []
  214. elif isinstance(v.node.expr, ast.Const):
  215. call_name = self.expr(v.node.expr, current_klass) + "." + v.node.attrname
  216. call_args = []
  217. else:
  218. raise TranslationError("unsupported type (in _callfunc)", v.node.expr)
  219. else:
  220. raise TranslationError("unsupported type (in _callfunc)", v.node)
  221. kwargs = []
  222. for ch4 in v.args:
  223. if isinstance(ch4, ast.Keyword):
  224. kwarg = ch4.name + ":" + self.expr(ch4.expr, current_klass)
  225. kwargs.append(kwarg)
  226. else:
  227. arg = self.expr(ch4, current_klass)
  228. call_args.append(arg)
  229. if kwargs:
  230. try: call_this, method_name = call_name.rsplit(".", 1)
  231. except ValueError:
  232. # Must be a function call ...
  233. return ("pyjs_kwargs_function_call("+call_name+", "
  234. + "["+", ".join(['{' + ', '.join(kwargs) + '}']+call_args)+"]"
  235. + ")" )
  236. else:
  237. return ("pyjs_kwargs_method_call("+call_this+", '"+method_name+"', "
  238. + "["+", ".join(['{' + ', '.join(kwargs) + '}']+call_args)+"]"
  239. + ")")
  240. else:
  241. return call_name + "(" + ", ".join(call_args) + ")"
  242. def _print(self, node, current_klass):
  243. call_args = []
  244. for ch4 in node.nodes:
  245. arg = self.expr(ch4, current_klass)
  246. call_args.append(arg)
  247. print >>self.output, "pyjslib_printFunc([", ', '.join(call_args), "],", int(isinstance(node, ast.Printnl)), ");"
  248. def _getattr(self, v):
  249. attr_name = v.attrname
  250. if isinstance(v.expr, ast.Name):
  251. obj = self._name(v.expr)
  252. return obj + "." + attr_name
  253. elif isinstance(v.expr, ast.Getattr):
  254. return self._getattr(v.expr) + "." + attr_name
  255. elif isinstance(v.expr, ast.Subscript):
  256. return self._subscript(v.expr, self.module_prefix) + "." + attr_name
  257. elif isinstance(v.expr, ast.CallFunc):
  258. return self._callfunc(v.expr, self.module_prefix) + "." + attr_name
  259. else:
  260. raise TranslationError("unsupported type (in _getattr)", v.expr)
  261. def _name(self, v):
  262. if v.name == "True":
  263. return "true"
  264. elif v.name == "False":
  265. return "false"
  266. elif v.name == "None":
  267. return "null"
  268. elif v.name == self.method_self:
  269. return "this"
  270. elif v.name in self.method_imported_globals:
  271. return self.module_prefix + v.name
  272. elif self.imported_classes.has_key(v.name):
  273. return "__" + self.imported_classes[v.name] + '_' + v.name + ".prototype.__class__"
  274. elif v.name in self.top_level_classes:
  275. return "__" + self.module_prefix + v.name + ".prototype.__class__"
  276. else:
  277. return v.name
  278. def _name2(self, v, current_klass, attr_name):
  279. obj = v.name
  280. if obj in self.method_imported_globals:
  281. call_name = self.module_prefix + obj + "." + attr_name
  282. elif self.imported_classes.has_key(obj):
  283. #attr_str = ""
  284. #if attr_name != "__init__":
  285. attr_str = ".prototype.__class__." + attr_name
  286. call_name = "__" + self.imported_classes[obj] + '_' + obj + attr_str
  287. elif obj in self.imported_modules:
  288. call_name = obj + "_" + attr_name
  289. elif obj[0] == obj[0].upper():
  290. call_name = "__" + self.module_prefix + obj + ".prototype.__class__." + attr_name
  291. else:
  292. call_name = self._name(v) + "." + attr_name
  293. return call_name
  294. def _getattr2(self, v, current_klass, attr_name):
  295. if isinstance(v.expr, ast.Getattr):
  296. call_name = self._getattr2(v.expr, current_klass, v.attrname + "." + attr_name)
  297. else:
  298. obj = self.expr(v.expr, current_klass)
  299. call_name = obj + "." + v.attrname + "." + attr_name
  300. return call_name
  301. def _class(self, node):
  302. """
  303. Handle a class definition.
  304. In order to translate python semantics reasonably well, the following
  305. structure is used:
  306. A special object is created for the class, which inherits attributes
  307. from the superclass, or Object if there's no superclass. This is the
  308. class object; the object which you refer to when specifying the
  309. class by name. Static, class, and unbound methods are copied
  310. from the superclass object.
  311. A special constructor function is created with the same name as the
  312. class, which is used to create instances of that class.
  313. A javascript class (e.g. a function with a prototype attribute) is
  314. created which is the javascript class of created instances, and
  315. which inherits attributes from the class object. Bound methods are
  316. copied from the superclass into this class rather than inherited,
  317. because the class object contains unbound, class, and static methods
  318. that we don't necessarily want to inherit.
  319. The type of a method can now be determined by inspecting its
  320. static_method, unbound_method, class_method, or instance_method
  321. attribute; only one of these should be true.
  322. Much of this work is done in pyjs_extend, is pyjslib.py
  323. """
  324. class_name = self.module_prefix + node.name
  325. current_klass = Klass(class_name)
  326. init_method = None
  327. for child in node.code:
  328. if isinstance(child, ast.Function):
  329. current_klass.add_function(child.name)
  330. if child.name == "__init__":
  331. init_method = child
  332. if len(node.bases) == 0:
  333. base_class = "pyjslib_Object"
  334. elif len(node.bases) == 1:
  335. if isinstance(node.bases[0], ast.Name):
  336. if self.imported_classes.has_key(node.bases[0].name):
  337. base_class = self.imported_classes[node.bases[0].name] + '_' + node.bases[0].name
  338. else:
  339. base_class = self.module_prefix + node.bases[0].name
  340. elif isinstance(node.bases[0], ast.Getattr):
  341. base_class = self._name(node.bases[0].expr) + "_" + node.bases[0].attrname
  342. else:
  343. raise TranslationError("unsupported type (in _class)", node.bases[0])
  344. current_klass.set_base(base_class)
  345. else:
  346. raise TranslationError("more than one base (in _class)", node)
  347. print >>self.output, "function __" + class_name + "() {"
  348. # call superconstructor
  349. #if base_class:
  350. # print >>self.output, " __" + base_class + ".call(this);"
  351. print >>self.output, "}"
  352. if not init_method:
  353. init_method = ast.Function([], "__init__", ["self"], [], 0, None, [])
  354. #self._method(init_method, current_klass, class_name)
  355. # Generate a function which constructs the object
  356. clsfunc = ast.Function([],
  357. node.name,
  358. init_method.argnames[1:],
  359. init_method.defaults,
  360. init_method.flags,
  361. None,
  362. [ast.Discard(ast.CallFunc(ast.Name("JS"), [ast.Const(
  363. # I attempted lazy initialization, but then you can't access static class members
  364. # " if(!__"+base_class+".__was_initialized__)"+
  365. # " __" + class_name + "_initialize();\n" +
  366. " var instance = new __" + class_name + "();\n" +
  367. " if(instance.__init__) instance.__init__.apply(instance, arguments);\n" +
  368. " return instance;"
  369. )]))])
  370. self._function(clsfunc, False)
  371. print >>self.output, "function __" + class_name + "_initialize() {"
  372. print >>self.output, " if(__"+class_name+".__was_initialized__) return;"
  373. print >>self.output, " __"+class_name+".__was_initialized__ = true;"
  374. cls_obj = "__" + class_name + '.prototype.__class__'
  375. if class_name == "pyjslib_Object":
  376. print >>self.output, " "+cls_obj+" = {};"
  377. else:
  378. if base_class and base_class not in ("object", "pyjslib_Object"):
  379. print >>self.output, " if(!__"+base_class+".__was_initialized__)"
  380. print >>self.output, " __"+base_class+"_initialize();"
  381. print >>self.output, " pyjs_extend(__" + class_name + ", __"+base_class+");"
  382. else:
  383. print >>self.output, " pyjs_extend(__" + class_name + ", __pyjslib_Object);"
  384. print >>self.output, " "+cls_obj+".__new__ = "+class_name+";"
  385. for child in node.code:
  386. if isinstance(child, ast.Pass):
  387. pass
  388. elif isinstance(child, ast.Function):
  389. self._method(child, current_klass, class_name)
  390. elif isinstance(child, ast.Assign):
  391. self.classattr(child, current_klass)
  392. elif isinstance(child, ast.Discard) and isinstance(child.expr, ast.Const):
  393. # Probably a docstring, turf it
  394. pass
  395. else:
  396. raise TranslationError("unsupported type (in _class)", child)
  397. print >>self.output, "}"
  398. def classattr(self, node, current_klass):
  399. self._assign(node, current_klass, True)
  400. def _method(self, node, current_klass, class_name):
  401. # reset global var scope
  402. self.method_imported_globals = set()
  403. arg_names = list(node.argnames)
  404. classmethod = False
  405. staticmethod = False
  406. if node.decorators:
  407. for d in node.decorators:
  408. if d.name == "classmethod":
  409. classmethod = True
  410. elif d.name == "staticmethod":
  411. staticmethod = True
  412. if staticmethod:
  413. staticfunc = ast.Function([], class_name+"_"+node.name, node.argnames, node.defaults, node.flags, node.doc, node.code, node.lineno)
  414. self._function(staticfunc, True)
  415. print >>self.output, " __" + class_name + ".prototype.__class__." + node.name + " = " + class_name+"_"+node.name+";";
  416. print >>self.output, " __" + class_name + ".prototype.__class__." + node.name + ".static_method = true;";
  417. return
  418. else:
  419. if len(arg_names) == 0:
  420. raise TranslationError("methods must take an argument 'self' (in _method)", node)
  421. self.method_self = arg_names[0]
  422. #if not classmethod and arg_names[0] != "self":
  423. # raise TranslationError("first arg not 'self' (in _method)", node)
  424. normal_arg_names = arg_names[1:]
  425. if node.kwargs: kwargname = normal_arg_names.pop()
  426. if node.varargs: varargname = normal_arg_names.pop()
  427. declared_arg_names = list(normal_arg_names)
  428. if node.kwargs: declared_arg_names.append(kwargname)
  429. function_args = "(" + ", ".join(declared_arg_names) + ")"
  430. if classmethod:
  431. fexpr = "__" + class_name + ".prototype.__class__." + node.name
  432. else:
  433. fexpr = "__" + class_name + ".prototype." + node.name
  434. print >>self.output, " "+fexpr + " = function" + function_args + " {"
  435. # default arguments
  436. self._default_args_handler(node, normal_arg_names, current_klass)
  437. if node.varargs:
  438. self._varargs_handler(node, varargname, declared_arg_names, current_klass)
  439. for child in node.code:
  440. self._stmt(child, current_klass)
  441. print >>self.output, " };"
  442. self._kwargs_parser(node, fexpr, normal_arg_names, current_klass)
  443. if classmethod:
  444. # Have to create a version on the instances which automatically passes the
  445. # class as "self"
  446. altexpr = "__" + class_name + ".prototype." + node.name
  447. print >>self.output, " "+altexpr + " = function() {"
  448. print >>self.output, " return " + fexpr + ".apply(this.__class__, arguments);"
  449. print >>self.output, " };"
  450. print >>self.output, " "+fexpr+".class_method = true;"
  451. print >>self.output, " "+altexpr+".instance_method = true;"
  452. else:
  453. # For instance methods, we need an unbound version in the class object
  454. altexpr = "__" + class_name + ".prototype.__class__." + node.name
  455. print >>self.output, " "+altexpr + " = function() {"
  456. print >>self.output, " return " + fexpr + ".call.apply("+fexpr+", arguments);"
  457. print >>self.output, " };"
  458. print >>self.output, " "+altexpr+".unbound_method = true;"
  459. print >>self.output, " "+fexpr+".instance_method = true;"
  460. if node.kwargs or len(node.defaults):
  461. print >>self.output, " "+altexpr + ".parse_kwargs = " + fexpr + ".parse_kwargs;"
  462. self.method_self = None
  463. self.method_imported_globals = set()
  464. def _stmt(self, node, current_klass):
  465. if isinstance(node, ast.Return):
  466. self._return(node, current_klass)
  467. elif isinstance(node, ast.Break):
  468. self._break(node, current_klass)
  469. elif isinstance(node, ast.Continue):
  470. self._continue(node, current_klass)
  471. elif isinstance(node, ast.Assign):
  472. self._assign(node, current_klass)
  473. elif isinstance(node, ast.AugAssign):
  474. self._augassign(node, current_klass)
  475. elif isinstance(node, ast.Discard):
  476. self._discard(node, current_klass)
  477. elif isinstance(node, ast.If):
  478. self._if(node, current_klass)
  479. elif isinstance(node, ast.For):
  480. self._for(node, current_klass)
  481. elif isinstance(node, ast.While):
  482. self._while(node, current_klass)
  483. elif isinstance(node, ast.Subscript):
  484. self._subscript_stmt(node, current_klass)
  485. elif isinstance(node, ast.Global):
  486. self._global(node, current_klass)
  487. elif isinstance(node, ast.Pass):
  488. pass
  489. elif isinstance(node, ast.Function):
  490. self._function(node, True)
  491. elif isinstance(node, ast.Printnl):
  492. self._print(node, current_klass)
  493. elif isinstance(node, ast.Print):
  494. self._print(node, current_klass)
  495. else:
  496. raise TranslationError("unsupported type (in _stmt)", node)
  497. def _augassign(self, node, current_klass):
  498. v = node.node
  499. if isinstance(v, ast.Getattr):
  500. lhs = self._getattr(v)
  501. else:
  502. lhs = self._name(node.node)
  503. op = node.op
  504. rhs = self.expr(node.expr, current_klass)
  505. print >>self.output, " " + lhs + " " + op + " " + rhs + ";"
  506. def _assign(self, node, current_klass, top_level = False):
  507. if len(node.nodes) != 1:
  508. tempvar = '__temp'+str(node.lineno)
  509. tnode = ast.Assign([ast.AssName(tempvar, "OP_ASSIGN", node.lineno)], node.expr, node.lineno)
  510. self._assign(tnode, current_klass, top_level)
  511. for v in node.nodes:
  512. tnode2 = ast.Assign([v], ast.Name(tempvar, node.lineno), node.lineno)
  513. self._assign(tnode2, current_klass, top_level)
  514. return
  515. v = node.nodes[0]
  516. if isinstance(v, ast.AssAttr):
  517. attr_name = v.attrname
  518. if isinstance(v.expr, ast.Name):
  519. obj = v.expr.name
  520. lhs = " " + self._name(v.expr) + "." + attr_name
  521. elif isinstance(v.expr, ast.Getattr):
  522. lhs = " " + self._getattr(v)
  523. elif isinstance(v.expr, ast.Subscript):
  524. lhs = " " + self._subscript(v.expr, current_klass) + "." + attr_name
  525. else:
  526. raise TranslationError("unsupported type (in _assign)", v.expr)
  527. if v.flags == "OP_ASSIGN":
  528. op = "="
  529. else:
  530. raise TranslationError("unsupported flag (in _assign)", v)
  531. elif isinstance(v, ast.AssName):
  532. if top_level:
  533. if current_klass:
  534. lhs = "__" + current_klass.name + ".prototype.__class__." + v.name
  535. else:
  536. self.top_level_vars.add(v.name)
  537. lhs = "var " + self.module_prefix + v.name
  538. else:
  539. if v.name in self.method_imported_globals:
  540. lhs = " " + self.module_prefix + v.name
  541. else:
  542. lhs = " var " + v.name
  543. if v.flags == "OP_ASSIGN":
  544. op = "="
  545. else:
  546. raise TranslationError("unsupported flag (in _assign)", v)
  547. elif isinstance(v, ast.Subscript):
  548. if v.flags == "OP_ASSIGN":
  549. obj = self.expr(v.expr, current_klass)
  550. if len(v.subs) != 1:
  551. raise TranslationError("must have one sub (in _assign)", v)
  552. idx = self.expr(v.subs[0], current_klass)
  553. value = self.expr(node.expr, current_klass)
  554. print >>self.output, " " + obj + ".__setitem__(" + idx + ", " + value + ");"
  555. return
  556. else:
  557. raise TranslationError("unsupported flag (in _assign)", v)
  558. else:
  559. raise TranslationError("unsupported type (in _assign)", v)
  560. rhs = self.expr(node.expr, current_klass)
  561. print >>self.output, lhs + " " + op + " " + rhs + ";"
  562. def _discard(self, node, current_klass):
  563. if isinstance(node.expr, ast.CallFunc):
  564. if isinstance(node.expr.node, ast.Name) and node.expr.node.name == NATIVE_JS_FUNC_NAME:
  565. if len(node.expr.args) != 1:
  566. raise TranslationError("native javascript function %s must have one arg" % NATIVE_JS_FUNC_NAME, node.expr)
  567. if not isinstance(node.expr.args[0], ast.Const):
  568. raise TranslationError("native javascript function %s must have constant arg" % NATIVE_JS_FUNC_NAME, node.expr)
  569. print >>self.output, node.expr.args[0].value
  570. else:
  571. expr = self._callfunc(node.expr, current_klass)
  572. print >>self.output, " " + expr + ";"
  573. elif isinstance(node.expr, ast.Const):
  574. if node.expr.value is not None: # Empty statements generate ignore None
  575. print >>self.output, self._const(node.expr)
  576. else:
  577. raise TranslationError("unsupported type (in _discard)", node.expr)
  578. def _if(self, node, current_klass):
  579. for i in range(len(node.tests)):
  580. test, consequence = node.tests[i]
  581. if i == 0:
  582. keyword = "if"
  583. else:
  584. keyword = "else if"
  585. self._if_test(keyword, test, consequence, current_klass)
  586. if node.else_:
  587. keyword = "else"
  588. test = None
  589. consequence = node.else_
  590. self._if_test(keyword, test, consequence, current_klass)
  591. def _if_test(self, keyword, test, consequence, current_klass):
  592. if test:
  593. expr = self.expr(test, current_klass)
  594. print >>self.output, " " + keyword + " (" + expr + ") {"
  595. else:
  596. print >>self.output, " " + keyword + " {"
  597. if isinstance(consequence, ast.Stmt):
  598. for child in consequence.nodes:
  599. self._stmt(child, current_klass)
  600. else:
  601. raise TranslationError("unsupported type (in _if_test)", consequence)
  602. print >>self.output, " }"
  603. def _from(self, node):
  604. for name in node.names:
  605. self.imported_classes[name[0]] = node.modname
  606. def _compare(self, node, current_klass):
  607. lhs = self.expr(node.expr, current_klass)
  608. if len(node.ops) != 1:
  609. raise TranslationError("only one ops supported (in _compare)", node)
  610. op = node.ops[0][0]
  611. rhs_node = node.ops[0][1]
  612. rhs = self.expr(rhs_node, current_klass)
  613. if op == "in":
  614. return rhs + ".__contains__(" + lhs + ")"
  615. elif op == "not in":
  616. return "!" + rhs + ".__contains__(" + lhs + ")"
  617. elif op == "is":
  618. op = "=="
  619. return "(" + lhs + " " + op + " " + rhs + ")"
  620. def _not(self, node, current_klass):
  621. expr = self.expr(node.expr, current_klass)
  622. return "!(" + expr + ")"
  623. def _or(self, node, current_klass):
  624. expr = " || ".join([self.expr(child, current_klass) for child in node.nodes])
  625. return expr
  626. def _and(self, node, current_klass):
  627. expr = " && ".join([self.expr(child, current_klass) for child in node.nodes])
  628. return expr
  629. def _for(self, node, current_klass):
  630. assign_name = ""
  631. assign_tuple = ""
  632. # based on Bob Ippolito's Iteration in Javascript code
  633. if isinstance(node.assign, ast.AssName):
  634. assign_name = node.assign.name
  635. if node.assign.flags == "OP_ASSIGN":
  636. op = "="
  637. elif isinstance(node.assign, ast.AssTuple):
  638. op = "="
  639. i = 0
  640. for child in node.assign:
  641. child_name = child.name
  642. if assign_name == "":
  643. assign_name = "temp_" + child_name
  644. assign_tuple += """
  645. var %(child_name)s %(op)s %(assign_name)s.__getitem__(%(i)i);
  646. """ % locals()
  647. i += 1
  648. else:
  649. raise TranslationError("unsupported type (in _for)", node.assign)
  650. if isinstance(node.list, ast.Name):
  651. list_expr = self._name(node.list)
  652. elif isinstance(node.list, ast.Getattr):
  653. list_expr = self._getattr(node.list)
  654. elif isinstance(node.list, ast.CallFunc):
  655. list_expr = self._callfunc(node.list, current_klass)
  656. else:
  657. raise TranslationError("unsupported type (in _for)", node.list)
  658. lhs = "var " + assign_name
  659. iterator_name = "__" + assign_name
  660. print >>self.output, """
  661. var %(iterator_name)s = %(list_expr)s.__iter__();
  662. try {
  663. while (true) {
  664. %(lhs)s %(op)s %(iterator_name)s.next();
  665. %(assign_tuple)s
  666. """ % locals()
  667. for node in node.body.nodes:
  668. self._stmt(node, current_klass)
  669. print >>self.output, """
  670. }
  671. } catch (e) {
  672. if (e != StopIteration) {
  673. throw e;
  674. }
  675. }
  676. """ % locals()
  677. def _while(self, node, current_klass):
  678. test = self.expr(node.test, current_klass)
  679. print >>self.output, " while (" + test + ") {"
  680. if isinstance(node.body, ast.Stmt):
  681. for child in node.body.nodes:
  682. self._stmt(child, current_klass)
  683. else:
  684. raise TranslationError("unsupported type (in _while)", node.body)
  685. print >>self.output, " }"
  686. def _const(self, node):
  687. if isinstance(node.value, int):
  688. return str(node.value)
  689. elif isinstance(node.value, float):
  690. return str(node.value)
  691. elif isinstance(node.value, str):
  692. return "'" + node.value.encode('string_escape') + "'"
  693. elif node.value is None:
  694. return "null"
  695. else:
  696. raise TranslationError("unsupported type (in _const)", node)
  697. def _unarysub(self, node, current_klass):
  698. return "-" + self.expr(node.expr, current_klass)
  699. def _add(self, node, current_klass):
  700. return self.expr(node.left, current_klass) + " + " + self.expr(node.right, current_klass)
  701. def _sub(self, node, current_klass):
  702. return self.expr(node.left, current_klass) + " - " + self.expr(node.right, current_klass)
  703. def _div(self, node, current_klass):
  704. return self.expr(node.left, current_klass) + " / " + self.expr(node.right, current_klass)
  705. def _mul(self, node, current_klass):
  706. return self.expr(node.left, current_klass) + " * " + self.expr(node.right, current_klass)
  707. def _mod(self, node, current_klass):
  708. if isinstance(node.left, ast.Const) and isinstance(node.left.value, StringType):
  709. self.imported_js.add("sprintf.js") # Include the sprintf functionality if it is used
  710. return "sprintf("+self.expr(node.left, current_klass) + ", " + self.expr(node.right, current_klass)+")"
  711. return self.expr(node.left, current_klass) + " % " + self.expr(node.right, current_klass)
  712. def _invert(self, node, current_klass):
  713. return "~" + self.expr(node.expr, current_klass)
  714. def _bitand(self, node, current_klass):
  715. return " & ".join([self.expr(child, current_klass) for child in node.nodes])
  716. def _bitor(self, node, current_klass):
  717. return " | ".join([self.expr(child, current_klass) for child in node.nodes])
  718. def _subscript(self, node, current_klass):
  719. if node.flags == "OP_APPLY":
  720. if len(node.subs) == 1:
  721. return self.expr(node.expr, current_klass) + ".__getitem__(" + self.expr(node.subs[0], current_klass) + ")"
  722. else:
  723. raise TranslationError("must have one sub (in _subscript)", node)
  724. else:
  725. raise TranslationError("unsupported flag (in _subscript)", node)
  726. def _subscript_stmt(self, node, current_klass):
  727. if node.flags == "OP_DELETE":
  728. print >>self.output, " " + self.expr(node.expr, current_klass) + ".__delitem__(" + self.expr(node.subs[0], current_klass) + ");"
  729. else:
  730. raise TranslationError("unsupported flag (in _subscript)", node)
  731. def _list(self, node, current_klass):
  732. return "new pyjslib_List([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])"
  733. def _dict(self, node, current_klass):
  734. items = []
  735. for x in node.items:
  736. key = self.expr(x[0], current_klass)
  737. value = self.expr(x[1], current_klass)
  738. items.append("[" + key + ", " + value + "]")
  739. return "new pyjslib_Dict([" + ", ".join(items) + "])"
  740. def _tuple(self, node, current_klass):
  741. return "new pyjslib_Tuple([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])"
  742. def _slice(self, node, current_klass):
  743. if node.flags == "OP_APPLY":
  744. lower = "null"
  745. upper = "null"
  746. if node.lower != None:
  747. lower = self.expr(node.lower, current_klass)
  748. if node.upper != None:
  749. upper = self.expr(node.upper, current_klass)
  750. return "pyjslib_slice(" + self.expr(node.expr, current_klass) + ", " + lower + ", " + upper + ")"
  751. else:
  752. raise TranslationError("unsupported flag (in _slice)", node)
  753. def _global(self, node, current_klass):
  754. for name in node.names:
  755. self.method_imported_globals.add(name)
  756. def expr(self, node, current_klass):
  757. if isinstance(node, ast.Const):
  758. return self._const(node)
  759. # @@@ not sure if the parentheses should be here or in individual operator functions - JKT
  760. elif isinstance(node, ast.Mul):
  761. return " ( " + self._mul(node, current_klass) + " ) "
  762. elif isinstance(node, ast.Add):
  763. return " ( " + self._add(node, current_klass) + " ) "
  764. elif isinstance(node, ast.Sub):
  765. return " ( " + self._sub(node, current_klass) + " ) "
  766. elif isinstance(node, ast.Div):
  767. return " ( " + self._div(node, current_klass) + " ) "
  768. elif isinstance(node, ast.Mod):
  769. return self._mod(node, current_klass)
  770. elif isinstance(node, ast.UnarySub):
  771. return self._unarysub(node, current_klass)
  772. elif isinstance(node, ast.Not):
  773. return self._not(node, current_klass)
  774. elif isinstance(node, ast.Or):
  775. return self._or(node, current_klass)
  776. elif isinstance(node, ast.And):
  777. return self._and(node, current_klass)
  778. elif isinstance(node, ast.Invert):
  779. return self._invert(node, current_klass)
  780. elif isinstance(node, ast.Bitand):
  781. return self._bitand(node, current_klass)
  782. elif isinstance(node, ast.Bitor):
  783. return self._bitor(node, current_klass)
  784. elif isinstance(node, ast.Compare):
  785. return self._compare(node, current_klass)
  786. elif isinstance(node, ast.CallFunc):
  787. return self._callfunc(node, current_klass)
  788. elif isinstance(node, ast.Name):
  789. return self._name(node)
  790. elif isinstance(node, ast.Subscript):
  791. return self._subscript(node, current_klass)
  792. elif isinstance(node, ast.Getattr):
  793. return self._getattr(node)
  794. elif isinstance(node, ast.List):
  795. return self._list(node, current_klass)
  796. elif isinstance(node, ast.Dict):
  797. return self._dict(node, current_klass)
  798. elif isinstance(node, ast.Tuple):
  799. return self._tuple(node, current_klass)
  800. elif isinstance(node, ast.Slice):
  801. return self._slice(node, current_klass)
  802. else:
  803. raise TranslationError("unsupported type (in expr)", node)
  804. import cStringIO
  805. def translate(file_name, module_name):
  806. output = cStringIO.StringIO()
  807. mod = compiler.parseFile(file_name)
  808. t = Translator(module_name, mod, output)
  809. return output.getvalue()
  810. class PlatformParser:
  811. def __init__(self, platform_dir = ""):
  812. self.platform_dir = platform_dir
  813. self.parse_cache = {}
  814. self.platform = ""
  815. def setPlatform(self, platform):
  816. self.platform = platform
  817. def parseModule(self, module_name, file_name):
  818. if self.parse_cache.has_key(file_name):
  819. mod = self.parse_cache[file_name]
  820. else:
  821. print "Importing " + module_name
  822. mod = compiler.parseFile(file_name)
  823. self.parse_cache[file_name] = mod
  824. platform_file_name = self.generatePlatformFilename(file_name)
  825. if self.platform and os.path.isfile(platform_file_name):
  826. mod = copy.deepcopy(mod)
  827. mod_override = compiler.parseFile(platform_file_name)
  828. self.merge(mod, mod_override)
  829. return mod
  830. def generatePlatformFilename(self, file_name):
  831. (module_name, extension) = os.path.splitext(os.path.basename(file_name))
  832. platform_file_name = module_name + self.platform + extension
  833. return os.path.join(os.path.dirname(file_name), self.platform_dir, platform_file_name)
  834. def merge(self, tree1, tree2):
  835. for child in tree2.node:
  836. if isinstance(child, ast.Function):
  837. self.replaceFunction(tree1, child.name, child)
  838. elif isinstance(child, ast.Class):
  839. self.replaceClassMethods(tree1, child.name, child)
  840. return tree1
  841. def replaceFunction(self, tree, function_name, function_node):
  842. # find function to replace
  843. for child in tree.node:
  844. if isinstance(child, ast.Function) and child.name == function_name:
  845. self.copyFunction(child, function_node)
  846. return
  847. raise TranslationError("function not found: " + function_name, function_node)
  848. def replaceClassMethods(self, tree, class_name, class_node):
  849. # find class to replace
  850. old_class_node = None
  851. for child in tree.node:
  852. if isinstance(child, ast.Class) and child.name == class_name:
  853. old_class_node = child
  854. break
  855. if not old_class_node:
  856. raise TranslationError("class not found: " + class_name, class_node)
  857. # replace methods
  858. for function_node in class_node.code:
  859. if isinstance(function_node, ast.Function):
  860. found = False
  861. for child in old_class_node.code:
  862. if isinstance(child, ast.Function) and child.name == function_node.name:
  863. found = True
  864. self.copyFunction(child, function_node)
  865. break
  866. if not found:
  867. raise TranslationError("class method not found: " + class_name + "." + function_node.name, function_node)
  868. def copyFunction(self, target, source):
  869. target.code = source.code
  870. target.argnames = source.argnames
  871. target.defaults = source.defaults
  872. target.doc = source.doc # @@@ not sure we need to do this any more
  873. class AppTranslator:
  874. def __init__(self, library_dirs=["../library"], parser=None):
  875. self.extension = ".py"
  876. self.library_modules = []
  877. self.library_dirs = library_dirs
  878. if not parser:
  879. self.parser = PlatformParser()
  880. else:
  881. self.parser = parser
  882. def findFile(self, file_name):
  883. if os.path.isfile(file_name):
  884. return file_name
  885. for library_dir in self.library_dirs:
  886. full_file_name = os.path.join(os.path.dirname(__file__), library_dir, file_name)
  887. if os.path.isfile(full_file_name):
  888. return full_file_name
  889. raise Exception("file not found: " + file_name)
  890. def translate(self, module_name, is_app=True):
  891. if module_name not in self.library_modules:
  892. self.library_modules.append(module_name)
  893. file_name = self.findFile(module_name + self.extension)
  894. if is_app:
  895. module_name_translated = ""
  896. else:
  897. module_name_translated = module_name
  898. output = cStringIO.StringIO()
  899. mod = self.parser.parseModule(module_name, file_name)
  900. t = Translator(module_name_translated, mod, output)
  901. module_str = output.getvalue()
  902. imported_modules_str = ""
  903. for module in t.imported_modules:
  904. if module not in self.library_modules:
  905. imported_modules_str += self.translate(module, False)
  906. for js in t.imported_js:
  907. path = self.findFile(js)
  908. if os.path.isfile(path):
  909. print 'Including', js
  910. imported_modules_str += '\n//\n// BEGIN '+js+'\n//\n'
  911. imported_modules_str += file(path).read()
  912. imported_modules_str += '\n//\n// END '+js+'\n//\n'
  913. else:
  914. print >>sys.stderr, 'Warning: Unable to find imported javascript:', js
  915. return imported_modules_str + module_str
  916. def translateLibraries(self, library_modules=[]):
  917. self.library_modules = library_modules
  918. imported_modules_str = ""
  919. for library in self.library_modules:
  920. imported_modules_str += self.translate(library, False)
  921. return imported_modules_str
  922. if __name__ == "__main__":
  923. import sys
  924. file_name = sys.argv[1]
  925. if len(sys.argv) > 2:
  926. module_name = sys.argv[2]
  927. else:
  928. module_name = None
  929. print translate(file_name, module_name),