Skip to content

Commit

Permalink
Added Autotype Collector.
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigo-pino committed Feb 26, 2021
1 parent be90765 commit bb0238a
Show file tree
Hide file tree
Showing 6 changed files with 542 additions and 55 deletions.
2 changes: 2 additions & 0 deletions src/devdeb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def run_pipeline():
pass
2 changes: 1 addition & 1 deletion src/parsing/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ExpressionNode(Node):
class VarDeclarationNode(ExpressionNode):
def __init__(self, idx, typex, expression=None):
self.id = idx
self.typex = typex
self.type = typex
self.expr = expression


Expand Down
269 changes: 262 additions & 7 deletions src/semantics/autotype_collector.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from semantics.utils import conforms, join, join_list, smart_add
import semantics.visitor as visitor
from semantics.tools import Context, Scope
from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode
from semantics.tools import Context, ErrorType, Scope, SelfType, SemanticError, TypeBag
from parsing.ast import ArithmeticNode, AssignNode, AttrDeclarationNode, BlocksNode, BooleanNode, CaseNode, CaseOptionNode, ClassDeclarationNode, ComparerNode, ComplementNode, ConditionalNode, InstantiateNode, IntNode, IsVoidNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, NotNode, ProgramNode, StringNode, VarDeclarationNode, VariableNode

class AutotypeCollector:
def __init__(self, context:Context):
Expand Down Expand Up @@ -35,14 +36,268 @@ def visit(self, node, scope):

@visitor.when(AttrDeclarationNode)
def visit(self, node, scope):
self.current_attrb = self.current_type.get_attribute(node.id)
node_type = self.update_type(self.current_attrb.type)

node_type = self.current_type.get_attribute(node.id).swap_self_type(self.current_type)
if not node.expr:
self.current_attrb = None
node.inferenced_type = node_type
return

self.visit(node.expr, scope)
node_expr = node.expr.inferenced_type
node_expr = conforms(node_expr, node_type)

var = scope.find_variable(node.id)
var.type = node_type

node.inferenced_type = node_type

@visitor.when(MethodDeclarationNode)
def visit(self, node, scopex):
scope = scopex.create_child()
current_method = self.current_type.get_method(node.id)
for idx, typex in zip(current_method.param_names, current_method.param_types):
scope.define_variable(idx, typex)

self.visit(node.body, scope)
ret_type_decl = self.current_method.return_type.swap_self_type(self.current_type)
ret_type_expr = node.body.inferenced_type
ret_type_expr = conforms(ret_type_expr, ret_type_decl)
node.body.inferenced_type = ret_type_expr

node.inferenced_type = ret_type_decl.clone()
ret_type_decl.swap_types(SelfType(), self.current_type)

@visitor.when(BlocksNode)
def visit(self, node, scope):
for expr in node.body:
self.visit(expr, scope)
node.inferenced_type = node.body[-1].inferenced_type

@visitor.when(ConditionalNode)
def visit(self, node, scope):
self.visit(node.condition)
condition_type = node.condition.inferenced_type
bool_type = self.context.get_type("Bool")
conforms(condition_type, bool_type)

self.visit(node.then_body)
then_type = node.then_body.inferenced_type
self.visit(node.else_body)
else_type = node.else_body.inferenced_type

joined_type = join(then_type, else_type)
node.inferenced_type = joined_type

@visitor.when(CaseNode)
def visit(self, node, scope:Scope):
self.visit(node.expr, scope)

type_list = []
for var in node.casevars:
child = scope.create_child()
self.visit(var, child)
type_list.append(var.inferenced_type)

joined_type = join_list(type_list)
node.inferenced_type = joined_type

@visitor.when(CaseOptionNode)
def visit(self, node, scope):
try:
node_type = self.context.get_type(node.type, selftype=False, autotype=False)
except SemanticError as err:
node_type = ErrorType()

scope.define_variable(node.id, node_type)
self.visit(node.expr, scope)
node.inferenced_type = node.expr.inferenced_type

@visitor.when(LoopNode)
def visit(self, node, scope):
self.visit(node.condition, scope)
condition_type = node.condition.inferenced_type
bool_type = self.context.get_type("Bool")
conforms(condition_type, bool_type)

self.visit(node.bodyexpr, scope)
node.inferenced_type = self.context.get_type("Object")

@visitor.when(LetNode)
def visit(self, node, scope):
child = scope.create_child()
for var in node.var_decl:
self.visit(var, child)
self.visit(node.in_expr, scope)
node.inferenced_type = node.in_expr.inferenced_type

@visitor.when(VarDeclarationNode)
def visit(self, node, scope):
try:
node_type = self.context.get_type(node.type).swap_self_type(self.current_type)
except SemanticError as err:
node_type = ErrorType()

if not scope.is_local(node.id):
scope.define_variable(node.id, node_type)
node.defined = True
else:
#add error
node.defined = False

if node.expr:
self.visit(node.expr, scope)
expr_type = node.expr.inferenced_type
conforms(expr_type, node_type)
node.expr.inferenced_type = expr_type

node.inferenced_type = node_type

@visitor.when(AssignNode)
def visit(self, node, scope:Scope):
var = scope.find_variable(node.id)
if not var:
var_type = ErrorType()
node.defined = False
else:
var_type = var.type.swap_self_type(self.current_type)
node.defined = True

self.visit(node.expr, scope)
node_expr = node.expr.inferenced_type

if var and var.name != 'self':
conforms(node_expr, var_type)
var.type = var_type
node.inferenced_type = var_type

@visitor.when(MethodCallNode)
def visit(self, node, scope):
if node.expr == None:
caller = self.current_type
elif node.type == None:
self.visit(node.expr)
caller = node.expr.inferenced_type
else:
self.visit(node.expr)
bridge = node.expr.inferenced_type
caller = self.context.get_type(node.type, selftype=False, autotype=False)
conforms(bridge, caller)

methods = None
if len(caller.type_set) > 1:
methods_by_name = self.context.get_method_by_name(node.id, len(node.args))
types = [typex for _, typex in methods_by_name]
conforms(caller, TypeBag(set(types)))
if len(caller.type_set):
methods = [(t, t.get_method) for t in caller.heads]
else:
pass #Add Error
elif len(caller.type_set) == 1:
caller_type = caller.heads[0]
try:
methods = [caller_type, caller_type.get_method(node.id)]
except SemanticError:
pass #Add Error

if methods:
type_set = set()
heads = []
for typex, method in methods:
ret_type = method.return_type.clone()
ret_type.swap_self_type(typex)
smart_add(type_set, heads, ret_type)
for i in range(len(node.args)):
arg, param_type = node.args[i], method.param_types[i]
self.visit(arg, scope)
arg_type = arg.inferenced_type
conforms(arg_type, param_type)
node.inferenced_type = TypeBag(type_set, heads)
else:
node.inferenced_type = ErrorType()

@visitor.when(ArithmeticNode)
def visit(self, node, scope):
self.visit(node.left, scope)
left_type = node.left.inferenced_type

self.visit(node.right, scope)
right_type = node.right.inferenced_type

int_type = self.context.get_type("Int")
conforms(left_type, int_type)
conforms(right_type, int_type)
node.inferenced_type = int_type

@visitor.when(ComparerNode)
def visit(self, node, scope):
self.visit(node.left, scope)
left_type = node.left.inferenced_type

self.visit(node.right, scope)
right_type = node.right.inferenced_type

conforms(left_type, right_type)
conforms(right_type, left_type)
node.inferenced_type = self.context.get_type("Bool")

@visitor.when(VariableNode)
def visit(self, node, scope):
var = scope.find_variable(node.expr)
if var:
node.defined = True
var_type = var.type
else:
node.defined = False
var_type = ErrorType()
node.inferenced_type = var_type

@visitor.when(NotNode)
def visit(self, node, scope):
self.visit(node.expr, scope)
expr_type = node.expr.inferenced_type
bool_type = self.context.get_type("Bool")
conforms(expr_type, bool_type)

node.inferenced_type = bool_type

@visitor.when(ComplementNode)
def visit(self, node, scope):
self.visit(node.expr, scope)
expr_type = node.expr.inferenced_type
int_type = self.context.get_type("int")
conforms(expr_type, int_type)

node.inferenced_type = int_type

@visitor.when(IsVoidNode)
def visit(self, node, scope):
self.visit(node.expr, scope)
node.inferenced_type = self.context.get_type("Bool")

@visitor.when(InstantiateNode)
def visit(self, node, scope):
try:
node_type = self.context.get_type(node.expr, selftype=False, autotype=False)
except SemanticError as err:
node_type = ErrorType()
node.inferenced_type = node_type

@visitor.when(IntNode)
def visit(self, node, scope):
node.inferenced_type = self.context.get_type("Int")

@visitor.when(StringNode)
def visit(self, node, scope):
node.inferenced_type = self.context.get_type("String")

@visitor.when(BooleanNode)
def visit(self, node, scope):
node.inferenced_type = self.context.get_type("Bool")



# todo: Revisar los auto types que me hace falta y que no
# todo: completar de manera acorde el autotype collector
# todo: completar de manera acorde el autotype collector
# todo: Annadir error en VarDeclarationNode
# todo: Annadir error en MethodCallNode (2)
# todo: annadir error en INsyantiate Node
# todo: Cambiar self.error a que cada error tengo la tupla de localizacion, asi permite organizar los errores
Loading

0 comments on commit bb0238a

Please sign in to comment.