PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/python/compiler/Module.java

http://github.com/nriley/jython
Java | 673 lines | 546 code | 111 blank | 16 comment | 55 complexity | 66b1de2b340cace491a810bf7e0e8c4d MD5 | raw file
  1. // Copyright (c) Corporation for National Research Initiatives
  2. package org.python.compiler;
  3. import java.io.IOException;
  4. import java.io.OutputStream;
  5. import java.util.ArrayList;
  6. import java.util.Enumeration;
  7. import java.util.Hashtable;
  8. import java.util.List;
  9. import java.util.Map;
  10. import org.objectweb.asm.Label;
  11. import org.objectweb.asm.Opcodes;
  12. import org.objectweb.asm.Type;
  13. import org.python.antlr.ParseException;
  14. import org.python.antlr.PythonTree;
  15. import org.python.antlr.ast.Suite;
  16. import org.python.antlr.base.mod;
  17. import org.python.core.CodeBootstrap;
  18. import org.python.core.CodeFlag;
  19. import org.python.core.CodeLoader;
  20. import org.python.core.CompilerFlags;
  21. import org.python.core.Py;
  22. import org.python.core.PyException;
  23. import org.python.core.PyRunnableBootstrap;
  24. import org.python.core.util.StringUtil;
  25. class PyIntegerConstant extends Constant implements ClassConstants, Opcodes
  26. {
  27. int value;
  28. public PyIntegerConstant(int value) {
  29. this.value = value;
  30. }
  31. public void get(Code c) throws IOException {
  32. c.getstatic(module.classfile.name, name, $pyInteger);
  33. }
  34. public void put(Code c) throws IOException {
  35. module.classfile.addField(name, $pyInteger, access);
  36. c.iconst(value);
  37. c.invokestatic("org/python/core/Py", "newInteger", "(I)" + $pyInteger);
  38. c.putstatic(module.classfile.name, name, $pyInteger);
  39. }
  40. @Override
  41. public int hashCode() {
  42. return value;
  43. }
  44. @Override
  45. public boolean equals(Object o) {
  46. if (o instanceof PyIntegerConstant)
  47. return ((PyIntegerConstant)o).value == value;
  48. else
  49. return false;
  50. }
  51. }
  52. class PyFloatConstant extends Constant implements ClassConstants, Opcodes
  53. {
  54. double value;
  55. public PyFloatConstant(double value) {
  56. this.value = value;
  57. }
  58. public void get(Code c) throws IOException {
  59. c.getstatic(module.classfile.name, name, $pyFloat);
  60. }
  61. public void put(Code c) throws IOException {
  62. module.classfile.addField(name, $pyFloat, access);
  63. c.ldc(new Double(value));
  64. c.invokestatic("org/python/core/Py", "newFloat", "(D)" + $pyFloat);
  65. c.putstatic(module.classfile.name, name, $pyFloat);
  66. }
  67. @Override
  68. public int hashCode() {
  69. return (int)value;
  70. }
  71. @Override
  72. public boolean equals(Object o) {
  73. if (o instanceof PyFloatConstant)
  74. return ((PyFloatConstant)o).value == value;
  75. else
  76. return false;
  77. }
  78. }
  79. class PyComplexConstant extends Constant implements ClassConstants, Opcodes
  80. {
  81. double value;
  82. public PyComplexConstant(double value) {
  83. this.value = value;
  84. }
  85. public void get(Code c) throws IOException {
  86. c.getstatic(module.classfile.name, name, $pyComplex);
  87. }
  88. public void put(Code c) throws IOException {
  89. module.classfile.addField(name, $pyComplex, access);
  90. c.ldc(new Double(value));
  91. c.invokestatic("org/python/core/Py", "newImaginary", "(D)" + $pyComplex);
  92. c.putstatic(module.classfile.name, name, $pyComplex);
  93. }
  94. @Override
  95. public int hashCode() {
  96. return (int)value;
  97. }
  98. @Override
  99. public boolean equals(Object o) {
  100. if (o instanceof PyComplexConstant)
  101. return ((PyComplexConstant)o).value == value;
  102. else
  103. return false;
  104. }
  105. }
  106. class PyStringConstant extends Constant implements ClassConstants, Opcodes
  107. {
  108. String value;
  109. public PyStringConstant(String value) {
  110. this.value = value;
  111. }
  112. public void get(Code c) throws IOException {
  113. c.getstatic(module.classfile.name, name, $pyStr);
  114. }
  115. public void put(Code c) throws IOException {
  116. module.classfile.addField(name, $pyStr, access);
  117. c.ldc(value);
  118. c.invokestatic("org/python/core/PyString", "fromInterned", "(" + $str + ")" + $pyStr);
  119. c.putstatic(module.classfile.name, name, $pyStr);
  120. }
  121. @Override
  122. public int hashCode() {
  123. return value.hashCode();
  124. }
  125. @Override
  126. public boolean equals(Object o) {
  127. if (o instanceof PyStringConstant)
  128. return ((PyStringConstant)o).value.equals(value);
  129. else
  130. return false;
  131. }
  132. }
  133. class PyUnicodeConstant extends Constant implements ClassConstants, Opcodes
  134. {
  135. String value;
  136. public PyUnicodeConstant(String value) {
  137. this.value = value;
  138. }
  139. public void get(Code c) throws IOException {
  140. c.getstatic(module.classfile.name, name, $pyUnicode);
  141. }
  142. public void put(Code c) throws IOException {
  143. module.classfile.addField(name, $pyUnicode, access);
  144. c.ldc(value);
  145. c.invokestatic("org/python/core/PyUnicode", "fromInterned", "(" + $str + ")" + $pyUnicode);
  146. c.putstatic(module.classfile.name, name, $pyUnicode);
  147. }
  148. @Override
  149. public int hashCode() {
  150. return value.hashCode();
  151. }
  152. @Override
  153. public boolean equals(Object o) {
  154. if (o instanceof PyUnicodeConstant)
  155. return ((PyUnicodeConstant)o).value.equals(value);
  156. else
  157. return false;
  158. }
  159. }
  160. class PyLongConstant extends Constant implements ClassConstants, Opcodes
  161. {
  162. String value;
  163. public PyLongConstant(String value) {
  164. this.value = value;
  165. }
  166. public void get(Code c) throws IOException {
  167. c.getstatic(module.classfile.name, name, $pyLong);
  168. }
  169. public void put(Code c) throws IOException {
  170. module.classfile.addField(name, $pyLong, access);
  171. c.ldc(value);
  172. c.invokestatic("org/python/core/Py", "newLong", "(" + $str + ")" + $pyLong);
  173. c.putstatic(module.classfile.name, name, $pyLong);
  174. }
  175. @Override
  176. public int hashCode() {
  177. return value.hashCode();
  178. }
  179. @Override
  180. public boolean equals(Object o) {
  181. if (o instanceof PyLongConstant)
  182. return ((PyLongConstant)o).value.equals(value);
  183. else return false;
  184. }
  185. }
  186. class PyCodeConstant extends Constant implements ClassConstants, Opcodes
  187. {
  188. public String co_name;
  189. public int argcount;
  190. public List<String> names;
  191. public int id;
  192. public int co_firstlineno;
  193. public boolean arglist, keywordlist;
  194. String fname;
  195. // for nested scopes
  196. public List<String> cellvars;
  197. public List<String> freevars;
  198. public int jy_npurecell;
  199. public int moreflags;
  200. public PyCodeConstant() {
  201. }
  202. public void get(Code c) throws IOException {
  203. c.getstatic(module.classfile.name, name, $pyCode);
  204. }
  205. public void put(Code c) throws IOException {
  206. module.classfile.addField(name, $pyCode, access);
  207. c.iconst(argcount);
  208. //Make all names
  209. int nameArray;
  210. if (names != null) {
  211. nameArray = CodeCompiler.makeStrings(c, names);
  212. } else { // classdef
  213. nameArray = CodeCompiler.makeStrings(c, null);
  214. }
  215. c.aload(nameArray);
  216. c.freeLocal(nameArray);
  217. c.aload(1);
  218. c.ldc(co_name);
  219. c.iconst(co_firstlineno);
  220. c.iconst(arglist ? 1 : 0);
  221. c.iconst(keywordlist ? 1 : 0);
  222. c.getstatic(module.classfile.name, "self", "L"+module.classfile.name+";");
  223. c.iconst(id);
  224. if (cellvars != null) {
  225. int strArray = CodeCompiler.makeStrings(c, cellvars);
  226. c.aload(strArray);
  227. c.freeLocal(strArray);
  228. } else
  229. c.aconst_null();
  230. if (freevars != null) {
  231. int strArray = CodeCompiler.makeStrings(c, freevars);
  232. c.aload(strArray);
  233. c.freeLocal(strArray);
  234. } else
  235. c.aconst_null();
  236. c.iconst(jy_npurecell);
  237. c.iconst(moreflags);
  238. c.invokestatic("org/python/core/Py", "newCode", "(I" + $strArr + $str + $str + "IZZ" + $pyFuncTbl + "I" + $strArr + $strArr + "II)" + $pyCode);
  239. c.putstatic(module.classfile.name, name, $pyCode);
  240. }
  241. }
  242. public class Module implements Opcodes, ClassConstants, CompilationContext
  243. {
  244. ClassFile classfile;
  245. Constant filename;
  246. String sfilename;
  247. public Constant mainCode;
  248. public boolean linenumbers;
  249. Future futures;
  250. Hashtable scopes;
  251. long mtime;
  252. public Module(String name, String filename, boolean linenumbers) {
  253. this(name, filename, linenumbers, org.python.core.imp.NO_MTIME);
  254. }
  255. public Module(String name, String filename, boolean linenumbers, long mtime) {
  256. this.linenumbers = linenumbers;
  257. this.mtime = mtime;
  258. classfile = new ClassFile(name, "org/python/core/PyFunctionTable",
  259. ACC_SYNCHRONIZED | ACC_PUBLIC, mtime);
  260. constants = new Hashtable();
  261. sfilename = filename;
  262. if (filename != null)
  263. this.filename = PyString(filename);
  264. else
  265. this.filename = null;
  266. codes = new ArrayList();
  267. futures = new Future();
  268. scopes = new Hashtable();
  269. }
  270. public Module(String name) {
  271. this(name, name+".py", true, org.python.core.imp.NO_MTIME);
  272. }
  273. // This block of code handles the pool of Python Constants
  274. Hashtable constants;
  275. private Constant findConstant(Constant c) {
  276. Constant ret = (Constant)constants.get(c);
  277. if (ret != null)
  278. return ret;
  279. ret = c;
  280. c.module = this;
  281. //More sophisticated name mappings might be nice
  282. c.name = "_"+constants.size();
  283. constants.put(ret, ret);
  284. return ret;
  285. }
  286. public Constant PyInteger(int value) {
  287. return findConstant(new PyIntegerConstant(value));
  288. }
  289. public Constant PyFloat(double value) {
  290. return findConstant(new PyFloatConstant(value));
  291. }
  292. public Constant PyComplex(double value) {
  293. return findConstant(new PyComplexConstant(value));
  294. }
  295. public Constant PyString(String value) {
  296. return findConstant(new PyStringConstant(value));
  297. }
  298. public Constant PyUnicode(String value) {
  299. return findConstant(new PyUnicodeConstant(value));
  300. }
  301. public Constant PyLong(String value) {
  302. return findConstant(new PyLongConstant(value));
  303. }
  304. List codes;
  305. //XXX: this can probably go away now that we can probably just copy the list.
  306. private List<String> toNameAr(List names,boolean nullok) {
  307. int sz = names.size();
  308. if (sz == 0 && nullok) return null;
  309. List<String> nameArray = new ArrayList<String>();
  310. nameArray.addAll(names);
  311. return nameArray;
  312. }
  313. private int to_cell;
  314. public PyCodeConstant PyCode(mod tree, String name,
  315. boolean fast_locals, String className,
  316. boolean classBody, boolean printResults,
  317. int firstlineno, ScopeInfo scope)
  318. throws Exception
  319. {
  320. return PyCode(tree,name,fast_locals,className,classBody,
  321. printResults,firstlineno,scope,null);
  322. }
  323. public PyCodeConstant PyCode(mod tree, String name,
  324. boolean fast_locals, String className,
  325. boolean classBody, boolean printResults,
  326. int firstlineno,
  327. ScopeInfo scope,
  328. org.python.core.CompilerFlags cflags)
  329. throws Exception
  330. {
  331. PyCodeConstant code = new PyCodeConstant();
  332. ArgListCompiler ac = (scope != null)?scope.ac:null;
  333. if (ac != null) {
  334. code.arglist = ac.arglist;
  335. code.keywordlist = ac.keywordlist;
  336. code.argcount = ac.names.size();
  337. }
  338. code.co_name = name;
  339. code.co_firstlineno = firstlineno;
  340. code.id = codes.size();
  341. //Better names in the future?
  342. if (StringUtil.isJavaIdentifier(name))
  343. code.fname = name+"$"+code.id;
  344. else
  345. code.fname = "f$"+code.id;
  346. codes.add(code);
  347. Code c = classfile.addMethod(
  348. code.fname,
  349. "(" + $pyFrame + $threadState + ")" + $pyObj,
  350. ACC_PUBLIC);
  351. CodeCompiler compiler = new CodeCompiler(this, printResults);
  352. if (classBody) {
  353. // Set the class's __module__ to __name__. fails when there's no __name__
  354. c.aload(1);
  355. c.ldc("__module__");
  356. c.aload(1);
  357. c.ldc("__name__");
  358. c.invokevirtual("org/python/core/PyFrame", "getname", "(" + $str + ")" + $pyObj);
  359. c.invokevirtual("org/python/core/PyFrame", "setlocal", "(" + $str + $pyObj + ")V");
  360. }
  361. Label genswitch = new Label();
  362. if (scope.generator) {
  363. c.goto_(genswitch);
  364. }
  365. Label start = new Label();
  366. c.label(start);
  367. //Do something to add init_code to tree
  368. if (ac != null && ac.init_code.size() > 0) {
  369. ac.appendInitCode((Suite) tree);
  370. }
  371. int nparamcell = scope.jy_paramcells.size();
  372. if(nparamcell > 0) {
  373. Map<String, SymInfo> tbl = scope.tbl;
  374. List paramcells = scope.jy_paramcells;
  375. for(int i = 0; i < nparamcell; i++) {
  376. c.aload(1);
  377. SymInfo syminf = tbl.get(paramcells.get(i));
  378. c.iconst(syminf.locals_index);
  379. c.iconst(syminf.env_index);
  380. c.invokevirtual("org/python/core/PyFrame", "to_cell", "(II)V");
  381. }
  382. }
  383. compiler.parse(tree, c, fast_locals, className, classBody,
  384. scope, cflags);
  385. // similar to visitResume code in pyasm.py
  386. if (scope.generator) {
  387. c.label(genswitch);
  388. c.aload(1);
  389. c.getfield("org/python/core/PyFrame", "f_lasti", "I");
  390. Label[] yields = new Label[compiler.yields.size()+1];
  391. yields[0] = start;
  392. for (int i = 1; i < yields.length; i++) {
  393. yields[i] = (Label) compiler.yields.get(i-1);
  394. }
  395. c.tableswitch(0, yields.length - 1, start, yields);
  396. }
  397. // !classdef only
  398. if (!classBody) code.names = toNameAr(compiler.names,false);
  399. code.cellvars = toNameAr(scope.cellvars, true);
  400. code.freevars = toNameAr(scope.freevars, true);
  401. code.jy_npurecell = scope.jy_npurecell;
  402. if (compiler.optimizeGlobals) {
  403. code.moreflags |= org.python.core.CodeFlag.CO_OPTIMIZED.flag;
  404. }
  405. if (compiler.my_scope.generator) {
  406. code.moreflags |= org.python.core.CodeFlag.CO_GENERATOR.flag;
  407. }
  408. if (cflags != null) {
  409. if (cflags.isFlagSet(CodeFlag.CO_GENERATOR_ALLOWED)) {
  410. code.moreflags |= org.python.core.CodeFlag.CO_GENERATOR_ALLOWED.flag;
  411. }
  412. if (cflags.isFlagSet(CodeFlag.CO_FUTURE_DIVISION)) {
  413. code.moreflags |= org.python.core.CodeFlag.CO_FUTURE_DIVISION.flag;
  414. }
  415. }
  416. code.module = this;
  417. code.name = code.fname;
  418. return code;
  419. }
  420. //This block of code writes out the various standard methods
  421. public void addInit() throws IOException {
  422. Code c = classfile.addMethod("<init>", "(Ljava/lang/String;)V", ACC_PUBLIC);
  423. c.aload(0);
  424. c.invokespecial("org/python/core/PyFunctionTable", "<init>", "()V");
  425. addConstants(c);
  426. }
  427. public void addRunnable() throws IOException {
  428. Code c = classfile.addMethod("getMain", "()" + $pyCode, ACC_PUBLIC);
  429. mainCode.get(c);
  430. c.areturn();
  431. }
  432. public void addMain() throws IOException {
  433. Code c = classfile.addMethod("main", "(" + $strArr + ")V",
  434. ACC_PUBLIC | ACC_STATIC);
  435. c.new_(classfile.name);
  436. c.dup();
  437. c.ldc(classfile.name);
  438. c.invokespecial(classfile.name, "<init>", "(" + $str + ")V");
  439. c.invokevirtual(classfile.name, "getMain", "()" + $pyCode);
  440. String bootstrap = Type.getDescriptor(CodeBootstrap.class);
  441. c.invokestatic(Type.getInternalName(CodeLoader.class),
  442. CodeLoader.SIMPLE_FACTORY_METHOD_NAME,
  443. "(" + $pyCode + ")" + bootstrap);
  444. c.aload(0);
  445. c.invokestatic("org/python/core/Py", "runMain", "(" + bootstrap + $strArr + ")V");
  446. c.return_();
  447. }
  448. public void addBootstrap() throws IOException {
  449. Code c = classfile.addMethod(CodeLoader.GET_BOOTSTRAP_METHOD_NAME,
  450. "()" + Type.getDescriptor(CodeBootstrap.class),
  451. ACC_PUBLIC | ACC_STATIC);
  452. c.ldc(Type.getType("L" + classfile.name + ";"));
  453. c.invokestatic(Type.getInternalName(PyRunnableBootstrap.class),
  454. PyRunnableBootstrap.REFLECTION_METHOD_NAME,
  455. "(" + $clss + ")" + Type.getDescriptor(CodeBootstrap.class));
  456. c.areturn();
  457. }
  458. public void addConstants(Code c) throws IOException {
  459. classfile.addField("self", "L"+classfile.name+";",
  460. ACC_STATIC|ACC_FINAL);
  461. c.aload(0);
  462. c.putstatic(classfile.name, "self", "L"+classfile.name+";");
  463. Enumeration e = constants.elements();
  464. while (e.hasMoreElements()) {
  465. Constant constant = (Constant)e.nextElement();
  466. constant.put(c);
  467. }
  468. for(int i=0; i<codes.size(); i++) {
  469. PyCodeConstant pyc = (PyCodeConstant)codes.get(i);
  470. pyc.put(c);
  471. }
  472. c.return_();
  473. }
  474. public void addFunctions() throws IOException {
  475. Code code = classfile.addMethod(
  476. "call_function",
  477. "(I" + $pyFrame + $threadState + ")" + $pyObj,
  478. ACC_PUBLIC);
  479. code.aload(0); // this
  480. code.aload(2); // frame
  481. code.aload(3); // thread state
  482. Label def = new Label();
  483. Label[] labels = new Label[codes.size()];
  484. int i;
  485. for(i=0; i<labels.length; i++)
  486. labels[i] = new Label();
  487. //Get index for function to call
  488. code.iload(1);
  489. code.tableswitch(0, labels.length - 1, def, labels);
  490. for(i=0; i<labels.length; i++) {
  491. code.label(labels[i]);
  492. code.invokevirtual(classfile.name, ((PyCodeConstant)codes.get(i)).fname, "(" + $pyFrame + $threadState + ")" + $pyObj);
  493. code.areturn();
  494. }
  495. code.label(def);
  496. //Should probably throw internal exception here
  497. code.aconst_null();
  498. code.areturn();
  499. }
  500. public void write(OutputStream stream) throws IOException {
  501. addInit();
  502. addRunnable();
  503. addMain();
  504. addBootstrap();
  505. addFunctions();
  506. classfile.addInterface("org/python/core/PyRunnable");
  507. if (sfilename != null) {
  508. classfile.setSource(sfilename);
  509. }
  510. classfile.write(stream);
  511. }
  512. // Implementation of CompilationContext
  513. public Future getFutures() { return futures; }
  514. public String getFilename() { return sfilename; }
  515. public ScopeInfo getScopeInfo(PythonTree node) {
  516. return (ScopeInfo) scopes.get(node);
  517. }
  518. public void error(String msg,boolean err,PythonTree node)
  519. throws Exception
  520. {
  521. if (!err) {
  522. try {
  523. Py.warning(Py.SyntaxWarning, msg,
  524. (sfilename != null) ? sfilename : "?",
  525. node.getLine() ,null, Py.None);
  526. return;
  527. } catch(PyException e) {
  528. if (!e.match(Py.SyntaxWarning))
  529. throw e;
  530. }
  531. }
  532. throw new ParseException(msg,node);
  533. }
  534. public static void compile(mod node, OutputStream ostream,
  535. String name, String filename,
  536. boolean linenumbers, boolean printResults,
  537. CompilerFlags cflags)
  538. throws Exception
  539. {
  540. compile(node, ostream, name, filename, linenumbers, printResults, cflags, org.python.core.imp.NO_MTIME);
  541. }
  542. public static void compile(mod node, OutputStream ostream,
  543. String name, String filename,
  544. boolean linenumbers, boolean printResults,
  545. CompilerFlags cflags, long mtime)
  546. throws Exception
  547. {
  548. Module module = new Module(name, filename, linenumbers, mtime);
  549. if (cflags == null) {
  550. cflags = new CompilerFlags();
  551. }
  552. module.futures.preprocessFutures(node, cflags);
  553. new ScopesCompiler(module, module.scopes).parse(node);
  554. //Add __doc__ if it exists
  555. Constant main = module.PyCode(node, "<module>", false, null, false,
  556. printResults, 0,
  557. module.getScopeInfo(node),
  558. cflags);
  559. module.mainCode = main;
  560. module.write(ostream);
  561. }
  562. }