-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsemantic_checker.py
executable file
·652 lines (564 loc) · 34.5 KB
/
semantic_checker.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
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
from semantic_checker_utils import *
from our_ast import *
import visitor
#from parser import *
#from parser import main
#from lexer import main as lex_main
class TypeError(Exception):
#clase para reportar los errores de tipos
def __init__(self,wrongs):
super()
self.wrongs = wrongs
def __show__(self):
print("TypeError:")
for mistake in self.wrongs:
print(mistake)
class TypeChecker():
#Clase con todos los vititors para chequeo de tipos y de scope
def __init__(self, program_node):
self.program_node = program_node
self.wrongs = [] #Lista de strings con los errores detectados, realmente debido a que solo tenemos que detectar un error a la vez siempre devolvemos la lista con un solo errror excepto en casos super claros que podemos detectar mas de uno en un mismo analisis
def check(self):
#Metodo que pone a correr los chequeos semanticos y de tipos, pone a correr el patron visit visitando el nodo program que va a visitar todo recursivamente.
self.types_graph = TypesGraph(self.program_node)
self.visit(self.program_node)
@visitor.on('node')
def visit(self,node , scope):
pass
#casos de las constantes de visitar, aqui revisar que estoy devolviendo como string el tipo de las clases bases, revisar que esten bien escritos
@visitor.when(BoolNode)
def visit(self,node,scope):
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(StringNode)
def visit(self,node,scope):
node.static = "String"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "String"
@visitor.when(IntegerNode)
def visit(self,node,scope):
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(ProgramNode)
def visit(self,node,scope = None):
#visita inicial que va a visitar todas las clases
## Aqui creamos el types graph que hace chequeos de herencia y demas y es una estructura que acomoda el manejo de tipos, ver el modulo chequer utils para mas detalles
#seed_scope = Scope(parent = None,types_graph = self.types_graph,)
for classs in node.classes:
hes_scope = Scope(parent = None,types_graph = self.types_graph, current_class = classs.name)
self.visit(classs,hes_scope)
@visitor.when(ClassNode)
def visit(self,node, scope):
attrs = node.attrs
methods = node.methods
for attr in attrs:
#Aqui al visitar los atributos vamos a anadirlos al scope y despues este mismo scope lo pasamos al chequeo de metodos
self.visit(attr,scope)
for method in methods:
#creamos un nuevo escope porque en la declaracion de un metodo los parametros ocultan variables anteriores
new_scope = scope.create_child_scope()
self.visit(method,new_scope)
@visitor.when(MethodNode)
def visit(self,node, scope):
params = node.params
rt = node.return_type
body = node.body
for param in params:
#Aqui con las visitas se agregan al scope los parametros
self.visit(param,scope)
body_type = self.visit(body,scope)
if not scope.conform(body_type, rt):
mistake = "El tipo de retorno del cuerpo de la funcion con nombre " + str(node.name) + " en la clase " + str(scope.current_class) +" no se conforma con el tipo de retorno declarado de la funcion, ella espera retornar tipo " + str(rt) + " y retorna " + str(body_type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
@visitor.when(AttrNode)
def visit(self,node, scope):
var_name = node.name
var_type = node.type
var_value = node.value
if not scope.class_exist(var_type):
mistake = "Line:" + str(node.line )+ "Se esta intentando crear una variable de tipo " +str(var_type) + " que no existe en el modulo de COOL actual"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if scope.is_local(var_name):
#Si la variable esta definido en este mismo scope hay problemas de redifinicion, para evitar estos problemas es que creamos distintos scope para segmentos que "oculten" los scope anteriores.
mistake = "Line:" + str(node.line) +" La variable con nombre " + str(var_name) + "en la clase " + str(scope.current_class) + " se redefine 2 veces, cosa que no esta permitida"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if var_value != None:
right_type = self.visit(var_value, scope)
if not (scope.conform(right_type,var_type)):
#Significa que el lado derecho que se le asigna a la variable no tiene un tipo que se conforme al tipo esperado en la inicializacion de la varaible
mistake = "Line:" + str(node.line) +" La variable de nombre " +str(var_name) + "en la clase " + str(scope.current_class) + " que tiene tipo declarado " + str(var_type) + " no se conforma con el tipo estatico de la expresion que le asigna valor que tiene tipo = " + str(right_type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
scope.define_variable(var_name,var_type)
@visitor.when(ParamNode)
def visit(self,node,scope):
var_name = node.name
var_type = node.type
#var_value = node.value
if not scope.class_exist(var_type):
mistake = "Line:" + str(node.line) + "Se esta pasando como parametro una variable de tipo " + str(var_type) + " que no existe en el modulo de COOL actual"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if scope.is_local(var_name):
#Si la variable esta definido en este mismo scope hay problemas de redifinicion, para evitar estos problemas es que creamos distintos scope para segmentos que "oculten" los scope anteriores.
mistake = "Line:" + str(node.line) +" El parametro con nombre " + str(var_name) + "en la clase " + str(scope.current_class) + " se define 2 veces en la misma declaracion del metodo, cosa que no esta permitida"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
scope.define_variable(var_name,var_type)
@visitor.when(IdNode)
def visit(self,node,scope):
var_name = node.name
#scope.__show__()
if not scope.is_defined(var_name):
#Ver aqui que estoy haciendo este ID, puede ser una variable definida en el scope, o puede ser un atributo heredado de alguien, por eso lo buscon tambien con el find que me da el tipo de los atributos heredados
#Tener en cuenta que el scope como lo planteamos no detecta las varaibles de tipos heredadas, por eso es que las buscamos tambien en la herencia con el type graph
if not scope.find_attr(scope.current_class,var_name):
#Si no es una varaible del scope ni heredada no existe y por tanto reportamos el error
mistake = "Line:" + str(node.line) + " La variable de nombre " +str(var_name) + " en la clase " + str(scope.current_class) + " se usa pero no esta definida anteriormente, cosa que no esta permitida"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
#En este punto significa que la variable no estaba en el scope pero si era una variable heredada por lo que devolvemos el tipo estatico de la variable heredada.
result = scope.find_attr(scope.current_class,var_name)
node.static = result
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return result
result = scope.get_variable_info(var_name).type
node.static = result
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return result # Aqui es que la variable si esta en el scope por lo que la buscamos y devolvemos el .type
@visitor.when(AssigNode)
def visit(self,node, scope):
var_name = node.name
var_value = node.value
if not scope.is_defined(var_name):
mistake = "Line:" + str(node.line) + " La variable con nombre " + str(var_name) + " en la clase " + str(scope.current_class) + " se le asigna un valor sin antes estar inicializada."
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
var_type = scope.get_variable_info(var_name).type
rigth_type = self.visit(var_value,scope)
if not scope.conform(rigth_type, var_type):
mistake = "Line:" + str(node.line) + " La variable con nombre " + str(var_name) + " en la clase " + str(scope.current_class) + " se le asigna el tipo " + str(rigth_type) + " que no se conforma con el tipo declarado de dicha variable."
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = rigth_type
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return rigth_type
@visitor.when(LetNode)
def visit(self,node, scope):
body = node.body
inits = node.initializers
current_scope = scope.create_child_scope()
for init in inits:
#Aqui visito los inits por lo que agrego las varaibles al n_scope, que creo uno nuevo porque el let oculta definiciones pasadas.
self.visit(init,current_scope)
n_scope = current_scope.create_child_scope()
current_scope = n_scope
return_type = self.visit(body,current_scope) # El tipo del body del let
node.static = return_type
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return return_type
@visitor.when(DispatchSelfNode)
def visit(self,node,scope):
args = node.args
m_name = node.name
args_types = []
for arg in args:
#Aqui visito las expresiones que tiene como parametros el llamado al metodo estatico, el visit devuelve como string el tipo de las expresiones, los guardo en orden
args_types.append(self.visit(arg,scope))
signature = scope.find_method(scope.current_class,m_name)
if signature == False:
#TODO escribir bien el mistake en este caso, y recordar arreglar todos los mistakes para ensenar la linea de error
mistake = "Line:" + str(node.line) + " En la clase" + str(scope.current_class) +"no existe el metodo con nombre " + str(m_name )+ " y se esta llamando en esta linea"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if len(args_types) != len(signature) - 1:
#Ver que el signature tiene len igual a ala cantidad de parametros +1 al tener tambien el de tipo de retorno, por lo que si no tienen la misma cantidad de parametros hay algo mal.
mistake = "Line:" + str(node.line) + " En el llamado al metodo con nombre " + str(m_name) +" la cantidad de argumentos pasados = " +str(len(args_types)) + " no se conforma con la cantidad de argumentos esperados por el metodo = " + str(len(signature) -1 )
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
for i in range(len(args_types)):
sig_type = signature[i][1]#Tipo que espera la funcion tenga el parametro i
ex_type = args_types[i] # Tipo statico que tiene la expresion que se paso como parametro i.
if not scope.conform(ex_type,sig_type):
mistake = "Line:" + str(node.line) +"No se conforma el tipo de la expresion = " +str(ex_type)+ "del parametro "+ str(i+1)+ " con el tipo que espera el llamado al metodo = " + str(sig_type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
#Recordar aqui que si el tipo de retorno de la funcion es selftype devolvemos el tipo de la clase que llamo al metodo que en este caso al ser un selfdispatch es scope.currentclass
if signature[len(signature) -1][1] == "SELF_TYPE":
node.static = scope.current_class
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return scope.current_class
node.static = signature[len(signature) -1][1]
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return signature[len(signature) -1][1]
@visitor.when(DispatchStaticNode)
def visit(self, node,scope):
args = node.args
m_name = node.name
t0 = self.visit(node.expr, scope)#Aqui tengo el tipo estatico de la expresion al cual se le esta haciendo el llamado.
args_types = []
for arg in args:
args_types.append(self.visit(arg, scope))#Aqui capturo el tipo estatico de las expresiones pasadas como parametros a la funcion.
signature = scope.find_method(t0, m_name)#Capturo la signatura de la funcion, que es un llamado a la func m_name en la clase t0.
if signature == False:
# TODO escribir bien el mistake en este caso, y recordar arreglar todos los mistakes para ensenar la linea de error
mistake = "Line:" + str(node.line) + " Se hace un llamado al metodo de nombre " + str(m_name)+" de la clase " + str(t0) + " pero esta clase no tiene tal metodo"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if len(args_types) != len(signature) - 1:
mistake = "Line:" + str(node.line) +" En el llamado al metodo de nombre "+ str(m_name)+ " la cantidad de argumentos pasados = " + str(len(args_types)) +" no se conforma con la cantidad de argumentos esperados = " + str(len(signature ) -1)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
for i in range(len(args_types)):
sig_type = signature[i][1]
ex_type = args_types[i]
if not scope.conform(ex_type, sig_type):
mistake = "Line:" + str(node.line) +" En el llamado al metodo de nombre " + (str(m_name)) +" No se conforma en el parametro " + str(i+1) + " el tipo de la expresion que es "+ str(ex_type)+ " con el tipo que espera el llamado al metodo que es " + str(sig_type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
# Recordar aqui que si el tipo de retorno de la funcion es selftype devolvemos el tipo de la clase que llamo al metodo que en este caso al ser un static dispatch es t0
if signature[len(signature) - 1][1] == "SELF_TYPE":
node.static = t0
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return t0
node.static = signature[len(signature) - 1][1]
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return signature[len(signature) - 1][1]
@visitor.when(DispatchInheritsNode)
def visit(self,node,scope):
args = node.args
m_name = node.name
t0 = self.visit(node.expr, scope)
args_types = []
if not scope.conform(t0,node.type):
#Ver aqui que el tipo estatico de la expresion es t0 y se supone que node.type sea un ancestro de t0 para poder llamar a la funcion.
mistake = "Line:" + str(node.line) +" Se hace un llamado de herencia al metodo de nombre " + str(m_name) + " en la clase " + str(t0) + " , pero esta clase no es heredera del tipo declarado para el llamado " + str(node.type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
for arg in args:
args_types.append(self.visit(arg, scope))
signature = scope.find_method(node.type, m_name)#Ver que la signatura de la funcion es la que tiene la clase node.type con nombre de funcion m_name.
if signature == False:
# TODO escribir bien el mistake en este caso, y recordar arreglar todos los mistakes para ensenar la linea de error
mistake = "Line:" + str(node.line) + " Se hace un llamado al metodo de nombre " + str(m_name) + " de la clase " + str(node.type )+" , pero dicha clase no tiene el metodo llamado"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if len(args_types) != len(signature) - 1:
mistake = "Line:" + str(node.line) + " En el llamado al metodo de nombre "+ str(m_name) + " la cantidad de argumentos pasados = " + str(len(args_types))+" no se conforma con la cantidad de argumentos esperados por el metodo = " + str(len(signature) - 1)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
for i in range(len(args_types)):
sig_type = signature[i][1]
ex_type = args_types[i]
if not scope.conform(ex_type, sig_type):
mistake = "Line:" + str(node.line) + " En el llamado al metodo de nombre = " + str(m_name) + " en el parametro " + str(i+1) + "el tipo de la expresion = " + str(ex_type)+ " no se conforma con el tipo esperado por el metodo = " + str(sig_type)
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
# Recordar aqui que si el tipo de retorno de la funcion es selftype devolvemos el tipo de la clase que en este caso al ser un inherit dispatch es de tipo t0
if signature[len(signature) - 1][1] == "SELF_TYPE":
node.static = t0
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return t0
node.static = signature[len(signature) - 1][1]
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return signature[len(signature) - 1][1]
@visitor.when(SelfNode)
def visit(self,node, scope):
#Si es un self como id el tipo de la expresion es el tipo de la clase actual en la que esta el scope
node.static = scope.current_class
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return scope.current_class
@visitor.when(SelfTypeNode)
def visit(self,node, scope):
#Si es un selftipe como id el tipo de la expresion es el tipo de la clase actual en la que esta el scope
node.static = scope.current_class
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return scope.current_class
@visitor.when(IfNode)
def visit(self,node,scope):
condition_type = self.visit(node.condition,scope)
if condition_type != "Bool":
mistake = "Line:" + str(node.line) + " en este if la condicion no es de tipo estatico booleano,su tipo estatico es = " +str (condition_type)+ " cosa que no es permitida"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
typeA = self.visit(node.true_body,scope)
typeB = self.visit(node.false_body,scope)
node.static = scope.LCA(typeA,typeB)
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return scope.LCA(typeA,typeB)
@visitor.when(BlockNode)
def visit(self,node,scope):
final_type = "Object" # parche que no se si haga falta pero bueno, es que si el body es vacio, que no creo que pase nunca, entonces el finaltype no existe, devuelve Object en ese caso.
for expre in node.body:
final_type = self.visit(expre,scope)
node.static = final_type
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return final_type
@visitor.when(WhileNode)
def visit(self,node,scope):
condition_type = self.visit(node.condition,scope)
if condition_type != "Bool":
mistake = "Line:" + str(node.line) + "este while tiene como condicion una expresion que no tiene como tipo estatico un bool, tiene tipo estatico = " + str(condition_type )+" lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
self.visit(node.body,scope)
node.static = "Object"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Object"
@visitor.when(IsVoidNode)
def visit(self,node,scope):
self.visit(node.expr,scope)
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(LessOrEqualNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador de menor o igual recibe a la izquierda un tipo estatico que no es Int, tiene tipo estatico " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) +" este operador menor o igual recibe a la derecha un tipo estatico que no es Int , tiene tipo estatico " + str(rtype)+" lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(LessThanNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador menor estricto recibe una expresion a la izquierda que no tiene tipo estatico Int, tiene tipo estatico = " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) + " este operador menos estricto recibe una expresion a la derecha que no tiene tipo estatico Int,tiene tipo estatico " + str(rtype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(DivNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador division recibe una expresion a la izquierda que no tiene tipo estatico Int, tiene tipo estatico = " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) +" este operador division recibe una expresion a la derecha que no tiene tipo estatico Int, tiene tipo estatico = " + str(rtype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(StarNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador multiplicacion recibe una expresion a la izquierda que no tiene tipo estatico Int, tiene tipo estatico = " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) +" este operador multiplicacion recibe una expresion a la derecha que no tiene tipo estatico Int, tiene tipo estatico = " + str(rtype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(MinusNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador resta recibe una expresion a la izquierda que no tiene tipo estatico Int, tiene tipo estatico = " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) +" este operador resta recibe una expresion a la derecha que no tiene tipo estatico Int, tiene tipo estatico = " + str(rtype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(PlusNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if ltype != "Int":
mistake = "Line:" + str(node.line) +" este operador suma recibe una expresion a la izquierda que no tiene tipo estatico Int, tiene tipo estatico = " + str(ltype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if rtype != "Int":
mistake = "Line:" + str(node.line) +" este operador suma recibe una expresion a la derecha que no tiene tipo estatico Int, tiene tipo estatico = " + str(rtype)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(NotNode)
def visit(self,node,scope):
expre_type = self.visit(node.value,scope)
if expre_type != "Bool":
mistake = "Line:" + str(node.line) +" este operador not recibe una expresion que no tiene tipo estatico Bool, tiene tipo estatico = " + str(expre_type)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(NegationNode)
def visit(self,node,scope):
expre_type = self.visit(node.value,scope)
if expre_type != "Int":
mistake = "Line:" + str(node.line) +" este operador numero negativo recibe una expresion que no tiene tipo estatico Int, tiene tipo estatico = " + str(expre_type)+ " lo cual no es permitido"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Int"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Int"
@visitor.when(EqualNode)
def visit(self,node,scope):
ltype = self.visit(node.lvalue,scope)
rtype = self.visit(node.rvalue,scope)
if "String" == ltype or "String" == rtype or "Int" == ltype or "Int" == rtype or "Bool" == ltype or "Bool" ==rtype:
if ltype != rtype:
mistake = "Line:" + str(node.line )+" se utiliza el operador igual con uno de los dos operandos de tipo estatico de uno de los tipos built in y el otro miembro no tiene el mismo tipo estatico, los tipos built in solo se pueden comparar con objetos del mismo tipo"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
node.static = "Bool"
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return "Bool"
@visitor.when(NewNode)
def visit(self, node,scope):
#TODO ver cuando es que tengo que revisar que el tipo realmente exista como hago aqui..., igual creo que si el tipo no existe eventualmente va a reventar cuando busques sus metodos o atributos, o si no usas sus metodos o atributos es que lo instancias con NEw y aqui detectas ese error
if node.type != "SELF_TYPE" and (not scope.class_exist(node.type)):
mistake = "Line:" + str(node.line ) + " Se intenta hacer new a una clase que no esta declarada en el modulo actual de codigo COOL"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
if node.type == "SELF_TYPE":
node.static = scope.current_class
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return scope.current_class
node.static = node.type
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return node.type
@visitor.when(CaseNode)
def visit(self, node,scope):
branches = node.branches
condition = node.condition
t0 = self.visit(condition,scope)
seen = {}
list_expretions = []
for branch in branches:
if branch.type in seen:
mistake = "Line:" + str(node.line )+" En este case existen 2 branch al menos con el mismo tipo cosa que no esta permitida."
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
list_expretions.append(self.visit(branch,scope))
seen[branch.type] = True
#if len(list_expretions) == 1:
# #si existe un solo branch el tipo de retorno es este tipo evidentemente
# node.static = list_expretions[0]
# return list_expretions[0]
#si hay mas de un tipo vamos a encontrar el lca de todos los tipos que es igual al lca acomulativo de estos de izquierda a derecha
lca = list_expretions[0]
for i in range(len(list_expretions)):
#Ver que el lca de (node1,node2,... noden) = ...lca(lac(lca(node1,node2),node3),node3)...), osea hacer lca 2 a 2 de izquierda a derecha acomulativo.
lca = scope.LCA(lca, list_expretions[i])
node.static = lca
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return lca
@visitor.when(BranchNode)
def visit(self,node,scope):
id = node.name
type = node.type
if not scope.class_exist(type):
mistake = "Line:" + str(node.line) + "En este branch se esta decarando una variable de tipo = " + str(type) + " que no existe en el modulo de COOL actual"
self.wrongs.append(mistake)
raise TypeError(self.wrongs)
expr = node.expr
attr_node = AttrNode(id,type, line = node.line) #TOdo poner bien la linea de llamado,
new_scope = scope.create_child_scope()
self.visit(attr_node,new_scope)#Aqui lo que hago es que interpreto que el xi:Ti -> exprei como una que el xi:Ti es un Attr_node que crea la variable con nombre xi de tipo Ti y la usa en la expresion por lo que creo un nuevo scope donde esta variable existe y evaluo la expresion dada
return_type = self.visit(expr, new_scope) #Visito la expresion con la variable de id:type creada por que se puede usar en la expresion.
node.static = return_type
if "line" in node.__dict__:
print("-----------Line:" + str(node.line))
print(str(node) + " que tiene tipo static " + str(node.static))
return return_type #Retorno el tipo estatico de la expresion
#TESTING CODE#_______________
#program_node = main(source_path =r'C:\Users\David\Documents\Version del compilador de Rayniel 9 de junio\Compiler\test\test_cases\io.cl')
#checker = TypeChecker(program_node)
#checker.check()