// Copyright (c) Corporation for National Research Initiatives
package org.python.compiler;
import java.io.*;
import java.util.*;
import org.python.parser.*;
import org.python.parser.ast.*;
import org.python.core.Py;
import org.python.core.PyException;
class PyIntegerConstant extends Constant implements ClassConstants {
int value;
public PyIntegerConstant(int value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyInteger);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyInteger, access);
c.iconst(value);
int mref_newInteger = c.pool.Methodref("org/python/core/Py", "newInteger", "(I)" + $pyInteger);
c.invokestatic(mref_newInteger);
c.putstatic(module.classfile.name, name, $pyInteger);
}
public int hashCode() {
return value;
}
public boolean equals(Object o) {
if (o instanceof PyIntegerConstant)
return ((PyIntegerConstant) o).value == value;
else
return false;
}
}
class PyFloatConstant extends Constant implements ClassConstants {
double value;
public PyFloatConstant(double value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyFloat);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyFloat, access);
c.ldc(c.pool.Double(value));
int mref_newFloat = c.pool.Methodref("org/python/core/Py", "newFloat", "(D)" + $pyFloat);
c.invokestatic(mref_newFloat);
c.putstatic(module.classfile.name, name, $pyFloat);
}
public int hashCode() {
return (int) value;
}
public boolean equals(Object o) {
if (o instanceof PyFloatConstant)
return ((PyFloatConstant) o).value == value;
else
return false;
}
}
class PyComplexConstant extends Constant implements ClassConstants {
double value;
public PyComplexConstant(double value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyComplex);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyComplex, access);
c.ldc(c.pool.Double(value));
int mref_newImaginary = c.pool.Methodref("org/python/core/Py", "newImaginary", "(D)" + $pyComplex);
c.invokestatic(mref_newImaginary);
c.putstatic(module.classfile.name, name, $pyComplex);
}
public int hashCode() {
return (int) value;
}
public boolean equals(Object o) {
if (o instanceof PyComplexConstant)
return ((PyComplexConstant) o).value == value;
else
return false;
}
}
class PyStringConstant extends Constant implements ClassConstants {
String value;
public PyStringConstant(String value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyStr);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyStr, access);
c.ldc(value);
int mref_newString = c.pool.Methodref("org/python/core/Py", "newString", "(" + $str + ")" + $pyStr);
c.invokestatic(mref_newString);
c.putstatic(module.classfile.name, name, $pyStr);
}
public int hashCode() {
return value.hashCode();
}
public boolean equals(Object o) {
if (o instanceof PyStringConstant)
return ((PyStringConstant) o).value.equals(value);
else
return false;
}
}
class PyUnicodeConstant extends Constant implements ClassConstants {
String value;
public PyUnicodeConstant(String value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyUnicode);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyUnicode, access);
c.ldc(value);
int mref_newString = c.pool.Methodref("org/python/core/Py", "newUnicode", "(" + $str + ")" + $pyUnicode);
c.invokestatic(mref_newString);
c.putstatic(module.classfile.name, name, $pyUnicode);
}
public int hashCode() {
return value.hashCode();
}
public boolean equals(Object o) {
if (o instanceof PyUnicodeConstant)
return ((PyUnicodeConstant) o).value.equals(value);
else
return false;
}
}
class PyLongConstant extends Constant implements ClassConstants {
String value;
public PyLongConstant(String value) {
this.value = value;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyLong);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyLong, access);
c.ldc(value);
int mref_newLong = c.pool.Methodref("org/python/core/Py", "newLong", "(" + $str + ")" + $pyLong);
c.invokestatic(mref_newLong);
c.putstatic(module.classfile.name, name, $pyLong);
}
public int hashCode() {
return value.hashCode();
}
public boolean equals(Object o) {
if (o instanceof PyLongConstant)
return ((PyLongConstant) o).value.equals(value);
else
return false;
}
}
class PyCodeConstant extends Constant implements ClassConstants {
public String co_name;
public int argcount;
public String[] names;
public int id;
public int co_firstlineno;
public boolean arglist, keywordlist;
String fname;
// for nested scopes
public String[] cellvars;
public String[] freevars;
public int jy_npurecell;
public int moreflags;
public PyCodeConstant() {
;
}
public void get(Code c) throws IOException {
c.getstatic(module.classfile.name, name, $pyCode);
}
public void put(Code c) throws IOException {
module.classfile.addField(name, $pyCode, access);
c.iconst(argcount);
//Make all names
if (names != null) {
CodeCompiler.makeStrings(c, names, names.length);
} else { // classdef
CodeCompiler.makeStrings(c, null, 0);
}
c.aload(1);
c.ldc(co_name);
c.iconst(co_firstlineno);
c.iconst(arglist ? 1 : 0);
c.iconst(keywordlist ? 1 : 0);
int mref_self = c.pool.Fieldref(module.classfile.name, "self", "L" + module.classfile.name + ";");
c.getstatic(mref_self);
//c.aconst_null();
c.iconst(id);
if (cellvars != null)
CodeCompiler.makeStrings(c, cellvars, cellvars.length);
else
c.aconst_null();
if (freevars != null)
CodeCompiler.makeStrings(c, freevars, freevars.length);
else
c.aconst_null();
c.iconst(jy_npurecell);
c.iconst(moreflags);
int mref_newCode = c.pool.Methodref("org/python/core/Py", "newCode", "(I" + $strArr + $str + $str + "IZZ"
+ $pyFuncTbl + "I" + $strArr + $strArr + "II)" + $pyCode);
c.invokestatic(mref_newCode);
//c.aconst_null();
c.putstatic(module.classfile.name, name, $pyCode);
}
}
public class Module implements ClassConstants, CompilationContext {
ClassFile classfile;
Constant filename;
String sfilename;
public Constant mainCode;
public boolean linenumbers;
public boolean setFile = true;
Future futures;
Hashtable scopes;
public Module(String name, String filename, boolean linenumbers) {
this.linenumbers = linenumbers;
classfile = new ClassFile(name, "org/python/core/PyFunctionTable", ClassFile.SYNCHRONIZED | ClassFile.PUBLIC);
constants = new Hashtable();
sfilename = filename;
if (filename != null)
this.filename = PyString(filename);
else
this.filename = null;
codes = new Vector();
futures = new Future();
scopes = new Hashtable();
}
public Module(String name) {
this(name, name + ".py", true);
}
// This block of code handles the pool of Python Constants
Hashtable constants;
private Constant findConstant(Constant c) {
Constant ret = (Constant) constants.get(c);
if (ret != null)
return ret;
ret = c;
c.module = this;
//More sophisticated name mappings might be nice
c.name = "_" + constants.size();
constants.put(ret, ret);
return ret;
}
public Constant PyInteger(int value) {
return findConstant(new PyIntegerConstant(value));
}
public Constant PyFloat(double value) {
return findConstant(new PyFloatConstant(value));
}
public Constant PyComplex(double value) {
return findConstant(new PyComplexConstant(value));
}
public Constant PyString(String value) {
return findConstant(new PyStringConstant(value));
}
public Constant PyUnicode(String value) {
return findConstant(new PyUnicodeConstant(value));
}
public Constant PyLong(String value) {
return findConstant(new PyLongConstant(value));
}
/*public PyCodeConstant PyCode(SimpleNode tree, String name,
ArgListCompiler ac,
boolean fast_locals, boolean class_body)
throws Exception {
return PyCode(tree, name, ac, fast_locals, class_body, false, 0);
}
public PyCodeConstant PyCode(SimpleNode tree, String name,
ArgListCompiler ac,
boolean fast_locals, boolean class_body,
int firstlineno)
throws Exception {
return PyCode(tree, name, ac, fast_locals, class_body, false,
firstlineno);
}
public PyCodeConstant PyCode(SimpleNode tree, String name,
ArgListCompiler ac,
boolean fast_locals, boolean class_body,
boolean printResults)
throws Exception {
return PyCode(tree, name, ac, fast_locals, class_body, printResults, 0);
}*/
Vector codes;
private boolean isJavaIdentifier(String s) {
char[] chars = s.toCharArray();
if (chars.length == 0)
return false;
if (!Character.isJavaIdentifierStart(chars[0]))
return false;
for (int i = 1; i < chars.length; i++) {
if (!Character.isJavaIdentifierPart(chars[i]))
return false;
}
return true;
}
private String[] toNameAr(Vector names, boolean nullok) {
int sz = names.size();
if (sz == 0 && nullok)
return null;
String[] nameArray = new String[sz];
names.copyInto(nameArray);
return nameArray;
}
private int to_cell;
public PyCodeConstant PyCode(modType tree, String name, boolean fast_locals, String className, boolean classBody,
boolean printResults, int firstlineno, ScopeInfo scope) throws Exception {
return PyCode(tree, name, fast_locals, className, classBody, printResults, firstlineno, scope, null);
}
public PyCodeConstant PyCode(modType tree, String name, boolean fast_locals, String className, boolean classBody,
boolean printResults, int firstlineno, ScopeInfo scope, org.python.core.CompilerFlags cflags)
throws Exception {
PyCodeConstant code = new PyCodeConstant();
ArgListCompiler ac = (scope != null) ? scope.ac : null;
if (ac != null) {
code.arglist = ac.arglist;
code.keywordlist = ac.keywordlist;
code.argcount = ac.names.size();
}
code.co_name = name;
code.co_firstlineno = firstlineno;
code.id = codes.size();
//Better names in the future?
if (isJavaIdentifier(name))
code.fname = name + "$" + code.id;
else
code.fname = "f$" + code.id;
codes.addElement(code);
Code c = classfile.addMethod(code.fname, "(" + $pyFrame + ")" + $pyObj, ClassFile.PUBLIC);
CodeCompiler compiler = new CodeCompiler(this, printResults);
Label genswitch = c.getLabel();
if (scope.generator) {
c.goto_(genswitch);
}
Label start = c.getLabel();
start.setPosition();
//Do something to add init_code to tree
if (ac != null && ac.init_code.size() > 0) {
ac.appendInitCode((Suite) tree);
}
if (scope != null) {
int nparamcell = scope.jy_paramcells.size();
if (nparamcell > 0) {
if (to_cell == 0) {
to_cell = classfile.pool.Methodref("org/python/core/PyFrame", "to_cell", "(II)V");
}
Hashtable tbl = scope.tbl;
Vector paramcells = scope.jy_paramcells;
for (int i = 0; i < nparamcell; i++) {
c.aload(1);
SymInfo syminf = (SymInfo) tbl.get(paramcells.elementAt(i));
c.iconst(syminf.locals_index);
c.iconst(syminf.env_index);
c.invokevirtual(to_cell);
}
}
}
compiler.parse(tree, c, fast_locals, className, classBody, scope, cflags);
if (scope.generator) {
genswitch.setPosition();
c.aload(1);
if (compiler.f_lasti == 0) {
compiler.f_lasti = c.pool.Fieldref("org/python/core/PyFrame", "f_lasti", "I");
}
c.getfield(compiler.f_lasti);
Label[] yields = new Label[compiler.yields.size() + 1];
yields[0] = start;
for (int i = 1; i < yields.length; i++) {
yields[i] = (Label) compiler.yields.elementAt(i - 1);
}
c.tableswitch(start, 0, yields);
// XXX: Generate an error
}
// !classdef only
if (!classBody)
code.names = toNameAr(compiler.names, false);
if (scope != null) {
code.cellvars = toNameAr(scope.cellvars, true);
code.freevars = toNameAr(scope.freevars, true);
code.jy_npurecell = scope.jy_npurecell;
}
if (compiler.optimizeGlobals) {
code.moreflags |= org.python.core.PyTableCode.CO_OPTIMIZED;
}
if (compiler.my_scope.generator) {
code.moreflags |= org.python.core.PyTableCode.CO_GENERATOR;
}
if (cflags != null) {
if (cflags.generator_allowed) {
code.moreflags |= org.python.core.PyTableCode.CO_GENERATOR_ALLOWED;
}
if (cflags.division) {
code.moreflags |= org.python.core.PyTableCode.CO_FUTUREDIVISION;
}
}
code.module = this;
code.name = code.fname;
return code;
}
//This block of code writes out the various standard methods
public void addInit() throws IOException {
Code c = classfile.addMethod("<init>", "(Ljava/lang/String;)V", ClassFile.PUBLIC);
c.aload(0);
c.invokespecial(c.pool.Methodref("org/python/core/PyFunctionTable", "<init>", "()V"));
addConstants(c);
}
public void addRunnable() throws IOException {
Code c = classfile.addMethod("getMain", "()" + $pyCode, ClassFile.PUBLIC);
mainCode.get(c);
c.areturn();
}
public void addMain() throws IOException {
Code c = classfile.addMethod("main", "(" + $strArr + ")V", ClassFile.PUBLIC | ClassFile.STATIC);
c.new_(c.pool.Class(classfile.name));
c.dup();
c.ldc(classfile.name);
c.invokespecial(c.pool.Methodref(classfile.name, "<init>", "(" + $str + ")V"));
c.aload(0);
c.invokestatic(c.pool.Methodref("org/python/core/Py", "runMain", "(" + $pyRunnable + $strArr + ")V"));
c.return_();
}
public void addConstants(Code c) throws IOException {
classfile.addField("self", "L" + classfile.name + ";", ClassFile.STATIC | ClassFile.FINAL);
c.aload(0);
c.putstatic(c.pool.Fieldref(classfile.name, "self", "L" + classfile.name + ";"));
Enumeration e = constants.elements();
while (e.hasMoreElements()) {
Constant constant = (Constant) e.nextElement();
constant.put(c);
}
for (int i = 0; i < codes.size(); i++) {
PyCodeConstant pyc = (PyCodeConstant) codes.elementAt(i);
pyc.put(c);
}
c.return_();
}
public void addFunctions() throws IOException {
Code code = classfile.addMethod("call_function", "(I" + $pyFrame + ")" + $pyObj, ClassFile.PUBLIC);
code.aload(0);
code.aload(2);
Label def = code.getLabel();
Label[] labels = new Label[codes.size()];
int i;
for (i = 0; i < labels.length; i++)
labels[i] = code.getLabel();
//Get index for function to call
code.iload(1);
code.tableswitch(def, 0, labels);
for (i = 0; i < labels.length; i++) {
labels[i].setPosition();
code.invokevirtual(classfile.name, ((PyCodeConstant) codes.elementAt(i)).fname, "(" + $pyFrame + ")"
+ $pyObj);
code.areturn();
code.stack += 2;
}
def.setPosition();
//Should probably throw internal exception here
code.aconst_null();
code.areturn();
}
public void write(OutputStream stream) throws IOException {
addInit();
addRunnable();
addMain();
addFunctions();
classfile.addInterface("org/python/core/PyRunnable");
if (sfilename != null) {
classfile.addAttribute(new SourceFile(sfilename, classfile.pool));
}
classfile.addAttribute(new APIVersion(org.python.core.imp.APIVersion, classfile.pool));
classfile.write(stream);
}
// Implementation of CompilationContext
public Future getFutures() {
return futures;
}
public String getFilename() {
return sfilename;
}
public ScopeInfo getScopeInfo(SimpleNode node) {
return (ScopeInfo) scopes.get(node);
}
public void error(String msg, boolean err, SimpleNode node) throws Exception {
if (!err) {
try {
Py.warning(Py.SyntaxWarning, msg, (sfilename != null) ? sfilename : "?", node.beginLine, null, Py.None);
return;
} catch (PyException e) {
if (!Py.matchException(e, Py.SyntaxWarning))
throw e;
}
}
throw new ParseException(msg, node);
}
public static void compile(modType node, OutputStream ostream, String name, String filename, boolean linenumbers,
boolean printResults, boolean setFile, org.python.core.CompilerFlags cflags) throws Exception {
Module module = new Module(name, filename, linenumbers);
module.setFile = setFile;
module.futures.preprocessFutures(node, cflags);
new ScopesCompiler(module, module.scopes).parse(node);
//Add __doc__ if it exists
//Add __file__ for filename (if it exists?)
Constant main = module
.PyCode(node, "?", false, null, false, printResults, 0, module.getScopeInfo(node), cflags);
module.mainCode = main;
module.write(ostream);
}
}