-
Notifications
You must be signed in to change notification settings - Fork 0
/
typecheck.py
77 lines (74 loc) · 3.81 KB
/
typecheck.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import concrete
import math
class TypeException(Exception):
pass
def is_type(value, type, context):
if isinstance(type, concrete.ConcreteUndefined) or isinstance(value, concrete.ConcreteUndefined):
return True
elif isinstance(value, concrete.ConcreteMatter):
return is_type(value.value, type, context)
elif isinstance(type, concrete.ConcreteType):
if type.value == 'Integer':
return isinstance(value, concrete.ConcreteInteger)
elif type.value == 'Decimal':
return isinstance(value, concrete.ConcreteDecimal)
elif type.value == 'String':
return isinstance(value, concrete.ConcreteString)
elif type.value == 'List':
return isinstance(value, concrete.ConcreteList)
elif type.value == 'Set':
return isinstance(value, concrete.ConcreteSet)
elif type.value == 'Object':
return isinstance(value, concrete.ConcreteObject)
elif type.value == 'Function':
return isinstance(value, concrete.ConcreteFunction)
elif type.value == 'ExternalFunction':
return isinstance(value, concrete.ConcreteExternalFunction)
elif type.value == 'Any':
return True
elif isinstance(type, concrete.ConcreteList):
if isinstance(value, concrete.ConcreteList):
# Handle case for both infinite lists
# Min length to compare is the lcm of the lengths of the infinite sequence
if type.is_infinite() and value.is_infinite():
return all(is_type(value[i], type[i], context) for i in range(math.lcm(type.inf_seq_length(), value.inf_seq_length())))
# Handle case where list type is constantly sized
# A constantly sized list type indicates the value must be of the same length
elif not type.is_infinite() and not value.is_infinite():
if len(type) == len(value):
return all(is_type(value[i], type[i], context) for i in range(len(type)))
else:
return False
# Handle case of arbitrary length list type
# This takes place when the type is infinite and the second is not
elif type.is_infinite() and not value.is_infinite():
return all(is_type(value[i], type[i], context) for i in range(len(value)))
else:
return False
else:
return False
elif isinstance(type, concrete.ConcreteSet):
if isinstance(value, concrete.ConcreteSet):
return all(any(is_type(x, y, context) for y in type.value) for x in value.value)
else:
return False
elif isinstance(type, concrete.ConcreteObject):
if isinstance(value, concrete.ConcreteObject):
# Each attribute's type in the type object corresponds with the attributes value in the value object
return all((attribute in value.values and is_type(value.values[attribute], type.types[attribute], context)) for attribute in type.types)
else:
return False
elif isinstance(type, concrete.ConcreteMatter):
return is_type(value, type.value, context)
elif isinstance(type, concrete.ConcreteAlgebraicType):
return any(is_type(value, x, context) for x in type.value)
elif isinstance(type, concrete.ConcreteSelfReference):
return is_type(value, context.scope.get_value(type.value), context)
elif isinstance(type, concrete.ConcreteFunctionType):
return isinstance(value, concrete.ConcreteFunction) or isinstance(value, concrete.ConcreteExternalFunction)
else:
#Case will most likely not work
return (type == value)
def check_type(value, type, context):
if not is_type(value, type, context):
raise TypeException('Expected: ' + str(type) + ' but got: ' + str(value))