Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions java-type-checker/java-type-checker.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python">
<configuration sdkName="" />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
111 changes: 109 additions & 2 deletions java-type-checker/java_type_checker/expressions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from .types import Type
from .types import *


class Expression(object):
Expand Down Expand Up @@ -31,6 +31,20 @@ def __init__(self, name, declared_type):
self.name = name #: The name of the variable
self.declared_type = declared_type #: The declared type of the variable (Type)

def static_type(self):
"""
Returns the compile-time type of this expression, i.e. the most specific type that describes
all the possible values it could take on at runtime.
"""
return self.declared_type

def check_types(self):
"""
Validates the structure of this expression, checking for any logical inconsistencies in the
child nodes and the operation this expression applies to them.
"""
pass


class Literal(Expression):
""" A literal value entered in the code, e.g. `5` in the expression `x + 5`.
Expand All @@ -39,6 +53,20 @@ def __init__(self, value, type):
self.value = value #: The literal value, as a string
self.type = type #: The type of the literal (Type)

def static_type(self):
"""
Returns the compile-time type of this expression, i.e. the most specific type that describes
all the possible values it could take on at runtime.
"""
return self.type

def check_types(self):
"""
Validates the structure of this expression, checking for any logical inconsistencies in the
child nodes and the operation this expression applies to them.
"""
pass


class NullLiteral(Literal):
def __init__(self):
Expand All @@ -50,11 +78,53 @@ class MethodCall(Expression):
A Java method invocation, i.e. `foo.bar(0, 1, 2)`.
"""
def __init__(self, receiver, method_name, *args):
self.receiver = receiver
self.receiver = receiver #: The object whose method we are calling (Expression)
self.method_name = method_name #: The name of the method to call (String)
self.args = args #: The method arguments (list of Expressions)

def static_type(self):
"""
Returns the compile-time type of this expression, i.e. the most specific type that describes
all the possible values it could take on at runtime.
"""
return self.receiver.static_type().method_named(self.method_name).return_type

def check_types(self):
"""
Validates the structure of this expression, checking for any logical inconsistencies in the
child nodes and the operation this expression applies to them.
"""

# attempt to call method on primitive
if not self.receiver.static_type().is_instantiable:
raise JavaTypeError(
"Type {0} does not have methods".format(
self.receiver.static_type().name ))

# flags nonexistent method
self.receiver.static_type().method_named(self.method_name)

# flags wrong number of arguments
if len(self.args) != len(self.receiver.static_type().method_named(self.method_name).argument_types):
raise JavaTypeError(
"Wrong number of arguments for {0}.{1}(): expected {2}, got {3}".format(
self.receiver.static_type().name,
self.method_name,
len(self.receiver.static_type().method_named(self.method_name).argument_types),
len(self.args)))

# checks type of arguments
# flags wrong argument type
for i in range(len(self.args)):
if (self.args[i].check_types() != self.receiver.static_type().method_named(self.method_name).argument_types[i]
and not self.args[i].static_type().is_subtype_of(self.receiver.static_type().method_named(self.method_name).argument_types[i])):
raise JavaTypeError(
"{0}.{1}() expects arguments of type {2}, but got {3}".format(
self.receiver.static_type().name,
self.method_name,
names(self.receiver.static_type().method_named(self.method_name).argument_types),
names([t.static_type() for t in self.args])))


class ConstructorCall(Expression):
"""
Expand All @@ -64,6 +134,43 @@ def __init__(self, instantiated_type, *args):
self.instantiated_type = instantiated_type #: The type to instantiate (Type)
self.args = args #: Constructor arguments (list of Expressions)

def static_type(self):
"""
Returns the compile-time type of this expression, i.e. the most specific type that describes
all the possible values it could take on at runtime.
"""
return self.instantiated_type

def check_types(self):
"""
Validates the structure of this expression, checking for any logical inconsistencies in the
child nodes and the operation this expression applies to them.
"""

# flags attempts to instantiate primitives
if not self.instantiated_type.is_instantiable:
raise JavaTypeError(
"Type {0} is not instantiable".format(
self.instantiated_type.name))

# flags wrong number of arguments
if len(self.args) != len(self.instantiated_type.constructor.argument_types):
raise JavaTypeError(
"Wrong number of arguments for {0} constructor: expected {1}, got {2}".format(
self.instantiated_type.name,
len(self.instantiated_type.constructor.argument_types),
len(self.args)))

# flags wrong argument type
for i in range(len(self.args)):
if self.args[i].check_types() != (self.instantiated_type.constructor.argument_types[i])\
and not self.args[i].static_type().is_subtype_of(self.instantiated_type.constructor.argument_types[i]):
raise JavaTypeError(
"{0} constructor expects arguments of type {1}, but got {2}".format(
self.instantiated_type.name,
names(self.instantiated_type.constructor.argument_types),
names([t.static_type() for t in self.args])))


class JavaTypeError(Exception):
""" Indicates a compile-time type error in an expression.
Expand Down
20 changes: 18 additions & 2 deletions java-type-checker/java_type_checker/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ def __init__(self, name, direct_supertypes=[]):
def is_subtype_of(self, other):
""" True if this type can be used where the other type is expected.
"""
return True # TODO: implement
if other is self or other in self.direct_supertypes:
return True

for thing in self.direct_supertypes:
if thing.is_subtype_of(other):
return True

return False

def is_supertype_of(self, other):
""" Convenience counterpart to is_subtype_of().
Expand Down Expand Up @@ -66,11 +73,20 @@ def method_named(self, name):
raise NoSuchMethod("{0} has no method named {1}".format(self.name, name))


class NullType(Type):
class NullType(ClassOrInterface):
""" The type of the value `null` in Java.
"""
def __init__(self):
super().__init__("null")
self.is_instantiable = False

def is_subtype_of(self, other):
""" True if this type can be used where the other type is expected.
"""
if other.is_subtype_of(Type.object):
return True

return False


class NoSuchMethod(Exception):
Expand Down
4 changes: 2 additions & 2 deletions java-type-checker/tests/test_null.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def test_cannot_call_method_on_null(self):
null.hashCode();
"""
self.assertCompileError(
NoSuchMethod, # Think: why shouldn’t this be NullPointerException?
"Cannot invoke method hashCode() on null",
JavaTypeError, # Think: why shouldn’t this be NullPointerException?
"Type null does not have methods",
MethodCall(
NullLiteral(),
"hashCode"))
Expand Down
25 changes: 17 additions & 8 deletions python-attr-lookup/src/plang/PythonObject.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package plang;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

/**
* The runtime state of an object in Python.
Expand Down Expand Up @@ -51,7 +47,14 @@ public List<PythonObject> getMRO() {
* result (i.e. it remembers the list buildMRO() returned and keeps returning it).
*/
protected List<PythonObject> buildMRO() {
throw new UnsupportedOperationException("not implemented yet");

mro = new ArrayList<>();

mro.add(this);

mro.addAll(type.buildMRO());

return mro;
}

/**
Expand All @@ -62,7 +65,13 @@ protected List<PythonObject> buildMRO() {
* @throws PythonAttributeException When there is no attribute on this object with that name.
*/
public final PythonObject get(String attrName) throws PythonAttributeException {
throw new UnsupportedOperationException("not implemented yet");

for(PythonObject o : getMRO()) {
if (o.attrs.containsKey(attrName))
return o.attrs.get(attrName);
}

throw new PythonAttributeException(this, attrName);
}

/**
Expand All @@ -74,7 +83,7 @@ public final PythonObject get(String attrName) throws PythonAttributeException {
* @param value Its new value
*/
public final void set(String attrName, PythonObject value) {
throw new UnsupportedOperationException("not implemented yet");
attrs.put(attrName, value);
}

@Override
Expand Down
16 changes: 13 additions & 3 deletions python-attr-lookup/src/plang/PythonType.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package plang;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
Expand Down Expand Up @@ -41,15 +40,26 @@ public PythonObject getBase() {

@Override
protected List<PythonObject> buildMRO() {
throw new UnsupportedOperationException("not implemented yet");

List<PythonObject> mro = new ArrayList<>();

mro.add(this);

if (base != null)
mro.addAll(base.buildMRO());

return mro;
}

/**
* Creates and returns a new instance of this class, i.e. a PythonObject whose type is
* this PythonType.
*/
public PythonObject instantiate() {
throw new UnsupportedOperationException("not implemented yet");

PythonObject pObject = new PythonObject(this);

return pObject;
}

@Override
Expand Down