forked from CS-327-team/Compilers_project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconcat_slice.py
152 lines (122 loc) · 4.02 KB
/
concat_slice.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from dataclasses import dataclass
from fractions import Fraction
from typing import Union, Mapping
@dataclass
class NumLiteral:
value: Fraction
def __init__(self, *args):
self.value = Fraction(*args)
@dataclass
class BinOp:
operator: str
left: "AST"
right: "AST"
@dataclass
class Boolean:
value: bool
@dataclass
class Variable:
name: str
#defining slicing method for string slicing
def slicing(self,name,start_index:NumLiteral,end_index:NumLiteral):
if start_index>len(name)-1:
raise IndexError
if end_index<=start_index:
raise IndexError
if end_index>len(name):
raise IndexError
else:
string_slice=name[start_index:end_index]
return string_slice
@dataclass
class Let:
var: "AST"
e1: "AST"
e2: "AST"
AST = NumLiteral | BinOp | Variable | Let
Value = Fraction
class InvalidProgram(Exception):
pass
#Modified Binop("+",left,right) for typechecking of strings for concatenation
def typeof(s: AST):
match s:
case Variable(name):
return "type string"
case NumLiteral(value):
return "type Fraction"
case Boolean(value):
return "type boolean"
case BinOp("+", left, right):
if typeof(left) == "type boolean" or typeof(right) == "type boolean":
raise TypeError()
elif typeof(left)!=typeof(right):
raise TypeError()
else:
if typeof(left) == "type string" and typeof(right) == "type string":
return "type string"
else:
return TypeError()
def eval(program: AST, environment: Mapping[str, Value] = None) -> Value:
typeof(program)
if environment is None:
environment = {}
match program:
case NumLiteral(value):
return value
case Variable(name):
return name
case Boolean(value):
return value
case Let(Variable(name), e1, e2):
v1 = eval(e1, environment)
return eval(e2, environment | {name: v1})
case BinOp("+", left, right):
return eval(left, environment) + eval(right, environment)
case BinOp("-", left, right):
return eval(left, environment) - eval(right, environment)
case BinOp("*", left, right):
return eval(left, environment) * eval(right, environment)
case BinOp("/", left, right):
return eval(left, environment) / eval(right, environment)
case BinOp(">", left, right):
return eval(left, environment) > eval(right, environment)
case BinOp("<", left, right):
return eval(left, environment) < eval(right, environment)
case BinOp("==", left, right):
return eval(left, environment) == eval(right, environment)
raise InvalidProgram()
def test_eval():
e1 = NumLiteral(2)
e2 = NumLiteral(7)
e3 = NumLiteral(9)
e4 = NumLiteral(5)
e5 = BinOp("+", e2, e3)
e6 = BinOp("/", e5, e4)
e7 = BinOp("*", e1, e6)
assert eval(e7) == Fraction(32, 5)
def test_let_eval():
a = Variable("a")
e1 = NumLiteral(5)
e2 = BinOp("+", a, a)
e = Let(a, e1, e2)
assert eval(e) == 10
e = Let(a, e1, Let(a, e2, e2))
assert eval(e) == 20
e = Let(a, e1, BinOp("+", a, Let(a, e2, e2)))
assert eval(e) == 25
e = Let(a, e1, BinOp("+", Let(a, e2, e2), a))
assert eval(e) == 25
e3 = NumLiteral(6)
e = BinOp("+", Let(a, e1, e2), Let(a, e3, e2))
assert eval(e) == 22
#Sanity Check for concatenation
def test_concat():
a=Variable("hello")
b=Variable("world")
c=BinOp("+",a,b)
assert eval(c)== "helloworld"
#Sanity Check for slicing
def test_slice(a:Variable):
Variable.slicing(Variable,a,1,4)
test_concat()
test_slice("hello")