├── .gitignore ├── LICENSE ├── README.rst ├── pycow ├── __init__.py ├── decorators.py ├── demo │ ├── demo.html │ ├── demo.py │ └── demo.py.js ├── js │ └── pycow.js ├── pycow.py └── utils.py ├── scripts └── pycow └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.kpf 2 | *.pyc 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | PyCow 2 | ===== 3 | A Python to JavaScript with MooTools converter. 4 | 5 | Project Lead/Maintainer: 6 | Patrick Schneider 7 | 8 | License 9 | ------- 10 | PyCow is licensed under the Apache License, Version 2.0; see the LICENSE file. 11 | 12 | Description 13 | ----------- 14 | PyCow translates Python code to JavaScript code with the "MooTools way of class declaration". 15 | 16 | It generally depends on the fact that JavaScript shares almost all of its semantics with Python, 17 | so PyCow just has to change the syntax most of the time. 18 | 19 | Installation 20 | ------------ 21 | PyCow is a pure-python library and is installed via the Python Distribution Utilities ("Distutils"). 22 | See http://docs.python.org/install/index.html#install-index. 23 | 24 | Examples 25 | -------- 26 | Some explanatory examples can be found on http://wiki.github.com/p2k/PyCow/examples. 27 | 28 | -------------------------------------------------------------------------------- /pycow/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from pycow import * 3 | from utils import * 4 | -------------------------------------------------------------------------------- /pycow/decorators.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # PyCow - Python to JavaScript with MooTools translator 4 | # Copyright 2009 Patrick Schneider 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # 20 | # This file contains some compatibility decorators which implement parts of 21 | # MooTool's functionality. 22 | # 23 | 24 | import copy 25 | from types import ClassType, FunctionType 26 | 27 | __all__ = ["Implements", "Class"] 28 | 29 | def Implements(*args): 30 | """ 31 | This class decorator is used to implement methods of given classes into the 32 | decorated class. Your class needs a `implement` method for this to work. 33 | See the `Class` decorator. 34 | 35 | """ 36 | def do_implement(target): 37 | for cls in args: 38 | target.implement(cls) 39 | return target 40 | return do_implement 41 | 42 | @classmethod 43 | def implement(cls, properties): 44 | """ 45 | Implements the passed in properties into the base Class, altering the 46 | base Class. 47 | The same as creating a new Class with the Implements decorator, but 48 | handy when you need to modify existing classes. 49 | 50 | Note: `properties` must be either a dictionary or a class. 51 | """ 52 | oldstyle = isinstance(cls, ClassType) 53 | if isinstance(properties, type): 54 | properties = properties.__dict__ 55 | for name, value in properties.iteritems(): 56 | if name.startswith("__") and name.endswith("__"): continue 57 | if oldstyle: 58 | cls.__dict__[name] = value 59 | else: 60 | setattr(cls, name, value) 61 | return cls 62 | 63 | def parent(self, *args): 64 | """ 65 | Call the parent class' method. This uses a stacktrace and thus may not be 66 | very efficient. Use super() instead. 67 | """ 68 | import traceback 69 | getattr(super(self.__class__, self), traceback.extract_stack(None, 2)[0][2])(*args) 70 | 71 | def Class(cls): 72 | """ 73 | This class decorator patches some things in your classes for MooTools 74 | compatibility. Namely it modifies the constructor to create shallow copies 75 | of class-bound properties (to reflect MooTools' behaviour) and adds a 76 | `implement` and `parent` method to the class. 77 | 78 | """ 79 | 80 | __orig_init__ = cls.__init__ 81 | 82 | def __moo__init__(self, *args, **kwargs): 83 | """ 84 | MooTools compatibility constructor. Makes shallow copies of all class 85 | properties and calls the original constructor. 86 | """ 87 | for name, value in self.__class__.__dict__.iteritems(): 88 | if name.startswith("__") and name.endswith("__"): continue 89 | if isinstance(value, FunctionType): continue 90 | setattr(self, name, copy.copy(value)) 91 | 92 | __orig_init__(self, *args, **kwargs) 93 | 94 | cls.__init__ = __moo__init__ 95 | if isinstance(cls, ClassType): 96 | cls.__dict__["implement"] = implement 97 | else: 98 | cls.implement = implement 99 | cls.parent = parent 100 | 101 | return cls 102 | -------------------------------------------------------------------------------- /pycow/demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | PyCow Demo 4 | 5 | 6 | 21 | 22 | 23 |

24 | 		
25 | 	
26 | 
27 | 


--------------------------------------------------------------------------------
/pycow/demo/demo.py:
--------------------------------------------------------------------------------
  1 | 
  2 | # Import statements are ignored atm, you must look after them for yourself
  3 | 
  4 | from pycow.decorators import Implements, Class
  5 | from pycow.utils import Events, Options, Hash
  6 | 
  7 | # Use __all__ to hide classes and functions
  8 | 
  9 | __all__ = ["Someclass", "a_function"]
 10 | 
 11 | # Classes, subclasses and functions
 12 | 
 13 | @Class
 14 | class Someclass(object):
 15 | 	"""
 16 | 	Docstring of class
 17 | 	"""
 18 | 	def __init__(self, something): # PyCow removes 'self' from method declarations
 19 | 		"""
 20 | 		Docstring of constructor/method
 21 | 		"""
 22 | 		self.something = something + "string literal" # PyCow replaces 'self' with 'this'
 23 | 	
 24 | 	def a_method(self, otherthing):
 25 | 		print self.something + otherthing # 'print' is translated to 'alert'
 26 | 	
 27 | 	def another_method(self):
 28 | 		obj = SomeExtension() # PyCow can infer types of callables (even declared later); here it will place 'new', because SomeExtension is a class
 29 | 		self.member = "test"
 30 | 
 31 | @Class
 32 | class SomeExtension(Someclass):
 33 | 	def __init__(self):
 34 | 		super(SomeExtension, self).__init__("1234") # PyCow correctly treats the 'super' function of Python; here it's the call to the super constructor
 35 | 	
 36 | 	def a_method(self, otherthing):
 37 | 		super(SomeExtension, self).a_method(otherthing) # Here it's a call to the super class' method
 38 | 		
 39 | 		# Note: this.parent has been backported to python, so you could use self.parent(otherthing) here, too.
 40 | 		
 41 | 		print otherthing, self.something
 42 | 
 43 | def a_function(somevalue = "Default"): # Default values
 44 | 	"""
 45 | 	Docstring of function
 46 | 	
 47 | 	Note that PyCow removes
 48 | 			whitespaces.
 49 | 	
 50 | 	
 51 | 	
 52 | 	And normalizes newlines.
 53 | 	"""
 54 | 	test = 2 # PyCow automatically declares local variables
 55 | 	test = 4 # once
 56 | 	print test+    2 # Because PyCow parses semantics only, it will ignore whitespaces (but avoid to do something like that anyways)
 57 | 
 58 | obj = Someclass("a lengthy ")
 59 | 
 60 | obj.a_method("test") # PyCow's type inference does not include types of variables (atm)
 61 | 
 62 | obj = SomeExtension()
 63 | 
 64 | obj.a_method(" sub")
 65 | 
 66 | a_function() # PyCow does not put "new" here, because a_function is a simple function
 67 | 
 68 | @Implements(Options)
 69 | @Class
 70 | class ClassWithOptions(object):
 71 | 	"""
 72 | 	A class with implements Options using the `Implements` decorator.
 73 | 	This is MooTools functionality ported to Python.
 74 | 	"""
 75 | 	
 76 | 	# Note: In Python semantics, this declares a class-bound member, but MooTools
 77 | 	# sees this as object-bound members. The Class decorator will convert all
 78 | 	# class-bound members to object-bound members on instantiation.
 79 | 	options = {
 80 | 		"name": "value",
 81 | 		"foo": "bar",
 82 | 	}
 83 | 	
 84 | 	def __init__(self, options):
 85 | 		self.setOptions(options)
 86 | 		print self.options["foo"], self.options["name"]
 87 | 	
 88 | 	# Static methods supported
 89 | 	@staticmethod
 90 | 	def somestatic(input):
 91 | 		print "Static " + input
 92 | 
 93 | # Variable scope
 94 | global x # Because of the 'global' statement
 95 | x = "hello again" # PyCow does not declare x as local here
 96 | 
 97 | def another_function():
 98 | 	global x
 99 | 	x = "go ahead" # and here
100 | 	return x
101 | 
102 | # Standard statements
103 | 
104 | if True: # If statement
105 | 	print "Welcome"
106 | 	if False:
107 | 		pass
108 | 	else:
109 | 		print "Nested if"
110 | else:
111 | 	print "You're not welcome..."
112 | 
113 | i = 0
114 | while i < 3 and not False: # While statement
115 | 	print i
116 | 	i += 1 # Assignment operator
117 | 
118 | print "---"
119 | 
120 | for j in xrange(3): # For statement (xrange)
121 | 	print j
122 | 
123 | print "----"
124 | 
125 | for i in xrange(1,4): # For statement (xrange; with start)
126 | 	print i
127 | 	for j in xrange(i,4,2): # For statement (xrange; nested; with start and step)
128 | 		print j
129 | 
130 | print "-----"
131 | 
132 | for j in xrange(4,1,-1): # For statement (xrange; with start and step backwards)
133 | 	print j
134 | 
135 | i = [1,2,3]
136 | for j in i: # For statement (simple variable)
137 | 	print j
138 | 
139 | for j in ["a","b","c"+"d"]: # For statement (arbitrary expression)
140 | 	print j
141 | 
142 | for key, value in {"a": 1, "b": 2}.iteritems(): # For statement (dictionary)
143 | 	print key, value
144 | 
145 | f = lambda x: x*2 # Lambda functions
146 | 
147 | a = [1,2,3,f(2)] # List expression
148 | 
149 | print a[1:3] # Slicing
150 | 
151 | b = {} # Empty dictionary
152 | 
153 | # Dictionary with strings and numbers as indices
154 | b = {"a": 1, "b": 2,
155 | 	 1: "x", 2: "y",
156 | 	 "-test-": 1+2, "0HAY0": "a"+"B"}
157 | 
158 | # Accessing subscript (simple string)
159 | print b["a"]
160 | 
161 | # Accessing subscript (other string; assignment)
162 | b["-test-"] = 3
163 | 
164 | # Accessing subscript (number)
165 | print b[1]
166 | 
167 | # Deleting from map
168 | del b["a"]
169 | 
170 | # Modulo operator on strings, i.e. sprintf
171 | print "Demo %d %s %.2f" % (b["-test-"], "abc", 0.123456)
172 | 
173 | # Operator precedence test
174 | print (1 > 2) and ((2 * 3) > 8) # removes all parentheses
175 | print 1 * (2 + 4) * -(1 + 2) # keeps all parentheses
176 | print (True and True) and False or False
177 | 
178 | # isinstance
179 | print isinstance([], list)
180 | print isinstance(Hash(), Hash)
181 | 


--------------------------------------------------------------------------------
/pycow/demo/demo.py.js:
--------------------------------------------------------------------------------
  1 | /* This file was generated with PyCow - the Python to JavaScript translator */
  2 | 
  3 | /* from pycow.decorators import Implements, Class */;
  4 | 
  5 | /* from pycow.utils import Events, Options, Hash */;
  6 | 
  7 | /**
  8 |  * Docstring of class
  9 |  */
 10 | var Someclass = new Class({
 11 | 
 12 | 	/**
 13 | 	 * Docstring of constructor/method
 14 | 	 */
 15 | 	initialize: function (something) {
 16 | 		this.something = something + "string literal";
 17 | 	},
 18 | 
 19 | 	a_method: function (otherthing) {
 20 | 		dbgprint(this.something + otherthing);
 21 | 	},
 22 | 
 23 | 	another_method: function () {
 24 | 		var obj = new SomeExtension();
 25 | 		this.member = "test";
 26 | 	}
 27 | });
 28 | 
 29 | var SomeExtension = new Class({
 30 | 	Extends: Someclass,
 31 | 
 32 | 	initialize: function () {
 33 | 		this.parent("1234");
 34 | 	},
 35 | 
 36 | 	a_method: function (otherthing) {
 37 | 		this.parent(otherthing);
 38 | 		dbgprint(otherthing, this.something);
 39 | 	}
 40 | });
 41 | 
 42 | /**
 43 |  * Docstring of function
 44 |  *
 45 |  * Note that PyCow removes
 46 |  * whitespaces.
 47 |  *
 48 |  * And normalizes newlines.
 49 |  */
 50 | var a_function = function (somevalue) {
 51 | 	if (!$defined(somevalue)) somevalue = "Default";
 52 | 	var test = 2;
 53 | 	test = 4;
 54 | 	dbgprint(test + 2);
 55 | };
 56 | 
 57 | var obj = new Someclass("a lengthy ");
 58 | 
 59 | /* Warning: Cannot infer type of -> */ obj.a_method("test");
 60 | 
 61 | obj = new SomeExtension();
 62 | 
 63 | /* Warning: Cannot infer type of -> */ obj.a_method(" sub");
 64 | 
 65 | a_function();
 66 | 
 67 | /**
 68 |  * A class with implements Options using the `Implements` decorator.
 69 |  * This is MooTools functionality ported to Python.
 70 |  */
 71 | var ClassWithOptions = new Class({
 72 | 	Implements: Options,
 73 | 	options: {
 74 | 		name: "value",
 75 | 		foo: "bar"
 76 | 	},
 77 | 
 78 | 	initialize: function (options) {
 79 | 		/* Warning: Cannot infer type of -> */ this.setOptions(options);
 80 | 		dbgprint(this.options.foo, this.options.name);
 81 | 	}
 82 | });
 83 | ClassWithOptions.somestatic = function (input) {
 84 | 	dbgprint("Static " + input);
 85 | };
 86 | 
 87 | 
 88 | x = "hello again";
 89 | 
 90 | var another_function = function () {
 91 | 	x = "go ahead";
 92 | 	return x;
 93 | };
 94 | 
 95 | if (true) {
 96 | 	dbgprint("Welcome");
 97 | 	if (false)
 98 | 		/* pass */;
 99 | 	else
100 | 		dbgprint("Nested if");
101 | }
102 | else
103 | 	dbgprint("You're not welcome...");
104 | 
105 | var i = 0;
106 | 
107 | while (i < 3 && !false) {
108 | 	dbgprint(i);
109 | 	i++;
110 | }
111 | 
112 | dbgprint("---");
113 | 
114 | for (var __iter0_ = new XRange(3); __iter0_.hasNext();) {
115 | 	var j = __iter0_.next();
116 | 	dbgprint(j);
117 | }
118 | delete __iter0_;
119 | 
120 | dbgprint("----");
121 | 
122 | for (var __iter0_ = new XRange(1, 4); __iter0_.hasNext();) {
123 | 	i = __iter0_.next();
124 | 	dbgprint(i);
125 | 	for (var __iter1_ = new XRange(i, 4, 2); __iter1_.hasNext();) {
126 | 		j = __iter1_.next();
127 | 		dbgprint(j);
128 | 	}
129 | 	delete __iter1_;
130 | }
131 | delete __iter0_;
132 | 
133 | dbgprint("-----");
134 | 
135 | for (var __iter0_ = new XRange(4, 1, -1); __iter0_.hasNext();) {
136 | 	j = __iter0_.next();
137 | 	dbgprint(j);
138 | }
139 | delete __iter0_;
140 | 
141 | i = [1, 2, 3];
142 | 
143 | for (var __iter0_ = new _Iterator(i); __iter0_.hasNext();) {
144 | 	j = __iter0_.next();
145 | 	dbgprint(j);
146 | }
147 | delete __iter0_;
148 | 
149 | for (var __iter0_ = new _Iterator(["a", "b", "c" + "d"]); __iter0_.hasNext();) {
150 | 	j = __iter0_.next();
151 | 	dbgprint(j);
152 | }
153 | delete __iter0_;
154 | 
155 | for (var __iter0_ = new _Iterator({
156 | 			a: 1,
157 | 			b: 2
158 | 		}); __iter0_.hasNext();) {
159 | 	var value = __iter0_.next();
160 | 	var key = __iter0_.key();
161 | 	dbgprint(key, value);
162 | }
163 | delete __iter0_;
164 | 
165 | var f = function (x) {return x * 2;};
166 | 
167 | var a = [1, 2, 3, /* Warning: Cannot infer type of -> */ f(2)];
168 | 
169 | dbgprint(a.slice(1, 3));
170 | 
171 | var b = {};
172 | 
173 | b = {
174 | 	a: 1,
175 | 	b: 2,
176 | 	1: "x",
177 | 	2: "y",
178 | 	"-test-": 1 + 2,
179 | 	"0HAY0": "a" + "B"
180 | };
181 | 
182 | dbgprint(b.a);
183 | 
184 | b["-test-"] = 3;
185 | 
186 | dbgprint(b[1]);
187 | 
188 | delete b.a;
189 | 
190 | dbgprint("Demo %d %s %.2f".sprintf(b["-test-"], "abc", 0.123456));
191 | 
192 | dbgprint(1 > 2 && 2 * 3 > 8);
193 | 
194 | dbgprint(1 * (2 + 4) * -(1 + 2));
195 | 
196 | dbgprint((true && true) && false || false);
197 | 
198 | dbgprint([] instanceof Array);
199 | 
200 | dbgprint(new Hash() instanceof Hash);
201 | 
202 | 


--------------------------------------------------------------------------------
/pycow/js/pycow.js:
--------------------------------------------------------------------------------
  1 | 
  2 | /*
  3 |  * PyCow - Python to JavaScript with MooTools translator
  4 |  * Copyright (C) 2009 by p2k
  5 |  *
  6 |  * Licensed under the Apache License, Version 2.0 (the "License");
  7 |  * you may not use this file except in compliance with the License.
  8 |  * You may obtain a copy of the License at
  9 |  *
 10 |  *     http://www.apache.org/licenses/LICENSE-2.0
 11 |  *
 12 |  * Unless required by applicable law or agreed to in writing, software
 13 |  * distributed under the License is distributed on an "AS IS" BASIS,
 14 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 |  * See the License for the specific language governing permissions and
 16 |  * limitations under the License.
 17 |  *
 18 |  */
 19 | 
 20 | /*
 21 |  This script contains some Python-compatibility functions and objects.
 22 | */
 23 | 
 24 | /**
 25 |  * len(object) -> integer
 26 |  *
 27 |  * Return the number of items of a sequence or mapping.
 28 |  */
 29 | len = function (obj) {
 30 | 	var l = 0;
 31 | 	switch ($type(obj)) {
 32 | 		case 'array':
 33 | 		case 'string':
 34 | 			return obj.length;
 35 | 		case 'object':
 36 | 			for (var key in obj)
 37 | 				l++;
 38 | 			return l;
 39 | 		default:
 40 | 			return 1;
 41 | 	}
 42 | };
 43 | 
 44 | /**
 45 |  * str(object) -> string
 46 |  * 
 47 |  * Return a nice string representation of the object.
 48 |  * If the argument is a string, the return value is the same object.
 49 |  */
 50 | str = function (obj) {
 51 | 	if (!$defined(obj))
 52 | 		return "null";
 53 | 	else if ($defined(obj.__str__))
 54 | 		return obj.__str__();
 55 | 	else if ($type(obj) == "number")
 56 | 		return String(obj);
 57 | 	else if ($type(obj) == "string")
 58 | 		return obj;
 59 | 	else
 60 | 		return repr(obj);
 61 | };
 62 | 
 63 | /**
 64 |  * repr(object) -> string
 65 |  *
 66 |  * Return the canonical string representation of the object.
 67 |  * For most object types, eval(repr(object)) == object.
 68 |  */
 69 | repr = function (obj) {
 70 | 	if ($defined(obj.__repr__))
 71 | 		return obj.__repr__();
 72 | 	else if ($type(obj) == "boolean")
 73 | 		return String(obj);
 74 | 	else if ($type(obj) == "array")
 75 | 		return "["+obj.map(repr).join(", ")+"]";
 76 | 	else
 77 | 		return JSON.encode(obj);
 78 | };
 79 | 
 80 | /**
 81 |  * range([start,] stop[, step]) -> list of integers
 82 |  *
 83 |  * Return a list containing an arithmetic progression of integers.
 84 |  * range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
 85 |  * When step is given, it specifies the increment (or decrement).
 86 |  * For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
 87 |  * These are exactly the valid indices for a list of 4 elements.
 88 |  */
 89 | range = function (start, stop, step) {
 90 | 	if (!$defined(stop)) {
 91 | 		stop = start;
 92 | 		start = 0;
 93 | 	}
 94 | 	if (!$defined(step) || step == 0)
 95 | 		step = 1;
 96 | 	out = new Array();
 97 | 	if (step > 0) {
 98 | 		for (var i = start; i < stop; i += step)
 99 | 			out.push(i);
100 | 	}
101 | 	else {
102 | 		for (var i = start; i > stop; i += step)
103 | 			out.push(i);
104 | 	}
105 | 	return out;
106 | };
107 | 
108 | dbgprint = function () {
109 | 	var s = "";
110 | 	var first = true;
111 | 	
112 | 	for (var i = 0; i < arguments.length; i++) {
113 | 		if (first)
114 | 			first = false;
115 | 		else
116 | 			s += " ";
117 | 		s += str(arguments[i]);
118 | 	}
119 | 	
120 | 	if ($defined(window.console))
121 | 		window.console.info(s);
122 | 	else if (Browser.Engine.presto && $defined(opera.postError))
123 | 		opera.postError(s);
124 | 	else
125 | 		alert(s);
126 | }
127 | 
128 | /*  
129 |  *  Javascript sprintf
130 |  *  http://www.webtoolkit.info/
131 |  */
132 | 
133 | sprintfWrapper = {
134 | 	init : function () {
135 | 		if (!$defined(arguments))
136 | 			return null;
137 | 		if (arguments.length < 1)
138 | 			return null;
139 | 		if ($type(arguments[0]) != "string")
140 | 			return null;
141 | 		if (!$defined(RegExp))
142 | 			return null;
143 | 		
144 | 		var string = arguments[0];
145 | 		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
146 | 		var matches = new Array();
147 | 		var strings = new Array();
148 | 		var convCount = 0;
149 | 		var stringPosStart = 0;
150 | 		var stringPosEnd = 0;
151 | 		var matchPosEnd = 0;
152 | 		var newString = '';
153 | 		var match = null;
154 | 		
155 | 		while ((match = exp.exec(string))) {
156 | 			if (match[9])
157 | 				convCount += 1;
158 | 				
159 | 			stringPosStart = matchPosEnd;
160 | 			stringPosEnd = exp.lastIndex - match[0].length;
161 | 			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);
162 | 			
163 | 			matchPosEnd = exp.lastIndex;
164 | 			matches[matches.length] = {
165 | 				match: match[0],
166 | 				left: match[3] ? true : false,
167 | 				sign: match[4] || '',
168 | 				pad: match[5] || ' ',
169 | 				min: match[6] || 0,
170 | 				precision: match[8],
171 | 				code: match[9] || '%',
172 | 				negative: parseInt(arguments[convCount]) < 0 ? true : false,
173 | 				argument: String(arguments[convCount])
174 | 			};
175 | 		}
176 | 		strings[strings.length] = string.substring(matchPosEnd);
177 | 
178 | 		if (matches.length == 0)
179 | 			return string;
180 | 		if ((arguments.length - 1) < convCount)
181 | 			return null;
182 | 
183 | 		var code = null;
184 | 		var match = null;
185 | 		var i = null;
186 | 
187 | 		for (i=0; i 127) && (c < 2048)) {
268 | 			utftext += String.fromCharCode((c >> 6) | 192);
269 | 			utftext += String.fromCharCode((c & 63) | 128);
270 | 		}
271 | 		else {
272 | 			utftext += String.fromCharCode((c >> 12) | 224);
273 | 			utftext += String.fromCharCode(((c >> 6) & 63) | 128);
274 | 			utftext += String.fromCharCode((c & 63) | 128);
275 | 		}
276 | 	}
277 | 	
278 | 	return utftext;
279 | };
280 | 
281 | sprintf = sprintfWrapper.init;
282 | 
283 | String.implement({
284 | 	sprintf: function () {
285 | 		var args = $A(arguments);
286 | 		args.splice(0, 0, this);
287 | 		return sprintfWrapper.init.apply(this, args);
288 | 	},
289 | 	startswith: function (s) {
290 | 		return this.slice(0,s.length) == s;
291 | 	},
292 | 	endswith: function (s) {
293 | 		return this.slice(this.length-s.length) == s;
294 | 	},
295 | 	encode: function (encoding) {
296 | 		encoding = encoding.toLowerCase();
297 | 		if (encoding == "utf8" || encoding == "utf-8")
298 | 			return utf8encode(this);
299 | 		throw Error("Unknown encoding: " + encoding);
300 | 	}
301 | });
302 | 
303 | String.alias("toLowerCase", "lower");
304 | String.alias("toUpperCase", "upper");
305 | Hash.alias("extend", "update");
306 | 
307 | Array.implement({
308 | 	/**
309 | 	 * A.insert(index, object) -- insert object before index
310 | 	 */
311 | 	insert: function (index, object) {
312 | 		this.splice(index, 0, object);
313 | 	},
314 | 	/**
315 | 	 * A.append(object) -- append object to array
316 | 	 */
317 | 	append: function (object) {
318 | 		this[this.length] = object;
319 | 	}
320 | });
321 | 
322 | /**
323 |  * A.pop([index]) -> item -- remove and return item at index (default last).
324 |  * Returns undefined if list is empty or index is out of range.
325 |  */
326 | Array.prototype.pop = function (index) {
327 | 	if (!$defined(index))
328 | 		index = this.length-1;
329 | 
330 | 	if (index == -1 || index >= this.length)
331 | 		return undefined;
332 | 	var elt = this[index];
333 | 	this.splice(index, 1);
334 | 	return elt;
335 | };
336 | 
337 | IndexError = function () {};
338 | IndexError.prototype = new Error;
339 | 
340 | /**
341 |  * Java-Style iterator class.
342 |  */
343 | _Iterator = new Class({
344 | 	initialize: function (object) {
345 | 		this.obj = object;
346 | 		this.pos = -1;
347 | 		if (object instanceof Array)
348 | 			this.elts = null;
349 | 		else {
350 | 			this.elts = new Array();
351 | 			for (var x in object) {
352 | 				if (object.hasOwnProperty(x))
353 | 					this.elts.push(x);
354 | 			}
355 | 		}
356 | 	},
357 | 	hasNext: function () {
358 | 		if (this.elts == null) {
359 | 			if (this.pos >= this.obj.length-1)
360 | 				return false;
361 | 		}
362 | 		else {
363 | 			if (this.pos >= this.elts.length-1)
364 | 				return false;
365 | 		}
366 | 		return true;
367 | 	},
368 | 	next: function () {
369 | 		if (this.elts == null) {
370 | 			if (this.pos >= this.obj.length-1)
371 | 				throw new IndexError();
372 | 			return this.obj[++this.pos];
373 | 		}
374 | 		else {
375 | 			if (this.pos >= this.elts.length-1)
376 | 				throw new IndexError();
377 | 			return this.obj[this.elts[++this.pos]];
378 | 		}
379 | 	},
380 | 	key: function () {
381 | 		if (this.elts == null)
382 | 			return this.pos;
383 | 		else {
384 | 			if (this.pos >= this.elts.length)
385 | 				throw new IndexError();
386 | 			return this.elts[this.pos];
387 | 		}
388 | 	}
389 | });
390 | 
391 | XRange = new Class({
392 | 	initialize: function (start, stop, step) {
393 | 		if (!$defined(stop)) {
394 | 			stop = start;
395 | 			start = 0;
396 | 		}
397 | 		if (!$defined(step) || step == 0)
398 | 			step = 1;
399 | 		this.start = start;
400 | 		this.stop = stop;
401 | 		this.step = step;
402 | 	},
403 | 	hasNext: function () {
404 | 		return !((this.step > 0 && this.start >= this.stop) || (this.step < 0 && this.start <= this.stop));
405 | 	},
406 | 	next: function () {
407 | 		if ((this.step > 0 && this.start >= this.stop) || (this.step < 0 && this.start <= this.stop))
408 | 			throw new IndexError();
409 | 		var ret = this.start;
410 | 		this.start += this.step;
411 | 		return ret;
412 | 	}
413 | });
414 | 


--------------------------------------------------------------------------------
/pycow/pycow.py:
--------------------------------------------------------------------------------
   1 | #!/usr/bin/env python
   2 | 
   3 | #
   4 | # PyCow - Python to JavaScript with MooTools translator
   5 | # Copyright 2009 Patrick Schneider 
   6 | #
   7 | # Licensed under the Apache License, Version 2.0 (the "License");
   8 | # you may not use this file except in compliance with the License.
   9 | # You may obtain a copy of the License at
  10 | #
  11 | #     http://www.apache.org/licenses/LICENSE-2.0
  12 | #
  13 | # Unless required by applicable law or agreed to in writing, software
  14 | # distributed under the License is distributed on an "AS IS" BASIS,
  15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16 | # See the License for the specific language governing permissions and
  17 | # limitations under the License.
  18 | #
  19 | 
  20 | #
  21 | # Some Notes:
  22 | #
  23 | # PyCow does a limited type inference, so it can distinguish function calls
  24 | # from class instantiations. However, some conditions can prevent a correct
  25 | # evaluation.
  26 | #
  27 | # PyCow cannot parse comments but can parse docstrings.
  28 | #
  29 | # No kwargs.
  30 | #
  31 | 
  32 | import ast, simplejson, re, random
  33 | from StringIO import StringIO
  34 | 
  35 | __all__ = ["ParseError", "translate_string", "translate_file"]
  36 | 
  37 | class ParseError(Exception):
  38 | 	"""
  39 | 	This exception is raised if the parser detects fatal errors.
  40 | 	
  41 | 	"""
  42 | 	def __init__(self, value):
  43 | 		self.value = value
  44 | 	
  45 | 	def __str__(self):
  46 | 		return repr(self.value)
  47 | 
  48 | class PyCowContext(ast.NodeVisitor):
  49 | 	"""
  50 | 	First-pass context parser. Builds an execution context for type inference
  51 | 	and captures docstrings.
  52 | 	
  53 | 	"""
  54 | 	
  55 | 	def __init__(self, node, parent = None):
  56 | 		"""
  57 | 		Parse the node as a new context. The parent must be another context
  58 | 		object. Only Module, Class, Method and Function nodes are allowed.
  59 | 		
  60 | 		"""
  61 | 		self.docstring = ""
  62 | 		self.module_license = ""
  63 | 		self.module_all = None
  64 | 		self.node = node
  65 | 		if node.__class__.__name__ == "FunctionDef":
  66 | 			if parent.type == "Class":
  67 | 				self.type = "Method"
  68 | 			else:
  69 | 				self.type = "Function"
  70 | 			self.name = node.name
  71 | 			self.__get_docstring()
  72 | 		elif node.__class__.__name__ == "ClassDef":
  73 | 			self.type = "Class"
  74 | 			self.name = node.name
  75 | 			self.__get_docstring()
  76 | 		elif node.__class__.__name__ == "Module":
  77 | 			self.type = "Module"
  78 | 			self.name = "(Module)"
  79 | 			self.__get_docstring()
  80 | 		else:
  81 | 			raise ValueError("Only Module, ClassDef and FunctionDef nodes are allowed")
  82 | 		
  83 | 		self.parent = parent
  84 | 		self.identifiers = {}
  85 | 		self.variables = [] # Holds declared local variables (filled on second pass)
  86 | 		
  87 | 		self.visit_For = self.visit_body
  88 | 		self.visit_While = self.visit_body
  89 | 		self.visit_If = self.visit_body
  90 | 		self.visit_TryExcept = self.visit_body
  91 | 		self.visit_ExceptHandler = self.visit_body
  92 | 		
  93 | 		self.visit_ClassDef = self.visit_func_or_class
  94 | 		self.visit_FunctionDef = self.visit_func_or_class
  95 | 		
  96 | 		self.visit_body(node)
  97 | 	
  98 | 	def visit_func_or_class(self, node):
  99 | 		if self.identifiers.has_key(node.name):
 100 | 			old_ctx = self.identifiers[node.name]
 101 | 			raise ParseError("%s identifier '%s' at line %d is illegaly overwritten on line %d" % (
 102 | 				old_ctx.type,
 103 | 				node.name,
 104 | 				old_ctx.node.lineno,
 105 | 				node.lineno,
 106 | 			))
 107 | 		self.identifiers[node.name] = PyCowContext(node, self)
 108 | 	
 109 | 	def visit_body(self, node):
 110 | 		for stmt in node.body:
 111 | 			self.visit(stmt)
 112 | 		for stmt in getattr(node, "orelse", []):
 113 | 			self.visit(stmt)
 114 | 	
 115 | 	def visit_Assign(self, stmt):
 116 | 		if not self.type == "Module": return
 117 | 		if len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Name):
 118 | 			if stmt.targets[0].id == "__all__":
 119 | 				if not isinstance(stmt.value, ast.List):
 120 | 					raise ParseError("Value of `__all__` must be a list expression (line %d)" % (stmt.lineno))
 121 | 				self.module_all = []
 122 | 				for expr in stmt.value.elts:
 123 | 					if not isinstance(expr, ast.Str):
 124 | 						raise ParseError("All elements of `__all__` must be strings (line %d)" % (expr.lineno))
 125 | 					self.module_all.append(expr.s)
 126 | 			elif stmt.targets[0].id == "__license__":
 127 | 				if not isinstance(stmt.value, ast.Str):
 128 | 					raise ParseError("Value of `__license__` must be a string (line %d)" % (stmt.lineno))
 129 | 				self.module_license = stmt.value.s
 130 | 	
 131 | 	def visit_TryFinally(self, node):
 132 | 		for stmt in node.body:
 133 | 			self.visit(stmt)
 134 | 		for stmt in node.finalbody:
 135 | 			self.visit(stmt)
 136 | 	
 137 | 	def generic_visit(self, node):
 138 | 		pass
 139 | 	
 140 | 	def child(self, identifier):
 141 | 		"""
 142 | 		Get a named child context.
 143 | 		
 144 | 		"""
 145 | 		if self.identifiers.has_key(identifier):
 146 | 			return self.identifiers[identifier]
 147 | 		return None
 148 | 
 149 | 	def lookup(self, identifier):
 150 | 		"""
 151 | 		Get a context in this or the parents context.
 152 | 		Jumps over Class contexts.
 153 | 		
 154 | 		"""
 155 | 		if self.type != "Class":
 156 | 			if self.identifiers.has_key(identifier):
 157 | 				return self.identifiers[identifier]
 158 | 		if self.parent != None:
 159 | 			return self.parent.lookup(identifier)
 160 | 		return None
 161 | 	
 162 | 	def class_context(self):
 163 | 		"""
 164 | 		Return the topmost class context (useful to get the context for `self`).
 165 | 		
 166 | 		"""
 167 | 		if self.type == "Class":
 168 | 			return self
 169 | 		elif self.parent == None:
 170 | 			return None
 171 | 		return self.parent.class_context()
 172 | 	
 173 | 	def declare_variable(self, name):
 174 | 		"""
 175 | 		Returns False if the variable is already declared and True if not.
 176 | 		
 177 | 		"""
 178 | 		if name in self.variables:
 179 | 			return False
 180 | 		else:
 181 | 			self.variables.append(name)
 182 | 			return True
 183 | 
 184 | 	def __get_docstring(self):
 185 | 		if len(self.node.body) > 0:
 186 | 			stmt = self.node.body[0]
 187 | 			if isinstance(stmt, ast.Expr):
 188 | 				if isinstance(stmt.value, ast.Str):
 189 | 					self.docstring = stmt.value.s
 190 | 
 191 | class PyCow(ast.NodeVisitor):
 192 | 	"""
 193 | 	Second-pass main parser.
 194 | 	
 195 | 	"""
 196 | 	OP_MAP = {
 197 | 		"Add":	("+", 6, True), # chars, precedence, associates
 198 | 		"Sub":	("-", 6, True),
 199 | 		"Mult":	("*", 5, True),
 200 | 		"Div":	("/", 5, True),
 201 | 		"FloorDiv":	("/", 5, True),
 202 | 		"Mod":	("%", 5, True),
 203 | 		#"Pow":	?,
 204 | 		"LShift":	("<<", 7, True),
 205 | 		"RShift":	(">>", 7, True),
 206 | 		"BitOr":	("|", 12, True),
 207 | 		"BitXor":	("^", 11, True),
 208 | 		"BitAnd":	("&", 10, True),
 209 | 		
 210 | 		"USub":	("-", 4, False),
 211 | 		"UAdd": ("+", 4, False),
 212 | 		
 213 | 		"And":	("&&", 13, True),
 214 | 		"Or":	("||", 14, True),
 215 | 		
 216 | 		"Not":	("!", 4, False),
 217 | 		
 218 | 		"Eq":	("==", 9, True),
 219 | 		"NotEq":("!=", 9, True),
 220 | 		"Lt":	("<", 8, True),
 221 | 		"LtE":	("<=", 8, True),
 222 | 		"Gt":	(">", 8, True),
 223 | 		"GtE":	(">=", 8, True),
 224 | 	}
 225 | 	
 226 | 	NO_SEMICOLON = [
 227 | 		"Global",
 228 | 		"If",
 229 | 		"While",
 230 | 		"For",
 231 | 	]
 232 | 	
 233 | 	RESERVED_WORDS = [
 234 | 		"null",
 235 | 		"undefined",
 236 | 		"true",
 237 | 		"false",
 238 | 		"new",
 239 | 		"var",
 240 | 		"switch",
 241 | 		"case",
 242 | 		"function",
 243 | 		"this",
 244 | 		"default",
 245 | 		"throw",
 246 | 		"delete",
 247 | 		"instanceof",
 248 | 		"typeof",
 249 | 	]
 250 | 	
 251 | 	IDENTIFIER_RE = re.compile("[A-Za-z_$][0-9A-Za-z_$]*")
 252 | 	
 253 | 	def __init__(self, outfile = None, indent = "\t", namespace = "", warnings = True):
 254 | 		if outfile == None:
 255 | 			outfile = StringIO()
 256 | 		self.__out = outfile
 257 | 		self.__ichars = indent
 258 | 		self.__ilevel = 0
 259 | 		self.__mod_context = None
 260 | 		self.__curr_context = None
 261 | 		self.__namespace = namespace
 262 | 		self.__iteratorid = 0
 263 | 		self.__warnings = warnings
 264 | 	
 265 | 	def output(self):
 266 | 		if isinstance(self.__out, StringIO):
 267 | 			return self.__out.getvalue()
 268 | 		else:
 269 | 			self.__out.seek(0)
 270 | 			return self.__out.read()
 271 | 	
 272 | 	def visit_Module(self, mod):
 273 | 		"""
 274 | 		Initial node.
 275 | 		There is and can be only one Module node.
 276 | 		
 277 | 		"""
 278 | 		# Build context
 279 | 		self.__mod_context = PyCowContext(mod)
 280 | 		self.__curr_context = self.__mod_context
 281 | 		
 282 | 		if self.__mod_context.module_license != "":
 283 | 			first = True
 284 | 			for line in self.__mod_context.module_license.split("\n"):
 285 | 				if first:
 286 | 					self.__out.write("/* %s\n" % (line))
 287 | 					first = False
 288 | 				else:
 289 | 					self.__out.write(" * %s\n" % (line))
 290 | 			self.__out.write(" */\n\n")
 291 | 		
 292 | 		# Parse body
 293 | 		if self.__namespace != "":
 294 | 			if "." in self.__namespace:
 295 | 				self.__build_namespace(self.__namespace)
 296 | 			if self.__mod_context.docstring != "":
 297 | 				self.__write_docstring(self.__mod_context.docstring)
 298 | 			if "." not in self.__namespace:
 299 | 				self.__write("var ")
 300 | 			self.__write("%s = (function() {\n" % (self.__namespace))
 301 | 			self.__indent()
 302 | 		else:
 303 | 			if self.__mod_context.docstring != "": self.__write_docstring(self.__mod_context.docstring)
 304 | 		
 305 | 		public_identifiers = self.__mod_context.module_all
 306 | 		
 307 | 		for stmt in mod.body:
 308 | 			if isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and \
 309 | 					isinstance(stmt.targets[0], ast.Name) and \
 310 | 					stmt.targets[0].id in ("__all__", "__license__"):
 311 | 				continue
 312 | 			if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
 313 | 				continue # Module docstring
 314 | 			self.__do_indent()
 315 | 			self.visit(stmt)
 316 | 			self.__semicolon(stmt)
 317 | 			self.__write("\n") # Extra newline on module layer
 318 | 		
 319 | 		if self.__namespace != "":
 320 | 			self.__write_indented("return {")
 321 | 			self.__indent()
 322 | 			if public_identifiers == None:
 323 | 				public_identifiers = self.__mod_context.identifiers.iterkeys()
 324 | 			first = True
 325 | 			for id in public_identifiers:
 326 | 				if first:
 327 | 					first = False
 328 | 					self.__write("\n")
 329 | 				else:
 330 | 					self.__write(",\n")
 331 | 				self.__write_indented("%s: %s" % (id, id))
 332 | 			self.__indent(False)
 333 | 			self.__write("\n")
 334 | 			self.__write_indented("};\n")
 335 | 			self.__indent(False)
 336 | 			self.__write_indented("})();\n")
 337 | 		self.__curr_context = None
 338 | 
 339 | 	def visit_ImportFrom(self, i):
 340 | 		"""
 341 | 		Ignored.
 342 | 		"""
 343 | 		self.__write("/* from %s import " % (i.module))
 344 | 		first = True
 345 | 		for name in i.names:
 346 | 			if first:
 347 | 				first = False
 348 | 			else:
 349 | 				self.__write(", ")
 350 | 			self.__write(name.name)
 351 | 			if name.asname:
 352 | 				self.__write(" as %s" % (name.asname))
 353 | 		self.__write(" */")
 354 | 	
 355 | 	def visit_Import(self, i):
 356 | 		"""
 357 | 		Ignored.
 358 | 		"""
 359 | 		self.__write("/* import ")
 360 | 		first = True
 361 | 		for name in i.names:
 362 | 			if first:
 363 | 				first = False
 364 | 			else:
 365 | 				self.__write(", ")
 366 | 			self.__write(name.name)
 367 | 			if name.asname:
 368 | 				self.__write(" as %s" % (name.asname))
 369 | 		self.__write(" */")
 370 | 
 371 | 	def visit_Print(self, p):
 372 | 		"""
 373 | 		Translate `print` to `dbgprint()`.
 374 | 		
 375 | 		"""
 376 | 		
 377 | 		self.__write("dbgprint(")
 378 | 		first = True
 379 | 		for expr in p.values:
 380 | 			if first:
 381 | 				first = False
 382 | 			else:
 383 | 				self.__write(", ")
 384 | 			self.visit(expr)
 385 | 		self.__write(")")
 386 | 	
 387 | 	def visit_Num(self, n):
 388 | 		self.__write(str(n.n))
 389 | 	
 390 | 	def visit_Str(self, s):
 391 | 		"""
 392 | 		Output a quoted string.
 393 | 		Cleverly uses JSON to convert it ;)
 394 | 		
 395 | 		"""
 396 | 		self.__write(simplejson.dumps(s.s))
 397 | 	
 398 | 	def visit_Call(self, c):
 399 | 		"""
 400 | 		Translates a function/method call or class instantiation.
 401 | 		
 402 | 		"""
 403 | 		
 404 | 		cls = self.__curr_context.class_context()
 405 | 		# Check for 'super'
 406 | 		if cls != None and isinstance(c.func, ast.Name) and c.func.id == "super":
 407 | 			if len(c.args) != 2:
 408 | 				raise ParseError("`super` can only be parsed with two arguments (line %d)" % (c.lineno))
 409 | 			if not isinstance(c.args[0], ast.Name) or not isinstance(c.args[1], ast.Name):
 410 | 				raise ParseError("Arguments of `super` must be simple names, no other expressions allowed (line %d)" % (c.lineno))
 411 | 			if c.args[0].id != cls.name:
 412 | 				raise ParseError("First argument of `super` must be the current class name (line %d)" % (c.lineno))
 413 | 			if c.args[1].id != "self":
 414 | 				raise ParseError("Second argument of `super` must be `self` (line %d)" % (c.lineno))
 415 | 			self.__write("this.parent")
 416 | 			return
 417 | 		
 418 | 		type = None
 419 | 		if isinstance(c.func, ast.Name):
 420 | 			if c.func.id == "Hash" or c.func.id == "Array": # Some hardcoded classes/functions
 421 | 				type = "Class"
 422 | 			elif c.func.id == "len" or c.func.id == "repr":
 423 | 				type = "Function"
 424 | 			elif c.func.id == "isinstance": # Translate to instanceof
 425 | 				if len(c.args) != 2:
 426 | 					raise ParseError("The isinstance call must have exactly two parameters (line %d)" % (c.lineno))
 427 | 				self.visit(c.args[0])
 428 | 				self.__write(" instanceof ")
 429 | 				if isinstance(c.args[1], ast.Name) and c.args[1].id == "list":
 430 | 					self.__write("Array")
 431 | 				else:
 432 | 					self.visit(c.args[1])
 433 | 				return
 434 | 			else:
 435 | 				# Look in current context
 436 | 				type = getattr(self.__curr_context.lookup(c.func.id), "type", None)
 437 | 		elif isinstance(c.func, ast.Attribute):
 438 | 			if cls != None and isinstance(c.func.value, ast.Call) and isinstance(c.func.value.func, ast.Name) and c.func.value.func.id == "super":
 439 | 				# A super call
 440 | 				if self.__curr_context.name == c.func.attr:
 441 | 					# Super constructor/method
 442 | 					self.visit(c.func.value) # Checks for errors on the 'super' call
 443 | 					self.__write("(")
 444 | 					self.__parse_args(c)
 445 | 					self.__write(")")
 446 | 					return
 447 | 				else:
 448 | 					raise ParseError("The method name of a `super` call must match the current method's name (line %d)" % (c.lineno))
 449 | 			elif isinstance(c.func.value, ast.Name) and c.func.value.id == "self":
 450 | 				# Look in Class context
 451 | 				if cls != None:
 452 | 					type = getattr(cls.child(c.func.attr), "type", None)
 453 | 			else:
 454 | 				# Create attribute chain
 455 | 				attrlst = [c.func.attr]
 456 | 				value = c.func.value
 457 | 				while isinstance(value, ast.Attribute):
 458 | 					attrlst.append(value.attr)
 459 | 					value = value.value
 460 | 				if isinstance(value, ast.Name): # The last value must be a Name
 461 | 					ctx = self.__curr_context.lookup(value.id)
 462 | 					while ctx != None: # Walk up
 463 | 						ctx = ctx.child(attrlst.pop())
 464 | 						if ctx != None and len(attrlst) == 0: # Win
 465 | 							type = ctx.type
 466 | 							break
 467 | 		
 468 | 		if type == None and self.__warnings:
 469 | 			self.__write("/* Warning: Cannot infer type of -> */ ")
 470 | 		elif type == "Class":
 471 | 			self.__write("new ")
 472 | 		
 473 | 		self.visit(c.func)
 474 | 		self.__write("(")
 475 | 		self.__parse_args(c)
 476 | 		self.__write(")")
 477 | 	
 478 | 	def visit_Name(self, n):
 479 | 		"""
 480 | 		Translate an identifier. If the context is a method, substitute `self`
 481 | 		with `this`.
 482 | 		
 483 | 		Some special keywords:
 484 | 		True -> true
 485 | 		False -> false
 486 | 		None -> null
 487 | 		
 488 | 		"""
 489 | 		if self.__curr_context.type == "Method" and n.id == "self":
 490 | 			self.__write("this")
 491 | 		elif n.id == "True" or n.id == "False":
 492 | 			self.__write(n.id.lower())
 493 | 		elif n.id == "None":
 494 | 			self.__write("null")
 495 | 		elif n.id in self.RESERVED_WORDS:
 496 | 			raise ParseError("`%s` is a reserved word and cannot be used as an identifier (line %d)" % (n.id, n.lineno))
 497 | 		else:
 498 | 			self.__write(n.id)
 499 | 	
 500 | 	def visit_Expr(self, expr):
 501 | 		self.visit(expr.value)
 502 | 	
 503 | 	def visit_BinOp(self, o):
 504 | 		"""
 505 | 		Translates a binary operator.
 506 | 		Note: The modulo operator on strings is translated to left.sprintf(right)
 507 | 		and currently the only spot where tuples are allowed.
 508 | 		
 509 | 		"""
 510 | 		if isinstance(o.left, ast.Str) and isinstance(o.op, ast.Mod) and isinstance(o.right, ast.Tuple):
 511 | 			self.visit(o.left)
 512 | 			self.__write(".sprintf(")
 513 | 			first = True
 514 | 			for elt in o.right.elts:
 515 | 				if first:
 516 | 					first = False
 517 | 				else:
 518 | 					self.__write(", ")
 519 | 				self.visit(elt)
 520 | 			self.__write(")")
 521 | 		else:
 522 | 			chars, prec, assoc = self.__get_op_cpa(o.op)
 523 | 			self.visit(o.left)
 524 | 			self.__write(" %s " % (chars))
 525 | 			eprec, eassoc = self.__get_expr_pa(o.right)
 526 | 			if eprec >= prec: self.__write("(")
 527 | 			self.visit(o.right)
 528 | 			if eprec >= prec: self.__write(")")
 529 | 	
 530 | 	def visit_BoolOp(self, o):
 531 | 		"""
 532 | 		Translates a boolean operator.
 533 | 		
 534 | 		"""
 535 | 		first = True
 536 | 		chars, prec, assoc = self.__get_op_cpa(o.op)
 537 | 		for expr in o.values:
 538 | 			if first:
 539 | 				first = False
 540 | 			else:
 541 | 				self.__write(" %s " % (self.__get_op(o.op)))
 542 | 			eprec, eassoc = self.__get_expr_pa(expr)
 543 | 			if eprec >= prec: self.__write("(")
 544 | 			self.visit(expr)
 545 | 			if eprec >= prec: self.__write(")")
 546 | 	
 547 | 	def visit_UnaryOp(self, o):
 548 | 		"""
 549 | 		Translates a unary operator.
 550 | 		
 551 | 		"""
 552 | 		self.__write(self.__get_op(o.op))
 553 | 		prec, assoc = self.__get_expr_pa(o.operand)
 554 | 		if isinstance(o.operand, ast.Num): prec = 3
 555 | 		if prec > 2: self.__write("(")
 556 | 		self.visit(o.operand)
 557 | 		if prec > 2: self.__write(")")
 558 | 	
 559 | 	def visit_Compare(self, c):
 560 | 		"""
 561 | 		Translate a compare block.
 562 | 		
 563 | 		"""
 564 | 		self.visit(c.left)
 565 | 		
 566 | 		if len(c.ops) > 1:
 567 | 			raise ParseError("Comparisons with more than one operator are not supported (line %d)" % (c.lineno))
 568 | 		
 569 | 		op, expr = c.ops[0], c.comparators[0]
 570 | 		self.__write(" %s " % (self.__get_op(op)))
 571 | 		prec, assoc = self.__get_expr_pa(expr)
 572 | 		if prec > 2: self.__write("(")
 573 | 		self.visit(expr)
 574 | 		if prec > 2: self.__write(")")
 575 | 	
 576 | 	def visit_Global(self, g):
 577 | 		"""
 578 | 		Declares variables as global.
 579 | 		
 580 | 		"""
 581 | 		for name in g.names:
 582 | 			self.__curr_context.declare_variable(name)
 583 | 	
 584 | 	def visit_Lambda(self, l):
 585 | 		"""
 586 | 		Translates a lambda function.
 587 | 		
 588 | 		"""
 589 | 		self.__write("function (")
 590 | 		self.__parse_args(l.args)
 591 | 		self.__write(") {return ")
 592 | 		self.visit(l.body)
 593 | 		self.__write(";}")
 594 | 	
 595 | 	def visit_Yield(self, y):
 596 | 		"""
 597 | 		Translate the yield operator.
 598 | 		
 599 | 		"""
 600 | 		self.__write("yield ")
 601 | 		self.visit(l.value)
 602 | 	
 603 | 	def visit_Return(self, r):
 604 | 		"""
 605 | 		Translate the return statement.
 606 | 		
 607 | 		"""
 608 | 		if r.value:
 609 | 			self.__write("return ")
 610 | 			self.visit(r.value)
 611 | 		else:
 612 | 			self.__write("return")
 613 | 	
 614 | 	def visit_List(self, l):
 615 | 		"""
 616 | 		Translate a list expression.
 617 | 		
 618 | 		"""
 619 | 		self.__write("[")
 620 | 		first = True
 621 | 		for expr in l.elts:
 622 | 			if first:
 623 | 				first = False
 624 | 			else:
 625 | 				self.__write(", ")
 626 | 			self.visit(expr)
 627 | 		self.__write("]")
 628 | 	
 629 | 	def visit_Dict(self, d):
 630 | 		"""
 631 | 		Translate a dictionary expression.
 632 | 		
 633 | 		"""
 634 | 		self.__write("{")
 635 | 		self.__indent()
 636 | 		first = True
 637 | 		for i in xrange(len(d.keys)):
 638 | 			key, value = d.keys[i], d.values[i]
 639 | 			if first:
 640 | 				first = False
 641 | 				self.__write("\n")
 642 | 			else:
 643 | 				self.__write(",\n")
 644 | 			if isinstance(key, ast.Num):
 645 | 				self.__write_indented("%d: " % (key.n))
 646 | 			elif not isinstance(key, ast.Str):
 647 | 				raise ParseError("Only numbers and string literals are allowed in dictionary expressions (line %d)" % (key.lineno))
 648 | 			else:
 649 | 				if self.IDENTIFIER_RE.match(key.s):
 650 | 					self.__write_indented("%s: " % (key.s))
 651 | 				else:
 652 | 					self.__write_indented("\"%s\": " % (key.s))
 653 | 			self.visit(value)
 654 | 		self.__indent(False)
 655 | 		if len(d.keys) > 0:
 656 | 			self.__write("\n")
 657 | 			self.__do_indent()
 658 | 		self.__write("}")
 659 | 	
 660 | 	def visit_Subscript(self, s):
 661 | 		"""
 662 | 		Translate a subscript expression.
 663 | 		
 664 | 		"""
 665 | 		self.visit(s.value)
 666 | 		if isinstance(s.slice, ast.Index):
 667 | 			if isinstance(s.slice.value, ast.Str):
 668 | 				if self.IDENTIFIER_RE.match(s.slice.value.s):
 669 | 					self.__write(".%s" % (s.slice.value.s))
 670 | 					return
 671 | 			self.__write("[")
 672 | 			self.visit(s.slice.value)
 673 | 			self.__write("]")
 674 | 		elif isinstance(s.slice, ast.Slice):
 675 | 			if s.slice.step != None:
 676 | 				raise ParseError("Subscript slice stepping '%s' is not supported (line %d)" % (str(s.slice.__class__.__name__), s.lineno))
 677 | 			if isinstance(s.ctx, ast.Load):
 678 | 				self.__write(".slice(")
 679 | 				if s.slice.lower != None:
 680 | 					self.visit(s.slice.lower)
 681 | 				else:
 682 | 					self.__write("0")
 683 | 				if s.slice.upper != None:
 684 | 					self.__write(", ")
 685 | 					self.visit(s.slice.upper)
 686 | 				self.__write(")")
 687 | 			elif isinstance(s.ctx, ast.Delete):
 688 | 				raise ParseError("Subscript slice deleting is not supported (line %d)" % (s.lineno))
 689 | 			else:
 690 | 				raise ParseError("Subscript slice assignment is not supported (line %d)" % (s.lineno))
 691 | 		else:
 692 | 			raise ParseError("Subscript slice type '%s' is not supported (line %d)" % (str(s.slice.__class__.__name__), s.lineno))
 693 | 	
 694 | 	def visit_Delete(self, d):
 695 | 		"""
 696 | 		Translate a delete statement.
 697 | 		
 698 | 		"""
 699 | 		first = True
 700 | 		for target in d.targets:
 701 | 			if first:
 702 | 				first = False
 703 | 			else:
 704 | 				self.__write("; ")
 705 | 			self.__write("delete ")
 706 | 			self.visit(target)
 707 | 
 708 | 	def visit_Assign(self, a):
 709 | 		"""
 710 | 		Translate an assignment.
 711 | 		Declares a new local variable if applicable.
 712 | 		
 713 | 		"""
 714 | 		is_class = self.__curr_context.type == "Class"
 715 | 		
 716 | 		if len(a.targets) > 1:
 717 | 			raise ParseError("Cannot handle assignment unpacking (line %d)" % (a.lineno))
 718 | 		if isinstance(a.targets[0], ast.Name):
 719 | 			if self.__curr_context.declare_variable(a.targets[0].id):
 720 | 				if not is_class: self.__write("var ")
 721 | 		elif is_class:
 722 | 			raise ParseError("Only simple variable assignments are allowed on class scope (line %d)" % (a.targets[0].id, a.lineno))
 723 | 		self.visit(a.targets[0])
 724 | 		if is_class:
 725 | 			self.__write(": ")
 726 | 		else:
 727 | 			self.__write(" = ")
 728 | 		self.visit(a.value)
 729 | 	
 730 | 	def visit_AugAssign(self, a):
 731 | 		"""
 732 | 		Translate an assignment operator.
 733 | 		
 734 | 		"""
 735 | 		self.visit(a.target)
 736 | 		if isinstance(a.value, ast.Num) and a.value.n == 1:
 737 | 			if isinstance(a.op, ast.Add):
 738 | 				self.__write("++")
 739 | 				return
 740 | 			elif isinstance(a.op, ast.Sub):
 741 | 				self.__write("--")
 742 | 				return
 743 | 		self.__write(" %s= " % (self.__get_op(a.op)))
 744 | 		self.visit(a.value)
 745 | 	
 746 | 	def visit_Pass(self, p):
 747 | 		"""
 748 | 		Translate the `pass` statement. Places a comment.
 749 | 		
 750 | 		"""
 751 | 		self.__write("/* pass */")
 752 | 	
 753 | 	def visit_Continue(self, c):
 754 | 		"""
 755 | 		Translate the `continue` statement.
 756 | 		
 757 | 		"""
 758 | 		self.__write("continue")
 759 | 	
 760 | 	def visit_Break(self, c):
 761 | 		"""
 762 | 		Translate the `break` statement.
 763 | 		
 764 | 		"""
 765 | 		self.__write("break")
 766 | 	
 767 | 	def visit_Attribute(self, a):
 768 | 		"""
 769 | 		Translate an attribute chain.
 770 | 		
 771 | 		"""
 772 | 		self.visit(a.value)
 773 | 		attr = a.attr
 774 | 		self.__write(".%s" % (attr))
 775 | 	
 776 | 	def visit_If(self, i):
 777 | 		"""
 778 | 		Translate an if-block.
 779 | 		
 780 | 		"""
 781 | 		self.__write("if (")
 782 | 		self.visit(i.test)
 783 | 		
 784 | 		# Parse body
 785 | 		braces = True
 786 | 		if len(i.body) == 1 \
 787 | 				and not isinstance(i.body[0], ast.If) \
 788 | 				and not isinstance(i.body[0], ast.While) \
 789 | 				and not isinstance(i.body[0], ast.For):
 790 | 			braces = False
 791 | 		
 792 | 		if braces:
 793 | 			self.__write(") {\n")
 794 | 		else:
 795 | 			self.__write(")\n")
 796 | 		
 797 | 		self.__indent()
 798 | 		for stmt in i.body:
 799 | 			self.__do_indent()
 800 | 			self.visit(stmt)
 801 | 			self.__semicolon(stmt)
 802 | 		self.__indent(False)
 803 | 		
 804 | 		if braces:
 805 | 			self.__write_indented("}\n")
 806 | 		
 807 | 		# Parse else
 808 | 		if len(i.orelse) == 0:
 809 | 			return
 810 | 		braces = True
 811 | 		if len(i.orelse) == 1 \
 812 | 				and not isinstance(i.orelse[0], ast.If) \
 813 | 				and not isinstance(i.orelse[0], ast.While) \
 814 | 				and not isinstance(i.orelse[0], ast.For):
 815 | 			braces = False
 816 | 		
 817 | 		elseif = False
 818 | 		if len(i.orelse) == 1 and isinstance(i.orelse[0], ast.If):
 819 | 			elseif = True
 820 | 			self.__write_indented("else ")
 821 | 		elif braces:
 822 | 			self.__write_indented("else {\n")
 823 | 		else:
 824 | 			self.__write_indented("else\n")
 825 | 		
 826 | 		if elseif:
 827 | 			self.visit(i.orelse[0])
 828 | 		else:
 829 | 			self.__indent()
 830 | 			for stmt in i.orelse:
 831 | 				self.__do_indent()
 832 | 				self.visit(stmt)
 833 | 				self.__semicolon(stmt)
 834 | 			self.__indent(False)
 835 | 			if braces:
 836 | 				self.__write_indented("}\n")
 837 | 		
 838 | 	
 839 | 	def visit_IfExp(self, i):
 840 | 		"""
 841 | 		Translate an if-expression.
 842 | 		
 843 | 		"""
 844 | 		self.visit(i.test)
 845 | 		self.__write(" ? ")
 846 | 		self.visit(i.body)
 847 | 		self.__write(" : ")
 848 | 		self.visit(i.orelse)
 849 | 		
 850 | 	def visit_While(self, w):
 851 | 		"""
 852 | 		Translate a while loop.
 853 | 		
 854 | 		"""
 855 | 		if len(w.orelse) > 0:
 856 | 			raise ParseError("`else` branches of the `while` statement are not supported (line %d)" % (w.lineno))
 857 | 		
 858 | 		self.__write("while (")
 859 | 		self.visit(w.test)
 860 | 		
 861 | 		# Parse body
 862 | 		if len(w.body) == 1:
 863 | 			self.__write(")\n")
 864 | 		else:
 865 | 			self.__write(") {\n")
 866 | 		
 867 | 		self.__indent()
 868 | 		for stmt in w.body:
 869 | 			self.__do_indent()
 870 | 			self.visit(stmt)
 871 | 			self.__semicolon(stmt)
 872 | 		self.__indent(False)
 873 | 		
 874 | 		if len(w.body) > 1:
 875 | 			self.__write_indented("}\n")
 876 | 	
 877 | 	def visit_For(self, f):
 878 | 		"""
 879 | 		Translate a for loop.
 880 | 		
 881 | 		"""
 882 | 		if len(f.orelse) > 0:
 883 | 			raise ParseError("`else` branches of the `for` statement are not supported (line %d)" % (f.lineno))
 884 | 		
 885 | 		# -- This solution is needed to keep all semantics --
 886 | 		#
 887 | 		# for (var __iter0_ = new XRange(start, stop, step); __iter0_.hasNext();) {
 888 | 		#     var value = __iter0_.next();
 889 | 		# 
 890 | 		# }
 891 | 		# delete __iter0_;
 892 | 		#
 893 | 		# for (var __iter0_ = new _Iterator(expr); __iter0_.hasNext();)) {
 894 | 		#     var value = __iter0_.next();
 895 | 		#     var key = __iter0_.key();
 896 | 		# }
 897 | 		# delete __iter0_;
 898 | 		
 899 | 		xrange = False
 900 | 		iterexpr = None
 901 | 		keyexpr = None
 902 | 		valexpr = None
 903 | 		iteritems = False
 904 | 		if isinstance(f.iter, ast.Call) and isinstance(f.iter.func, ast.Name) \
 905 | 				and (f.iter.func.id == "xrange" or f.iter.func.id == "range"):
 906 | 			xrange = True
 907 | 		if isinstance(f.iter, ast.Call) and isinstance(f.iter.func, ast.Attribute) \
 908 | 				and f.iter.func.attr == "iteritems":
 909 | 			iterexpr = f.iter.func.value
 910 | 			if not isinstance(f.target, ast.Tuple) or len(f.target.elts) != 2:
 911 | 				raise ParseError("Only 2-tuples are allowed as target in conjunction with an iteritems() call on the iterable of the `for` statement (line %d)" % (f.lineno))
 912 | 			iteritems = True
 913 | 			keyexpr = f.target.elts[0]
 914 | 			valexpr = f.target.elts[1]
 915 | 		else:
 916 | 			iterexpr = f.iter
 917 | 			valexpr = f.target
 918 | 		
 919 | 		if isinstance(f.target, ast.Tuple) and not iteritems:
 920 | 			raise ParseError("Tuple targets can only be used in conjunction with an iteritems() call on the iterable of the `for` statement (line %d)" % (f.lineno))
 921 | 		
 922 | 		itervar = "__iter%d_" % (self.__iteratorid)
 923 | 		self.__iteratorid += 1
 924 | 		if xrange:
 925 | 			self.__write("for (var %s = new XRange(" % (itervar))
 926 | 			self.__parse_args(f.iter)
 927 | 		else:
 928 | 			self.__write("for (var %s = new _Iterator(" % (itervar))
 929 | 			self.__indent()
 930 | 			self.__indent()
 931 | 			self.visit(iterexpr)
 932 | 			self.__indent(False)
 933 | 			self.__indent(False)
 934 | 		
 935 | 		self.__write("); %s.hasNext();) {\n" % (itervar))
 936 | 		
 937 | 		# Parse body
 938 | 		self.__indent()
 939 | 		self.__do_indent()
 940 | 		if isinstance(valexpr, ast.Name) and self.__curr_context.declare_variable(valexpr.id):
 941 | 			self.__write("var ")
 942 | 		self.visit(valexpr)
 943 | 		self.__write(" = %s.next();\n" % (itervar))
 944 | 		
 945 | 		if keyexpr != None:
 946 | 			self.__do_indent()
 947 | 			if isinstance(keyexpr, ast.Name) and self.__curr_context.declare_variable(keyexpr.id):
 948 | 				self.__write("var ")
 949 | 			self.visit(keyexpr)
 950 | 			self.__write(" = %s.key();\n" % (itervar))
 951 | 		
 952 | 		for stmt in f.body:
 953 | 			self.__do_indent()
 954 | 			self.visit(stmt)
 955 | 			self.__semicolon(stmt)
 956 | 		self.__indent(False)
 957 | 		
 958 | 		self.__write_indented("}\n")
 959 | 		self.__write_indented("delete %s;\n" % (itervar))
 960 | 		self.__iteratorid -= 1
 961 | 	
 962 | 	def visit_ClassDef(self, c):
 963 | 		"""
 964 | 		Translates a Python class into a MooTools class.
 965 | 		This inserts a Class context which influences the translation of
 966 | 		functions and assignments.
 967 | 		
 968 | 		"""
 969 | 		self.__push_context(c.name)
 970 | 		
 971 | 		# Write docstring
 972 | 		if len(self.__curr_context.docstring) > 0:
 973 | 			self.__write_docstring(self.__curr_context.docstring)
 974 | 			self.__do_indent()
 975 | 		self.__write("var %s = new Class({\n" % (c.name))
 976 | 		self.__indent()
 977 | 		
 978 | 		# Special decorators
 979 | 		decorators = self.__get_decorators(c)
 980 | 		if decorators.has_key("Implements"):
 981 | 			self.__write_indented("Implements: ")
 982 | 			if len(decorators["Implements"]) == 1:
 983 | 				self.visit(decorators["Implements"][0])
 984 | 				self.__write(",\n")
 985 | 			else:
 986 | 				self.__write("[")
 987 | 				first = True
 988 | 				for expr in decorators["Implements"]:
 989 | 					if first:
 990 | 						first = False
 991 | 					else:
 992 | 						self.__write(", ")
 993 | 					self.visit(expr)
 994 | 				self.__write("],\n")
 995 | 		if not decorators.has_key("Class"):
 996 | 			import sys
 997 | 			sys.stderr.write("Warning: The class `%s` of line %d in the input file/string does not have the `Class` decorator!\n" % (c.name, c.lineno))
 998 | 		
 999 | 		# Base classes
1000 | 		bases = filter(lambda b: not isinstance(b, ast.Name) or b.id != "object", c.bases)
1001 | 		if len(bases) > 0:
1002 | 			self.__write_indented("Extends: ")
1003 | 			if len(bases) == 1:
1004 | 				self.visit(bases[0])
1005 | 				self.__write(",\n")
1006 | 			else:
1007 | 				self.__write("[")
1008 | 				first = True
1009 | 				for expr in bases:
1010 | 					if first:
1011 | 						first = False
1012 | 					else:
1013 | 						self.__write(", ")
1014 | 					self.visit(expr)
1015 | 				self.__write("],\n")
1016 | 		
1017 | 		first = True
1018 | 		first_docstring = True
1019 | 		statics = []
1020 | 		for stmt in c.body:
1021 | 			if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
1022 | 				if first_docstring:
1023 | 					first_docstring = False
1024 | 				else:
1025 | 					if not first:
1026 | 						self.__write("\n")
1027 | 					self.__do_indent()
1028 | 					self.__write_docstring(stmt.value.s)
1029 | 					if not first:
1030 | 						self.__do_indent()
1031 | 				continue
1032 | 			if isinstance(stmt, ast.FunctionDef):
1033 | 				if self.__get_decorators(stmt).has_key("staticmethod"):
1034 | 					statics.append(stmt)
1035 | 					continue
1036 | 			if first:
1037 | 				first = False
1038 | 			else:
1039 | 				self.__write(",\n")
1040 | 			if isinstance(stmt, ast.FunctionDef):
1041 | 				self.__write("\n")
1042 | 			self.__do_indent()
1043 | 			self.visit(stmt)
1044 | 		self.__write("\n")
1045 | 		self.__indent(False)
1046 | 		
1047 | 		self.__write_indented("})")
1048 | 		for stmt in statics:
1049 | 			self.__write(";\n")
1050 | 			self.__do_indent()
1051 | 			self.visit(stmt)
1052 | 		self.__pop_context()
1053 | 	
1054 | 	def visit_FunctionDef(self, f):
1055 | 		"""
1056 | 		Translate a Python function into a JavaScript function.
1057 | 		Depending on the context, it is translated to `var name = function (...)`
1058 | 		or `name: function (...)`.
1059 | 		
1060 | 		"""
1061 | 		self.__push_context(f.name)
1062 | 		is_method = self.__curr_context.type == "Method"
1063 | 		
1064 | 		# Special decorators
1065 | 		decorators = self.__get_decorators(f)
1066 | 		is_static = decorators.has_key("staticmethod")
1067 | 		
1068 | 		# Write docstring
1069 | 		if len(self.__curr_context.docstring) > 0:
1070 | 			self.__write_docstring(self.__curr_context.docstring)
1071 | 			self.__do_indent()
1072 | 		if is_method:
1073 | 			if is_static:
1074 | 				self.__write("%s.%s = function (" % (self.__curr_context.class_context().name, f.name))
1075 | 			elif f.name == "__init__":
1076 | 				self.__write("initialize: function (")
1077 | 			else:
1078 | 				self.__write("%s: function (" % (f.name))
1079 | 		else:
1080 | 			self.__write("var %s = function (" % (f.name))
1081 | 		
1082 | 		# Parse arguments
1083 | 		self.__parse_args(f.args, is_method and not is_static)
1084 | 		self.__write(") {\n")
1085 | 		
1086 | 		# Parse defaults
1087 | 		self.__indent()
1088 | 		self.__parse_defaults(f.args)
1089 | 		
1090 | 		# Parse body
1091 | 		for stmt in f.body:
1092 | 			if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
1093 | 				continue # Skip docstring
1094 | 			if isinstance(stmt, ast.Global): # The `global` statement is invisible
1095 | 				self.visit(stmt)
1096 | 				continue
1097 | 			self.__do_indent()
1098 | 			self.visit(stmt)
1099 | 			self.__semicolon(stmt)
1100 | 		self.__pop_context()
1101 | 		self.__indent(False)
1102 | 		
1103 | 		self.__write_indented("}")
1104 | 	
1105 | 	def generic_visit(self, node):
1106 | 		raise ParseError("Could not parse node type '%s' (line %d)" % (str(node.__class__.__name__), node.lineno))
1107 | 	
1108 | 	def __parse_args(self, args, strip_first = False):
1109 | 		"""
1110 | 		Translate a list of arguments.
1111 | 		
1112 | 		"""
1113 | 		first = True
1114 | 		for arg in args.args:
1115 | 			if first:
1116 | 				if strip_first and isinstance(arg, ast.Name):
1117 | 					strip_first = False
1118 | 					continue
1119 | 				first = False
1120 | 			else:
1121 | 				self.__write(", ")
1122 | 			self.visit(arg)
1123 | 		if getattr(args, "vararg", None) != None:
1124 | 			raise ParseError("Variable arguments on function definitions are not supported")
1125 | 	
1126 | 	def __parse_defaults(self, args):
1127 | 		"""
1128 | 		Translate the default arguments list.
1129 | 		
1130 | 		"""
1131 | 		if len(args.defaults) > 0:
1132 | 			first = len(args.args) - len(args.defaults)
1133 | 			for i in xrange(len(args.defaults)):
1134 | 				self.__write_indented("if (!$defined(")
1135 | 				self.visit(args.args[first+i])
1136 | 				self.__write(")) ")
1137 | 				self.visit(args.args[first+i])
1138 | 				self.__write(" = ")
1139 | 				self.visit(args.defaults[i])
1140 | 				self.__write(";\n")
1141 | 
1142 | 	def __get_decorators(self, stmt):
1143 | 		"""
1144 | 		Return a dictionary of decorators and their parameters.
1145 | 		
1146 | 		"""
1147 | 		decorators = {}
1148 | 		if isinstance(stmt, ast.FunctionDef):
1149 | 			for dec in stmt.decorator_list:
1150 | 				if isinstance(dec, ast.Name):
1151 | 					if dec.id == "staticmethod":
1152 | 						decorators["staticmethod"] = []
1153 | 						continue
1154 | 				raise ParseError("This function decorator is not supported. Only @staticmethod is supported for now. (line %d)" % (stmt.lineno))
1155 | 		else:
1156 | 			for dec in stmt.decorator_list:
1157 | 				if isinstance(dec, ast.Call) and isinstance(dec.func, ast.Name):
1158 | 					if dec.func.id == "Implements":
1159 | 						decorators["Implements"] = dec.args
1160 | 						continue
1161 | 				if isinstance(dec, ast.Name) and dec.id == "Class":
1162 | 					decorators["Class"] = []
1163 | 					continue
1164 | 				raise ParseError("This class decorator is not supported. Only decorators of pycow.decorators are supported (line %d)" % (stmt.lineno))
1165 | 		return decorators
1166 | 
1167 | 	def __get_op(self, op):
1168 | 		"""
1169 | 		Translates an operator.
1170 | 		
1171 | 		"""
1172 | 		return self.OP_MAP[op.__class__.__name__][0]
1173 | 	
1174 | 	def __get_op_cpa(self, op):
1175 | 		"""
1176 | 		Get operator chars, precedence and associativity.
1177 | 		
1178 | 		"""
1179 | 		return self.OP_MAP[op.__class__.__name__]
1180 | 
1181 | 	def __get_expr_pa(self, expr):
1182 | 		"""
1183 | 		Get the precedence and associativity of an expression.
1184 | 		
1185 | 		"""
1186 | 		if isinstance(expr, ast.Expr):
1187 | 			expr = expr.value
1188 | 		name = expr.__class__.__name__
1189 | 		if name in ("BoolOp", "BinOp", "UnaryOp"):
1190 | 			return self.__get_op_cpa(expr.op)[1:]
1191 | 		elif name in ("Lambda", "Dict", "List", "Num", "Str", "Name"):
1192 | 			return (1, False)
1193 | 		elif name == "IfExp":
1194 | 			return (15, False)
1195 | 		elif name in ("Attribute", "Subscript"):
1196 | 			return (1, True)
1197 | 		elif name in ("Call", "Repr"):
1198 | 			return (2, True)
1199 | 		elif name == "Compare":
1200 | 			return (8, True)
1201 | 
1202 | 	def __indent(self, updown = True):
1203 | 		if updown:
1204 | 			self.__ilevel += 1
1205 | 		else:
1206 | 			self.__ilevel -= 1
1207 | 	
1208 | 	def __write(self, s):
1209 | 		self.__out.write(s)
1210 | 	
1211 | 	def __write_indented(self, s):
1212 | 		self.__out.write(self.__ichars * self.__ilevel + s)
1213 | 	
1214 | 	def __write_docstring(self, s):
1215 | 		self.__out.write("/**\n")
1216 | 		gotnl = False
1217 | 		first = True
1218 | 		for line in s.split("\n"):
1219 | 			line = line.strip()
1220 | 			if line == "":
1221 | 				gotnl = True
1222 | 			else:
1223 | 				if gotnl and not first:
1224 | 					self.__write_indented(" *\n")
1225 | 				gotnl = False
1226 | 				first = False
1227 | 				self.__write_indented(" * %s\n" % (line))
1228 | 		self.__write_indented(" */\n")
1229 | 	
1230 | 	def __do_indent(self):
1231 | 		self.__out.write(self.__ichars * self.__ilevel)
1232 | 	
1233 | 	def __push_context(self, identifier):
1234 | 		"""
1235 | 		Walk context up.
1236 | 		
1237 | 		"""
1238 | 		old_context = self.__curr_context
1239 | 		self.__curr_context = self.__curr_context.child(identifier)
1240 | 		if self.__curr_context == None:
1241 | 			raise ParseError("Lost context on accessing '%s' from '%s (%s)'" % (identifier, old_context.name, old_context.type))
1242 | 	
1243 | 	def __pop_context(self):
1244 | 		"""
1245 | 		Walk context down.
1246 | 		
1247 | 		"""
1248 | 		self.__curr_context = self.__curr_context.parent
1249 | 	
1250 | 	def __semicolon(self, stmt, no_newline = False):
1251 | 		"""
1252 | 		Write a semicolon (and newline) for all statements except the ones
1253 | 		in NO_SEMICOLON.
1254 | 		
1255 | 		"""
1256 | 		if stmt.__class__.__name__ not in self.NO_SEMICOLON:
1257 | 			if no_newline:
1258 | 				self.__write(";")
1259 | 			else:
1260 | 				self.__write(";\n")
1261 | 	
1262 | 	def __build_namespace(self, namespace):
1263 | 		namespace = namespace.split(".")
1264 | 		
1265 | 		self.__write("window.%s = $defined(window.%s) ? window.%s : {};\n" % (namespace[0], namespace[0], namespace[0]))
1266 | 		
1267 | 		for i in xrange(1, len(namespace) - 1):
1268 | 			self.__write("%s.%s = $defined(%s.%s) ? %s.%s : {};\n" % (namespace[i-1], namespace[0], namespace[i-1], namespace[0], namespace[i-1], namespace[0]))
1269 | 		self.__write("\n")
1270 | 
1271 | def translate_string(input, indent = "\t", namespace = "", warnings = True):
1272 | 	"""
1273 | 	Translate a string of Python code to JavaScript.
1274 | 	Set the `indent` parameter, if you want an other indentation than tabs.
1275 | 	Set the `namespace` parameter, if you want to enclose the code in a namespace.
1276 | 	
1277 | 	"""
1278 | 	moo = PyCow(indent=indent, namespace=namespace, warnings=warnings)
1279 | 	moo.visit(ast.parse(input, "(string)"))
1280 | 	return moo.output()
1281 | 
1282 | def translate_file(in_filename, out_filename = "", indent = "\t", namespace = "", warnings = True):
1283 | 	"""
1284 | 	Translate a Python file to JavaScript.
1285 | 	If `out_filename` is not given, it will be set to in_filename + ".js".
1286 | 	Set the `indent` parameter, if you want an other indentation than tabs.
1287 | 	Set the `namespace` parameter, if you want to enclose the code in a namespace.
1288 | 	
1289 | 	"""
1290 | 	if out_filename == "":
1291 | 		out_filename = in_filename + ".js"
1292 | 	outfile = open(out_filename, "w")
1293 | 	outfile.write("/* This file was generated with PyCow - the Python to JavaScript translator */\n\n")
1294 | 	moo = PyCow(outfile, indent, namespace, warnings)
1295 | 	input = open(in_filename, "r").read()
1296 | 	try:
1297 | 		moo.visit(ast.parse(input, in_filename))
1298 | 	finally:
1299 | 		outfile.close()
1300 | 


--------------------------------------------------------------------------------
/pycow/utils.py:
--------------------------------------------------------------------------------
  1 | 
  2 | #
  3 | # PyCow - Python to JavaScript with MooTools translator
  4 | # Copyright 2009 Patrick Schneider 
  5 | #
  6 | # Licensed under the Apache License, Version 2.0 (the "License");
  7 | # you may not use this file except in compliance with the License.
  8 | # You may obtain a copy of the License at
  9 | #
 10 | #     http://www.apache.org/licenses/LICENSE-2.0
 11 | #
 12 | # Unless required by applicable law or agreed to in writing, software
 13 | # distributed under the License is distributed on an "AS IS" BASIS,
 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 | # See the License for the specific language governing permissions and
 16 | # limitations under the License.
 17 | #
 18 | 
 19 | #
 20 | # This file contains some compatibility classes which implement parts of
 21 | # MooTool's functionality.
 22 | #
 23 | 
 24 | from types import FunctionType, ClassType
 25 | import copy, re, simplejson
 26 | 
 27 | __all__ = ["Events", "Options", "Array", "Hash", "JSON"]
 28 | 
 29 | class Events(object):
 30 | 	def addEvent(self, type, fn, internal = False):
 31 | 		type = Events.removeOn(type)
 32 | 		evts = getattr(self, "$events", None)
 33 | 		if evts == None:
 34 | 			evts = {}
 35 | 			setattr(self, "$events", evts)
 36 | 		if not evts.has_key(type):
 37 | 			evts[type] = set()
 38 | 		evts[type].add(fn)
 39 | 		if internal: fn.internal = True
 40 | 		return self
 41 | 
 42 | 	def addEvents(self, events):
 43 | 		for type in events.iterkeys():
 44 | 			self.addEvent(type, events[type])
 45 | 		return self
 46 | 
 47 | 	def fireEvent(self, type, args = None, delay = None):
 48 | 		type = Events.removeOn(type)
 49 | 		evts = getattr(self, "$events", None)
 50 | 		if evts == None or not evts.has_key(type):
 51 | 			return self
 52 | 		
 53 | 		for fn in evts[type]:
 54 | 			if isinstance(args, list):
 55 | 				fn(*args)
 56 | 			elif args != None:
 57 | 				fn(args)
 58 | 			else:
 59 | 				fn()
 60 | 			#fn.create({'bind': this, 'delay': delay, 'arguments': args})()
 61 | 		
 62 | 		return self
 63 | 
 64 | 	def removeEvent(self, type, fn):
 65 | 		type = Events.removeOn(type)
 66 | 		evts = getattr(self, "$events", None)
 67 | 		if evts == None or not evts.has_key(type):
 68 | 			return self
 69 | 		
 70 | 		if not getattr(fn, "internal", False):
 71 | 			evts[type].remove(fn)
 72 | 		return self
 73 | 
 74 | 	def removeEvents(self, type):
 75 | 		evts = getattr(self, "$events", None)
 76 | 		if evts == None:
 77 | 			return self
 78 | 		for e in evts.iterkeys():
 79 | 			if type != e: continue
 80 | 			for fn in evts[e]:
 81 | 				self.removeEvent(e, fn)
 82 | 		return self
 83 | 
 84 | 	@staticmethod
 85 | 	def removeOn(string):
 86 | 		return re.sub(r"(?i)^on([A-Z])", lambda match: match.group(1).lower(), string)
 87 | 
 88 | class Options(object):
 89 | 	def setOptions(self, options = {}):
 90 | 		if getattr(self, "options", None) == None: return self
 91 | 		self.options.update(options)
 92 | 		if getattr(self, "addEvent", None): return self
 93 | 		for option in self.options.iterkeys():
 94 | 			if not isinstance(self.options[option], FunctionType) or not re.match(r"(?i)^on([A-Z])", option): continue
 95 | 			self.addEvent(option, self.options[option])
 96 | 			del self.options[option]
 97 | 		return self
 98 | 
 99 | class Array(list):
100 | 	@property
101 | 	def length(self):
102 | 		return self.__len__()
103 | 	
104 | 	def contains(self, value):
105 | 		return self.__contains__(value)
106 | 	
107 | 	def sort(self):
108 | 		list.sort(self)
109 | 		return self
110 | 	
111 | 	def reverse(self):
112 | 		list.reverse(self)
113 | 		return self
114 | 	
115 | 	def indexOf(self, value):
116 | 		try:
117 | 			return self.index(value)
118 | 		except ValueError:
119 | 			return -1
120 | 	
121 | 	def lastIndexOf(self, value):
122 | 		l = list(self)
123 | 		l.reverse()
124 | 		try:
125 | 			return self.__len__() - l.index(value)
126 | 		except ValueError:
127 | 			return -1
128 | 	
129 | 	def push(self, value):
130 | 		self.append(value)
131 | 	
132 | 	def erase(self, value):
133 | 		try:
134 | 			while True:
135 | 				self.remove(value)
136 | 		except ValueError:
137 | 			pass
138 | 		return self
139 | 
140 | class Hash(dict):
141 | 	def set(self, key, value):
142 | 		self[key] = value
143 | 	
144 | 	def get(self, key):
145 | 		try:
146 | 			return self[key]
147 | 		except KeyError:
148 | 			return None
149 | 	
150 | 	def has(self, key):
151 | 		return self.has_key(key)
152 | 
153 | 	def getValues(self):
154 | 		return self.values()
155 | 	
156 | 	def getKeys(self):
157 | 		return self.keys()
158 | 	
159 | 	def getClean(self):
160 | 		return dict(self)
161 | 	
162 | 	def extend(self, other):
163 | 		self.update(other)
164 | 	
165 | 	def erase(self, key):
166 | 		try:
167 | 			del self[key]
168 | 		except:
169 | 			pass
170 | 
171 | class JSON(object):
172 | 	def encode(self, obj):
173 | 		return simplejson.dumps(obj)
174 | 	
175 | 	def decode(self, string, secure=None):
176 | 		return simplejson.loads(string)
177 | 
178 | # Singleton
179 | JSON = JSON()
180 | 


--------------------------------------------------------------------------------
/scripts/pycow:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python
 2 | 
 3 | import sys
 4 | import os.path
 5 | from pycow import translate_file
 6 | 
 7 | if len(sys.argv) < 2:
 8 | 	print "=> PyCow - Python to JavaScript with MooTools converter <="
 9 | 	print "Usage: %s [OPTION]... filename.py" % (os.path.basename(sys.argv[0]))
10 | 	print "Options:"
11 | 	print " -o filename   Set the output file name (default: filename.py.js)"
12 | 	print " -n namespace  Enclose module in namespace"
13 | 	print " -W            Omit warning comments in output"
14 | 	sys.exit()
15 | 
16 | in_filename = ""
17 | out_filename = ""
18 | namespace = ""
19 | warnings = True
20 | 
21 | i = 1
22 | while i < len(sys.argv):
23 | 	arg = sys.argv[i]
24 | 	if arg == "-o":
25 | 		if i+1 >= len(sys.argv):
26 | 			print "Error parsing command line: Missing parameter for option '-o'."
27 | 			sys.exit(1)
28 | 		out_filename = sys.argv[i+1]
29 | 		i += 1
30 | 	elif arg == "-n":
31 | 		if i+1 >= len(sys.argv):
32 | 			print "Error parsing command line: Missing parameter for option '-n'."
33 | 			sys.exit(1)
34 | 		namespace = sys.argv[i+1]
35 | 		i += 1
36 | 	elif arg == "-W":
37 | 		warnings = False
38 | 	else:
39 | 		in_filename = arg
40 | 	i += 1
41 | 
42 | if in_filename == "":
43 | 	print "Error parsing command line: Missing input file."
44 | 	sys.exit(1)
45 | 
46 | translate_file(in_filename, out_filename, namespace=namespace, warnings=warnings)
47 | 


--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python
 2 | 
 3 | from distutils.core import setup
 4 | 
 5 | setup(
 6 | 	name='PyCow',
 7 | 	version='0.3',
 8 | 	description='Python to JavaScript converter',
 9 | 	author='p2k',
10 | 	author_email='patrick.p2k.schneider@gmail.com',
11 | 	url='http://github.com/p2k/PyCow',
12 | 	packages=['pycow'],
13 | 	package_data={'pycow': ['js/pycow.js', 'demo/*']},
14 | 	scripts=['scripts/pycow'],
15 | )
16 | 
17 | 


--------------------------------------------------------------------------------