-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreter.py
536 lines (499 loc) · 23.4 KB
/
interpreter.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
import re
from syntree import *
from Exceptions import *
import copy
import sys
sys.setrecursionlimit(3000)
#Definicion de estructura CLS
###################################################################################
# Clase CLS: Clase que funciona para evaluar funciones parcialmente. #
# Connstructod: - env: ambiente #
# - lista: de tuplas de la funcion con expresion #
# Salida: - Un objeto CLS #
###################################################################################
class CLS:
def __init__(self,env,lista):
self.env = env
self.lista = lista
self.tipo = 'CLS'
def getLista(self):
return self.lista
def getEnv(self):
return self.env
def remplazar(self,cola):
self.lista = cola
###################################################################################
# Funcion match: Verificacion de que dos nodos hacen match segun su valor y tipo. #
# Entrada: - n1 Nodo 1 #
# - n2 Nodo 2 (Opcional) #
# Salida: - True hizo match #
# - False caso contrario. #
###################################################################################
def match(n1, n2=None):
if isinstance(n1,bool):
return match(n2,NodoGen("BOOLEANO",str(n1)))
elif isinstance(n2,bool):
return match(n1,NodoGen("BOOLEANO",str(n2)))
if isinstance(n2,int) and not isinstance(n2,bool):
return match(n1,NodoGen("ENTERO",str(n2)))
elif isinstance(n1,int) and not isinstance(n1,bool):
return match(n2,NodoGen("ENTERO",str(n1)))
elif isinstance(n2,str):
return match(n1,NodoGen("LISTAVACIA",n2))
elif n1.tipo == 'LISTAPATRON':
return match(n1.hijo[0],n2)
elif n2.tipo == 'LISTAPATRON':
return match(n1,n2.hijo[0])
elif n1.tipo == 'PATRON':
return match(n1.hijo,n2)
elif n2.tipo == 'PATRON':
return match(n1,n2.hijo)
elif n1.tipo == 'BOOLEANO' and n2.tipo == 'BOOLEANO':
if n1.hijo == 'True' and n2.hijo == 'True':
return True
elif n1.hijo == 'False' and n2.hijo == 'False':
return True
else:
return False
elif n1.tipo == 'LISTAVACIA' and n2.tipo == 'LISTAVACIA':
return True
elif n1.tipo == 'VARIABLE' or n2.tipo == 'VARIABLE':
return True
elif n1.tipo == 'LISTA' and n2.tipo == 'LISTA':
return igualdad_listas([],n1,n2)
elif n1.tipo == 'ENTERO' and n2.tipo == 'ENTERO':
if int(n1.hijo) == int(n2.hijo):
return True
else:
return False
else:
return False
###################################################################################
# Funcion replace: Reemplaza el valor asociado a una variable. #
# Entrada: - env Diccionario donde se almacenan los valores de las varibales #
# - x Variable #
# - y Valor asociado #
# Salida: - Diccionario con el valor reemplazado #
###################################################################################
def replace(env,x,y):
env[x] = y
return env
###################################################################################
# Funcion extend: Agrega una nueva entrada al diccionario #
# Entrada: - env Diccionario donde se almacenan los valores de las variables #
# - x Variable #
# - y Valor asociado #
# Salida: - Diccionario un nuevo valor #
###################################################################################
def extend(env,x,y):
if isinstance(y,bool):
env[x] = str(y)
else:
env[x] = y
return env
###################################################################################
# Funcion lookup: Busca el valor asociado a una variable #
# Entrada: - env Diccionario donde se almacenan los valores de las variables #
# - x Variable a buscar. #
# Salida: - Valor asociado si la variable esta en el diccionario #
# - False en caso contrario. #
###################################################################################
def lookup(env,x):
if env.has_key(x):
if env[x] != 'fake':
return env[x]
else:
raise RecursionError('Error de recursion')
else:
return False
###################################################################################
# Funcion is_int: Verifica que dos parametros son enteros #
# Entrada: - x Valor 1 #
# - y Valor 2. #
# Salida: - True si ambos valores son enteros #
# - False en caso contrario. #
###################################################################################
def is_int(x,y):
if isinstance(x, int) and isinstance(y,int):
return True
else:
return False
###################################################################################
# Funcion no_bool: Verifica que dos parametros no son booleanos #
# Entrada: - x Valor 1 #
# - y Valor 2. #
# Salida: - True si ambos valores no son bool. #
# - False en caso contrario. #
###################################################################################
def no_bool(x,y):
if not isinstance(x,bool) and not isinstance(y,bool):
return True
else:
return False
###################################################################################
# Funcion is_bool: Verifica que dos parametros son booleanos #
# Entrada: - x Valor 1 #
# - y Valor 2. #
# Salida: - True si ambos valores son bool. #
# - False en caso contrario. #
###################################################################################
def is_bool(x,y):
if isinstance(x,bool) and isinstance(y,bool):
return True
else:
return False
###################################################################################
# Funcion eval: Calcular el valor asociado a un nodo. #
# Entrada: - env Diccionario con los valores asociados a una variable #
# - nodo: Nodo al cual se le quiere obtener el valor. #
# Salida: - Valor asociado a un nodo. #
###################################################################################
def eval(env,nodo, h=None):
if h == None:
if nodo.tipo == '':
nodo = nodo.hijo
return eval(env,nodo)
elif nodo.tipo == 'PAREN':
nodo = nodo.hijo
return eval(env,nodo)
elif nodo.tipo == 'LISTAVACIA':
return nodo
elif nodo.tipo == 'BOOLEANO':
if nodo.hijo == 'True':
return True
else:
return False
elif nodo.tipo == 'LISTA':
k1 = eval(env,nodo.hijo1)
k2 = eval(env,nodo.hijo2)
if isinstance(k1,int) and not isinstance(k1,bool):
nod1 = NodoGen('ENTERO',k1)
elif isinstance(k1,bool):
nod1 = NodoGen('BOOLEANO',str(k1))
elif isinstance(k1,str):
nod1 = NodoGen('LISTAVACIA',k1)
else:
nod1 = k1
if isinstance(k2,int) and not isinstance(k2,bool):
nod2 = NodoGen('ENTERO',k2)
elif isinstance(k2,bool):
nod2 = NodoGen('BOOLEANO',str(k2))
elif isinstance(k2,str):
nod2 = NodoGen('LISTAVACIA',k2)
else:
nod2 = k2
return NodoBin('LISTA',nod1,nod2)
elif nodo.tipo == 'MENOR':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(x,y) and no_bool(x,y):
return x < y
else:
raise TypeError('En la operacion de mayor.')
elif nodo.tipo == 'MAYOR':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(x,y) and no_bool(x,y):
return x > y
else:
raise TypeError('En la operacion de menor.')
elif nodo.tipo == 'NEGATIVO':
x = eval(env,nodo.hijo2)
if isinstance(x,int) and no_bool(x,y):
return -x
elif nodo.tipo == 'NO':
x = eval(env,nodo.hijo2)
if isinstance(x,bool):
return (not x)
else:
raise TypeError('En la negacion')
elif nodo.tipo == 'MENOROIGUAL':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(x,y) and no_bool(x,y):
return x <= y
else:
raise TypeError('En la operacion de menor o igual.')
elif nodo.tipo == 'MAYOROIGUAL':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(x,y) and no_bool(x,y):
return x >= y
else:
raise TypeError('En la operacion de mayor.')
elif nodo.tipo == 'DISTINTO':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if (is_int(x,y) and no_bool(x,y)):
return x != y
elif is_bool(x,y):
return x != y
else:
raise TypeError('En la operacion de diferencia.')
elif nodo.tipo == 'IGUAL':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if (is_int(x,y) and no_bool(x,y)):
return x == y
elif is_bool(x,y):
return x == y
else:
raise TypeError('En la operacion de igualdad.')
elif nodo.tipo == 'ENTERO':
return int(nodo.hijo)
elif nodo.tipo == 'VARIABLE':
if lookup(env,nodo.hijo):
return lookup(env,nodo.hijo)
else:
raise LookUpError('Variable "' +str(nodo.hijo) + '" no declarada.')
elif nodo.tipo == 'MAS':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(bajar(x),y) and no_bool(x,y):
return bajar(x) + y
else:
raise TypeError('En la operacion de suma.')
elif nodo.tipo == 'MENOS':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(bajar(x),y) and no_bool(x,y):
return bajar(x) - y
else:
raise TypeError('En la operacion de resta.')
elif nodo.tipo == 'PRODUCTO':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(bajar(x),y) and no_bool(x,y):
return bajar(x)*y
else:
raise TypeError('En la operacion de producto.')
elif nodo.tipo == 'COCIENTE':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_int(bajar(x),y) and no_bool(x,y):
if y == 0:
raise ZeroDivisionError('Division entre Cero.')
else:
return bajar(x) / y
else:
raise TypeError('En la operacion de division.')
elif nodo.tipo == 'OR':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_bool(x,y):
return x or y
else:
raise TypeError('En or logico')
elif nodo.tipo =='AND':
x = eval(env,nodo.hijo1)
y = eval(env,nodo.hijo2)
if is_bool(x,y):
return x and y
else:
raise TypeError('En and logico')
elif nodo.tipo == 'PATRON':
return eval(env,nodo.hijo)
elif nodo.tipo == 'IF':
if eval(env,nodo.hijo1):
return eval(env, nodo.hijo2)
else:
return eval(env,nodo.hijo3)
elif nodo.tipo == 'LET':
if nodo.hijo1.hijo.tipo == 'LISTA':
if nodo.hijo2.tipo == 'LISTA':
members = []
members.append(nodo.hijo1.hijo.hijo1.hijo.hijo) #(LISTA (PATRON (VARIABLE a)
members = members + getMembers([],nodo.hijo1.hijo.hijo2)
for i in members:
extend(env,i,'fake')
env1 = env
memV1 = binCLS([],nodo.hijo2)
if len(members) == len(memV1):
for k in range(len(members)):
replace(env1,members[k],memV1[k])
return apply(eval(env1,eval(env1,nodo.hijo3.hijo.hijo1.hijo1)),nodo.hijo3.hijo.hijo2)
elif len(members) < len(memV1):
resto = []
i = 0
for k in range(len(members)-1):
i = k
replace(env1,members[k],memV1[k])
for k in range(len(memV1) - i):
if i+1 == len(memV1):
break
else:
resto.append(memV1[i+1])
i += 1
replace(env1,members[len(members)-1],resto)
return eval(env1,nodo.hijo3)
else:
raise MatchingError('.')
else:
raise MatchingError('.')
else:
env1 = extend(copy.deepcopy(env),nodo.hijo1.hijo.hijo,'fake')
v1 = eval(env1,nodo.hijo2)
return eval(replace(env1,nodo.hijo1.hijo.hijo,v1),nodo.hijo3)
elif re.match(nodo.tipo,'FUN'):
hijos = hijos_fun(nodo)
tuplas = []
for i in hijos: # i : NodoFunH
if len(i.hijo1.hijo) > 1: # chequeo multiples valores
nueva_fun = transformar(nodo)
return eval(env,nueva_fun)
else:
tuplas.append((i.hijo1.hijo[0],i.hijo2)) # Se toma el unico hijo de NLP
clausura = CLS(env,tuplas)
return clausura
elif re.match(nodo.tipo,'APLICAR'):
return apply(eval(env,nodo.hijo1),eval(env,nodo.hijo2))
else:
return nodo
###################################################################################
# Clase PatExp: Objeto que consta de dos elementos, una lista con los patrones #
# de una funciona y su correspondiente expresion #
# con objetos PatExp #
# Constructor: - Lista de patrones y Expresion #
# Salida: - Objeto del tipo PatExp #
###################################################################################
class PatExp:
def __init__(self,lista,exp):
self.lista = lista
self.exp = exp
###################################################################################
# Funcion getPatrones: procesa una lista de funciones hijos y devuelve otra lista #
# con objetos PatExp #
# Entrada: - Lista de funciones hijos #
# Salida: - Retorna una lista con objetos PatExp #
###################################################################################
def getPatrones(hijos):
ref = []
for i in hijos:
patexp = PatExp([],None)
for j in i.hijo1.hijo:
patexp.lista.append(j)
patexp.exp = i.hijo2
ref.append(patexp)
return ref
###################################################################################
# Funcion transformar: Convierte una funcion con varios patrones en una que un #
# solo patron que va a los demas patrones. #
# Entrada: - nodofun Nodo tipo NodoFun que contiene todos los patrones de la FUN. #
# Salida: - Funcion aplanada con un solo argumento. #
###################################################################################
def transformar(nodofun):
# Se obtienen los patrones
patrones = getPatrones(nodofun.hijo)
# Se agrega el primer elemento de patron
length = len(patrones[0].lista)
nuevoarb = NodoFunP('FUN',[NodoFunH(NodoListaPatron('LISTAPATRON',[patrones[0].lista[0]]),NodoFunP('FUN',[NodoFunH(NodoListaPatron('LISTAPATRON',patrones[0].lista[1:length]),patrones[0].exp)]))]) #p
for i in range(len(patrones)):
if i == len(patrones)-1:
break
else:
if match(patrones[0].lista[0],patrones[i+1].lista[0]):
# Se lo agrego al hijo del primer hijo de p
nuevoarb.hijo[0].hijo2.hijo.append(NodoFunH(NodoListaPatron('LISTAPATRON',patrones[i+1].lista[1:length]),patrones[i+1].exp))
else:
nuevoarb.hijo.append(NodoFunH(NodoListaPatron('LISTAPATRON',[patrones[i+1].lista[0]]),NodoFunP('FUN',[NodoFunH(NodoListaPatron('LISTAPATRON',patrones[i+1].lista[1:length]),patrones[i+1].exp)])))
return nuevoarb
def hijos_fun(arb_fun):
return arb_fun.hijo
###################################################################################
# Funcion no_bool: Verifica que dos parametros no son booleanos #
# Entrada: - x Valor 1 #
# - y Valor 2. #
# Salida: - True si ambos valores no son bool. #
# - False en caso contrario. #
###################################################################################
def bajar(nodo):
if isinstance(nodo,int):
return int(nodo)
elif isinstance(nodo,str):
return nodo
elif nodo.tipo == 'ENTERO':
return bajar(nodo.hijo)
elif nodo.tipo == 'PATRON':
return bajar(nodo.hijo)
elif nodo.tipo == 'VARIABLE':
return bajar(nodo.hijo)
###################################################################################
# Funcion no_bool: Verifica que dos parametros no son booleanos #
# Entrada: - x Valor 1 #
# - y Valor 2. #
# Salida: - True si ambos valores no son bool. #
# - False en caso contrario. #
###################################################################################
def igualdad_listas(lista,a,b):
if match(a.hijo1,b.hijo1):
lista.append((bajar(a.hijo1),b.hijo1))
if a.hijo2.tipo == 'LISTA' and b.hijo2.tipo == 'LISTA':
igualdad_listas(lista,a.hijo2,b.hijo2)
elif a.hijo2.tipo != 'LISTA' and b.hijo2.tipo == 'LISTA':
if match(a.hijo2,b.hijo2):
lista.append((bajar(a.hijo2),b.hijo2))
else:
lista = []
else:
if match(a.hijo2,b.hijo2):
lista.append((bajar(a.hijo2),b.hijo2))
else:
lista = []
if lista == []: return False
return lista
else:
lista = []
return False
###################################################################################
# Funcion apply: esta funcion recibe un CLS y una expresion #
# Entrada: - cls Clausura #
# - v Expresion #
# Salida: - Devuelve el eval de una expresion con el ambiente modificado. #
###################################################################################
def apply(cls,v):
if isinstance(cls,CLS):
ltuplas = cls.getLista()
head = ltuplas[0]
if isinstance(match(head[0],v),list):
b = match(head[0],v)
for i in range(len(b)):
cls.env[b[i][0]] = b[i][1]
return eval(extend(copy.deepcopy(cls.env),bajar(head[0]),v),head[1])
if match(head[0],v):
return eval(extend(copy.deepcopy(cls.env),bajar(head[0]),v),head[1])
else:
ltuplas = ltuplas[1:len(ltuplas)] # Cola de la lista
cls_cola = CLS(cls.env,ltuplas)
if len(cls_cola.lista) == 0:
raise MatchingError('no hubo match con '+ str(v) + ' ' + str(head[0]))
else:
return apply(cls_cola,v)
else:
raise ApplyError(' ocurrio un error de aplicacion con '+ str(v) + ' y '+ str(cls))
###################################################################################
# Funcion binCLS: recibe una lista vacia y un arbol lista #
# Entrada: - lista vacia #
# - arbol lista #
# Salida: - Devuelve una lista con todos los elementos de un arbol lista #
###################################################################################
def binCLS(lista,nodolista):
if nodolista.hijo2.tipo == 'LISTA':
lista.append(nodolista.hijo1)
return binCLS(lista,nodolista.hijo2)
else:
lista.append(nodolista.hijo1)
lista.append(nodolista.hijo2)
return lista
###################################################################################
# Funcion getMembers: recibe una lista vacia y un nodo #
# Entrada: - lista vacia #
# - arbol lista #
# Salida: - Devuelve una lista con todos los elementos de un arbol lista #
###################################################################################
def getMembers(lista,nodo):
if nodo.hijo.tipo != 'LISTA':
lista.append(nodo.hijo.hijo)
return lista
else:
lista.append(nodo.hijo.hijo1.hijo.hijo)
return getMembers(lista,nodo.hijo.hijo2)