Skip to content

Commit

Permalink
Able to access builtins in the same way as local functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Aug 31, 2015
1 parent 3d3350c commit fd14a05
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 80 deletions.
9 changes: 7 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ Install `voc`, then run the sample script::
Writing sample.class...
Done.

This will produce a `sample.class` that you can run on any Java 1.7+ VM::
This will produce a `sample.class` that you can run on any Java 1.7+ VM. You will
need to make sure that the python.jar support file is in your classpath::

$ java sample
$ java -XX:-UseSplitVerifier --classpath python.jar:. sample
Hello, World

The ``-CC:-UsesplitVerifier`` argument is necessary to turn off stack map
verification in Java 7. This could be addressed by computing stack maps
for generated code.

Documentation
-------------

Expand Down
24 changes: 13 additions & 11 deletions python/org/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@


public class Python {
public static Hashtable<String, org.python.Object> builtins;
public static Hashtable<java.lang.String, org.python.Object> builtins;

/**
* Load all the builtins into the dictionary as callables
*/
static {
builtins = new Hashtable<String, org.python.Object>();
builtins = new Hashtable<java.lang.String, org.python.Object>();

// Iterate over all methods, adding the static ones to builtins
for (Method method: Python.class.getMethods()) {
Expand Down Expand Up @@ -929,15 +929,17 @@ public static org.python.Object pow(org.python.Object x, org.python.Object y, or
* end: string appended after the last value, default a newline.
* flush: whether to forcibly flush the stream.
*/
public static void print(org.python.Object... args) {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < args.length; i++) {
buffer.append(args[i]);
if (i != args.length - 1) {
buffer.append(" ");
}
}
System.out.println(buffer.toString());
// public static void print(org.python.Object... args) {
public static void print(org.python.Object args) {
System.out.println(args);
// StringBuilder buffer = new StringBuilder();
// for (int i = 0; i < args.length; i++) {
// buffer.append(args[i]);
// if (i != args.length - 1) {
// buffer.append(" ");
// }
// }
// System.out.println(buffer.toString());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion python/org/python/Callable.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@


public interface Callable {
public org.python.Object invoke(org.python.Object... args);
public org.python.Object invoke(java.lang.Object... args);
}
2 changes: 1 addition & 1 deletion python/org/python/Constructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public Constructor(java.lang.reflect.Constructor constructor) {
this.constructor = constructor;
}

public org.python.Object invoke(org.python.Object... args) {
public org.python.Object invoke(java.lang.Object... args) {
try {
return (org.python.Object) this.constructor.newInstance();
} catch (IllegalAccessException e) {
Expand Down
5 changes: 3 additions & 2 deletions python/org/python/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ public Function(Method method) {
this.method = method;
}

public org.python.Object invoke(org.python.Object... args) {
public org.python.Object invoke(java.lang.Object... args) {
System.out.println("INVOKING " + method + ", args: " + args);
try {
return (org.python.Object) this.method.invoke(null, (java.lang.Object [])args);
return (org.python.Object) this.method.invoke(null, args);
} catch (IllegalAccessException e) {
throw new RuntimeError("Illegal access to Java function " + this.method);
} catch (InvocationTargetException e) {
Expand Down
2 changes: 1 addition & 1 deletion python/org/python/InstanceMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public InstanceMethod(java.lang.reflect.Method method) {
this.method = method;
}

public org.python.Object invoke(org.python.Object... args) {
public org.python.Object invoke(java.lang.Object... args) {
try {
return (org.python.Object) this.method.invoke(args);
} catch (IllegalAccessException e) {
Expand Down
14 changes: 14 additions & 0 deletions python/org/python/Object.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,23 +249,37 @@ public org.python.Object __add__(org.python.Object other) {
if (other.type == String.class) {
return new org.python.Object(((String) this.value) + ((String) other.value));
} else if (other.type == Long.class) {
return new org.python.Object(((String) this.value) + ((long) other.value));
} else if (other.type == Float.class) {
return new org.python.Object(((String) this.value) + ((float) other.value));
} else if (other.type == Map.class) {
} else if (other.type == Set.class) {
} else if (other.type == Object.class) {
} else if (other.type == ArrayList.class) {
}
} else if (this.type == Long.class) {
if (other.type == String.class) {
return new org.python.Object(((Long) other.value) + ((String) this.value));
} else if (other.type == Long.class) {
return new org.python.Object(((Long) this.value) + ((Long) other.value));
} else if (other.type == Float.class) {
return new org.python.Object(((float) this.value) + ((float) other.value));
} else if (other.type == Map.class) {
} else if (other.type == Set.class) {
} else if (other.type == Object.class) {
} else if (other.type == ArrayList.class) {
}
} else if (this.type == Float.class) {
if (other.type == String.class) {
return new org.python.Object(((float) other.value) + ((String) this.value));
} else if (other.type == Long.class) {
return new org.python.Object(((float) this.value) + ((float) other.value));
} else if (other.type == Float.class) {
} else if (other.type == Map.class) {
} else if (other.type == Set.class) {
} else if (other.type == Object.class) {
} else if (other.type == ArrayList.class) {
}
} else if (this.type == Map.class) {
} else if (this.type == Set.class) {
} else if (this.type == Object.class) {
Expand Down
2 changes: 1 addition & 1 deletion python/org/python/StaticMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public StaticMethod(java.lang.reflect.Method method) {
this.method = method;
}

public org.python.Object invoke(org.python.Object... args) {
public org.python.Object invoke(java.lang.Object... args) {
try {
return (org.python.Object) this.method.invoke(args);
} catch (IllegalAccessException e) {
Expand Down
4 changes: 2 additions & 2 deletions voc/java/klass.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ def __init__(
# through 45.65535 inclusive. For k ≥ 2, JDK release 1.k supports class
# file format versions in the range 45.0 through 44+k.0 inclusive.

# Java 6 is v50.0
self.major_version = 50
# Java 7 is v51.0
self.major_version = 51
self.minor_version = 0

# Each value in the interfaces array must be a valid index into the
Expand Down
12 changes: 6 additions & 6 deletions voc/java/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1059,14 +1059,14 @@ def __len__(self):
return 3

def __arg_repr__(self):
return ' %s.%s' % (self.field.klass.name, self.field.name_and_type.name)
return ' %s.%s (%s)' % (self.field.class_name, self.field.name, self.field.name_and_type.descriptor)

@classmethod
def read_extra(cls, reader, dump=None):
field = reader.constant_pool[reader.read_u2()]
return cls(
field.klass.name.bytes.decode('utf8'),
field.name_and_type.name.bytes.decode('utf8'),
field.class_name,
field.name,
field.name_and_type.descriptor.bytes.decode('utf8')
)

Expand Down Expand Up @@ -2956,14 +2956,14 @@ def __len__(self):
return 3

def __arg_repr__(self):
return ' %s.%s' % (self.field.klass.name, self.field.name_and_type.name)
return ' %s.%s (%s)' % (self.field.klass.name, self.field.name, self.field.name_and_type.descriptor)

@classmethod
def read_extra(cls, reader, dump=None):
field = reader.constant_pool[reader.read_u2()]
return cls(
field.klass.name.bytes.decode('utf8'),
field.name_and_type.name.bytes.decode('utf8'),
field.class_name,
field.name,
field.name_and_type.descriptor.bytes.decode('utf8')
)

Expand Down
8 changes: 8 additions & 0 deletions voc/python/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ def add_self(self):
def method_name(self):
return self.name

@property
def module(self):
return self.parent

def tweak(self, code):
return self.void_return(code)

Expand Down Expand Up @@ -119,6 +123,10 @@ def __init__(self, parent, commands=None):
def method_name(self):
return 'main'

@property
def module(self):
return self.parent

@property
def signature(self):
return '([Ljava/lang/String;)V'
Expand Down
15 changes: 12 additions & 3 deletions voc/python/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
Code as JavaCode,
opcodes as JavaOpcodes,
SourceFile,
Signature,
# LineNumberTable
)
from .block import Block, IgnoreBlock
from .method import MainMethod, Method, extract_parameters
from .blocks import Block, IgnoreBlock
from .methods import MainMethod, Method, extract_parameters
from .opcodes import ASTORE_name, ALOAD_name


Expand Down Expand Up @@ -135,7 +136,15 @@ def transpile(self):

# Add a globals dictionary to the module.
classfile.fields.append(
JavaField('globals', 'Ljava/util/Hashtable;', public=True, static=True)
JavaField(
'globals',
'Ljava/util/Hashtable;',
public=True,
static=True,
attributes=[
Signature('Ljava/util/Hashtable<Ljava/lang/String;Lorg/python/Object;>;')
]
)
)

# Add a static method to the module.
Expand Down
65 changes: 15 additions & 50 deletions voc/python/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,53 +1291,27 @@ def convert(self, context, arguments):
JavaOpcodes.ATHROW(),
END_TRY()
]
elif arguments[0].operation.name == 'print':
if len(arguments) == 2:
# Just the one argument - no need to use a StringBuilder.
code.append(JavaOpcodes.GETSTATIC('java/lang/System', 'out', 'Ljava/io/PrintStream;'))
code.extend(arguments[1].operation.convert(context, arguments[1].arguments))
else:
# Multiple arguments; use a StringBuilder to concatenate, and put a space
# between each argument.
code.extend([
JavaOpcodes.GETSTATIC('java/lang/System', 'out', 'Ljava/io/PrintStream;'),
JavaOpcodes.NEW('java/lang/StringBuilder'),
JavaOpcodes.DUP(),
JavaOpcodes.INVOKESPECIAL('java/lang/StringBuilder', '<init>', '()V'),
])

code.extend(arguments[1].operation.convert(context, arguments[1].arguments))
code.extend([
JavaOpcodes.INVOKEVIRTUAL('java/lang/StringBuilder', 'append', '(Ljava/lang/Object;)Ljava/lang/StringBuilder;'),
])

for argument in arguments[2:]:
code.extend([
JavaOpcodes.LDC(" "),
JavaOpcodes.INVOKEVIRTUAL('java/lang/StringBuilder', 'append', '(Ljava/lang/String;)Ljava/lang/StringBuilder;')
])
code.extend(argument.operation.convert(context, argument.arguments))
code.extend([
JavaOpcodes.INVOKEVIRTUAL('java/lang/StringBuilder', 'append', '(Ljava/lang/Object;)Ljava/lang/StringBuilder;'),
])

# The None value in the code list is a special case;
# Python explicitly returns None and then pops the empty
# result; Java can just return. We put a marker here that
# the POP/STORE_* result can use to identify the special case.
code.extend([
JavaOpcodes.INVOKEVIRTUAL('java/io/PrintStream', 'println', '(Ljava/lang/Object;)V'),
None
])


else:
method_name = arguments[0].operation.name

code = [
# Retrieve the callable from globals
JavaOpcodes.GETSTATIC(context.descriptor, 'globals', 'Ljava/util/Hashtable;'),
JavaOpcodes.GETSTATIC(context.module.descriptor, 'globals', 'Ljava/util/Hashtable;'),
JavaOpcodes.LDC(method_name),
JavaOpcodes.INVOKEVIRTUAL('java/util/Hashtable', 'get', '(Ljava/lang/Object;)Ljava/lang/Object;'),

# If there's nothing in the globals, then look for a builtin.
IF(
[JavaOpcodes.DUP()],
JavaOpcodes.IFNONNULL
),
JavaOpcodes.POP(),
JavaOpcodes.GETSTATIC('org/Python', 'builtins', 'Ljava/util/Hashtable;'),
JavaOpcodes.LDC(method_name),
JavaOpcodes.INVOKEVIRTUAL('java/util/Hashtable', 'get', '(Ljava/lang/Object;)Ljava/lang/Object;'),
END_IF(),

JavaOpcodes.CHECKCAST('org/python/Callable'),

# Create an array to pass in arguments to invoke()
Expand All @@ -1354,19 +1328,10 @@ def convert(self, context, arguments):
code.append(JavaOpcodes.AASTORE())

code.extend([
JavaOpcodes.INVOKEINTERFACE('org/python/Callable', 'invoke', '([Lorg/python/Object;)Lorg/python/Object;', 2),
JavaOpcodes.INVOKEINTERFACE('org/python/Callable', 'invoke', '([Ljava/lang/Object;)Lorg/python/Object;', 2),
])
return code

# if class:
# JavaOpcodes.NEW('java/lang/CLASSNAME'),
# JavaOpcodes.DUP(),
# JavaOpcodes.INVOKESPECIAL('java/lang/CLASSNAME', '<init>', '()V'),
# elif method:
# JavaOpcodes.INVOKEVIRTUAL('java/lang/CLASSNAME', method_name, descriptor)
# elif staticmethod:
# JavaOpcodes.INVOKESTATIC('java/lang/CLASSNAME', method_name, descriptor)


class MAKE_FUNCTION(Opcode):
def __init__(self, argc):
Expand Down

0 comments on commit fd14a05

Please sign in to comment.