diff --git a/java-type-checker/.idea/compiler.xml b/java-type-checker/.idea/compiler.xml
new file mode 100644
index 0000000..40ed937
--- /dev/null
+++ b/java-type-checker/.idea/compiler.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java-type-checker/.idea/misc.xml b/java-type-checker/.idea/misc.xml
index c24fcb0..d4fc832 100644
--- a/java-type-checker/.idea/misc.xml
+++ b/java-type-checker/.idea/misc.xml
@@ -1,16 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/java-type-checker/java_type_checker/expressions.py b/java-type-checker/java_type_checker/expressions.py
index 27ed57e..fecbfb2 100644
--- a/java-type-checker/java_type_checker/expressions.py
+++ b/java-type-checker/java_type_checker/expressions.py
@@ -1,3 +1,4 @@
+
# -*- coding: utf-8 -*-
from .types import Type
@@ -31,6 +32,12 @@ 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):
+ return self.declared_type
+
+ def check_types(self):
+ pass
+
class Literal(Expression):
""" A literal value entered in the code, e.g. `5` in the expression `x + 5`.
@@ -39,22 +46,52 @@ 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):
+ return self.type
+
+ def check_types(self):
+ pass
+
class NullLiteral(Literal):
def __init__(self):
super().__init__("null", Type.null)
+ def static_type(self):
+ return Type.null
+
+ def check_types(self):
+ pass
+
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):
+ return self.receiver.declared_type.method_named(self.method_name).return_type
+
+ def check_types(self):
+
+ for arg in self.args:
+ arg.check_types()
+
+ receiver_type = self.receiver.static_type()
+ if not receiver_type.is_subtype_of(Type.object):
+ raise JavaTypeError("Type {0} does not have methods".format(receiver_type.name))
+
+ method = receiver_type.method_named(self.method_name)
+ expected_types = method.argument_types
+ actual_types = [arg.static_type() for arg in self.args]
+ call_name = "{0}.{1}()".format(self.receiver.static_type().name, self.method_name)
+
+ check_arguments(expected_types, actual_types, call_name)
+
class ConstructorCall(Expression):
"""
@@ -64,6 +101,23 @@ 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):
+ return self.instantiated_type
+
+ def check_types(self):
+
+ for arg in self.args:
+ arg.check_types()
+
+ if not self.instantiated_type.is_instantiable:
+ raise JavaTypeError("Type {0} is not instantiable".format(self.instantiated_type.name))
+
+ expected_types = self.instantiated_type.constructor.argument_types
+ actual_types = [arg.static_type() for arg in self.args]
+ call_name = "{0} constructor".format(self.instantiated_type.name)
+
+ check_arguments(expected_types, actual_types, call_name)
+
class JavaTypeError(Exception):
""" Indicates a compile-time type error in an expression.
@@ -71,7 +125,26 @@ class JavaTypeError(Exception):
pass
+def check_arguments(expected_types, actual_types, call_name):
+ """"
+ Helper to check arguments. Raises JavaTypeError.
+ """
+ if len(expected_types) != len(actual_types):
+ raise JavaTypeError(
+ "Wrong number of arguments for {0}: expected {1}, got {2}".format(
+ call_name,
+ len(expected_types),
+ len(actual_types)))
+
+ for expected_type, actual_type in zip(expected_types, actual_types):
+ if not expected_type.is_supertype_of(actual_type):
+ raise JavaTypeError(
+ "{0} expects arguments of type {1}, but got {2}".format(
+ call_name,
+ names(expected_types),
+ names(actual_types)))
+
def names(named_things):
""" Helper for formatting pretty error messages
"""
- return "(" + ", ".join([e.name for e in named_things]) + ")"
+ return "(" + ", ".join([e.name for e in named_things]) + ")"
\ No newline at end of file
diff --git a/java-type-checker/java_type_checker/types.py b/java-type-checker/java_type_checker/types.py
index 465f7f4..73e6834 100644
--- a/java-type-checker/java_type_checker/types.py
+++ b/java-type-checker/java_type_checker/types.py
@@ -12,7 +12,12 @@ 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:
+ return True
+ for direct_supertype in self.direct_supertypes:
+ if other is direct_supertype or direct_supertype.is_subtype_of(other):
+ return True
+ return False
def is_supertype_of(self, other):
""" Convenience counterpart to is_subtype_of().
@@ -39,7 +44,6 @@ def __init__(self, name, argument_types=[], return_type=None):
class ClassOrInterface(Type):
"""
Describes the API of a class-like Java type (class or interface).
-
(This type model does not draw a distinction between classes and interfaces,
and assumes they are all instantiable. Other than instantiability, the
distinction makes no difference to us here: we are only checking types, not
@@ -72,6 +76,18 @@ class NullType(Type):
def __init__(self):
super().__init__("null")
+ def method_named(self, name):
+ """
+ Raises a NoSuchMethod error since null has no method.
+ """
+ raise NoSuchMethod("Cannot invoke method {1}() on null".format(self.name, name))
+
+ def is_subtype_of(self, other):
+ return type(other) == ClassOrInterface
+
+ def is_supertype_of(self, other):
+ return other.is_subtype_of(self)
+
class NoSuchMethod(Exception):
pass
@@ -88,7 +104,7 @@ class NoSuchMethod(Exception):
Type.null = NullType()
Type.object = ClassOrInterface("Object",
- methods=[
- Method("equals", argument_types=[object], return_type=Type.boolean),
- Method("hashCode", return_type=Type.int),
- ])
+ methods=[
+ Method("equals", argument_types=[object], return_type=Type.boolean),
+ Method("hashCode", return_type=Type.int),
+ ])
\ No newline at end of file
diff --git a/java-type-checker/tests/test_static_types.py b/java-type-checker/tests/test_static_types.py
index fcedb26..9e39ea5 100755
--- a/java-type-checker/tests/test_static_types.py
+++ b/java-type-checker/tests/test_static_types.py
@@ -35,5 +35,6 @@ def test_object_instantiation_static_type_is_the_instantiate_type(self):
Graphics.point,
ConstructorCall(Graphics.point).static_type())
+
if __name__ == '__main__':
unittest.main()
diff --git a/python-attr-lookup/python-attr-lookup.iml b/python-attr-lookup/python-attr-lookup.iml
index 01e8e1b..498c02d 100644
--- a/python-attr-lookup/python-attr-lookup.iml
+++ b/python-attr-lookup/python-attr-lookup.iml
@@ -20,5 +20,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python-attr-lookup/src/plang/PythonObject.java b/python-attr-lookup/src/plang/PythonObject.java
index a8e311f..164a4d8 100644
--- a/python-attr-lookup/src/plang/PythonObject.java
+++ b/python-attr-lookup/src/plang/PythonObject.java
@@ -51,7 +51,10 @@ public List getMRO() {
* result (i.e. it remembers the list buildMRO() returned and keeps returning it).
*/
protected List buildMRO() {
- throw new UnsupportedOperationException("not implemented yet");
+ mro = new ArrayList<>();
+ mro.add(this);
+ mro.addAll(type.buildMRO());
+ return mro;
}
/**
@@ -62,7 +65,13 @@ protected List 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");
+ List check = getMRO();
+ for (PythonObject obj : check) {
+ if (obj.attrs.containsKey(attrName)) {
+ return obj.attrs.get(attrName);
+ }
+ }
+ throw new PythonAttributeException(this, attrName);
}
/**
@@ -74,7 +83,8 @@ 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");
+ if (attrs.containsKey(attrName)) attrs.replace(attrName, value);
+ else attrs.put(attrName, value);
}
@Override
diff --git a/python-attr-lookup/src/plang/PythonType.java b/python-attr-lookup/src/plang/PythonType.java
index 4e2be4a..d49c648 100644
--- a/python-attr-lookup/src/plang/PythonType.java
+++ b/python-attr-lookup/src/plang/PythonType.java
@@ -41,7 +41,12 @@ public PythonObject getBase() {
@Override
protected List buildMRO() {
- throw new UnsupportedOperationException("not implemented yet");
+ List mroList = new ArrayList<>();
+ mroList.add(this);
+ if (base != null) {
+ mroList.addAll(base.buildMRO());
+ }
+ return mroList;
}
/**
@@ -49,11 +54,11 @@ protected List buildMRO() {
* this PythonType.
*/
public PythonObject instantiate() {
- throw new UnsupportedOperationException("not implemented yet");
+ return new PythonObject(this);
}
@Override
public String toString() {
return "PythonType<" + name + ">";
}
-}
+}
\ No newline at end of file