Skip to content

Commit

Permalink
Make original code work
Browse files Browse the repository at this point in the history
  • Loading branch information
pressureless committed Jun 22, 2021
1 parent 3f54b48 commit 6f013e6
Showing 1 changed file with 153 additions and 126 deletions.
279 changes: 153 additions & 126 deletions airtight/hindley_milner_ast.py
Expand Up @@ -21,6 +21,129 @@
# which comprise the little language for which types
# will be inferred




#=======================================================#
# Types and type constructors

class TypeVariable(object):
"""A type variable standing for an arbitrary type.
All type variables have a unique id, but names are only assigned lazily,
when required.
"""

next_variable_id = 0

def __init__(self):
self.id = TypeVariable.next_variable_id
TypeVariable.next_variable_id += 1
self.instance = None
self.__name = None

next_variable_name = 'a'

def _getName(self):
"""Names are allocated to TypeVariables lazily, so that only TypeVariables
present
"""
if self.__name is None:
self.__name = TypeVariable.next_variable_name
TypeVariable.next_variable_name = chr(ord(TypeVariable.next_variable_name) + 1)
return self.__name

name = property(_getName)

def __str__(self):
if self.instance is not None:
return str(self.instance)
else:
return str(self.name)

def __repr__(self):
return "TypeVariable(id = {0})".format(self.id)


class TypeOperator(object):
"""An n-ary type constructor which builds a new type from old"""

def __init__(self, name, types):
self.name = name
self.types = types

def __str__(self):
num_types = len(self.types)
# print(self.__class__.__name__, self.postfix, len(self.types))

if num_types == 0:
return str(self.name)
elif num_types == 1:
return '[{0}]'.format(str(self.types[0]))
elif num_types == 2:
return "({0} {1} {2})".format(str(self.types[0]), str(self.name), str(self.types[1]))
else:
return "{0} {1}" % (str(self.name), ' '.join(map(str, self.types)))


class Function(TypeOperator):
"""A binary type constructor which builds function types"""

def __init__(self, from_type, to_type):
super(Function, self).__init__("->", [from_type, to_type])

class Union(object):
def __init__(self, *types):
self.types = types

def __str__(self):
return ' | '.join(str(t) for t in self.types)

def Multi_Apply(ident, args):
if len(args) == 1:
return Apply(ident, args[0])
else:
return Apply(Multi_Apply(ident, args[:-1]), args[-1])

def Multi_Lambda(args, body, expected=None):
if not expected:
expected = None
rest_expected = []
else:
rest_expected = expected[1:]
expected = expected[0]

if len(args) > 1:
return Lambda(
args[0],
Multi_Lambda(args[1:], body, expected=rest_expected),
expected=expected)
elif len(args) == 0:
return LambdaNoArgs(body)
else:
return Lambda(args[0], body, expected=expected, return_expected=None if rest_expected == [] else rest_expected[0])

def Multi_Function(types):
if len(types) == 2:
return Function(types[0], types[1])
else:
return Function(types[0], Multi_Function(types[1:]))

class List(TypeOperator):
"""Builds list types"""

def __init__(self, element_type):
super(List, self).__init__("list", [element_type])

def __str__(self):
return '[{0}]'.format(str(self.types[0]))

# Basic types are constructed with a nullary type constructor
Integer = TypeOperator("Integer", []) # Basic integer
Bool = TypeOperator("Bool", []) # Basic bool
Float = TypeOperator("Float", []) # Basic float
String = TypeOperator("String", []) # Basic string

class Top:
a_type = None
a_native = False
Expand Down Expand Up @@ -109,17 +232,24 @@ def __str__(self):
return '{name}@{type}'.format(name=str(self.name), type=str(self.a_type))

class anInteger(Ident):
pass
def __init__(self, name, a_type=Integer):
self.name = name
self.a_type = a_type

class aString(Ident):
def __init__(self, name):
self.name = "'%s'" % name
def __init__(self, name, a_type=String):
self.name = name
self.a_type = a_type

class aBoolean(Ident):
pass
def __init__(self, name, a_type=Bool):
self.name = name
self.a_type = a_type

class aFloat(Ident):
pass
def __init__(self, name, a_type=Float):
self.name = name
self.a_type = a_type

class Apply(Top):
"""Function application"""
Expand Down Expand Up @@ -200,127 +330,6 @@ def __str__(self):



#=======================================================#
# Types and type constructors

class TypeVariable(object):
"""A type variable standing for an arbitrary type.
All type variables have a unique id, but names are only assigned lazily,
when required.
"""

next_variable_id = 0

def __init__(self):
self.id = TypeVariable.next_variable_id
TypeVariable.next_variable_id += 1
self.instance = None
self.__name = None

next_variable_name = 'a'

def _getName(self):
"""Names are allocated to TypeVariables lazily, so that only TypeVariables
present
"""
if self.__name is None:
self.__name = TypeVariable.next_variable_name
TypeVariable.next_variable_name = chr(ord(TypeVariable.next_variable_name) + 1)
return self.__name

name = property(_getName)

def __str__(self):
if self.instance is not None:
return str(self.instance)
else:
return str(self.name)

def __repr__(self):
return "TypeVariable(id = {0})".format(self.id)


class TypeOperator(object):
"""An n-ary type constructor which builds a new type from old"""

def __init__(self, name, types):
self.name = name
self.types = types

def __str__(self):
num_types = len(self.types)
# print(self.__class__.__name__, self.postfix, len(self.types))

if num_types == 0:
return str(self.name)
elif num_types == 1:
return '[{0}]'.format(str(self.types[0]))
elif num_types == 2:
return "({0} {1} {2})".format(str(self.types[0]), str(self.name), str(self.types[1]))
else:
return "{0} {1}" % (str(self.name), ' '.join(map(str, self.types)))


class Function(TypeOperator):
"""A binary type constructor which builds function types"""

def __init__(self, from_type, to_type):
super(Function, self).__init__("->", [from_type, to_type])

class Union(object):
def __init__(self, *types):
self.types = types

def __str__(self):
return ' | '.join(str(t) for t in self.types)

def Multi_Apply(ident, args):
if len(args) == 1:
return Apply(ident, args[0])
else:
return Apply(Multi_Apply(ident, args[:-1]), args[-1])

def Multi_Lambda(args, body, expected=None):
if not expected:
expected = None
rest_expected = []
else:
rest_expected = expected[1:]
expected = expected[0]

if len(args) > 1:
return Lambda(
args[0],
Multi_Lambda(args[1:], body, expected=rest_expected),
expected=expected)
elif len(args) == 0:
return LambdaNoArgs(body)
else:
return Lambda(args[0], body, expected=expected, return_expected=None if rest_expected == [] else rest_expected[0])

def Multi_Function(types):
if len(types) == 2:
return Function(types[0], types[1])
else:
return Function(types[0], Multi_Function(types[1:]))

class List(TypeOperator):
"""Builds list types"""

def __init__(self, element_type):
super(List, self).__init__("list", [element_type])

def __str__(self):
return '[{0}]'.format(str(self.types[0]))

# Basic types are constructed with a nullary type constructor
Integer = TypeOperator("Integer", []) # Basic integer
Bool = TypeOperator("Bool", []) # Basic bool
Float = TypeOperator("Float", []) # Basic float
String = TypeOperator("String", []) # Basic string




#=======================================================#
Expand Down Expand Up @@ -479,6 +488,22 @@ def find_type(expected, env):
elif isinstance(expected, TypeVariable):
return expected

def is_integer_literal(name):
"""Checks whether name is an integer literal string.
Args:
name: The identifier to check
Returns:
True if name is an integer literal, otherwise False
"""
result = True
try:
int(name)
except:
result = False
return result

def getType(name, env, non_generic):
"""Get the type of identifier name from the type environment env.
Expand All @@ -497,6 +522,8 @@ def getType(name, env, non_generic):
return [fresh(t, non_generic) for t in type_]
else:
return fresh(type_, non_generic)
# elif is_integer_literal(name):
# return Integer
else:
if isinstance(name, Ident):
name = name.name
Expand Down

0 comments on commit 6f013e6

Please sign in to comment.