From f7774b43b2da6b70c5ba45be70acac2627976a5a Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 9 Feb 2018 01:28:41 -0600 Subject: [PATCH 1/3] Add Amanda's python-attr-lookup solutions --- python-attr-lookup/src/plang/PythonObject.java | 16 +++++++++++++--- python-attr-lookup/src/plang/PythonType.java | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) 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..d834f5a 100644 --- a/python-attr-lookup/src/plang/PythonType.java +++ b/python-attr-lookup/src/plang/PythonType.java @@ -41,7 +41,18 @@ public PythonObject getBase() { @Override protected List buildMRO() { - throw new UnsupportedOperationException("not implemented yet"); + List mro = new ArrayList<>(); + PythonType type = this; + while (type != null) { + mro.add(type); + if (base == null) return mro; + else if (base.getType() == null) { + mro.add(base); + return mro; + } + type = base.getType(); + } + return mro; } /** @@ -49,7 +60,7 @@ protected List buildMRO() { * this PythonType. */ public PythonObject instantiate() { - throw new UnsupportedOperationException("not implemented yet"); + return new PythonObject(this); } @Override From b0418e30be53a3619f2f4e7d27734a2ba48524f6 Mon Sep 17 00:00:00 2001 From: Amanda Date: Wed, 14 Feb 2018 14:45:16 -0600 Subject: [PATCH 2/3] Add HW 1 with passed test cases --- .../java_type_checker/expressions.py | 80 ++++++++++++++++++- java-type-checker/java_type_checker/types.py | 28 +++++-- java-type-checker/tests/test_static_types.py | 1 + 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/java-type-checker/java_type_checker/expressions.py b/java-type-checker/java_type_checker/expressions.py index 27ed57e..3b51b40 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): + return True + class Literal(Expression): """ A literal value entered in the code, e.g. `5` in the expression `x + 5`. @@ -39,22 +46,61 @@ 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): + return True + class NullLiteral(Literal): def __init__(self): super().__init__("null", Type.null) + def static_type(self): + return Type.null + 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.static_type().method_named(self.method_name).return_type + + def check_types(self): + try: + method = self.receiver.static_type().method_named(self.method_name) + except AttributeError: # handles both primitive and null cases + raise JavaTypeError("Type {0} does not have methods".format(self.receiver.static_type().name)) + if len(self.args) != len(method.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(method.argument_types), + len(self.args) + ) + ) + + for i, arg in enumerate(self.args): + if type(arg) == ConstructorCall: + arg.check_types() + if arg.static_type() != method.argument_types[i]: + if not(arg.static_type().is_subtype_of(method.argument_types[i])): + if arg.static_type().name != "null": + raise JavaTypeError( + "{0}.{1}() expects arguments of type ({2}), but got ({3})".format( + self.receiver.static_type().name, + self.method_name, + ', '.join([i.name for i in method.argument_types]), + ', '.join([i.static_type().name for i in self.args]))) + class ConstructorCall(Expression): """ @@ -64,6 +110,36 @@ 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): + + item = self.instantiated_type + if not item.is_instantiable: + raise JavaTypeError( + "Type {0} is not instantiable".format(item.name)) + if len(self.args) != len(item.constructor.argument_types): + raise JavaTypeError( + "Wrong number of arguments for {0} constructor: expected {1}, got {2}".format( + item.name, + len(item.constructor.argument_types), + len(self.args) + ) + ) + for i, arg in enumerate(self.args): + if type(arg) == ConstructorCall: + arg.check_types() + if item.constructor.argument_types[i].is_instantiable and arg.static_type().name == "null": + continue # skips remaining code + if arg.static_type() != item.constructor.argument_types[i]: + if not(arg.static_type().is_subtype_of(item.constructor.argument_types[i])): + raise JavaTypeError( + "{0} constructor expects arguments of type ({1}), but got ({2})".format( + item.name, + ', '.join([i.name for i in item.constructor.argument_types]), + ', '.join([i.static_type().name for i in self.args]))) + class JavaTypeError(Exception): """ Indicates a compile-time type error in an expression. @@ -74,4 +150,4 @@ class JavaTypeError(Exception): 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..5ad0d57 100644 --- a/java-type-checker/java_type_checker/types.py +++ b/java-type-checker/java_type_checker/types.py @@ -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 self.name == other.name: + return True + if other in self.direct_supertypes: + return True + for i in self.direct_supertypes: + if i.is_subtype_of(other): + return True + return False def is_supertype_of(self, other): """ Convenience counterpart to is_subtype_of(). @@ -39,7 +46,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 @@ -63,7 +69,12 @@ def method_named(self, name): return supertype.method_named(name) except NoSuchMethod: pass - raise NoSuchMethod("{0} has no method named {1}".format(self.name, name)) + raise NoSuchMethod( + "{0} has no method named {1}".format( + self.name, + name + ) + ) class NullType(Type): @@ -72,6 +83,9 @@ class NullType(Type): def __init__(self): super().__init__("null") + def method_named(self, name): + raise NoSuchMethod("Cannot invoke method {0}() on null".format(name)) + class NoSuchMethod(Exception): pass @@ -88,7 +102,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() From d6d42fb2d4d524c4a92eaf1ae672b00278787514 Mon Sep 17 00:00:00 2001 From: Amanda Date: Sun, 6 May 2018 17:13:06 -0500 Subject: [PATCH 3/3] final submission of hw 1 --- java-type-checker/.idea/compiler.xml | 15 +++ java-type-checker/.idea/misc.xml | 12 -- .../java_type_checker/expressions.py | 103 +++++++++--------- java-type-checker/java_type_checker/types.py | 26 +++-- python-attr-lookup/python-attr-lookup.iml | 10 ++ python-attr-lookup/src/plang/PythonType.java | 18 +-- 6 files changed, 95 insertions(+), 89 deletions(-) create mode 100644 java-type-checker/.idea/compiler.xml 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 3b51b40..fecbfb2 100644 --- a/java-type-checker/java_type_checker/expressions.py +++ b/java-type-checker/java_type_checker/expressions.py @@ -36,7 +36,7 @@ def static_type(self): return self.declared_type def check_types(self): - return True + pass class Literal(Expression): @@ -50,7 +50,7 @@ def static_type(self): return self.type def check_types(self): - return True + pass class NullLiteral(Literal): @@ -60,6 +60,9 @@ def __init__(self): def static_type(self): return Type.null + def check_types(self): + pass + class MethodCall(Expression): """ @@ -71,35 +74,23 @@ def __init__(self, receiver, method_name, *args): self.args = args #: The method arguments (list of Expressions) def static_type(self): - return self.receiver.static_type().method_named(self.method_name).return_type + return self.receiver.declared_type.method_named(self.method_name).return_type def check_types(self): - try: - method = self.receiver.static_type().method_named(self.method_name) - except AttributeError: # handles both primitive and null cases - raise JavaTypeError("Type {0} does not have methods".format(self.receiver.static_type().name)) - if len(self.args) != len(method.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(method.argument_types), - len(self.args) - ) - ) - - for i, arg in enumerate(self.args): - if type(arg) == ConstructorCall: - arg.check_types() - if arg.static_type() != method.argument_types[i]: - if not(arg.static_type().is_subtype_of(method.argument_types[i])): - if arg.static_type().name != "null": - raise JavaTypeError( - "{0}.{1}() expects arguments of type ({2}), but got ({3})".format( - self.receiver.static_type().name, - self.method_name, - ', '.join([i.name for i in method.argument_types]), - ', '.join([i.static_type().name for i in self.args]))) + + 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): @@ -115,30 +106,17 @@ def static_type(self): def check_types(self): - item = self.instantiated_type - if not item.is_instantiable: - raise JavaTypeError( - "Type {0} is not instantiable".format(item.name)) - if len(self.args) != len(item.constructor.argument_types): - raise JavaTypeError( - "Wrong number of arguments for {0} constructor: expected {1}, got {2}".format( - item.name, - len(item.constructor.argument_types), - len(self.args) - ) - ) - for i, arg in enumerate(self.args): - if type(arg) == ConstructorCall: - arg.check_types() - if item.constructor.argument_types[i].is_instantiable and arg.static_type().name == "null": - continue # skips remaining code - if arg.static_type() != item.constructor.argument_types[i]: - if not(arg.static_type().is_subtype_of(item.constructor.argument_types[i])): - raise JavaTypeError( - "{0} constructor expects arguments of type ({1}), but got ({2})".format( - item.name, - ', '.join([i.name for i in item.constructor.argument_types]), - ', '.join([i.static_type().name for i in self.args]))) + 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): @@ -147,6 +125,25 @@ 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 """ diff --git a/java-type-checker/java_type_checker/types.py b/java-type-checker/java_type_checker/types.py index 5ad0d57..73e6834 100644 --- a/java-type-checker/java_type_checker/types.py +++ b/java-type-checker/java_type_checker/types.py @@ -12,12 +12,10 @@ 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. """ - if self.name == other.name: + if other is self: return True - if other in self.direct_supertypes: - return True - for i in self.direct_supertypes: - if i.is_subtype_of(other): + for direct_supertype in self.direct_supertypes: + if other is direct_supertype or direct_supertype.is_subtype_of(other): return True return False @@ -69,12 +67,7 @@ def method_named(self, name): return supertype.method_named(name) except NoSuchMethod: pass - raise NoSuchMethod( - "{0} has no method named {1}".format( - self.name, - name - ) - ) + raise NoSuchMethod("{0} has no method named {1}".format(self.name, name)) class NullType(Type): @@ -84,7 +77,16 @@ def __init__(self): super().__init__("null") def method_named(self, name): - raise NoSuchMethod("Cannot invoke method {0}() on null".format(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): 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/PythonType.java b/python-attr-lookup/src/plang/PythonType.java index d834f5a..d49c648 100644 --- a/python-attr-lookup/src/plang/PythonType.java +++ b/python-attr-lookup/src/plang/PythonType.java @@ -41,18 +41,12 @@ public PythonObject getBase() { @Override protected List buildMRO() { - List mro = new ArrayList<>(); - PythonType type = this; - while (type != null) { - mro.add(type); - if (base == null) return mro; - else if (base.getType() == null) { - mro.add(base); - return mro; - } - type = base.getType(); + List mroList = new ArrayList<>(); + mroList.add(this); + if (base != null) { + mroList.addAll(base.buildMRO()); } - return mro; + return mroList; } /** @@ -67,4 +61,4 @@ public PythonObject instantiate() { public String toString() { return "PythonType<" + name + ">"; } -} +} \ No newline at end of file