From 2e7ba2bea68bffb3e7f0ae066efb789423648894 Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Sat, 21 May 2016 12:28:08 +0600 Subject: [PATCH] Adds order, comparison and composition operators to the Type It allows to compare any two types, store them in STL container such as std::set, use them as a key in std::map and use composition operators during type inference procedure. Operator | is a disjunction-like operator used to get sum of several possible types within a type. For example: 2 | 2 -> 2 2 | 3 -> (2, 3) 2 | * -> (2, *) (Object) | (SmallInt) -> ((Object), (SmallInt)) This operator may be used to aggregate possible types within a linear sequence where several type outcomes are possible: x <- y isNil ifTrue: [ nil ] ifFalse: [ 42 ]. In this case x will have composite type (nil, 42). On the other hand, when dealing with loops we need some kind of a reduction operator that will act as a conjunction: 2 & 2 -> 2 2 & 3 -> (SmallInt) 2 & (SmallInt) -> (SmallInt) & * -> * (SmallInt) & (Object) -> * This operator is used during induction run of the type analyzer to prove that variable does not leave it's local type domain, i.e it's type is not reduced to a *. Issue: #17 --- include/inference.h | 159 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 155 insertions(+), 4 deletions(-) diff --git a/include/inference.h b/include/inference.h index 1cf8964..665aae2 100644 --- a/include/inference.h +++ b/include/inference.h @@ -4,6 +4,8 @@ #include #include +#include + namespace type { using namespace st; @@ -27,16 +29,20 @@ class Type { // tkMonotype (class name) (SmallInt) // tkComposite (class name, ...) (SmallInt, *) // tkArray class name [...] Array[String, *, (*, *), (True, False)] - std::string toString() const; + std::string toString(bool subtypesOnly = false) const; Type(TKind kind = tkUndefined) : m_kind(kind), m_value(0) {} Type(TObject* literal, TKind kind = tkLiteral) { set(literal, kind); } Type(TClass* klass, TKind kind = tkMonotype) { set(klass, kind); } + Type(const Type& copy) : m_kind(copy.m_kind), m_value(copy.m_value), m_subTypes(copy.m_subTypes) {} + void setKind(TKind kind) { m_kind = kind; } TKind getKind() const { return m_kind; } TObject* getValue() const { return m_value; } + typedef std::vector TSubTypes; + void reset() { m_kind = tkUndefined; m_value = 0; @@ -53,11 +59,156 @@ class Type { m_value = klass; } - typedef std::vector TSubTypes; const TSubTypes& getSubTypes() const { return m_subTypes; } - const Type& operator[] (std::size_t index) const { return m_subTypes[index]; } - void addSubType(const Type& type) { m_subTypes.push_back(type); } + void addSubType(const Type& type) { + if (std::find(m_subTypes.begin(), m_subTypes.end(), type) == m_subTypes.end()) + m_subTypes.push_back(type); + } + + const Type& operator [] (std::size_t index) const { return m_subTypes[index]; } + + bool operator < (const Type& other) const { + if (m_kind != other.m_kind) + return m_kind < other.m_kind; + + if (m_value != other.m_value) + return m_value < other.m_value; + + if (m_subTypes.size() != other.m_subTypes.size()) + return m_subTypes.size() < other.m_subTypes.size(); + + for (std::size_t index = 0; index < m_subTypes.size(); index++) { + if (m_subTypes[index] < other.m_subTypes[index]) + return true; + } + + return false; + } + + bool operator == (const Type& other) const { + if (m_kind != other.m_kind) + return false; + + if (m_value != other.m_value) + return false; + + if (m_subTypes != other.m_subTypes) + return false; + + return true; + } + + Type& operator = (const Type& other) { + m_kind = other.m_kind; + m_value = other.m_value; + m_subTypes = other.m_subTypes; + + return *this; + } + + Type operator | (const Type& other) const { return Type(*this) |= other; } + Type operator & (const Type& other) const { return Type(*this) &= other; } + + Type& operator |= (const Type& other) { + if (*this == other) + return *this; + + if (m_kind == tkUndefined) + return *this = other; + + if (m_kind != tkComposite) { + m_subTypes.push_back(*this); + m_kind = tkComposite; + } + + if (other.m_kind != tkComposite) { + addSubType(other); + } else { + for (std::size_t index = 0; index < other.m_subTypes.size(); index++) + addSubType(other[index]); + } + + return *this; + } + + // ? & _ -> ? + // * & _ -> * + + // 2 & 2 -> 2 + // 2 & 3 -> (SmallInt) + // 2 & (SmallInt) -> (SmallInt) + // true & false -> (Boolean) + + // (2, 3) & (SmallInt) -> (SmallInt) + // (SmallInt) & (SmallInt) -> (SmallInt) + // (SmallInt) & (SmallInt) -> (SmallInt) + // (SmallInt) & true -> * + // (SmallInt) & (Object) -> * + + // Array[2,3] & (Array) -> (Array) + // + Type& operator &= (const Type& other) { + if (other.m_kind == tkUndefined || other.m_kind == tkPolytype) + return *this = Type((m_kind == tkUndefined) ? tkUndefined : other.m_kind); + + switch (m_kind) { + case tkUndefined: + case tkPolytype: + return *this = Type((other.m_kind == tkUndefined) ? tkUndefined : m_kind); + + case tkLiteral: + if (m_value == other.m_value) { // 2 & 3 + return *this; // 2 & 2 + } else { + // TODO true & false -> (Boolean) + TClass* const klass = isSmallInteger(m_value) ? globals.smallIntClass : m_value->getClass(); + return *this = (Type(klass) &= other); + } + + case tkMonotype: { + if (m_value == other.m_value) // (SmallInt) & (Object) + return *this; // (SmallInt) & (SmallInt) + + TObject* const otherValue = other.m_value; + TClass* const otherKlass = isSmallInteger(otherValue) ? globals.smallIntClass : otherValue->getClass(); + if (other.m_kind == tkLiteral && m_value == otherKlass) + return *this; // (SmallInt) & 42 + else + return *this = Type(tkPolytype); + } + + case tkArray: + if (other.m_kind == tkArray) { // Array[2, 3] & Array[2, 3] + if (m_value == other.m_value) { // Array[true, false] & Object[true, false] + if (*this == other) + return *this; + else + return *this = Type(m_value, tkMonotype); // Array[2, 3] & (Array) + } + } + return *this = (Type(m_value) &= other); + + case tkComposite: + if (m_subTypes.empty()) { + reset(); + return *this; + } + + Type& result = m_subTypes[0]; + for (std::size_t index = 1; index < m_subTypes.size(); index++) { + result &= m_subTypes[index]; + + if (result.getKind() == tkUndefined || result.getKind() == tkPolytype) + return *this = result; + } + + return *this = result; + } + + reset(); + return *this; + } private: TKind m_kind;