From 92290e10599ef259aab398d7499780cc098802c4 Mon Sep 17 00:00:00 2001 From: Mack Hartley Date: Fri, 9 Feb 2018 17:20:09 -0600 Subject: [PATCH] Finished first homework --- .../inspectionProfiles/Project_Default.xml | 9 +++ java-type-checker/.idea/misc.xml | 2 +- java-type-checker/.idea/type-checker.iml | 2 +- .../java_type_checker/expressions.py | 81 +++++++++++++++++++ java-type-checker/java_type_checker/types.py | 18 ++++- python-attr-lookup/.idea/misc.xml | 2 +- python-attr-lookup/python-attr-lookup.iml | 10 +++ .../src/plang/PythonObject.java | 21 ++++- python-attr-lookup/src/plang/PythonType.java | 16 +++- 9 files changed, 152 insertions(+), 9 deletions(-) diff --git a/java-type-checker/.idea/inspectionProfiles/Project_Default.xml b/java-type-checker/.idea/inspectionProfiles/Project_Default.xml index b169286..8813ec9 100644 --- a/java-type-checker/.idea/inspectionProfiles/Project_Default.xml +++ b/java-type-checker/.idea/inspectionProfiles/Project_Default.xml @@ -7,6 +7,15 @@ + + + + diff --git a/java-type-checker/.idea/misc.xml b/java-type-checker/.idea/misc.xml index c24fcb0..5371031 100644 --- a/java-type-checker/.idea/misc.xml +++ b/java-type-checker/.idea/misc.xml @@ -12,5 +12,5 @@ - + \ No newline at end of file diff --git a/java-type-checker/.idea/type-checker.iml b/java-type-checker/.idea/type-checker.iml index 52e75c6..0acd853 100644 --- a/java-type-checker/.idea/type-checker.iml +++ b/java-type-checker/.idea/type-checker.iml @@ -2,7 +2,7 @@ - + diff --git a/java-type-checker/java_type_checker/expressions.py b/java-type-checker/java_type_checker/expressions.py index 27ed57e..b972dd7 100644 --- a/java-type-checker/java_type_checker/expressions.py +++ b/java-type-checker/java_type_checker/expressions.py @@ -31,6 +31,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,10 +45,24 @@ 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) + self.declared_type = Type.null + + def static_type(self): + return Type.null + + # def check_types(self): + # raise NoSuchMethod() + class MethodCall(Expression): @@ -55,6 +75,31 @@ def __init__(self, receiver, method_name, *args): 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): + if self.receiver.declared_type == Type.null: + self.receiver.declared_type.check_for_null_method(self.method_name) + + if not self.receiver.declared_type.is_subtype_of(Type.object): + raise JavaTypeError("Type {0} does not have methods".format(self.receiver.declared_type.name)) + + method = self.receiver.declared_type.method_named(self.method_name) + if len(method.argument_types) != len(self.args): + raise JavaTypeError("Wrong number of arguments for {3}.{0}(): expected {1}, got {2}".format(self.method_name, + len(method.argument_types), + len(self.args), + self.receiver.declared_type.name)) + for i in range(len(method.argument_types)): + if not self.args[i].static_type().is_subtype_of(method.argument_types[i]): + raise JavaTypeError("{3}.{0}() expects arguments of type {1}, but got {2}".format(self.method_name, + names(method.argument_types), + typeNames(self.args), + self.receiver.declared_type.name)) + # if self.args[i].type == Type.null and method + self.args[i].check_types() # THIS IS AMAZING <----------- + class ConstructorCall(Expression): """ @@ -64,6 +109,33 @@ 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): + if self.instantiated_type == Type.null: + raise JavaTypeError("Type null is not instantiable") + + if not self.static_type().is_subtype_of(Type.object): + raise JavaTypeError("Type "+self.instantiated_type.name+" is not instantiable") + + 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))) + + constructorString = self.instantiated_type.name + reqArgs = names(self.instantiated_type.constructor.argument_types) + givenArgs = typeNames(self.args) + + for i in range(len(self.args)): + self.args[i].check_types() + + for i in range(len(self.args)): + if 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(constructorString, + reqArgs, + givenArgs)) + + class JavaTypeError(Exception): """ Indicates a compile-time type error in an expression. @@ -74,4 +146,13 @@ class JavaTypeError(Exception): def names(named_things): """ Helper for formatting pretty error messages """ + # str = "(" + return "(" + ", ".join([e.name for e in named_things]) + ")" + + +def typeNames(items): + """ Helper for formatting pretty error messages for type names + """ + return "(" + ", ".join([e.static_type().name for e in items]) + ")" + diff --git a/java-type-checker/java_type_checker/types.py b/java-type-checker/java_type_checker/types.py index 465f7f4..9840fac 100644 --- a/java-type-checker/java_type_checker/types.py +++ b/java-type-checker/java_type_checker/types.py @@ -12,7 +12,15 @@ 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 + elif len(self.direct_supertypes) == 0: + return False + else: + for supertype in self.direct_supertypes: + if supertype.is_subtype_of(other): + return True + return False def is_supertype_of(self, other): """ Convenience counterpart to is_subtype_of(). @@ -72,6 +80,14 @@ class NullType(Type): def __init__(self): super().__init__("null") + def is_subtype_of(self, other): + if not other.is_subtype_of(Type.object): + return False + return True + + def check_for_null_method(self, method_name): + raise NoSuchMethod("Cannot invoke method {0}() on null".format(method_name)) + class NoSuchMethod(Exception): pass diff --git a/python-attr-lookup/.idea/misc.xml b/python-attr-lookup/.idea/misc.xml index 0548357..57d62b3 100644 --- a/python-attr-lookup/.idea/misc.xml +++ b/python-attr-lookup/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/python-attr-lookup/python-attr-lookup.iml b/python-attr-lookup/python-attr-lookup.iml index 01e8e1b..6543de3 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..8b0369b 100644 --- a/python-attr-lookup/src/plang/PythonObject.java +++ b/python-attr-lookup/src/plang/PythonObject.java @@ -51,7 +51,15 @@ 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"); + + List result = new ArrayList<>(); + + result.add(this); + if(type != null) { + result.addAll(this.type.buildMRO()); + } + return result; + } /** @@ -62,7 +70,14 @@ 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"); + + for(PythonObject o : getMRO()) { + if(o.attrs.containsKey(attrName)) { + return o.attrs.get(attrName); + } + } + + throw new PythonAttributeException(this, attrName); } /** @@ -74,7 +89,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 diff --git a/python-attr-lookup/src/plang/PythonType.java b/python-attr-lookup/src/plang/PythonType.java index 4e2be4a..2c503f8 100644 --- a/python-attr-lookup/src/plang/PythonType.java +++ b/python-attr-lookup/src/plang/PythonType.java @@ -41,7 +41,14 @@ public PythonObject getBase() { @Override protected List buildMRO() { - throw new UnsupportedOperationException("not implemented yet"); + + List result = new ArrayList<>(); + result.add(this); + if(this.base != null) { + result.addAll(this.base.buildMRO()); + } + return result; + } /** @@ -49,7 +56,12 @@ protected List buildMRO() { * this PythonType. */ public PythonObject instantiate() { - throw new UnsupportedOperationException("not implemented yet"); + + if(name != null && !name.equals("")) { + return new PythonObject(this); + } + + throw new UnsupportedOperationException("PyObject name cannot be null"); } @Override