Skip to content

Commit

Permalink
Adds order, comparison and composition operators to the Type
Browse files Browse the repository at this point in the history
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)

    <any type> & * -> *
    (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
  • Loading branch information
0x7CFE committed May 21, 2016
1 parent 55e65b4 commit 75fc796
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 6 deletions.
159 changes: 155 additions & 4 deletions include/inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <vm.h>
#include <analysis.h>

#include <algorithm>

namespace type {

using namespace st;
Expand All @@ -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<Type> TSubTypes;

void reset() {
m_kind = tkUndefined;
m_value = 0;
Expand All @@ -53,11 +59,156 @@ class Type {
m_value = klass;
}

typedef std::vector<Type> 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;
Expand Down
5 changes: 3 additions & 2 deletions src/TypeAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using namespace type;

std::string Type::toString() const {
std::string Type::toString(bool subtypesOnly /*= false*/) const {
std::stringstream stream;

switch (m_kind) {
Expand Down Expand Up @@ -33,7 +33,8 @@ std::string Type::toString() const {
break;

case tkArray:
stream << getValue()->cast<TClass>()->name->toString();
if (subtypesOnly)
stream << getValue()->cast<TClass>()->name->toString();
case tkComposite: {
stream << (m_kind == tkComposite ? "(" : "[");

Expand Down

0 comments on commit 75fc796

Please sign in to comment.