From 0933dd1daf93bd30ee4f21791e4475a8e2a43f19 Mon Sep 17 00:00:00 2001 From: adrian Date: Fri, 19 Feb 2021 04:04:37 -0500 Subject: [PATCH 001/432] Finish lexer --- .vscode/settings.json | 3 + src/lexer.py | 126 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 src/lexer.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..26df38bf5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.enabled": false +} \ No newline at end of file diff --git a/src/lexer.py b/src/lexer.py new file mode 100644 index 000000000..a54aab718 --- /dev/null +++ b/src/lexer.py @@ -0,0 +1,126 @@ +import ply.lex as lex + + +literals = [ + '+', '-', '*', '/', '~', '=', '<', ':', '{', + '}', '@', ',', '.', '(', ')', ';', '$' +] + +reserved = { + 'true': 'TRUE', + 'false': 'FALSE', + 'if': 'IF', + 'then': 'THEN', + 'else': 'ELSE', + 'fi': 'FI', + 'class': 'CLASS', + 'inherits': 'INHERITS', + 'while': 'WHILE', + 'loop': 'LOOP', + 'pool': 'POOL', + 'let': 'LET', + 'in': 'IN', + 'case': 'CASE', + 'of': 'OF', + 'esac': 'ESAC', + 'new': 'NEW', + 'isvoid': 'ISVOID', + 'not': 'NOT' +} + +tokens = [ + 'LESSEQ', + 'ASSIGN', + 'RET', + 'ID', + 'STRING', + 'INT', + 'COMMENT', +] +tokens = tokens + list(reserved.values()) + +states = ( + ('aux', 'exclusive'), +) + +t_LESSEQ = r'\<=' +t_ASSIGN = r'\<-' +t_RET = r'\=>' + + +def t_ID(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + lower_case = t.value.lower() + if lower_case in ('true', 'false') and t.value[0].isupper(): + t.type = 'ID' + return t + t.type = reserved.get(t.value.lower(), 'ID') + return t + + +def t_STRING(t): + r'\"([^\\\n]|(\\.))*?\"' + t.value = str(t.value) + return t + + +def t_INT(t): + r'\d+' + t.value = int(t.value) + return t + +# One-line comments +def t_COMMENT(t): + r'(--.*(\n | $))' + return t + +# Multiline comments +def t_aux(t): + r'\(\*' + t.lexer.comm_start = t.lexer.lexpos - 2 + t.lexer.level = 1 + t.lexer.begin('aux') + + +def t_aux_lcomment(t): + r'\(\*' + t.lexer.level += 1 + + +def t_aux_rcomment(t): + r'\*\)' + t.lexer.level -= 1 + if t.lexer.level == 0: + t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos+1] + t.type = "COMMENT" + t.lexer.lineno += t.value.count('\n') + t.lexer.begin('INITIAL') + return t + + +def t_aux_pass(t): + r'[^.]' + pass + +# Define a rule so we can track line numbers +def t_ANY_newline(t): + r'\n+' + t.lexer.lineno += len(t.value) + + +# A string containing ignored characters (spaces and tabs) +t_ANY_ignore = ' \t' + +# Error handling rule +def t_ANY_error(t): + print("Illegal character '%s'" % t.value[0]) + t.lexer.skip(1) + + +def tokenize(data: str) -> list: + lexer = lex.lex() + lexer.input(data) + tokens = [] + for token in lexer: + tokens.append(token) + return tokens From f5f986dd49545ac681bbda7273fd653c3b6308ce Mon Sep 17 00:00:00 2001 From: adrian Date: Wed, 24 Feb 2021 03:18:51 -0500 Subject: [PATCH 002/432] Create parsing package --- .gitignore | 3 + .vscode/settings.json | 5 +- doc/team.yml | 15 +- src/coolc.sh | 2 +- src/lexing/__init__.py | 6 + src/{lexer.py => lexing/lexing_rules.py} | 67 ++++-- src/parsing/__init__.py | 4 + src/parsing/ast.py | 191 ++++++++++++++++ src/parsing/parsetab.py | 84 +++++++ src/parsing/parsing_rules.py | 270 +++++++++++++++++++++++ src/semantics/__init__.py | 0 11 files changed, 618 insertions(+), 29 deletions(-) create mode 100644 src/lexing/__init__.py rename src/{lexer.py => lexing/lexing_rules.py} (68%) create mode 100644 src/parsing/__init__.py create mode 100644 src/parsing/ast.py create mode 100644 src/parsing/parsetab.py create mode 100644 src/parsing/parsing_rules.py create mode 100644 src/semantics/__init__.py diff --git a/.gitignore b/.gitignore index 4acafde18..d568784ec 100644 --- a/.gitignore +++ b/.gitignore @@ -408,3 +408,6 @@ dmypy.json # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +src/__pycache__ +src/cool_example.cl +src/testing.py \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 26df38bf5..7e34d83ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "python.linting.enabled": false + "python.linting.enabled": false, + "python.linting.flake8Enabled": false, + "python.linting.pydocstyleEnabled": false, + "python.linting.pylintEnabled": true, } \ No newline at end of file diff --git a/doc/team.yml b/doc/team.yml index c16162532..2169aab60 100644 --- a/doc/team.yml +++ b/doc/team.yml @@ -1,10 +1,7 @@ members: - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX + - name: Adrián Rodríguez Portales + github: adrian13579 + group: C412 + - name: Rdrigo Pino + github: RodroVMS + group: C412 diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..4fe55f7f4 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -5,7 +5,7 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Copyright (c) 2021: Adrian, Rodrigo" # TODO: líneas a los valores correctos # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" diff --git a/src/lexing/__init__.py b/src/lexing/__init__.py new file mode 100644 index 000000000..7ccc0d5f6 --- /dev/null +++ b/src/lexing/__init__.py @@ -0,0 +1,6 @@ +from . import lexing_rules +from ply import lex + +lexer = lex.lex(module=lexing_rules) +# Set starting col +lexer.col = 1 diff --git a/src/lexer.py b/src/lexing/lexing_rules.py similarity index 68% rename from src/lexer.py rename to src/lexing/lexing_rules.py index a54aab718..ba63e79e7 100644 --- a/src/lexer.py +++ b/src/lexing/lexing_rules.py @@ -1,11 +1,11 @@ -import ply.lex as lex - +# Lexer rules +######################################################################################### literals = [ '+', '-', '*', '/', '~', '=', '<', ':', '{', '}', '@', ',', '.', '(', ')', ';', '$' ] - +# keywords reserved = { 'true': 'TRUE', 'false': 'FALSE', @@ -43,13 +43,28 @@ ('aux', 'exclusive'), ) -t_LESSEQ = r'\<=' -t_ASSIGN = r'\<-' -t_RET = r'\=>' + +def t_LESSEQ(t): + r'\<=' + set_pos(t) + return t + + +def t_ASSIGN(t): + r'\<-' + set_pos(t) + return t + + +def t_RET(t): + r'\=>' + set_pos(t) + return t def t_ID(t): r'[a-zA-Z_][a-zA-Z_0-9]*' + set_pos(t) lower_case = t.value.lower() if lower_case in ('true', 'false') and t.value[0].isupper(): t.type = 'ID' @@ -60,21 +75,30 @@ def t_ID(t): def t_STRING(t): r'\"([^\\\n]|(\\.))*?\"' + set_pos(t) t.value = str(t.value) return t def t_INT(t): r'\d+' + set_pos(t) t.value = int(t.value) return t -# One-line comments +# One-line comments rule + + def t_COMMENT(t): r'(--.*(\n | $))' + t.lexer.lineno += 1 + t.col = t.lexer.col + t.lexer.col = 1 return t -# Multiline comments +# Multiline comments rules + + def t_aux(t): r'\(\*' t.lexer.comm_start = t.lexer.lexpos - 2 @@ -102,25 +126,32 @@ def t_aux_pass(t): r'[^.]' pass -# Define a rule so we can track line numbers +# Rule so we can track line numbers + + def t_ANY_newline(t): r'\n+' t.lexer.lineno += len(t.value) + t.lexer.col = 1 + +def t_WHITESPACE(t): + r'\s' + t.lexer.col += len(t.value) -# A string containing ignored characters (spaces and tabs) -t_ANY_ignore = ' \t' # Error handling rule + + def t_ANY_error(t): print("Illegal character '%s'" % t.value[0]) t.lexer.skip(1) +######################################################################################### + +def set_pos(token): + token.col = token.lexer.col + token.lexer.col += len(token.value) + # token.row = token.lexer.lineno -def tokenize(data: str) -> list: - lexer = lex.lex() - lexer.input(data) - tokens = [] - for token in lexer: - tokens.append(token) - return tokens +# TODO: Add line and column for each token diff --git a/src/parsing/__init__.py b/src/parsing/__init__.py new file mode 100644 index 000000000..cffabef01 --- /dev/null +++ b/src/parsing/__init__.py @@ -0,0 +1,4 @@ +from ply import yacc +from . import parsing_rules + +parser = yacc.yacc(module=parsing_rules) diff --git a/src/parsing/ast.py b/src/parsing/ast.py new file mode 100644 index 000000000..5d0803779 --- /dev/null +++ b/src/parsing/ast.py @@ -0,0 +1,191 @@ +from typing import List, Tuple + + +class Node: + def __init__(self) -> None: + self.line = 0 + self.col = 0 + + def get_position(self) -> Tuple[int, int]: + return self.line, self.col + + def set_position(self, line: int, col: int) -> None: + self.line = line + self.col = col + + +class ProgramNode(Node): + def __init__(self, declarations): + self.declarations = declarations + + +class DeclarationNode(Node): + pass + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, idx, features, parent=None): + self.id = idx + self.parent = parent + self.features = features + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx, typex, expression=None): + self.id = idx + self.typex = typex + self.expression = expression + + +class MethodDeclarationNode(DeclarationNode): + def __init__(self, idx, params, return_type, body): + self.id = idx + self.params: List[VarDeclarationNode] = params + self.type = return_type + self.body = body + + +class ExpressionNode(Node): + pass + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, idx, typex, expression=None): + self.id = idx + self.typex = typex + self.expr = expression + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr): + self.id = idx + self.expr = expr + + +class MethodCallNode(ExpressionNode): + def __init__(self, expr=None, typex=None, idx=None, args=None): + self.expr = expr + self.type = typex + self.id = idx + self.args = args + + +class ConditionalNode(ExpressionNode): + def __init__(self, condition: ExpressionNode, then_body: ExpressionNode, else_body: ExpressionNode): + self.condition = condition + self.then_body = then_body + self.else_body = else_body + + +class LoopNode(ExpressionNode): + def __init__(self, condition: ExpressionNode, body: ExpressionNode): + self.condition = condition + self.body = body + + +class LetNode(ExpressionNode): + def __init__(self, var_decl_list: List[VarDeclarationNode], in_expr: ExpressionNode): + self.var_decl_list = var_decl_list + self.in_expr = in_expr + + +class CaseNode(ExpressionNode): + def __init__(self, case_expr, options): + self.case_expr = case_expr + self.options: List[CaseOptionNode] = options + + +class CaseOptionNode(ExpressionNode): + def __init__(self, idx, typex, ret_expr): + self.id = idx + self.type = typex + self.expr = ret_expr + + +class BlocksNode(ExpressionNode): + def __init__(self, expr_list): + self.expr_list = expr_list + + +class UnaryNode(ExpressionNode): + def __init__(self, expr): + self.expr = expr + + +class IsVoidNode(UnaryNode): + pass + + +class NotNode(UnaryNode): + pass + + +class ComplementNode(UnaryNode): + pass + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right): + self.left = left + self.right = right + + +class ComparerNode(BinaryNode): + pass + + +class LessNode(ComparerNode): + pass + + +class LessOrEqualNode(ComparerNode): + pass + + +class EqualsNode(ComparerNode): + pass + + +class ArithmeticNode(BinaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class AtomicNode(ExpressionNode): + def __init__(self, value): + self.value = value + + +class BooleanNode(AtomicNode): + pass + + +class IntNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + pass + + +class InstantiateNode(AtomicNode): + pass diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py new file mode 100644 index 000000000..560569f3a --- /dev/null +++ b/src/parsing/parsetab.py @@ -0,0 +1,84 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | param\n | emptyparam : ID ':' IDexpression_list : expression ';' expression\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expression \n | emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " + +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,13,14,19,23,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,20,21,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'ID':([4,8,9,16,17,18,20,21,31,32,34,37,38,39,40,41,42,43,44,45,46,52,54,55,56,57,58,59,60,61,62,63,64,92,93,95,96,97,98,99,101,103,104,105,113,119,121,124,126,133,136,],[6,10,11,11,23,24,11,11,35,51,24,35,35,35,71,35,35,74,35,35,35,78,35,35,83,84,35,35,35,35,35,35,35,35,35,35,35,71,111,114,35,35,117,35,114,35,35,130,35,35,-30,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'}':([9,12,15,16,20,21,22,28,29,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,19,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([11,24,33,71,114,],[17,32,52,98,124,]),'(':([11,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[18,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([18,25,26,27,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([23,35,111,],[31,54,121,]),',':([26,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,20,21,],[12,22,28,29,]),'attribute':([9,16,20,21,],[13,13,13,13,]),'method':([9,16,20,21,],[14,14,14,14,]),'empty':([9,16,18,20,21,34,55,103,105,126,],[15,15,27,15,15,27,82,82,82,82,]),'params_list':([18,34,],[25,53,]),'param':([18,34,],[26,26,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,108,109,115,81,81,128,129,81,135,]),'expression_list':([39,],[67,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> program","S'",1,None,None,None), + ('program -> class_list','program',1,'p_program','parsing_rules.py',13), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',18), + ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',19), + ('class -> CLASS ID INHERITS ID { feature_list }','class',7,'p_class','parsing_rules.py',27), + ('class -> CLASS ID { feature_list }','class',5,'p_class','parsing_rules.py',28), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',36), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',37), + ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',38), + ('attribute -> ID : ID ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',46), + ('attribute -> ID : ID','attribute',3,'p_attribute','parsing_rules.py',47), + ('method -> ID ( params_list ) : ID { expression }','method',9,'p_method','parsing_rules.py',55), + ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',60), + ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',61), + ('params_list -> empty','params_list',1,'p_params_list','parsing_rules.py',62), + ('param -> ID : ID','param',3,'p_param','parsing_rules.py',70), + ('expression_list -> expression ; expression','expression_list',3,'p_expression_list','parsing_rules.py',75), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',76), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',84), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',89), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',94), + ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',99), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',104), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',109), + ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',110), + ('let_single -> ID : ID ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',118), + ('let_single -> ID : ID','let_single',3,'p_let_single','parsing_rules.py',119), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',127), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',132), + ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',133), + ('case_single -> ID : ID RET expression ;','case_single',6,'p_case_single','parsing_rules.py',141), + ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',146), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',147), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',148), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',158), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',159), + ('args_list -> empty','args_list',1,'p_args_list','parsing_rules.py',160), + ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',167), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',172), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',177), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',182), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',187), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',192), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',197), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',202), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',207), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',212), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',217), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',222), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',227), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',232), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',237), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',242), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',247), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',252), +] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py new file mode 100644 index 000000000..f42d62cb9 --- /dev/null +++ b/src/parsing/parsing_rules.py @@ -0,0 +1,270 @@ +from lexing.lexing_rules import tokens + +from .ast import (AssignNode, AttrDeclarationNode, BlocksNode, BooleanNode, + CaseNode, CaseOptionNode, ClassDeclarationNode, + ComplementNode, ConditionalNode, DivNode, EqualsNode, + InstantiateNode, IntNode, IsVoidNode, LessNode, + LessOrEqualNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, + MinusNode, NotNode, PlusNode, ProgramNode, StarNode, + StringNode, VarDeclarationNode) + + +def p_program(p): + """program : class_list""" + p[0] = ProgramNode(p[1]) + + +def p_class_list(p): + """class_list : class ';' class_list + | class ';'""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + elif len(p) == 3: + p[0] = [p[1]] + + +def p_class(p): + """class : CLASS ID INHERITS ID '{' feature_list '}' + | CLASS ID '{' feature_list '}'""" + if len(p) == 8: + p[0] = ClassDeclarationNode(p[2], p[6], p[4]) + elif len(p) == 6: + p[0] = ClassDeclarationNode(p[2], p[4]) + + +def p_feature_list(p): + """feature_list : attribute ';' feature_list + | method ';' feature_list + | empty""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + elif len(p) == 2: + p[0] = [] + + +def p_attribute(p): + """attribute : ID ':' ID ASSIGN expression + | ID ':' ID """ + if len(p) == 6: + p[0] = AttrDeclarationNode(p[1], p[3], p[5]) + else: + p[0] = AttrDeclarationNode(p[1], p[3]) + + +def p_method(p): + """method : ID '(' params_list ')' ':' ID '{' expression '}'""" + p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) + + +def p_params_list(p): + """params_list : param ',' params_list + | param + | empty""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + +def p_param(p): + """param : ID ':' ID""" + p[0] = VarDeclarationNode(p[1], p[3]) + + +def p_expression_list(p): + """expression_list : expression ';' expression + | expression ';' """ + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + +def p_expression_assigment(p): + """expression : ID ASSIGN expression""" + p[0] = AssignNode(p[1], p[3]) + + +def p_expression_if_then_else(p): + """expression : IF expression THEN expression ELSE expression FI""" + p[0] = ConditionalNode(p[2], p[4], p[6]) + + +def p_expression_while(p): + """expression : WHILE expression LOOP expression POOL""" + p[0] = LoopNode(p[2], p[4]) + + +def p_expression_block(p): + """expression : '{' expression_list '}'""" + p[0] = BlocksNode(p[2]) + + +def p_expression_let_in(p): + """expression : LET let_list IN expression""" + p[0] = LetNode(p[2], p[4]) + + +def p_let_list(p): + """let_list : let_single ',' let_list + | let_single""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + +def p_let_single(p): + """let_single : ID ':' ID ASSIGN expression + | ID ':' ID""" + if len(p) == 6: + p[0] = VarDeclarationNode(p[1], p[3], p[5]) + else: + p[0] = VarDeclarationNode(p[1], p[3]) + + +def p_expression_case(p): + """expression : CASE expression OF case_list ESAC""" + p[0] = CaseNode(p[2], p[4]) + + +def p_case_list(p): + """case_list : case_single case_list + | case_single""" + if len(p) == 3: + p[0] = [p[1]] + p[2] + else: + p[0] = [p[1]] + + +def p_case_single(p): + """case_single : ID ':' ID RET expression ';'""" + p[0] = CaseOptionNode(p[1],p[3],p[5]) + + +def p_expression_dispatch(p): + """expression : expression '@' ID '.' ID '(' args_list ')' + | expression '.' ID '(' args_list ')' + | ID '(' args_list ')'""" + if len(p) == 9: + p[0] = MethodCallNode(p[1],p[3],p[5],p[7]) + elif len(p) == 7: + p[0] = MethodCallNode(p[1], None, p[3], p[5]) + else: + p[0]= MethodCallNode(None, None, p[1], p[3]) + + +def p_args_list(p): + """args_list : expression ',' args_list + | expression + | empty""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + +def p_expression_instatiate(p): + """expression : NEW ID""" + p[0] = InstantiateNode(p[2]) + + +def p_expression_isvoid(p): + """expression : ISVOID expression""" + p[0] = IsVoidNode(p[2]) + + +def p_expression_not(p): + """expression : NOT expression""" + p[0] = NotNode(p[2]) + + +def p_expression_complement(p): + """expression : '~' expression""" + p[0] = ComplementNode(p[2]) + + +def p_expression_plus(p): + """expression : expression '+' expression""" + p[0] = PlusNode(p[1],p[3]) + + +def p_expression_minus(p): + """expression : expression '-' expression""" + p[0] = MinusNode(p[1],p[3]) + + +def p_expression_div(p): + """expression : expression '/' expression""" + p[0] = DivNode(p[1],p[3]) + + +def p_expression_star(p): + """expression : expression '*' expression""" + p[0] = StarNode(p[1],p[3]) + + +def p_expression_less(p): + """expression : expression '<' expression""" + p[0] = LessNode(p[1],p[3]) + + +def p_expression_lesseq(p): + """expression : expression LESSEQ expression""" + p[0] = LessOrEqualNode(p[1],p[3]) + + +def p_expression_equals(p): + """expression : expression '=' expression""" + p[0] = EqualsNode(p[1],p[3]) + + +def p_expression_parentheses(p): + """expression : '(' expression ')'""" + p[0] = p[2] + + +def p_expression_string(p): + """expression : STRING""" + p[0] = StringNode(p[1]) + + +def p_expression_variable(p): + """expression : ID""" + p[0] = InstantiateNode(p[1]) + + +def p_expression_true(p): + """expression : TRUE""" + p[0] = BooleanNode(True) + + +def p_expression_false(p): + """expression : FALSE""" + p[0] = BooleanNode(False) + + +def p_expression_int(p): + """expression : INT""" + p[0] = IntNode(p[1]) + + +def p_empty(p): + """empty : """ + pass + + +def p_error(p): + print(f"Syntax error in input! {p}") + + +precedence = ( + ('right', 'ASSIGN'), + ('right', 'NOT'), + ('nonassoc', 'LESSEQ', '<', '='), + ('left', '+','-'), + ('left', '*', '/'), + ('right', 'ISVOID'), + ('left', '~'), + ('left', '@'), + ('left', '.') +) diff --git a/src/semantics/__init__.py b/src/semantics/__init__.py new file mode 100644 index 000000000..e69de29bb From e3d473e2dc376aba4e3a6aa714ee24ef496324da Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 04:30:57 -0500 Subject: [PATCH 003/432] Create utils.py in parsing and lexing --- src/lexing/__init__.py | 1 + src/lexing/lexing_rules.py | 113 +++++++++++++++++++++++++++++++++-- src/lexing/utils.py | 14 +++++ src/parsing/parsing_rules.py | 1 + src/parsing/utils.py | 2 + 5 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 src/lexing/utils.py create mode 100644 src/parsing/utils.py diff --git a/src/lexing/__init__.py b/src/lexing/__init__.py index 7ccc0d5f6..6259d314d 100644 --- a/src/lexing/__init__.py +++ b/src/lexing/__init__.py @@ -4,3 +4,4 @@ lexer = lex.lex(module=lexing_rules) # Set starting col lexer.col = 1 +lexer.errors = [] diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index ba63e79e7..5fb4ef5ef 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -1,6 +1,8 @@ # Lexer rules ######################################################################################### +from lexing.utils import LexicographicError, set_pos + literals = [ '+', '-', '*', '/', '~', '=', '<', ':', '{', '}', '@', ',', '.', '(', ')', ';', '$' @@ -43,6 +45,109 @@ ('aux', 'exclusive'), ) +def t_plus(t): + r'\+' + t.type = '+' + set_pos(t) + return t + +def t_minus(t): + r'-' + t.type = '-' + set_pos(t) + return t + +def t_star(t): + r'\*' + t.type = '*' + set_pos(t) + return t + +def t_slash(t): + r'/' + t.type = '/' + set_pos(t) + return t + +def t_neg(t): + r'~' + t.type = '~' + set_pos(t) + return t + +def t_equal(t): + r'=' + t.type = '=' + set_pos(t) + return t + + +def t_less(t): + r'<' + t.type = '<' + set_pos(t) + return t + + +def t_colon(t): + r':' + t.type = ':' + set_pos(t) + return t + +def t_ocur(t): + r'\{' + t.type = '{' + set_pos(t) + return t + +def t_ccur(t): + r'\}' + t.type = '}' + set_pos(t) + return t + +def t_at(t): + r'@' + t.type = '@' + set_pos(t) + return t + +def t_comma(t): + r',' + t.type = ',' + set_pos(t) + return t + +def t_dot(t): + r'\.' + t.type = '.' + set_pos(t) + return t + +def t_opar(t): + r'\(' + t.type = '(' + set_pos(t) + return t + +def t_cpar(t): + r'\)' + t.type = ')' + set_pos(t) + return t + +def t_semicolon(t): + r';' + t.type = ';' + set_pos(t) + return t + +def t_dollar(t): + r'\$' + t.type = '$' + set_pos(t) + return t def t_LESSEQ(t): r'\<=' @@ -144,14 +249,12 @@ def t_WHITESPACE(t): def t_ANY_error(t): - print("Illegal character '%s'" % t.value[0]) + # print("Illegal character '%s'" % t.value[0]) + t.error.append(LexicographicError(t.lineno, t.col, t.value[0])) t.lexer.skip(1) ######################################################################################### -def set_pos(token): - token.col = token.lexer.col - token.lexer.col += len(token.value) - # token.row = token.lexer.lineno + # TODO: Add line and column for each token diff --git a/src/lexing/utils.py b/src/lexing/utils.py new file mode 100644 index 000000000..cb033f406 --- /dev/null +++ b/src/lexing/utils.py @@ -0,0 +1,14 @@ +class LexicographicError: + def __init__(self, line: int, col: int, char: str) -> None: + self.line = line + self.col = col + self.char = char + + def __str__(self) -> str: + return f'({self.line},{self.col}) - LexicographicError: ERROR "{self.char}"' + + + +def set_pos(token): + token.col = token.lexer.col + token.lexer.col += len(token.value) \ No newline at end of file diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index f42d62cb9..5030d5873 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -140,6 +140,7 @@ def p_case_list(p): def p_case_single(p): """case_single : ID ':' ID RET expression ';'""" p[0] = CaseOptionNode(p[1],p[3],p[5]) + def p_expression_dispatch(p): diff --git a/src/parsing/utils.py b/src/parsing/utils.py new file mode 100644 index 000000000..626cd0a21 --- /dev/null +++ b/src/parsing/utils.py @@ -0,0 +1,2 @@ +class SyntacticError: + pass From be90765a739f465b2e14d6bb1d56e4fc078da2ab Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 004/432] Added Type Builder and Type Collector --- src/semantics/autotype_collector.py | 48 ++++++++ src/semantics/tools.py | 177 ++++++++++++++++++++++++++++ src/semantics/type_builder.py | 98 +++++++++++++++ src/semantics/type_collector.py | 108 +++++++++++++++++ src/semantics/utils.py | 47 ++++++++ src/semantics/visitor.py | 80 +++++++++++++ 6 files changed, 558 insertions(+) create mode 100644 src/semantics/autotype_collector.py create mode 100644 src/semantics/tools.py create mode 100644 src/semantics/type_builder.py create mode 100644 src/semantics/type_collector.py create mode 100644 src/semantics/utils.py create mode 100644 src/semantics/visitor.py diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py new file mode 100644 index 000000000..2a74ee36c --- /dev/null +++ b/src/semantics/autotype_collector.py @@ -0,0 +1,48 @@ +import semantics.visitor as visitor +from semantics.tools import Context, Scope +from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode + +class AutotypeCollector: + def __init__(self, context:Context): + self.context = context + self.current_type = None + self.current_method = None + self.current_attrb = None + self.inference_graph = dict() + self.errors = [] + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode) -> Scope: + scope = Scope() + for declaration in node.declarations: + self.visit(declaration, scope.create_child()) + + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + scope.define_variable("self", self.current_type) + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + for feature in node.features: + self.visit(feature, 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) + + if not node.expr: + self.current_attrb = None + node.inferenced_type = node_type + return + + +# todo: Revisar los auto types que me hace falta y que no +# todo: completar de manera acorde el autotype collector \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py new file mode 100644 index 000000000..4b32c2cc2 --- /dev/null +++ b/src/semantics/tools.py @@ -0,0 +1,177 @@ +import itertools as itt +from collections import OrderedDict + +class InternalError(Exception): + @property + def text(self): + return "Internal Error: " + self.args[0] + +class SemanticError(Exception): + @property + def text(self): + return "Semantic Error: " + self.args[0] + +class TypeError(SemanticError): + @property + def text(self): + return "Type Error: " + self.args[0] + +class AttributeError(SemanticError): + @property + def text(self): + return "Attribute Error: " + self.args[0] + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name} : {self.type.name};' + + def __repr__(self): + return str(self) + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + +class Type: + def __init__(self, name:str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + self.index = -1 + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Type \'{self.name}\' already has parent type \'{self.parent.name}\'. Type \'{parent.name}\' cannot be set as parent.') + if parent.name in {"String", "Int", "Bool"}: + raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') + self.parent = parent + + def get_attribute(self, name:str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + +class SelfType(Type): + def __init__(self): + self.name = "SELF_TYPE" + def conforms_to(self, other): + #if isinstance(other, SelfType): + # return True + raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + def bypass(self): + raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + +class AutoType(Type): + pass + +class ErrorType(Type): + pass + +class Context: + def __init__(self) -> None: + self.types = {} + self.num_autotypes = 0 + self.type_graph = None + + def create_type(self, name:str) -> Type: + if name in self.types: + raise SemanticError(f'Type with the same name ({name}) already exists.') + if name[0] != name[0].upper: + raise SemanticError(f'Type name ({name}) must start with upper case') + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name:str, selftype=True, autotype=True) -> Type: + if selftype and name == "SELF_TYPE": + return SelfType() + if autotype and name == "AUTO_TYPE": + self.num_autotypes += 1 + return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + try: + return self.types[name] + except KeyError: + raise TypeError(f'Type "{name}" is not defined.') + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + def __str__(self): + return self.name + ":" + self.type + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + self.current_child = -1 + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + try: + return self.parent.find_variable(vname, self.index)# if self.parent else None + except AttributeError: + return None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) + + def next_child(self): + self.current_child += 1 + return self.children[self.current_child] + + def reset(self): + self.current_child = -1 + for child in self.children: + child.reset() \ No newline at end of file diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py new file mode 100644 index 000000000..9e4b70b3c --- /dev/null +++ b/src/semantics/type_builder.py @@ -0,0 +1,98 @@ +import semantics.visitor as visitor +from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import Context + +class TypeCollector(object): + def __init__(self) -> None: + self.context = Context() + self.errors = [] + + self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context = Context() + self.init_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + new_declarations = self.get_type_hierarchy() + node.declarations = new_declarations + self.context.type_graph = self.type_graph + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id) + self.type_graph[node.id] = [] + if node.parent: + if node.parent in {'String', 'Int, Bool'}: + raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + try: + self.type_graph[node.parent].append(node.id) + except KeyError: + self.type_graph[node.parent] = [node.id] + else: + node.parent = "Object" + self.type_graph["Object"] = [node.id] + except SemanticError as error: + self.add_error(node, error.text) + + def get_type_hierarchy(self): + visited = set(["Object"]) + new_order = [] + self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + + circular_heritage_errors = [] + for node in self.type_graph: + if not node in visited: + visited.add(node) + path = [node] + circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + new_order = new_order + [self.context.get_type(node) for node in path] + + if circular_heritage_errors: + error = "Semantic Error: Circular Heritage:\n" + error += "\n".join(err for err in circular_heritage_errors) + self.add_error(None, error) + + return new_order + + def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + if not root in graph: + return + + for node in graph[root]: + if node in visited: + continue + visited.add(node) + if node not in {"Int", "String", "IO", "Bool", "Object"}: + new_order.append(self.context.get_type(node)) + self.context.get_type(node).index = index + self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + + def check_circular_heritage(self, root, graph, path, visited): + for node in graph[root]: + if node in path: + return ' -> '.join(child for child in visited + [visited[0]]) + + visited.add(node) + path.append(node) + return self.check_circular_heritage(node, graph, path, visited) + + def init_default_classes(self): + self.context.create_type('Object').index = 0 + self.context.create_type('String') + self.context.create_type('Int') + self.context.create_type('IO') + self.context.create_type('Bool') + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py new file mode 100644 index 000000000..450f6844d --- /dev/null +++ b/src/semantics/type_collector.py @@ -0,0 +1,108 @@ +import semantics.visitor as visitor +from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import ErrorType, SelfType +from semantics.utils import Context + +class TypeBuilder: + def __init__(self, context: Context): + self.context = context + self.current_type = None + self.errors = [] + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.build_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + try: + self.context.get_type('Main').get_method('main', local=True) + except SemanticError as err: + self.add_error(node, err.text) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + + if node.parent: + try: + parent_type = self.context.get_type(node.parent) + self.current_type.set_parent(parent_type) + for idx, _ in list(parent_type.all_attributes(True)): + self.current_type.attributes.append(idx) + except SemanticError as err: + self.add_error(node, err.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + try: + attr_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(node, err.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as err: + self.add_error(err.text) + + @visitor.when(MethodDeclarationNode) + def visit(self, node): + try: + ret_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(err.text) + ret_type = ErrorType() + + params_type = [] + params_name = [] + for p_name, p_type in node.params: + try: + params_type.append(self.context.get_type(p_type)) + except SemanticError as err: + params_type.append(ErrorType()) + self.add_error(node, err.text) + params_name.append(p_name) + + try: + self.current_type.define_method(node.id, params_name, params_type, ret_type) + except SemanticError as err: + self.add_error(node, err.text) + + def build_default_classes(self): + Object = self.context.get_type("Object") + String = self.context.get_type("String") + Int = self.context.get_type("Int") + Io = self.context.get_type("IO") + Bool = self.context.get_type("Bool") + + String.set_parent(Object) + Int.set_parent(Object) + Io.set_parent(Object) + Bool.set_parent(Object) + + Object.define_method("abort", [], [], Object) + Object.define_method("type_name", [], [], String) + Object.define_method("copy", [], [], SelfType()) + + String.define_method("length", [], [], Int) + String.define_method("concat", ["s"], [String], String) + String.define_method("substr", ["i", "l"], [Int, Int], String) + + Io.define_method("out_string", ["x"],[String], SelfType()) + Io.define_method("out_int", ["x"],[Int], SelfType()) + Io.define_method("in_string", [],[], String) + Io.define_method("in_int", [], [], Int) + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/utils.py b/src/semantics/utils.py new file mode 100644 index 000000000..953f74326 --- /dev/null +++ b/src/semantics/utils.py @@ -0,0 +1,47 @@ +from semantics.tools import Type, ErrorType, AutoType + +def conforms(type1:Type, type2:Type): + if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): + return ErrorType() + if not isinstance(type1, AutoType) and isinstance(type2, AutoType): + type2.set_upper_limmit([type1]) + return type1 + if not isinstance(type1, AutoType): + type1 = AutoType("TEMP01", [type1], {type1}) + if not isinstance(type2, AutoType): + type2 = AutoType("TEMP02", [type2], {type2}) + + print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) + print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + + condition_set_list, conform_set_list = conforming(type1, type2) + type1.set_new_conditions(condition_set_list, conform_set_list) + + print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) + print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) + print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") + return type1 + +def conforming(auto1:AutoType, auto2:AutoType): + ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) + + condition_set_list = [] + conform_set_list = [] + for type2 in ord_types2: + conforms = conform_intersection(auto1.type_set, type2) + for i in range(len(condition_set_list)): + prev_conform = conform_set_list[i] + if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): + condition_set_list[i].add(type2) + break + else: + condition_set_list.append(set([type2])) + conform_set_list.append(conforms) + return condition_set_list, conform_set_list + +def conform_intersection(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result \ No newline at end of file diff --git a/src/semantics/visitor.py b/src/semantics/visitor.py new file mode 100644 index 000000000..964842836 --- /dev/null +++ b/src/semantics/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) From bb0238a28c984d533bc04a69b18a9e2864e36633 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 19:18:53 -0500 Subject: [PATCH 005/432] Added Autotype Collector. --- src/devdeb.py | 2 + src/parsing/ast.py | 2 +- src/semantics/autotype_collector.py | 269 +++++++++++++++++++++++++++- src/semantics/tools.py | 179 +++++++++++++++++- src/semantics/type_builder.py | 6 +- src/semantics/utils.py | 139 ++++++++++---- 6 files changed, 542 insertions(+), 55 deletions(-) create mode 100644 src/devdeb.py diff --git a/src/devdeb.py b/src/devdeb.py new file mode 100644 index 000000000..ef174c7e1 --- /dev/null +++ b/src/devdeb.py @@ -0,0 +1,2 @@ +def run_pipeline(): + pass \ No newline at end of file diff --git a/src/parsing/ast.py b/src/parsing/ast.py index 5d0803779..cd8f0f8c9 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -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 diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 2a74ee36c..da2dcc28a 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -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): @@ -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 \ No newline at end of file +# 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 \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 4b32c2cc2..f0dd3b0af 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,5 +1,7 @@ import itertools as itt from collections import OrderedDict +from typing import FrozenSet +from semantics.utils import from_dict_to_set class InternalError(Exception): @property @@ -73,6 +75,151 @@ def get_attribute(self, name:str): return self.parent.get_attribute(name) except SemanticError: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + + def get_method(self, name:str, local:bool = False): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method \'{name}\' already defined in \'{self.name}\'') + + try: + parent_method = self.get_method(name) + except SemanticError: + parent_method = None + if parent_method: + error_list = [] + if not return_type.conforms_to(parent_method.return_type): + error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") + if len(param_types) != len(parent_method.param_types): + error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") + else: + count = 0 + err = [] + for param_type, parent_param_type in zip(param_types, parent_method.param_types): + if param_type != parent_param_type: + err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") + count += 1 + if err: + s = f" -> Same param types:\n" + "\n".join(child for child in err) + error_list.append(s) + if error_list: + err = f"Redifined method \"{name}\" in class {self.name} does not have:\n" + "\n".join(child for child in error_list) + raise SemanticError(err) + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def least_common_ancestor(self, other): + this = self + if isinstance(this, ErrorType) or isinstance(other, ErrorType): + return ErrorType() + #raise SemanticError("Error Type detected while perfoming Join. Aborting.") + + while this.index < other.index: + other = other.parent + while other.index < this.index: + this = this.parent + if not (this and other): + return None + while this.name != other.name: + this = this.parent + other = other.parent + if this == None: + return None + return this + +class TypeBag: + def __init__(self, type_set, heads = []) -> None: + self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) + self.heads:list = heads + if len(type_set) == 1: + self.heads = list(self.type_set) + self.condition_list = [] + self.conform_list = [] + + def set_conditions(self, condition_list, conform_list): + self.condition_list = condition_list + self.conform_list = conform_list + self.update_type_set_from_conforms() + + def update_type_set_from_conforms(self): + intersect_set = set() + for conform_set in self.conforms_list: + intersect_set = intersect_set.union(conform_set) + self.type_set = self.type_set.intersection(intersect_set) + self.update_heads() + + def update_heads(self): + new_heads = [] + visited = set() + for head in self.upper_limmit: + if head in self.type_set: + new_heads.append(head) + continue + new_heads = [] + lower_index = 2**32 + for typex in self.type_set: + if typex in visited: + continue + if typex.conforms_to(head): + visited.add(typex) + if typex.index < lower_index: + new_heads = [typex] + lower_index = typex.index + elif typex.index == lower_index: + new_heads.append(typex) + new_heads += new_heads + self.upper_limmit = new_heads + + def swap_self_type(self, update_type): + try: + self.type_set.remove(SelfType()) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def swap_types(self, update_type, remove_type): + try: + self.type_set.remove(remove_type) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def clone(self): + clone = TypeBag(self.type_set, self.heads) + clone.condition_list = self.condition_list + clone.conform_list = self.conform_list + return clone class SelfType(Type): def __init__(self): @@ -80,15 +227,17 @@ def __init__(self): def conforms_to(self, other): #if isinstance(other, SelfType): # return True - raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") def bypass(self): - raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") class AutoType(Type): pass class ErrorType(Type): - pass + def __init__(self): + self.name = "" + self.type_set = FrozenSet() class Context: def __init__(self) -> None: @@ -106,15 +255,31 @@ def create_type(self, name:str) -> Type: def get_type(self, name:str, selftype=True, autotype=True) -> Type: if selftype and name == "SELF_TYPE": - return SelfType() + return TypeBag({SelfType()}) #SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 - return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: - return self.types[name] + return TypeBag({self.types[name]}) except KeyError: raise TypeError(f'Type "{name}" is not defined.') - + + def get_method_by_name(self, name:str, args:int) -> list: + def dfs(root:str, results:list): + try: + for typex in self.type_tree[root]: + for method in self.types[typex].methods: + if name == method.name and args == len(method.param_names): + results.append((method, self.types[typex])) + break + else: + dfs(typex, results) + except KeyError: + pass + results = [] + dfs("Object", results) + return results + def __str__(self): return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 9e4b70b3c..98f53b865 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -47,7 +47,7 @@ def visit(self, node): def get_type_hierarchy(self): visited = set(["Object"]) new_order = [] - self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) circular_heritage_errors = [] for node in self.type_graph: @@ -64,7 +64,7 @@ def get_type_hierarchy(self): return new_order - def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + def dfs_type_graph(self, root, graph, visited:set, new_order, index): if not root in graph: return @@ -75,7 +75,7 @@ def get_type_hierarchy(self, root, graph, visited:set, new_order, index): if node not in {"Int", "String", "IO", "Bool", "Object"}: new_order.append(self.context.get_type(node)) self.context.get_type(node).index = index - self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + self.dfs_type_graph(node, graph, visited, new_order, index + 1) def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 953f74326..2f9d90686 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,45 +1,110 @@ -from semantics.tools import Type, ErrorType, AutoType - -def conforms(type1:Type, type2:Type): - if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): - return ErrorType() - if not isinstance(type1, AutoType) and isinstance(type2, AutoType): - type2.set_upper_limmit([type1]) - return type1 - if not isinstance(type1, AutoType): - type1 = AutoType("TEMP01", [type1], {type1}) - if not isinstance(type2, AutoType): - type2 = AutoType("TEMP02", [type2], {type2}) +from semantics.tools import Type, ErrorType, AutoType, TypeBag + +def conforms(bag1:TypeBag, bag2:TypeBag): + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) - print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) - print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + bag1.set_conditions(condition_list, conform_list) + return bag1 + +def conform_to_condition(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result - condition_set_list, conform_set_list = conforming(type1, type2) - type1.set_new_conditions(condition_set_list, conform_set_list) +def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + ancestor_set = set() + head_list = [] + ordered_set1 = order_set_by_index(bag1.type_set) + ordered_set2 = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor - print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) - print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) - print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") - return type1 - -def conforming(auto1:AutoType, auto2:AutoType): - ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) - - condition_set_list = [] - conform_set_list = [] - for type2 in ord_types2: - conforms = conform_intersection(auto1.type_set, type2) - for i in range(len(condition_set_list)): - prev_conform = conform_set_list[i] - if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): - condition_set_list[i].add(type2) + join_result = TypeBag(ancestor_set, head_list) + return join_result + +def join_list(type_list): + typex = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + typex = join(typex, type_i) + return typex + +def smart_add(type_set:set, head_list:list, typex:Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex break - else: - condition_set_list.append(set([type2])) - conform_set_list.append(conforms) - return condition_set_list, conform_set_list + if not there_is: + head_list.append(typex) + return head_list, type_set + +def auto_add(type_set:set, head_list:list, bag:TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head in bag.heads: + ancestor = head_i.least_common_ancestor(head) + if ancestor in type_set: + head_i[i] = ancestor + aux.pop(head) + break + head_list += [typex for typex in aux] + return head_list, type_set + +def order_set_by_index(type_set): + return sorted(list(type_set), lambda x: x.index) + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set -def conform_intersection(type_set, parent) -> set: +def set_intersection(parent, type_set) -> set: set_result = set() for typex in type_set: if typex.conforms_to(parent): From 9eed010623d3a56723ed8957cfecd95b37bbad6e Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 21:13:10 -0500 Subject: [PATCH 006/432] Fix bugs in lexer --- src/lexing/lexing_rules.py | 215 ++++++++++++++++++----------------- src/lexing/utils.py | 3 + src/parsing/__init__.py | 1 + src/parsing/parsing_rules.py | 1 + src/parsing/utils.py | 11 +- 5 files changed, 128 insertions(+), 103 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index 5fb4ef5ef..f3145cfd1 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -45,36 +45,138 @@ ('aux', 'exclusive'), ) + +def t_LESSEQ(t): + r'\<=' + set_pos(t) + return t + + +def t_ASSIGN(t): + r'\<-' + set_pos(t) + return t + + +def t_RET(t): + r'\=>' + set_pos(t) + return t + + +def t_ID(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + set_pos(t) + lower_case = t.value.lower() + if lower_case in ('true', 'false') and t.value[0].isupper(): + t.type = 'ID' + return t + t.type = reserved.get(t.value.lower(), 'ID') + return t + + +def t_STRING(t): + r'\"([^\\\n]|(\\.))*?\"' + set_pos(t) + t.value = str(t.value) + return t + + +def t_INT(t): + r'\d+' + set_pos(t) + t.value = int(t.value) + return t + +# One-line comments rule + + +def t_COMMENT(t): + r'(--.*(\n | $))' + t.lexer.lineno += 1 + t.col = t.lexer.col + t.lexer.col = 1 + return t + +# Multiline comments rules + + +def t_aux(t): + r'\(\*' + t.lexer.comm_start = t.lexer.lexpos - 2 + t.lexer.level = 1 + t.lexer.begin('aux') + + +def t_aux_lcomment(t): + r'\(\*' + t.lexer.level += 1 + + +def t_aux_rcomment(t): + r'\*\)' + t.lexer.level -= 1 + if t.lexer.level == 0: + t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos+1] + t.type = "COMMENT" + t.lexer.lineno += t.value.count('\n') + t.lexer.begin('INITIAL') + return t + + +def t_aux_pass(t): + r'[^.]' + pass + +# Rule so we can track line numbers + + +def t_ANY_newline(t): + r'\n+' + t.lexer.lineno += len(t.value) + t.lexer.col = 1 + + +def t_WHITESPACE(t): + r'\s' + t.lexer.col += len(t.value) + + def t_plus(t): r'\+' t.type = '+' set_pos(t) return t + def t_minus(t): r'-' t.type = '-' set_pos(t) return t + def t_star(t): r'\*' t.type = '*' set_pos(t) return t + def t_slash(t): r'/' t.type = '/' set_pos(t) return t + def t_neg(t): r'~' t.type = '~' set_pos(t) return t + def t_equal(t): r'=' t.type = '=' @@ -95,166 +197,75 @@ def t_colon(t): set_pos(t) return t + def t_ocur(t): r'\{' t.type = '{' set_pos(t) return t + def t_ccur(t): r'\}' t.type = '}' set_pos(t) return t + def t_at(t): r'@' t.type = '@' set_pos(t) return t + def t_comma(t): r',' t.type = ',' set_pos(t) return t + def t_dot(t): r'\.' t.type = '.' set_pos(t) return t + def t_opar(t): r'\(' t.type = '(' set_pos(t) return t + def t_cpar(t): r'\)' t.type = ')' set_pos(t) return t + def t_semicolon(t): r';' t.type = ';' set_pos(t) return t + def t_dollar(t): r'\$' t.type = '$' set_pos(t) return t -def t_LESSEQ(t): - r'\<=' - set_pos(t) - return t - - -def t_ASSIGN(t): - r'\<-' - set_pos(t) - return t - - -def t_RET(t): - r'\=>' - set_pos(t) - return t - - -def t_ID(t): - r'[a-zA-Z_][a-zA-Z_0-9]*' - set_pos(t) - lower_case = t.value.lower() - if lower_case in ('true', 'false') and t.value[0].isupper(): - t.type = 'ID' - return t - t.type = reserved.get(t.value.lower(), 'ID') - return t - - -def t_STRING(t): - r'\"([^\\\n]|(\\.))*?\"' - set_pos(t) - t.value = str(t.value) - return t - - -def t_INT(t): - r'\d+' - set_pos(t) - t.value = int(t.value) - return t - -# One-line comments rule - - -def t_COMMENT(t): - r'(--.*(\n | $))' - t.lexer.lineno += 1 - t.col = t.lexer.col - t.lexer.col = 1 - return t - -# Multiline comments rules - - -def t_aux(t): - r'\(\*' - t.lexer.comm_start = t.lexer.lexpos - 2 - t.lexer.level = 1 - t.lexer.begin('aux') - - -def t_aux_lcomment(t): - r'\(\*' - t.lexer.level += 1 - - -def t_aux_rcomment(t): - r'\*\)' - t.lexer.level -= 1 - if t.lexer.level == 0: - t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos+1] - t.type = "COMMENT" - t.lexer.lineno += t.value.count('\n') - t.lexer.begin('INITIAL') - return t - - -def t_aux_pass(t): - r'[^.]' - pass - -# Rule so we can track line numbers - - -def t_ANY_newline(t): - r'\n+' - t.lexer.lineno += len(t.value) - t.lexer.col = 1 - - -def t_WHITESPACE(t): - r'\s' - t.lexer.col += len(t.value) - - # Error handling rule def t_ANY_error(t): # print("Illegal character '%s'" % t.value[0]) - t.error.append(LexicographicError(t.lineno, t.col, t.value[0])) + set_pos(t) + t.lexer.errors.append(LexicographicError(t.lineno, t.col, t.value[0])) t.lexer.skip(1) ######################################################################################### - - - - -# TODO: Add line and column for each token diff --git a/src/lexing/utils.py b/src/lexing/utils.py index cb033f406..b6db182e3 100644 --- a/src/lexing/utils.py +++ b/src/lexing/utils.py @@ -6,6 +6,9 @@ def __init__(self, line: int, col: int, char: str) -> None: def __str__(self) -> str: return f'({self.line},{self.col}) - LexicographicError: ERROR "{self.char}"' + + def __repr__(self) -> str: + return str(self) diff --git a/src/parsing/__init__.py b/src/parsing/__init__.py index cffabef01..39f5bd97f 100644 --- a/src/parsing/__init__.py +++ b/src/parsing/__init__.py @@ -2,3 +2,4 @@ from . import parsing_rules parser = yacc.yacc(module=parsing_rules) +parser.errors = [] \ No newline at end of file diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 5030d5873..e7ae00ebf 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -258,6 +258,7 @@ def p_error(p): print(f"Syntax error in input! {p}") + precedence = ( ('right', 'ASSIGN'), ('right', 'NOT'), diff --git a/src/parsing/utils.py b/src/parsing/utils.py index 626cd0a21..782b4f63b 100644 --- a/src/parsing/utils.py +++ b/src/parsing/utils.py @@ -1,2 +1,11 @@ class SyntacticError: - pass + def __init__(self, token, line, col) -> None: + self.line = line + self.token = token + self.col = col + + def __str__(self) -> str: + return f'({self.line}, {self.col}) - \ + SyntacticError: ERROR at or near "{self.token}"' + + From e45754b1b9aec9971ce2d40c825c7be8841ea6b3 Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 21:29:24 -0500 Subject: [PATCH 007/432] Fix expression_list production in parsing_rules.py --- src/parsing/parsetab.py | 56 ++++++++++++++++++------------------ src/parsing/parsing_rules.py | 6 ++-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 560569f3a..cd2692b64 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,9 +6,9 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | param\n | emptyparam : ID ':' IDexpression_list : expression ';' expression\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expression \n | emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | param\n | emptyparam : ID ':' IDexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expression \n | emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " -_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,13,14,19,23,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,20,21,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'ID':([4,8,9,16,17,18,20,21,31,32,34,37,38,39,40,41,42,43,44,45,46,52,54,55,56,57,58,59,60,61,62,63,64,92,93,95,96,97,98,99,101,103,104,105,113,119,121,124,126,133,136,],[6,10,11,11,23,24,11,11,35,51,24,35,35,35,71,35,35,74,35,35,35,78,35,35,83,84,35,35,35,35,35,35,35,35,35,35,35,71,111,114,35,35,117,35,114,35,35,130,35,35,-30,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'}':([9,12,15,16,20,21,22,28,29,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,19,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([11,24,33,71,114,],[17,32,52,98,124,]),'(':([11,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[18,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([18,25,26,27,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([23,35,111,],[31,54,121,]),',':([26,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,108,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,13,14,19,23,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,20,21,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'ID':([4,8,9,16,17,18,20,21,31,32,34,37,38,39,40,41,42,43,44,45,46,52,54,55,56,57,58,59,60,61,62,63,64,92,93,95,96,97,98,99,101,103,104,105,113,119,121,124,126,133,136,],[6,10,11,11,23,24,11,11,35,51,24,35,35,35,71,35,35,74,35,35,35,78,35,35,83,84,35,35,35,35,35,35,35,35,35,35,35,71,111,114,35,35,117,35,114,35,35,130,35,35,-30,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'}':([9,12,15,16,20,21,22,28,29,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,19,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([11,24,33,71,114,],[17,32,52,98,124,]),'(':([11,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[18,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([18,25,26,27,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([23,35,111,],[31,54,121,]),',':([26,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} _lr_action = {} for _k, _v in _lr_action_items.items(): @@ -17,7 +17,7 @@ _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,20,21,],[12,22,28,29,]),'attribute':([9,16,20,21,],[13,13,13,13,]),'method':([9,16,20,21,],[14,14,14,14,]),'empty':([9,16,18,20,21,34,55,103,105,126,],[15,15,27,15,15,27,82,82,82,82,]),'params_list':([18,34,],[25,53,]),'param':([18,34,],[26,26,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,108,109,115,81,81,128,129,81,135,]),'expression_list':([39,],[67,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,20,21,],[12,22,28,29,]),'attribute':([9,16,20,21,],[13,13,13,13,]),'method':([9,16,20,21,],[14,14,14,14,]),'empty':([9,16,18,20,21,34,55,103,105,126,],[15,15,27,15,15,27,82,82,82,82,]),'params_list':([18,34,],[25,53,]),'param':([18,34,],[26,26,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,68,109,115,81,81,128,129,81,135,]),'expression_list':([39,95,],[67,108,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} _lr_goto = {} for _k, _v in _lr_goto_items.items(): @@ -42,7 +42,7 @@ ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',61), ('params_list -> empty','params_list',1,'p_params_list','parsing_rules.py',62), ('param -> ID : ID','param',3,'p_param','parsing_rules.py',70), - ('expression_list -> expression ; expression','expression_list',3,'p_expression_list','parsing_rules.py',75), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',75), ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',76), ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',84), ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',89), @@ -57,28 +57,28 @@ ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',132), ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',133), ('case_single -> ID : ID RET expression ;','case_single',6,'p_case_single','parsing_rules.py',141), - ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',146), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',147), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',148), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',158), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',159), - ('args_list -> empty','args_list',1,'p_args_list','parsing_rules.py',160), - ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',167), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',172), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',177), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',182), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',187), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',192), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',197), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',202), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',207), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',212), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',217), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',222), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',227), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',232), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',237), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',242), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',247), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',252), + ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',147), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',148), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',149), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',159), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',160), + ('args_list -> empty','args_list',1,'p_args_list','parsing_rules.py',161), + ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',168), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',173), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',178), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',183), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',188), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',193), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',198), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',203), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',208), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',213), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',218), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',223), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',228), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',233), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',238), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',243), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',248), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',253), ] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index e7ae00ebf..5523baac5 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -72,11 +72,11 @@ def p_param(p): def p_expression_list(p): - """expression_list : expression ';' expression + """expression_list : expression ';' expression_list | expression ';' """ if len(p) == 4: p[0] = [p[1]] + p[3] - else: + elif len(p) == 3: p[0] = [p[1]] @@ -255,7 +255,7 @@ def p_empty(p): def p_error(p): - print(f"Syntax error in input! {p}") + print(f"Syntax error in input! {p} line:{p.lineno} col:{p.col}") From 73d7791968e0284785934764ecbbdf363b1f5a3c Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 21:33:27 -0500 Subject: [PATCH 008/432] Update lexing_rules.py for ignoring comments --- src/lexing/lexing_rules.py | 4 ++-- src/parsing/parsing_rules.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index f3145cfd1..b423d24d3 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -96,7 +96,7 @@ def t_COMMENT(t): t.lexer.lineno += 1 t.col = t.lexer.col t.lexer.col = 1 - return t + # return t # Multiline comments rules @@ -121,7 +121,7 @@ def t_aux_rcomment(t): t.type = "COMMENT" t.lexer.lineno += t.value.count('\n') t.lexer.begin('INITIAL') - return t + # return t def t_aux_pass(t): diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 5523baac5..167a8bfc1 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -255,7 +255,7 @@ def p_empty(p): def p_error(p): - print(f"Syntax error in input! {p} line:{p.lineno} col:{p.col}") + print(f"Syntax error in input! {p} ")#line:{p.lineno} col:{p.col}") From e7fb711cc6995d04ccc8aad061f05f110581d30c Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 21:53:17 -0500 Subject: [PATCH 009/432] Change None for empty list in params and args when a method has no parameter --- src/parsing/parsetab.py | 84 ++++++++++++++++++------------------ src/parsing/parsing_rules.py | 17 +++++--- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index cd2692b64..a1d8b3310 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,7 +6,7 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | param\n | emptyparam : ID ':' IDexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expression \n | emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' IDexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " _lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,13,14,19,23,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,20,21,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'ID':([4,8,9,16,17,18,20,21,31,32,34,37,38,39,40,41,42,43,44,45,46,52,54,55,56,57,58,59,60,61,62,63,64,92,93,95,96,97,98,99,101,103,104,105,113,119,121,124,126,133,136,],[6,10,11,11,23,24,11,11,35,51,24,35,35,35,71,35,35,74,35,35,35,78,35,35,83,84,35,35,35,35,35,35,35,35,35,35,35,71,111,114,35,35,117,35,114,35,35,130,35,35,-30,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'}':([9,12,15,16,20,21,22,28,29,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,19,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([11,24,33,71,114,],[17,32,52,98,124,]),'(':([11,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[18,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([18,25,26,27,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([23,35,111,],[31,54,121,]),',':([26,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} @@ -40,45 +40,45 @@ ('method -> ID ( params_list ) : ID { expression }','method',9,'p_method','parsing_rules.py',55), ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',60), ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',61), - ('params_list -> empty','params_list',1,'p_params_list','parsing_rules.py',62), - ('param -> ID : ID','param',3,'p_param','parsing_rules.py',70), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',75), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',76), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',84), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',89), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',94), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',99), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',104), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',109), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',110), - ('let_single -> ID : ID ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',118), - ('let_single -> ID : ID','let_single',3,'p_let_single','parsing_rules.py',119), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',127), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',132), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',133), - ('case_single -> ID : ID RET expression ;','case_single',6,'p_case_single','parsing_rules.py',141), - ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',147), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',148), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',149), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',159), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',160), - ('args_list -> empty','args_list',1,'p_args_list','parsing_rules.py',161), - ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',168), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',173), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',178), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',183), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',188), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',193), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',198), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',203), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',208), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',213), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',218), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',223), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',228), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',233), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',238), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',243), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',248), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',253), + ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',68), + ('param -> ID : ID','param',3,'p_param','parsing_rules.py',73), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',78), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',79), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',87), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',92), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',97), + ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',102), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',107), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',112), + ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',113), + ('let_single -> ID : ID ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',121), + ('let_single -> ID : ID','let_single',3,'p_let_single','parsing_rules.py',122), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',130), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',135), + ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',136), + ('case_single -> ID : ID RET expression ;','case_single',6,'p_case_single','parsing_rules.py',144), + ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',150), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',151), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',152), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',162), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',163), + ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',171), + ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',175), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',180), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',185), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',190), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',195), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',200), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',205), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',210), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',215), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',220), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',225), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',230), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',235), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',240), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',245), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',250), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',255), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',260), ] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 167a8bfc1..a7c4bdb8f 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -58,13 +58,16 @@ def p_method(p): def p_params_list(p): """params_list : param ',' params_list - | param - | empty""" + | param""" if len(p) == 4: p[0] = [p[1]] + p[3] else: p[0] = [p[1]] +def p_params_list_empty(p): + """params_list : empty""" + p[0] = [] + def p_param(p): """param : ID ':' ID""" @@ -157,13 +160,17 @@ def p_expression_dispatch(p): def p_args_list(p): """args_list : expression ',' args_list - | expression - | empty""" + | expression""" if len(p) == 4: p[0] = [p[1]] + p[3] else: p[0] = [p[1]] + +def p_args_list_empty(p): + """args_list : empty""" + p[0] = [] + def p_expression_instatiate(p): """expression : NEW ID""" p[0] = InstantiateNode(p[2]) @@ -251,7 +258,7 @@ def p_expression_int(p): def p_empty(p): """empty : """ - pass + p[0] = [] def p_error(p): From 31bc0d54d1733efb36f2ad4d29fc730f03c8f910 Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 25 Feb 2021 22:51:43 -0500 Subject: [PATCH 010/432] Add line and col for each ast node --- src/parsing/ast.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/parsing/ast.py b/src/parsing/ast.py index 5d0803779..e07038198 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -16,6 +16,7 @@ def set_position(self, line: int, col: int) -> None: class ProgramNode(Node): def __init__(self, declarations): + Node.__init__(self) self.declarations = declarations @@ -25,6 +26,7 @@ class DeclarationNode(Node): class ClassDeclarationNode(DeclarationNode): def __init__(self, idx, features, parent=None): + Node.__init__(self) self.id = idx self.parent = parent self.features = features @@ -32,13 +34,15 @@ def __init__(self, idx, features, parent=None): class AttrDeclarationNode(DeclarationNode): def __init__(self, idx, typex, expression=None): + Node.__init__(self) self.id = idx - self.typex = typex - self.expression = expression + self.type = typex + self.expr = expression class MethodDeclarationNode(DeclarationNode): def __init__(self, idx, params, return_type, body): + Node.__init__(self) self.id = idx self.params: List[VarDeclarationNode] = params self.type = return_type @@ -51,6 +55,7 @@ class ExpressionNode(Node): class VarDeclarationNode(ExpressionNode): def __init__(self, idx, typex, expression=None): + Node.__init__(self) self.id = idx self.typex = typex self.expr = expression @@ -58,12 +63,14 @@ def __init__(self, idx, typex, expression=None): class AssignNode(ExpressionNode): def __init__(self, idx, expr): + Node.__init__(self) self.id = idx self.expr = expr class MethodCallNode(ExpressionNode): def __init__(self, expr=None, typex=None, idx=None, args=None): + Node.__init__(self) self.expr = expr self.type = typex self.id = idx @@ -72,6 +79,7 @@ def __init__(self, expr=None, typex=None, idx=None, args=None): class ConditionalNode(ExpressionNode): def __init__(self, condition: ExpressionNode, then_body: ExpressionNode, else_body: ExpressionNode): + Node.__init__(self) self.condition = condition self.then_body = then_body self.else_body = else_body @@ -79,24 +87,28 @@ def __init__(self, condition: ExpressionNode, then_body: ExpressionNode, else_bo class LoopNode(ExpressionNode): def __init__(self, condition: ExpressionNode, body: ExpressionNode): + Node.__init__(self) self.condition = condition self.body = body class LetNode(ExpressionNode): def __init__(self, var_decl_list: List[VarDeclarationNode], in_expr: ExpressionNode): + Node.__init__(self) self.var_decl_list = var_decl_list self.in_expr = in_expr class CaseNode(ExpressionNode): def __init__(self, case_expr, options): + Node.__init__(self) self.case_expr = case_expr self.options: List[CaseOptionNode] = options class CaseOptionNode(ExpressionNode): def __init__(self, idx, typex, ret_expr): + Node.__init__(self) self.id = idx self.type = typex self.expr = ret_expr @@ -104,11 +116,13 @@ def __init__(self, idx, typex, ret_expr): class BlocksNode(ExpressionNode): def __init__(self, expr_list): + Node.__init__(self) self.expr_list = expr_list class UnaryNode(ExpressionNode): def __init__(self, expr): + Node.__init__(self) self.expr = expr @@ -126,6 +140,7 @@ class ComplementNode(UnaryNode): class BinaryNode(ExpressionNode): def __init__(self, left, right): + Node.__init__(self) self.left = left self.right = right @@ -168,6 +183,7 @@ class DivNode(ArithmeticNode): class AtomicNode(ExpressionNode): def __init__(self, value): + Node.__init__(self) self.value = value From 595e86fc549e6f7deabeb5afe355db3a82887b64 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 011/432] Added Type Builder and Type Collector --- src/semantics/autotype_collector.py | 48 ++++++++ src/semantics/tools.py | 177 ++++++++++++++++++++++++++++ src/semantics/type_builder.py | 98 +++++++++++++++ src/semantics/type_collector.py | 108 +++++++++++++++++ src/semantics/utils.py | 47 ++++++++ src/semantics/visitor.py | 80 +++++++++++++ 6 files changed, 558 insertions(+) create mode 100644 src/semantics/autotype_collector.py create mode 100644 src/semantics/tools.py create mode 100644 src/semantics/type_builder.py create mode 100644 src/semantics/type_collector.py create mode 100644 src/semantics/utils.py create mode 100644 src/semantics/visitor.py diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py new file mode 100644 index 000000000..2a74ee36c --- /dev/null +++ b/src/semantics/autotype_collector.py @@ -0,0 +1,48 @@ +import semantics.visitor as visitor +from semantics.tools import Context, Scope +from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode + +class AutotypeCollector: + def __init__(self, context:Context): + self.context = context + self.current_type = None + self.current_method = None + self.current_attrb = None + self.inference_graph = dict() + self.errors = [] + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode) -> Scope: + scope = Scope() + for declaration in node.declarations: + self.visit(declaration, scope.create_child()) + + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + scope.define_variable("self", self.current_type) + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + for feature in node.features: + self.visit(feature, 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) + + if not node.expr: + self.current_attrb = None + node.inferenced_type = node_type + return + + +# todo: Revisar los auto types que me hace falta y que no +# todo: completar de manera acorde el autotype collector \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py new file mode 100644 index 000000000..4b32c2cc2 --- /dev/null +++ b/src/semantics/tools.py @@ -0,0 +1,177 @@ +import itertools as itt +from collections import OrderedDict + +class InternalError(Exception): + @property + def text(self): + return "Internal Error: " + self.args[0] + +class SemanticError(Exception): + @property + def text(self): + return "Semantic Error: " + self.args[0] + +class TypeError(SemanticError): + @property + def text(self): + return "Type Error: " + self.args[0] + +class AttributeError(SemanticError): + @property + def text(self): + return "Attribute Error: " + self.args[0] + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name} : {self.type.name};' + + def __repr__(self): + return str(self) + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + +class Type: + def __init__(self, name:str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + self.index = -1 + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Type \'{self.name}\' already has parent type \'{self.parent.name}\'. Type \'{parent.name}\' cannot be set as parent.') + if parent.name in {"String", "Int", "Bool"}: + raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') + self.parent = parent + + def get_attribute(self, name:str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + +class SelfType(Type): + def __init__(self): + self.name = "SELF_TYPE" + def conforms_to(self, other): + #if isinstance(other, SelfType): + # return True + raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + def bypass(self): + raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + +class AutoType(Type): + pass + +class ErrorType(Type): + pass + +class Context: + def __init__(self) -> None: + self.types = {} + self.num_autotypes = 0 + self.type_graph = None + + def create_type(self, name:str) -> Type: + if name in self.types: + raise SemanticError(f'Type with the same name ({name}) already exists.') + if name[0] != name[0].upper: + raise SemanticError(f'Type name ({name}) must start with upper case') + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name:str, selftype=True, autotype=True) -> Type: + if selftype and name == "SELF_TYPE": + return SelfType() + if autotype and name == "AUTO_TYPE": + self.num_autotypes += 1 + return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + try: + return self.types[name] + except KeyError: + raise TypeError(f'Type "{name}" is not defined.') + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + def __str__(self): + return self.name + ":" + self.type + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + self.current_child = -1 + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + try: + return self.parent.find_variable(vname, self.index)# if self.parent else None + except AttributeError: + return None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) + + def next_child(self): + self.current_child += 1 + return self.children[self.current_child] + + def reset(self): + self.current_child = -1 + for child in self.children: + child.reset() \ No newline at end of file diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py new file mode 100644 index 000000000..9e4b70b3c --- /dev/null +++ b/src/semantics/type_builder.py @@ -0,0 +1,98 @@ +import semantics.visitor as visitor +from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import Context + +class TypeCollector(object): + def __init__(self) -> None: + self.context = Context() + self.errors = [] + + self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context = Context() + self.init_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + new_declarations = self.get_type_hierarchy() + node.declarations = new_declarations + self.context.type_graph = self.type_graph + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id) + self.type_graph[node.id] = [] + if node.parent: + if node.parent in {'String', 'Int, Bool'}: + raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + try: + self.type_graph[node.parent].append(node.id) + except KeyError: + self.type_graph[node.parent] = [node.id] + else: + node.parent = "Object" + self.type_graph["Object"] = [node.id] + except SemanticError as error: + self.add_error(node, error.text) + + def get_type_hierarchy(self): + visited = set(["Object"]) + new_order = [] + self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + + circular_heritage_errors = [] + for node in self.type_graph: + if not node in visited: + visited.add(node) + path = [node] + circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + new_order = new_order + [self.context.get_type(node) for node in path] + + if circular_heritage_errors: + error = "Semantic Error: Circular Heritage:\n" + error += "\n".join(err for err in circular_heritage_errors) + self.add_error(None, error) + + return new_order + + def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + if not root in graph: + return + + for node in graph[root]: + if node in visited: + continue + visited.add(node) + if node not in {"Int", "String", "IO", "Bool", "Object"}: + new_order.append(self.context.get_type(node)) + self.context.get_type(node).index = index + self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + + def check_circular_heritage(self, root, graph, path, visited): + for node in graph[root]: + if node in path: + return ' -> '.join(child for child in visited + [visited[0]]) + + visited.add(node) + path.append(node) + return self.check_circular_heritage(node, graph, path, visited) + + def init_default_classes(self): + self.context.create_type('Object').index = 0 + self.context.create_type('String') + self.context.create_type('Int') + self.context.create_type('IO') + self.context.create_type('Bool') + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py new file mode 100644 index 000000000..450f6844d --- /dev/null +++ b/src/semantics/type_collector.py @@ -0,0 +1,108 @@ +import semantics.visitor as visitor +from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import ErrorType, SelfType +from semantics.utils import Context + +class TypeBuilder: + def __init__(self, context: Context): + self.context = context + self.current_type = None + self.errors = [] + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.build_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + try: + self.context.get_type('Main').get_method('main', local=True) + except SemanticError as err: + self.add_error(node, err.text) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + + if node.parent: + try: + parent_type = self.context.get_type(node.parent) + self.current_type.set_parent(parent_type) + for idx, _ in list(parent_type.all_attributes(True)): + self.current_type.attributes.append(idx) + except SemanticError as err: + self.add_error(node, err.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + try: + attr_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(node, err.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as err: + self.add_error(err.text) + + @visitor.when(MethodDeclarationNode) + def visit(self, node): + try: + ret_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(err.text) + ret_type = ErrorType() + + params_type = [] + params_name = [] + for p_name, p_type in node.params: + try: + params_type.append(self.context.get_type(p_type)) + except SemanticError as err: + params_type.append(ErrorType()) + self.add_error(node, err.text) + params_name.append(p_name) + + try: + self.current_type.define_method(node.id, params_name, params_type, ret_type) + except SemanticError as err: + self.add_error(node, err.text) + + def build_default_classes(self): + Object = self.context.get_type("Object") + String = self.context.get_type("String") + Int = self.context.get_type("Int") + Io = self.context.get_type("IO") + Bool = self.context.get_type("Bool") + + String.set_parent(Object) + Int.set_parent(Object) + Io.set_parent(Object) + Bool.set_parent(Object) + + Object.define_method("abort", [], [], Object) + Object.define_method("type_name", [], [], String) + Object.define_method("copy", [], [], SelfType()) + + String.define_method("length", [], [], Int) + String.define_method("concat", ["s"], [String], String) + String.define_method("substr", ["i", "l"], [Int, Int], String) + + Io.define_method("out_string", ["x"],[String], SelfType()) + Io.define_method("out_int", ["x"],[Int], SelfType()) + Io.define_method("in_string", [],[], String) + Io.define_method("in_int", [], [], Int) + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/utils.py b/src/semantics/utils.py new file mode 100644 index 000000000..953f74326 --- /dev/null +++ b/src/semantics/utils.py @@ -0,0 +1,47 @@ +from semantics.tools import Type, ErrorType, AutoType + +def conforms(type1:Type, type2:Type): + if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): + return ErrorType() + if not isinstance(type1, AutoType) and isinstance(type2, AutoType): + type2.set_upper_limmit([type1]) + return type1 + if not isinstance(type1, AutoType): + type1 = AutoType("TEMP01", [type1], {type1}) + if not isinstance(type2, AutoType): + type2 = AutoType("TEMP02", [type2], {type2}) + + print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) + print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + + condition_set_list, conform_set_list = conforming(type1, type2) + type1.set_new_conditions(condition_set_list, conform_set_list) + + print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) + print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) + print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") + return type1 + +def conforming(auto1:AutoType, auto2:AutoType): + ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) + + condition_set_list = [] + conform_set_list = [] + for type2 in ord_types2: + conforms = conform_intersection(auto1.type_set, type2) + for i in range(len(condition_set_list)): + prev_conform = conform_set_list[i] + if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): + condition_set_list[i].add(type2) + break + else: + condition_set_list.append(set([type2])) + conform_set_list.append(conforms) + return condition_set_list, conform_set_list + +def conform_intersection(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result \ No newline at end of file diff --git a/src/semantics/visitor.py b/src/semantics/visitor.py new file mode 100644 index 000000000..964842836 --- /dev/null +++ b/src/semantics/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) From 114afa4848d42fabb466f360b53ff590f1ecc267 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 19:18:53 -0500 Subject: [PATCH 012/432] Added Autotype Collector. --- src/devdeb.py | 2 + src/parsing/ast.py | 2 +- src/semantics/autotype_collector.py | 269 +++++++++++++++++++++++++++- src/semantics/tools.py | 179 +++++++++++++++++- src/semantics/type_builder.py | 6 +- src/semantics/utils.py | 139 ++++++++++---- 6 files changed, 542 insertions(+), 55 deletions(-) create mode 100644 src/devdeb.py diff --git a/src/devdeb.py b/src/devdeb.py new file mode 100644 index 000000000..ef174c7e1 --- /dev/null +++ b/src/devdeb.py @@ -0,0 +1,2 @@ +def run_pipeline(): + pass \ No newline at end of file diff --git a/src/parsing/ast.py b/src/parsing/ast.py index e07038198..53abf401c 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -57,7 +57,7 @@ class VarDeclarationNode(ExpressionNode): def __init__(self, idx, typex, expression=None): Node.__init__(self) self.id = idx - self.typex = typex + self.type = typex self.expr = expression diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 2a74ee36c..da2dcc28a 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -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): @@ -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 \ No newline at end of file +# 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 \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 4b32c2cc2..f0dd3b0af 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,5 +1,7 @@ import itertools as itt from collections import OrderedDict +from typing import FrozenSet +from semantics.utils import from_dict_to_set class InternalError(Exception): @property @@ -73,6 +75,151 @@ def get_attribute(self, name:str): return self.parent.get_attribute(name) except SemanticError: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + + def get_method(self, name:str, local:bool = False): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method \'{name}\' already defined in \'{self.name}\'') + + try: + parent_method = self.get_method(name) + except SemanticError: + parent_method = None + if parent_method: + error_list = [] + if not return_type.conforms_to(parent_method.return_type): + error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") + if len(param_types) != len(parent_method.param_types): + error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") + else: + count = 0 + err = [] + for param_type, parent_param_type in zip(param_types, parent_method.param_types): + if param_type != parent_param_type: + err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") + count += 1 + if err: + s = f" -> Same param types:\n" + "\n".join(child for child in err) + error_list.append(s) + if error_list: + err = f"Redifined method \"{name}\" in class {self.name} does not have:\n" + "\n".join(child for child in error_list) + raise SemanticError(err) + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def least_common_ancestor(self, other): + this = self + if isinstance(this, ErrorType) or isinstance(other, ErrorType): + return ErrorType() + #raise SemanticError("Error Type detected while perfoming Join. Aborting.") + + while this.index < other.index: + other = other.parent + while other.index < this.index: + this = this.parent + if not (this and other): + return None + while this.name != other.name: + this = this.parent + other = other.parent + if this == None: + return None + return this + +class TypeBag: + def __init__(self, type_set, heads = []) -> None: + self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) + self.heads:list = heads + if len(type_set) == 1: + self.heads = list(self.type_set) + self.condition_list = [] + self.conform_list = [] + + def set_conditions(self, condition_list, conform_list): + self.condition_list = condition_list + self.conform_list = conform_list + self.update_type_set_from_conforms() + + def update_type_set_from_conforms(self): + intersect_set = set() + for conform_set in self.conforms_list: + intersect_set = intersect_set.union(conform_set) + self.type_set = self.type_set.intersection(intersect_set) + self.update_heads() + + def update_heads(self): + new_heads = [] + visited = set() + for head in self.upper_limmit: + if head in self.type_set: + new_heads.append(head) + continue + new_heads = [] + lower_index = 2**32 + for typex in self.type_set: + if typex in visited: + continue + if typex.conforms_to(head): + visited.add(typex) + if typex.index < lower_index: + new_heads = [typex] + lower_index = typex.index + elif typex.index == lower_index: + new_heads.append(typex) + new_heads += new_heads + self.upper_limmit = new_heads + + def swap_self_type(self, update_type): + try: + self.type_set.remove(SelfType()) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def swap_types(self, update_type, remove_type): + try: + self.type_set.remove(remove_type) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def clone(self): + clone = TypeBag(self.type_set, self.heads) + clone.condition_list = self.condition_list + clone.conform_list = self.conform_list + return clone class SelfType(Type): def __init__(self): @@ -80,15 +227,17 @@ def __init__(self): def conforms_to(self, other): #if isinstance(other, SelfType): # return True - raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") def bypass(self): - raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") class AutoType(Type): pass class ErrorType(Type): - pass + def __init__(self): + self.name = "" + self.type_set = FrozenSet() class Context: def __init__(self) -> None: @@ -106,15 +255,31 @@ def create_type(self, name:str) -> Type: def get_type(self, name:str, selftype=True, autotype=True) -> Type: if selftype and name == "SELF_TYPE": - return SelfType() + return TypeBag({SelfType()}) #SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 - return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: - return self.types[name] + return TypeBag({self.types[name]}) except KeyError: raise TypeError(f'Type "{name}" is not defined.') - + + def get_method_by_name(self, name:str, args:int) -> list: + def dfs(root:str, results:list): + try: + for typex in self.type_tree[root]: + for method in self.types[typex].methods: + if name == method.name and args == len(method.param_names): + results.append((method, self.types[typex])) + break + else: + dfs(typex, results) + except KeyError: + pass + results = [] + dfs("Object", results) + return results + def __str__(self): return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 9e4b70b3c..98f53b865 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -47,7 +47,7 @@ def visit(self, node): def get_type_hierarchy(self): visited = set(["Object"]) new_order = [] - self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) circular_heritage_errors = [] for node in self.type_graph: @@ -64,7 +64,7 @@ def get_type_hierarchy(self): return new_order - def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + def dfs_type_graph(self, root, graph, visited:set, new_order, index): if not root in graph: return @@ -75,7 +75,7 @@ def get_type_hierarchy(self, root, graph, visited:set, new_order, index): if node not in {"Int", "String", "IO", "Bool", "Object"}: new_order.append(self.context.get_type(node)) self.context.get_type(node).index = index - self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + self.dfs_type_graph(node, graph, visited, new_order, index + 1) def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 953f74326..2f9d90686 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,45 +1,110 @@ -from semantics.tools import Type, ErrorType, AutoType - -def conforms(type1:Type, type2:Type): - if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): - return ErrorType() - if not isinstance(type1, AutoType) and isinstance(type2, AutoType): - type2.set_upper_limmit([type1]) - return type1 - if not isinstance(type1, AutoType): - type1 = AutoType("TEMP01", [type1], {type1}) - if not isinstance(type2, AutoType): - type2 = AutoType("TEMP02", [type2], {type2}) +from semantics.tools import Type, ErrorType, AutoType, TypeBag + +def conforms(bag1:TypeBag, bag2:TypeBag): + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) - print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) - print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + bag1.set_conditions(condition_list, conform_list) + return bag1 + +def conform_to_condition(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result - condition_set_list, conform_set_list = conforming(type1, type2) - type1.set_new_conditions(condition_set_list, conform_set_list) +def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + ancestor_set = set() + head_list = [] + ordered_set1 = order_set_by_index(bag1.type_set) + ordered_set2 = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor - print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) - print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) - print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") - return type1 - -def conforming(auto1:AutoType, auto2:AutoType): - ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) - - condition_set_list = [] - conform_set_list = [] - for type2 in ord_types2: - conforms = conform_intersection(auto1.type_set, type2) - for i in range(len(condition_set_list)): - prev_conform = conform_set_list[i] - if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): - condition_set_list[i].add(type2) + join_result = TypeBag(ancestor_set, head_list) + return join_result + +def join_list(type_list): + typex = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + typex = join(typex, type_i) + return typex + +def smart_add(type_set:set, head_list:list, typex:Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex break - else: - condition_set_list.append(set([type2])) - conform_set_list.append(conforms) - return condition_set_list, conform_set_list + if not there_is: + head_list.append(typex) + return head_list, type_set + +def auto_add(type_set:set, head_list:list, bag:TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head in bag.heads: + ancestor = head_i.least_common_ancestor(head) + if ancestor in type_set: + head_i[i] = ancestor + aux.pop(head) + break + head_list += [typex for typex in aux] + return head_list, type_set + +def order_set_by_index(type_set): + return sorted(list(type_set), lambda x: x.index) + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set -def conform_intersection(type_set, parent) -> set: +def set_intersection(parent, type_set) -> set: set_result = set() for typex in type_set: if typex.conforms_to(parent): From 669cab49bfe9fe4bf09a70508b06d1d1993a1fb7 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 22:04:58 -0500 Subject: [PATCH 013/432] Fixed Bugs. --- src/devdeb.py | 53 +++- src/semantics/tools.py | 36 ++- src/semantics/type_builder.py | 152 ++++++----- src/semantics/type_collector.py | 156 +++++------ src/semantics/utils.py | 8 +- src/zTests/Misc/0HelloWorld.txt | 5 + src/zTests/Misc/0Simple.txt | 13 + src/zTests/Misc/0SimpleSpaced.txt | 13 + src/zTests/Misc/10.txt | 10 + src/zTests/Misc/11.txt | 10 + src/zTests/Misc/1Ackerman.txt | 24 ++ src/zTests/Misc/3.txt | 93 +++++++ src/zTests/Misc/5.txt | 64 +++++ src/zTests/Misc/6.txt | 436 ++++++++++++++++++++++++++++++ src/zTests/Misc/7.txt | 426 +++++++++++++++++++++++++++++ src/zTests/Misc/8.txt | 34 +++ src/zTests/Misc/9.txt | 23 ++ 17 files changed, 1388 insertions(+), 168 deletions(-) create mode 100644 src/zTests/Misc/0HelloWorld.txt create mode 100644 src/zTests/Misc/0Simple.txt create mode 100644 src/zTests/Misc/0SimpleSpaced.txt create mode 100644 src/zTests/Misc/10.txt create mode 100644 src/zTests/Misc/11.txt create mode 100644 src/zTests/Misc/1Ackerman.txt create mode 100644 src/zTests/Misc/3.txt create mode 100644 src/zTests/Misc/5.txt create mode 100644 src/zTests/Misc/6.txt create mode 100644 src/zTests/Misc/7.txt create mode 100644 src/zTests/Misc/8.txt create mode 100644 src/zTests/Misc/9.txt diff --git a/src/devdeb.py b/src/devdeb.py index ef174c7e1..86868597e 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -1,2 +1,51 @@ -def run_pipeline(): - pass \ No newline at end of file +import os +from parsing import parser +from semantics import type_collector, type_builder, autotype_collector + +def format_errors(errors, s = ""): + count = 1 + for error in errors: + s += str(count) + ". " + error + "\n" + count += 1 + return s + +def run_pipeline(program): + ast = parser.parse(program) + + collector = type_collector.TypeCollector() + collector.visit(ast) + context = collector.context + print('Context\n', context) + + builder = type_builder.TypeBuilder(context) + builder.visit(ast) + print('Context\n', context) + + auto_collector = autotype_collector.AutotypeCollector(context) + auto_collector.visit(ast) + + s = "Type Collector Errors:\n" + s = format_errors(collector.errors, s) + s += "Type Builder Errors:\n" + s = format_errors(builder.errors, s) + s += "Inference Gatherer Errors:\n" + s = format_errors(auto_collector.errors, s) + + print(s) + +folder_path = r'./zTests/Misc' +filenames = os.listdir(folder_path) +filenames.sort() + +for filename in filenames: + path = os.path.join(folder_path, filename) + file = open(path, "r") + program = file.read() + file.close() + + print(f"Running {filename}") + run_pipeline(program) + input() + +print("EndOfFiles") + diff --git a/src/semantics/tools.py b/src/semantics/tools.py index f0dd3b0af..4c0a459f6 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,7 +1,7 @@ import itertools as itt from collections import OrderedDict from typing import FrozenSet -from semantics.utils import from_dict_to_set +#from semantics.utils import from_dict_to_set class InternalError(Exception): @property @@ -155,6 +155,22 @@ def least_common_ancestor(self, other): if this == None: return None return this + + def __str__(self): + output = f'type {self.name}' + parent = '' if self.parent is None else f' : {self.parent.name}' + output += parent + output += ' {' + output += '\n\t' if self.attributes or self.methods else '' + output += '\n\t'.join(str(x) for x in self.attributes) + output += '\n\t' if self.attributes else '' + output += '\n\t'.join(str(x) for x in self.methods) + output += '\n' if self.methods else '' + output += '}\n' + return output + + def __repr__(self): + return str(self) class TypeBag: def __init__(self, type_set, heads = []) -> None: @@ -215,6 +231,7 @@ def swap_types(self, update_type, remove_type): pass return self + def clone(self): clone = TypeBag(self.type_set, self.heads) clone.condition_list = self.condition_list @@ -231,9 +248,6 @@ def conforms_to(self, other): def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") -class AutoType(Type): - pass - class ErrorType(Type): def __init__(self): self.name = "" @@ -248,18 +262,20 @@ def __init__(self) -> None: def create_type(self, name:str) -> Type: if name in self.types: raise SemanticError(f'Type with the same name ({name}) already exists.') - if name[0] != name[0].upper: + if name[0] != name[0].upper(): raise SemanticError(f'Type name ({name}) must start with upper case') typex = self.types[name] = Type(name) return typex - def get_type(self, name:str, selftype=True, autotype=True) -> Type: + def get_type(self, name:str, selftype=True, autotype=True, unpacked=False) -> Type: if selftype and name == "SELF_TYPE": return TypeBag({SelfType()}) #SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: + if unpacked: + return self.types[name] return TypeBag({self.types[name]}) except KeyError: raise TypeError(f'Type "{name}" is not defined.') @@ -339,4 +355,10 @@ def next_child(self): def reset(self): self.current_child = -1 for child in self.children: - child.reset() \ No newline at end of file + child.reset() + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set \ No newline at end of file diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 98f53b865..b4f31d8f1 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,14 +1,14 @@ import semantics.visitor as visitor -from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.utils import SemanticError -from semantics.utils import Context +from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.tools import SemanticError +from semantics.tools import ErrorType, SelfType +from semantics.tools import Context -class TypeCollector(object): - def __init__(self) -> None: - self.context = Context() +class TypeBuilder: + def __init__(self, context: Context): + self.context = context + self.current_type = None self.errors = [] - - self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} @visitor.on('node') def visit(self, node): @@ -16,82 +16,92 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): - self.context = Context() - self.init_default_classes() + self.build_default_classes() for class_def in node.declarations: self.visit(class_def) - new_declarations = self.get_type_hierarchy() - node.declarations = new_declarations - self.context.type_graph = self.type_graph - + try: + self.context.get_type('Main', unpacked=True).get_method('main', local=True) + except SemanticError as err: + self.add_error(node, err.text) + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id, unpacked=True) + + if node.parent: + try: + parent_type = self.context.get_type(node.parent, unpacked=True) + self.current_type.set_parent(parent_type) + for idx, _ in list(parent_type.all_attributes(True)): + self.current_type.attributes.append(idx) + except SemanticError as err: + self.add_error(node, err.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) def visit(self, node): try: - self.context.create_type(node.id) - self.type_graph[node.id] = [] - if node.parent: - if node.parent in {'String', 'Int, Bool'}: - raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") - try: - self.type_graph[node.parent].append(node.id) - except KeyError: - self.type_graph[node.parent] = [node.id] - else: - node.parent = "Object" - self.type_graph["Object"] = [node.id] - except SemanticError as error: - self.add_error(node, error.text) + attr_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(node, err.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as err: + self.add_error(err.text) - def get_type_hierarchy(self): - visited = set(["Object"]) - new_order = [] - self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) + @visitor.when(MethodDeclarationNode) + def visit(self, node): + try: + ret_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(err.text) + ret_type = ErrorType() + + params_type = [] + params_name = [] + for p_name, p_type in node.params: + try: + params_type.append(self.context.get_type(p_type)) + except SemanticError as err: + params_type.append(ErrorType()) + self.add_error(node, err.text) + params_name.append(p_name) + + try: + self.current_type.define_method(node.id, params_name, params_type, ret_type) + except SemanticError as err: + self.add_error(node, err.text) - circular_heritage_errors = [] - for node in self.type_graph: - if not node in visited: - visited.add(node) - path = [node] - circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) - new_order = new_order + [self.context.get_type(node) for node in path] - - if circular_heritage_errors: - error = "Semantic Error: Circular Heritage:\n" - error += "\n".join(err for err in circular_heritage_errors) - self.add_error(None, error) + def build_default_classes(self): + Object = self.context.get_type("Object", unpacked=True) + String = self.context.get_type("String", unpacked=True) + Int = self.context.get_type("Int", unpacked=True) + Io = self.context.get_type("IO", unpacked=True) + Bool = self.context.get_type("Bool", unpacked=True) - return new_order + String.set_parent(Object) + Int.set_parent(Object) + Io.set_parent(Object) + Bool.set_parent(Object) - def dfs_type_graph(self, root, graph, visited:set, new_order, index): - if not root in graph: - return - - for node in graph[root]: - if node in visited: - continue - visited.add(node) - if node not in {"Int", "String", "IO", "Bool", "Object"}: - new_order.append(self.context.get_type(node)) - self.context.get_type(node).index = index - self.dfs_type_graph(node, graph, visited, new_order, index + 1) - - def check_circular_heritage(self, root, graph, path, visited): - for node in graph[root]: - if node in path: - return ' -> '.join(child for child in visited + [visited[0]]) + Object.define_method("abort", [], [], Object) + Object.define_method("type_name", [], [], String) + Object.define_method("copy", [], [], SelfType()) - visited.add(node) - path.append(node) - return self.check_circular_heritage(node, graph, path, visited) + String.define_method("length", [], [], Int) + String.define_method("concat", ["s"], [String], String) + String.define_method("substr", ["i", "l"], [Int, Int], String) - def init_default_classes(self): - self.context.create_type('Object').index = 0 - self.context.create_type('String') - self.context.create_type('Int') - self.context.create_type('IO') - self.context.create_type('Bool') + Io.define_method("out_string", ["x"],[String], SelfType()) + Io.define_method("out_int", ["x"],[Int], SelfType()) + Io.define_method("in_string", [],[], String) + Io.define_method("in_int", [], [], Int) def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 450f6844d..77a110147 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,107 +1,99 @@ import semantics.visitor as visitor -from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.utils import SemanticError -from semantics.utils import ErrorType, SelfType -from semantics.utils import Context +from parsing.ast import Node, ProgramNode, ClassDeclarationNode +from semantics.tools import SemanticError +from semantics.tools import Context -class TypeBuilder: - def __init__(self, context: Context): - self.context = context - self.current_type = None +class TypeCollector(object): + def __init__(self) -> None: + self.context = Context() self.errors = [] - + self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + self.node_dict = dict() + @visitor.on('node') def visit(self, node): pass @visitor.when(ProgramNode) def visit(self, node): - self.build_default_classes() + self.context = Context() + self.init_default_classes() for class_def in node.declarations: self.visit(class_def) - try: - self.context.get_type('Main').get_method('main', local=True) - except SemanticError as err: - self.add_error(node, err.text) - - @visitor.when(ClassDeclarationNode) - def visit(self, node): - self.current_type = self.context.get_type(node.id) - - if node.parent: - try: - parent_type = self.context.get_type(node.parent) - self.current_type.set_parent(parent_type) - for idx, _ in list(parent_type.all_attributes(True)): - self.current_type.attributes.append(idx) - except SemanticError as err: - self.add_error(node, err.text) - - for feature in node.features: - self.visit(feature) + new_declarations = self.get_type_hierarchy() + node.declarations = new_declarations + self.context.type_graph = self.type_graph - @visitor.when(AttrDeclarationNode) + @visitor.when(ClassDeclarationNode) def visit(self, node): try: - attr_type = self.context.get_type(node.type) - except SemanticError as err: - self.add_error(node, err.text) - attr_type = ErrorType() - - try: - self.current_type.define_attribute(node.id, attr_type) - except SemanticError as err: - self.add_error(err.text) + self.context.create_type(node.id) + self.type_graph[node.id] = [] + self.node_dict[node.id] = node + if node.parent: + if node.parent in {'String', 'Int, Bool'}: + raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + try: + self.type_graph[node.parent].append(node.id) + except KeyError: + self.type_graph[node.parent] = [node.id] + else: + node.parent = "Object" + self.type_graph["Object"].append(node.id) + except SemanticError as error: + self.add_error(node, error.text) - @visitor.when(MethodDeclarationNode) - def visit(self, node): - try: - ret_type = self.context.get_type(node.type) - except SemanticError as err: - self.add_error(err.text) - ret_type = ErrorType() - - params_type = [] - params_name = [] - for p_name, p_type in node.params: - try: - params_type.append(self.context.get_type(p_type)) - except SemanticError as err: - params_type.append(ErrorType()) - self.add_error(node, err.text) - params_name.append(p_name) - - try: - self.current_type.define_method(node.id, params_name, params_type, ret_type) - except SemanticError as err: - self.add_error(node, err.text) + def get_type_hierarchy(self): + visited = set(["Object"]) + new_order = [] + self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) - def build_default_classes(self): - Object = self.context.get_type("Object") - String = self.context.get_type("String") - Int = self.context.get_type("Int") - Io = self.context.get_type("IO") - Bool = self.context.get_type("Bool") + circular_heritage_errors = [] + for node in self.type_graph: + if not node in visited: + visited.add(node) + path = [node] + circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + new_order = new_order + [self.context.get_type(node) for node in path] + + if circular_heritage_errors: + print(circular_heritage_errors) + error = "Semantic Error: Circular Heritage:\n" + error += "\n".join(err for err in circular_heritage_errors) + self.add_error(None, error) - String.set_parent(Object) - Int.set_parent(Object) - Io.set_parent(Object) - Bool.set_parent(Object) + return new_order - Object.define_method("abort", [], [], Object) - Object.define_method("type_name", [], [], String) - Object.define_method("copy", [], [], SelfType()) + def dfs_type_graph(self, root, graph, visited:set, new_order, index): + if not root in graph: + return + + for node in graph[root]: + if node in visited: + continue + visited.add(node) + if node not in {"Int", "String", "IO", "Bool", "Object"}: + new_order.append(self.node_dict[node]) + self.context.get_type(node).index = index + self.dfs_type_graph(node, graph, visited, new_order, index + 1) + + def check_circular_heritage(self, root, graph, path, visited): + for node in graph[root]: + if node in path: + return ' -> '.join(child for child in visited + [visited[0]]) - String.define_method("length", [], [], Int) - String.define_method("concat", ["s"], [String], String) - String.define_method("substr", ["i", "l"], [Int, Int], String) + visited.add(node) + path.append(node) + return self.check_circular_heritage(node, graph, path, visited) - Io.define_method("out_string", ["x"],[String], SelfType()) - Io.define_method("out_int", ["x"],[Int], SelfType()) - Io.define_method("in_string", [],[], String) - Io.define_method("in_int", [], [], Int) + def init_default_classes(self): + self.context.create_type('Object').index = 0 + self.context.create_type('String') + self.context.create_type('Int') + self.context.create_type('IO') + self.context.create_type('Bool') def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 2f9d90686..88c089983 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,4 +1,4 @@ -from semantics.tools import Type, ErrorType, AutoType, TypeBag +from semantics.tools import Type, TypeBag def conforms(bag1:TypeBag, bag2:TypeBag): ordered_set = order_set_by_index(bag2.type_set) @@ -98,11 +98,7 @@ def auto_add(type_set:set, head_list:list, bag:TypeBag): def order_set_by_index(type_set): return sorted(list(type_set), lambda x: x.index) -def from_dict_to_set(types:dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set + def set_intersection(parent, type_set) -> set: set_result = set() diff --git a/src/zTests/Misc/0HelloWorld.txt b/src/zTests/Misc/0HelloWorld.txt new file mode 100644 index 000000000..8ab5bd3a5 --- /dev/null +++ b/src/zTests/Misc/0HelloWorld.txt @@ -0,0 +1,5 @@ +class Main inherits IO { + main(): SELF_TYPE { + out_string("Hello, World.\n") + }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/0Simple.txt b/src/zTests/Misc/0Simple.txt new file mode 100644 index 000000000..9046024dc --- /dev/null +++ b/src/zTests/Misc/0Simple.txt @@ -0,0 +1,13 @@ +class Main{ + a: A; + + main(): A { + a <- new A + }; +}; + +class A { + method(): Int{ + 1 + }; +}; diff --git a/src/zTests/Misc/0SimpleSpaced.txt b/src/zTests/Misc/0SimpleSpaced.txt new file mode 100644 index 000000000..151be34fe --- /dev/null +++ b/src/zTests/Misc/0SimpleSpaced.txt @@ -0,0 +1,13 @@ +class Main { + a : A ; + + main ( ) : A { + a <- new A + } ; +} ; + +class A { + method ( ) : Int { + 1 + } ; +} ; \ No newline at end of file diff --git a/src/zTests/Misc/10.txt b/src/zTests/Misc/10.txt new file mode 100644 index 000000000..5cffd4f8c --- /dev/null +++ b/src/zTests/Misc/10.txt @@ -0,0 +1,10 @@ + +class Main{ + a: A; + main(b:Int): A { + b <- 3 + a + }; +}; + +class A{}; \ No newline at end of file diff --git a/src/zTests/Misc/11.txt b/src/zTests/Misc/11.txt new file mode 100644 index 000000000..f4afdca9a --- /dev/null +++ b/src/zTests/Misc/11.txt @@ -0,0 +1,10 @@ +class Silly +{ + capy() : SELF_TYPE { self }; +}; +class Sally inherits Silly { }; + +class Main { + x : Sally <- (new Sally).capy(); + main() : Sally { x }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/1Ackerman.txt b/src/zTests/Misc/1Ackerman.txt new file mode 100644 index 000000000..0ca3e1c7f --- /dev/null +++ b/src/zTests/Misc/1Ackerman.txt @@ -0,0 +1,24 @@ +class Main inherits IO{ + a : Ackermann ; + main(): SELF_TYPE {{ + a <- new Ackermann; + out_int(a.ackermann(1,3)); + } + }; +}; + +class Fact { + fact(n : Int): Int{ + if (n=0) then 1 else n*fact(n-1) fi + }; +}; + +class Ackermann { + ackermann(m:Int, n: Int): Int{ + if (m = 0 ) then n+1 else + if ( n = 0) then ackermann(m-1, 1) else + ackermann(m-1, ackermann(m, n-1)) + fi + fi + }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/3.txt b/src/zTests/Misc/3.txt new file mode 100644 index 000000000..a43e3fa4a --- /dev/null +++ b/src/zTests/Misc/3.txt @@ -0,0 +1,93 @@ +class CellularAutomaton inherits IO { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + self; + } + }; + + print() : SELF_TYPE { + { + out_string(population_map.concat("\n")); + self; + } + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + population_map.substr(position, 1) + }; + + cell_left_neighbor(position : Int) : String { + if position = 0 then + cell(num_cells() - 1) + else + cell(position - 1) + fi + }; + + cell_right_neighbor(position : Int) : String { + if position = num_cells() - 1 then + cell(0) + else + cell(position + 1) + fi + }; + + (* a cell will live if exactly 1 of itself and it's immediate + neighbors are alive *) + cell_at_next_evolution(position : Int) : String { + if ((if cell(position) = "X" then 1 else 0 fi) + + (if cell_left_neighbor(position) = "X" then 1 else 0 fi) + + (if cell_right_neighbor(position) = "X" then 1 else 0 fi) + = 1) + then + "X" + else + "." + fi + }; + + evolve() : SELF_TYPE { + (let position : Int in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; +}; + +class Main { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + cells <- (new CellularAutomaton).init(" X "); + cells.print(); + (let countdown : Int <- 20 in + while 0 < countdown loop + { + cells.evolve(); + cells.print(); + countdown <- countdown - 1; + } + pool + ); + self; + } + }; +}; diff --git a/src/zTests/Misc/5.txt b/src/zTests/Misc/5.txt new file mode 100644 index 000000000..daebec7e6 --- /dev/null +++ b/src/zTests/Misc/5.txt @@ -0,0 +1,64 @@ +(* hairy . . .*) + +class Foo inherits Bazz { + a : Razz <- case self of + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + b : Int <- a.doh() + g.doh() + doh() + printh(); + + doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; + +}; + +class Bar inherits Razz { + + c : Int <- doh(); + + d : Object <- printh(); +}; + + +class Razz inherits Foo { + + e : Bar <- case self of + n : Razz => (new Bar); + n : Bar => n; + esac; + + f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); + +}; + +class Bazz inherits IO { + + h : Int <- 1; + + g : Foo <- case self of + n : Bazz => (new Foo); + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + i : Object <- printh(); + + printh() : Int { { out_int(h); 0; } }; + + doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; +}; + +(* scary . . . *) +class Main inherits IO{ + a : Bazz <- new Bazz; + b : Foo <- new Foo; + c : Razz <- new Razz; + d : Bar <- new Bar; + + main(): String { out_string("do nothing, except this") }; + +}; + + diff --git a/src/zTests/Misc/6.txt b/src/zTests/Misc/6.txt new file mode 100644 index 000000000..25facd526 --- /dev/null +++ b/src/zTests/Misc/6.txt @@ -0,0 +1,436 @@ +(* The Game of Life + Tendo Kayiira, Summer '95 + With code taken from /private/cool/class/examples/cells.cl + + This introduction was taken off the internet. It gives a brief + description of the Game Of Life. It also gives the rules by which + this particular game follows. + + Introduction + + John Conway's Game of Life is a mathematical amusement, but it + is also much more: an insight into how a system of simple + cellualar automata can create complex, odd, and often aesthetically + pleasing patterns. It is played on a cartesian grid of cells + which are either 'on' or 'off' The game gets it's name from the + similarity between the behaviour of these cells and the behaviour + of living organisms. + + The Rules + + The playfield is a cartesian grid of arbitrary size. Each cell in + this grid can be in an 'on' state or an 'off' state. On each 'turn' + (called a generation,) the state of each cell changes simultaneously + depending on it's state and the state of all cells adjacent to it. + + For 'on' cells, + If the cell has 0 or 1 neighbours which are 'on', the cell turns + 'off'. ('dies of loneliness') + If the cell has 2 or 3 neighbours which are 'on', the cell stays + 'on'. (nothing happens to that cell) + If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', + the cell turns 'off'. ('dies of overcrowding') + + For 'off' cells, + If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which + are 'on', the cell stays 'off'. (nothing happens to that cell) + If the cell has 3 neighbours which are 'on', the cell turns + 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) + + Repeat for as many generations as desired. + + *) + + +class Board inherits IO { + + rows : Int; + columns : Int; + board_size : Int; + + size_of_board(initial : String) : Int { + initial.length() + }; + + board_init(start : String) : SELF_TYPE { + (let size :Int <- size_of_board(start) in + { + if size = 15 then + { + rows <- 3; + columns <- 5; + board_size <- size; + } + else if size = 16 then + { + rows <- 4; + columns <- 4; + board_size <- size; + } + else if size = 20 then + { + rows <- 4; + columns <- 5; + board_size <- size; + } + else if size = 21 then + { + rows <- 3; + columns <- 7; + board_size <- size; + } + else if size = 25 then + { + rows <- 5; + columns <- 5; + board_size <- size; + } + else if size = 28 then + { + rows <- 7; + columns <- 4; + board_size <- size; + } + else + { + rows <- 5; + columns <- 5; + board_size <- size; + } + fi fi fi fi fi fi; + self; + } + ) + }; + +}; + + + +class CellularAutomaton inherits Board { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + board_init(map); + self; + } + }; + + + + + print() : SELF_TYPE { + + (let i : Int <- 0 in + (let num : Int <- board_size in + { + out_string("\n"); + while i < num loop + { + out_string(population_map.substr(i,columns)); + out_string("\n"); + i <- i + columns; + } + pool; + out_string("\n"); + self; + } + ) ) + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + if board_size - 1 < position then + " " + else + population_map.substr(position, 1) + fi + }; + + north(position : Int): String { + if (position - columns) < 0 then + " " + else + cell(position - columns) + fi + }; + + south(position : Int): String { + if board_size < (position + columns) then + " " + else + cell(position + columns) + fi + }; + + east(position : Int): String { + if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + cell(position + 1) + fi + }; + + west(position : Int): String { + if position = 0 then + " " + else + if ((position / columns) * columns) = position then + " " + else + cell(position - 1) + fi fi + }; + + northwest(position : Int): String { + if (position - columns) < 0 then + " " + else if ((position / columns) * columns) = position then + " " + else + north(position - 1) + fi fi + }; + + northeast(position : Int): String { + if (position - columns) < 0 then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + north(position + 1) + fi fi + }; + + southeast(position : Int): String { + if board_size < (position + columns) then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + south(position + 1) + fi fi + }; + + southwest(position : Int): String { + if board_size < (position + columns) then + " " + else if ((position / columns) * columns) = position then + " " + else + south(position - 1) + fi fi + }; + + neighbors(position: Int): Int { + { + (if north(position) = "X" then 1 else 0 fi) + + (if south(position) = "X" then 1 else 0 fi) + + (if east(position) = "X" then 1 else 0 fi) + + (if west(position) = "X" then 1 else 0 fi) + + (if northeast(position) = "X" then 1 else 0 fi) + + (if northwest(position) = "X" then 1 else 0 fi) + + (if southeast(position) = "X" then 1 else 0 fi) + + (if southwest(position) = "X" then 1 else 0 fi); + } + }; + + +(* A cell will live if 2 or 3 of it's neighbors are alive. It dies + otherwise. A cell is born if only 3 of it's neighbors are alive. *) + + cell_at_next_evolution(position : Int) : String { + + if neighbors(position) = 3 then + "X" + else + if neighbors(position) = 2 then + if cell(position) = "X" then + "X" + else + "-" + fi + else + "-" + fi fi + }; + + + evolve() : SELF_TYPE { + (let position : Int <- 0 in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; + +(* This is where the background pattern is detremined by the user. More + patterns can be added as long as whoever adds keeps the board either + 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) + option(): String { + { + (let num : Int in + { + out_string("\nPlease chose a number:\n"); + out_string("\t1: A cross\n"); + out_string("\t2: A slash from the upper left to lower right\n"); + out_string("\t3: A slash from the upper right to lower left\n"); + out_string("\t4: An X\n"); + out_string("\t5: A greater than sign \n"); + out_string("\t6: A less than sign\n"); + out_string("\t7: Two greater than signs\n"); + out_string("\t8: Two less than signs\n"); + out_string("\t9: A 'V'\n"); + out_string("\t10: An inverse 'V'\n"); + out_string("\t11: Numbers 9 and 10 combined\n"); + out_string("\t12: A full grid\n"); + out_string("\t13: A 'T'\n"); + out_string("\t14: A plus '+'\n"); + out_string("\t15: A 'W'\n"); + out_string("\t16: An 'M'\n"); + out_string("\t17: An 'E'\n"); + out_string("\t18: A '3'\n"); + out_string("\t19: An 'O'\n"); + out_string("\t20: An '8'\n"); + out_string("\t21: An 'S'\n"); + out_string("Your choice => "); + num <- in_int(); + out_string("\n"); + if num = 1 then + " XX XXXX XXXX XX " + else if num = 2 then + " X X X X X " + else if num = 3 then + "X X X X X" + else if num = 4 then + "X X X X X X X X X" + else if num = 5 then + "X X X X X " + else if num = 6 then + " X X X X X" + else if num = 7 then + "X X X XX X " + else if num = 8 then + " X XX X X X " + else if num = 9 then + "X X X X X " + else if num = 10 then + " X X X X X" + else if num = 11 then + "X X X X X X X X" + else if num = 12 then + "XXXXXXXXXXXXXXXXXXXXXXXXX" + else if num = 13 then + "XXXXX X X X X " + else if num = 14 then + " X X XXXXX X X " + else if num = 15 then + "X X X X X X X " + else if num = 16 then + " X X X X X X X" + else if num = 17 then + "XXXXX X XXXXX X XXXX" + else if num = 18 then + "XXX X X X X XXXX " + else if num = 19 then + " XX X XX X XX " + else if num = 20 then + " XX X XX X XX X XX X XX " + else if num = 21 then + " XXXX X XX X XXXX " + else + " " + fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; + } + ); + } + }; + + + + + prompt() : Bool { + { + (let ans : String in + { + out_string("Would you like to continue with the next generation? \n"); + out_string("Please use lowercase y or n for your answer [y]: "); + ans <- in_string(); + out_string("\n"); + if ans = "n" then + false + else + true + fi; + } + ); + } + }; + + + prompt2() : Bool { + (let ans : String in + { + out_string("\n\n"); + out_string("Would you like to choose a background pattern? \n"); + out_string("Please use lowercase y or n for your answer [n]: "); + ans <- in_string(); + if ans = "y" then + true + else + false + fi; + } + ) + }; + + +}; + +class Main inherits CellularAutomaton { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + (let continue : Bool in + (let choice : String in + { + out_string("Welcome to the Game of Life.\n"); + out_string("There are many initial states to choose from. \n"); + while prompt2() loop + { + continue <- true; + choice <- option(); + cells <- (new CellularAutomaton).init(choice); + cells.print(); + while continue loop + if prompt() then + { + cells.evolve(); + cells.print(); + } + else + continue <- false + fi + pool; + } + pool; + self; + } ) ); } + }; +}; + diff --git a/src/zTests/Misc/7.txt b/src/zTests/Misc/7.txt new file mode 100644 index 000000000..098e965fe --- /dev/null +++ b/src/zTests/Misc/7.txt @@ -0,0 +1,426 @@ + +class VarList inherits IO { + isNil() : Bool { true }; + head() : Variable { { abort(); new Variable; } }; + tail() : VarList { { abort(); new VarList; } }; + add(x : Variable) : VarList { (new VarListNE).init(x, self) }; + print() : SELF_TYPE { out_string("\n") }; +}; + +class VarListNE inherits VarList { + x : Variable; + rest : VarList; + isNil() : Bool { false }; + head() : Variable { x }; + tail() : VarList { rest }; + init(y : Variable, r : VarList) : VarListNE { { x <- y; rest <- r; self; } }; + print() : SELF_TYPE { { x.print_self(); out_string(" "); + rest.print(); self; } }; +}; + +class LambdaList { + isNil() : Bool { true }; + headE() : VarList { { abort(); new VarList; } }; + headC() : Lambda { { abort(); new Lambda; } }; + headN() : Int { { abort(); 0; } }; + tail() : LambdaList { { abort(); new LambdaList; } }; + add(e : VarList, x : Lambda, n : Int) : LambdaList { + (new LambdaListNE).init(e, x, n, self) + }; +}; + +class LambdaListNE inherits LambdaList { + lam : Lambda; + num : Int; + env : VarList; + rest : LambdaList; + isNil() : Bool { false }; + headE() : VarList { env }; + headC() : Lambda { lam }; + headN() : Int { num }; + tail() : LambdaList { rest }; + init(e : VarList, l : Lambda, n : Int, r : LambdaList) : LambdaListNE { + { + env <- e; + lam <- l; + num <- n; + rest <- r; + self; + } + }; +}; + +class LambdaListRef { + nextNum : Int <- 0; + l : LambdaList; + isNil() : Bool { l.isNil() }; + headE() : VarList { l.headE() }; + headC() : Lambda { l.headC() }; + headN() : Int { l.headN() }; + reset() : SELF_TYPE { + { + nextNum <- 0; + l <- new LambdaList; + self; + } + }; + add(env : VarList, c : Lambda) : Int { + { + l <- l.add(env, c, nextNum); + nextNum <- nextNum + 1; + nextNum - 1; + } + }; + removeHead() : SELF_TYPE { + { + l <- l.tail(); + self; + } + }; +}; + + +class Expr inherits IO { + + print_self() : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't print self\n"); + abort(); + self; + } + }; + + beta() : Expr { + { + out_string("\nError: Expr is pure virtual; can't beta-reduce\n"); + abort(); + self; + } + }; + + substitute(x : Variable, e : Expr) : Expr { + { + out_string("\nError: Expr is pure virtual; can't substitute\n"); + abort(); + self; + } + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't gen_code\n"); + abort(); + self; + } + }; +}; + +class Variable inherits Expr { + name : String; + + init(n:String) : Variable { + { + name <- n; + self; + } + }; + + print_self() : SELF_TYPE { + out_string(name) + }; + + beta() : Expr { self }; + + substitute(x : Variable, e : Expr) : Expr { + if x = self then e else self fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + let cur_env : VarList <- env in + { while (if cur_env.isNil() then + false + else + not (cur_env.head() = self) + fi) loop + { out_string("get_parent()."); + cur_env <- cur_env.tail(); + } + pool; + if cur_env.isNil() then + { out_string("Error: free occurrence of "); + print_self(); + out_string("\n"); + abort(); + self; + } + else + out_string("get_x()") + fi; + } + }; +}; + +class Lambda inherits Expr { + arg : Variable; + body : Expr; + + init(a:Variable, b:Expr) : Lambda { + { + arg <- a; + body <- b; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("\\"); + arg.print_self(); + out_string("."); + body.print_self(); + self; + } + }; + + beta() : Expr { self }; + + apply(actual : Expr) : Expr { + body.substitute(arg, actual) + }; + + substitute(x : Variable, e : Expr) : Expr { + if x = arg then + self + else + let new_body : Expr <- body.substitute(x, e), + new_lam : Lambda <- new Lambda in + new_lam.init(arg, new_body) + fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("((new Closure"); + out_int(closures.add(env, self)); + out_string(").init("); + if env.isNil() then + out_string("new Closure))") + else + out_string("self))") fi; + self; + } + }; + + gen_closure_code(n : Int, env : VarList, + closures : LambdaListRef) : SELF_TYPE { + { + out_string("class Closure"); + out_int(n); + out_string(" inherits Closure {\n"); + out_string(" apply(y : EvalObject) : EvalObject {\n"); + out_string(" { out_string(\"Applying closure "); + out_int(n); + out_string("\\n\");\n"); + out_string(" x <- y;\n"); + body.gen_code(env.add(arg), closures); + out_string(";}};\n"); + out_string("};\n"); + } + }; +}; + + +class App inherits Expr { + fun : Expr; + arg : Expr; + + init(f : Expr, a : Expr) : App { + { + fun <- f; + arg <- a; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("(("); + fun.print_self(); + out_string(")@("); + arg.print_self(); + out_string("))"); + self; + } + }; + + beta() : Expr { + case fun of + l : Lambda => l.apply(arg); -- Lazy evaluation + e : Expr => + let new_fun : Expr <- fun.beta(), + new_app : App <- new App in + new_app.init(new_fun, arg); + esac + }; + + substitute(x : Variable, e : Expr) : Expr { + let new_fun : Expr <- fun.substitute(x, e), + new_arg : Expr <- arg.substitute(x, e), + new_app : App <- new App in + new_app.init(new_fun, new_arg) + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("(let x : EvalObject <- "); + fun.gen_code(env, closures); + out_string(",\n"); + out_string(" y : EvalObject <- "); + arg.gen_code(env, closures); + out_string(" in\n"); + out_string(" case x of\n"); + out_string(" c : Closure => c.apply(y);\n"); + out_string(" o : Object => { abort(); new EvalObject; };\n"); + out_string(" esac)"); + } + }; +}; + + + +class Term inherits IO { + + var(x : String) : Variable { + let v : Variable <- new Variable in + v.init(x) + }; + + lam(x : Variable, e : Expr) : Lambda { + let l : Lambda <- new Lambda in + l.init(x, e) + }; + + app(e1 : Expr, e2 : Expr) : App { + let a : App <- new App in + a.init(e1, e2) + }; + + (* + * Some useful terms + *) + i() : Expr { + let x : Variable <- var("x") in + lam(x,x) + }; + + k() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y") in + lam(x,lam(y,x)) + }; + + s() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y"), + z : Variable <- var("z") in + lam(x,lam(y,lam(z,app(app(x,z),app(y,z))))) + }; + +}; + + + +class Main inherits Term { + beta_reduce(e : Expr) : Expr { + { + out_string("beta-reduce: "); + e.print_self(); + let done : Bool <- false, + new_expr : Expr in + { + while (not done) loop + { + new_expr <- e.beta(); + if (new_expr = e) then + done <- true + else + { + e <- new_expr; + out_string(" =>\n"); + e.print_self(); + } + fi; + } + pool; + out_string("\n"); + e; + }; + } + }; + + eval_class() : SELF_TYPE { + { + out_string("class EvalObject inherits IO {\n"); + out_string(" eval() : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + closure_class() : SELF_TYPE { + { + out_string("class Closure inherits EvalObject {\n"); + out_string(" parent : Closure;\n"); + out_string(" x : EvalObject;\n"); + out_string(" get_parent() : Closure { parent };\n"); + out_string(" get_x() : EvalObject { x };\n"); + out_string(" init(p : Closure) : Closure {{ parent <- p; self; }};\n"); + out_string(" apply(y : EvalObject) : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + gen_code(e : Expr) : SELF_TYPE { + let cl : LambdaListRef <- (new LambdaListRef).reset() in + { + out_string("Generating code for "); + e.print_self(); + out_string("\n------------------cut here------------------\n"); + out_string("(*Generated by lam.cl (Jeff Foster, March 2000)*)\n"); + eval_class(); + closure_class(); + out_string("class Main {\n"); + out_string(" main() : EvalObject {\n"); + e.gen_code(new VarList, cl); + out_string("\n};\n};\n"); + while (not (cl.isNil())) loop + let e : VarList <- cl.headE(), + c : Lambda <- cl.headC(), + n : Int <- cl.headN() in + { + cl.removeHead(); + c.gen_closure_code(n, e, cl); + } + pool; + out_string("\n------------------cut here------------------\n"); + } + }; + + main() : Int { + { + i().print_self(); + out_string("\n"); + k().print_self(); + out_string("\n"); + s().print_self(); + out_string("\n"); + beta_reduce(app(app(app(s(), k()), i()), i())); + beta_reduce(app(app(k(),i()),i())); + gen_code(app(i(), i())); + gen_code(app(app(app(s(), k()), i()), i())); + gen_code(app(app(app(app(app(app(app(app(i(), k()), s()), s()), + k()), s()), i()), k()), i())); + gen_code(app(app(i(), app(k(), s())), app(k(), app(s(), s())))); + 0; + } + }; +}; diff --git a/src/zTests/Misc/8.txt b/src/zTests/Misc/8.txt new file mode 100644 index 000000000..51274315c --- /dev/null +++ b/src/zTests/Misc/8.txt @@ -0,0 +1,34 @@ +class H +{ + a:int; +}; + +class Z inherits H +{ + x:int; +}; + +class A inherits F +{ + b:int; +}; + +class B inherits A +{ + c:int; +}; + +class C inherits B +{ + e:int; +}; + +class D inherits C +{ + f:int; +}; + +class F inherits D +{ + g:int; +}; \ No newline at end of file diff --git a/src/zTests/Misc/9.txt b/src/zTests/Misc/9.txt new file mode 100644 index 000000000..978e266e2 --- /dev/null +++ b/src/zTests/Misc/9.txt @@ -0,0 +1,23 @@ + +class Main{ + a: A; + main(): A { + 1 + }; +}; + +class A { + oper(a : Int, b : Int): Int{ + a + b + }; +}; +class B inherits A { + oper(a : Int, b : Int, c : Int) : Int{ + a * b * c + }; +}; +class C inherits A { + oper(a : Int, b : String) : Bool{ + a + b + }; +}; \ No newline at end of file From 347ffcb0362100a457552b24e3e2531e5c487b3d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 12:27:05 -0500 Subject: [PATCH 014/432] Minor Re-Structuiring and bug fixes --- src/devdeb.py | 8 +- src/parsing/ast.py | 1 - src/semantics/autotype_collector.py | 40 +++-- src/semantics/tools.py | 151 ++++++++++++++++-- src/semantics/type_builder.py | 31 ++-- src/semantics/utils.py | 102 +----------- .../Misc/{0HelloWorld.txt => 00HelloRodro.cl} | 4 +- src/zTests/Misc/{0Simple.txt => 01Simple.cl} | 0 src/zTests/Misc/{10.txt => 02Simple.cl} | 3 +- src/zTests/Misc/{9.txt => 03Simple.cl} | 0 src/zTests/Misc/{11.txt => 04SallySilly.cl} | 0 .../Misc/{1Ackerman.txt => 05Ackerman.cl} | 0 src/zTests/Misc/{5.txt => 06FooBarRaz.cl} | 0 src/zTests/Misc/{8.txt => 07MultipleClass.cl} | 0 src/zTests/Misc/{3.txt => 08Cellullar.cl} | 0 src/zTests/Misc/{6.txt => 09GameOfLife.cl} | 0 src/zTests/Misc/0SimpleSpaced.txt | 13 -- src/zTests/Misc/{7.txt => 10BiG.cl} | 0 18 files changed, 194 insertions(+), 159 deletions(-) rename src/zTests/Misc/{0HelloWorld.txt => 00HelloRodro.cl} (61%) rename src/zTests/Misc/{0Simple.txt => 01Simple.cl} (100%) rename src/zTests/Misc/{10.txt => 02Simple.cl} (69%) rename src/zTests/Misc/{9.txt => 03Simple.cl} (100%) rename src/zTests/Misc/{11.txt => 04SallySilly.cl} (100%) rename src/zTests/Misc/{1Ackerman.txt => 05Ackerman.cl} (100%) rename src/zTests/Misc/{5.txt => 06FooBarRaz.cl} (100%) rename src/zTests/Misc/{8.txt => 07MultipleClass.cl} (100%) rename src/zTests/Misc/{3.txt => 08Cellullar.cl} (100%) rename src/zTests/Misc/{6.txt => 09GameOfLife.cl} (100%) delete mode 100644 src/zTests/Misc/0SimpleSpaced.txt rename src/zTests/Misc/{7.txt => 10BiG.cl} (100%) diff --git a/src/devdeb.py b/src/devdeb.py index 86868597e..b7c205cd4 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -36,8 +36,13 @@ def run_pipeline(program): folder_path = r'./zTests/Misc' filenames = os.listdir(folder_path) filenames.sort() +count = 4 for filename in filenames: + if count == 0: + print("Reach Count Limit") + break + path = os.path.join(folder_path, filename) file = open(path, "r") program = file.read() @@ -45,7 +50,8 @@ def run_pipeline(program): print(f"Running {filename}") run_pipeline(program) - input() + count -= 1 + print("-------------------------------------------------------------------------\n") print("EndOfFiles") diff --git a/src/parsing/ast.py b/src/parsing/ast.py index 53abf401c..8f7b3dd01 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -23,7 +23,6 @@ def __init__(self, declarations): class DeclarationNode(Node): pass - class ClassDeclarationNode(DeclarationNode): def __init__(self, idx, features, parent=None): Node.__init__(self) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index da2dcc28a..c3c0a1265 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -1,4 +1,4 @@ -from semantics.utils import conforms, join, join_list, smart_add +from semantics.tools import conforms, join, join_list, smart_add import semantics.visitor as visitor 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 @@ -7,8 +7,6 @@ class AutotypeCollector: def __init__(self, context:Context): self.context = context self.current_type = None - self.current_method = None - self.current_attrb = None self.inference_graph = dict() self.errors = [] @@ -26,7 +24,7 @@ def visit(self, node:ProgramNode) -> Scope: @visitor.when(ClassDeclarationNode) def visit(self, node, scope): - self.current_type = self.context.get_type(node.id) + self.current_type = self.context.get_type(node.id, unpacked=True) scope.define_variable("self", self.current_type) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) @@ -36,14 +34,14 @@ def visit(self, node, scope): @visitor.when(AttrDeclarationNode) def visit(self, node, scope): - node_type = self.current_type.get_attribute(node.id).swap_self_type(self.current_type) + node_type = self.current_type.get_attribute(node.id).type.swap_self_type(self.current_type) if not node.expr: node.inferenced_type = node_type return self.visit(node.expr, scope) node_expr = node.expr.inferenced_type - node_expr = conforms(node_expr, node_type) + conforms(node_expr, node_type) var = scope.find_variable(node.id) var.type = node_type @@ -58,9 +56,9 @@ def visit(self, node, scopex): 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_decl = 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) + conforms(ret_type_expr, ret_type_decl) node.body.inferenced_type = ret_type_expr node.inferenced_type = ret_type_decl.clone() @@ -68,20 +66,20 @@ def visit(self, node, scopex): @visitor.when(BlocksNode) def visit(self, node, scope): - for expr in node.body: + for expr in node.expr_list: self.visit(expr, scope) - node.inferenced_type = node.body[-1].inferenced_type + node.inferenced_type = node.expr_list[-1].inferenced_type @visitor.when(ConditionalNode) def visit(self, node, scope): - self.visit(node.condition) + 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.then_body) + self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type - self.visit(node.else_body) + self.visit(node.else_body, scope) else_type = node.else_body.inferenced_type joined_type = join(then_type, else_type) @@ -118,13 +116,13 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") conforms(condition_type, bool_type) - self.visit(node.bodyexpr, scope) + self.visit(node.body, 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: + for var in node.var_decl_list: self.visit(var, child) self.visit(node.in_expr, scope) node.inferenced_type = node.in_expr.inferenced_type @@ -172,12 +170,12 @@ def visit(self, node, scope:Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): if node.expr == None: - caller = self.current_type + caller = TypeBag({self.current_type}) elif node.type == None: - self.visit(node.expr) + self.visit(node.expr, scope) caller = node.expr.inferenced_type else: - self.visit(node.expr) + self.visit(node.expr, scope) bridge = node.expr.inferenced_type caller = self.context.get_type(node.type, selftype=False, autotype=False) conforms(bridge, caller) @@ -194,7 +192,7 @@ def visit(self, node, scope): elif len(caller.type_set) == 1: caller_type = caller.heads[0] try: - methods = [caller_type, caller_type.get_method(node.id)] + methods = [(caller_type, caller_type.get_method(node.id))] except SemanticError: pass #Add Error @@ -241,7 +239,7 @@ def visit(self, node, scope): @visitor.when(VariableNode) def visit(self, node, scope): - var = scope.find_variable(node.expr) + var = scope.find_variable(node.value) if var: node.defined = True var_type = var.type @@ -276,7 +274,7 @@ def visit(self, node, scope): @visitor.when(InstantiateNode) def visit(self, node, scope): try: - node_type = self.context.get_type(node.expr, selftype=False, autotype=False) + node_type = self.context.get_type(node.value, selftype=False, autotype=False) except SemanticError as err: node_type = ErrorType() node.inferenced_type = node_type diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 4c0a459f6..5e8c042bf 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,7 +1,8 @@ import itertools as itt from collections import OrderedDict from typing import FrozenSet -#from semantics.utils import from_dict_to_set + +from semantics.utils import conform_to_condition, order_set_by_index class InternalError(Exception): @property @@ -65,6 +66,16 @@ def set_parent(self, parent): raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') self.parent = parent + def define_attribute(self, name:str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') + def get_attribute(self, name:str): try: return next(attr for attr in self.attributes if attr.name == name) @@ -97,7 +108,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ parent_method = None if parent_method: error_list = [] - if not return_type.conforms_to(parent_method.return_type): + if conforms(return_type, parent_method.return_type): error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") @@ -176,8 +187,10 @@ class TypeBag: def __init__(self, type_set, heads = []) -> None: self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) self.heads:list = heads - if len(type_set) == 1: + if len(self.type_set) == 1: self.heads = list(self.type_set) + + self.name = self.generate_name() self.condition_list = [] self.conform_list = [] @@ -185,10 +198,11 @@ def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list self.update_type_set_from_conforms() + self.name = self.generate_name() def update_type_set_from_conforms(self): intersect_set = set() - for conform_set in self.conforms_list: + for conform_set in self.conform_list: intersect_set = intersect_set.union(conform_set) self.type_set = self.type_set.intersection(intersect_set) self.update_heads() @@ -196,7 +210,7 @@ def update_type_set_from_conforms(self): def update_heads(self): new_heads = [] visited = set() - for head in self.upper_limmit: + for head in self.heads: if head in self.type_set: new_heads.append(head) continue @@ -213,7 +227,7 @@ def update_heads(self): elif typex.index == lower_index: new_heads.append(typex) new_heads += new_heads - self.upper_limmit = new_heads + self.heads = new_heads def swap_self_type(self, update_type): try: @@ -231,6 +245,14 @@ def swap_types(self, update_type, remove_type): pass return self + def generate_name(self): + if len(self.type_set) == 1: + return self.heads[0].name + + s = "{" + s += ', '.join(typex.name for typex in sorted(self.type_set, key = lambda t: t.index)) + s += "}" + return s def clone(self): clone = TypeBag(self.type_set, self.heads) @@ -241,6 +263,7 @@ def clone(self): class SelfType(Type): def __init__(self): self.name = "SELF_TYPE" + self.index = 2**31 def conforms_to(self, other): #if isinstance(other, SelfType): # return True @@ -248,10 +271,28 @@ def conforms_to(self, other): def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") + + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + class ErrorType(Type): def __init__(self): self.name = "" - self.type_set = FrozenSet() + self.index = 2**32 + self.type_set = frozenset() + def conforms_to(self, other): + return True + def bypass(self): + return True + + def swap_self_type(self, update_type): + return self + + def set_conditions(self, *params): + return class Context: def __init__(self) -> None: @@ -338,7 +379,7 @@ def find_variable(self, vname, index=None): return next(x for x in locals if x.name == vname) except StopIteration: try: - return self.parent.find_variable(vname, self.index)# if self.parent else None + return self.parent.find_variable(vname, self.index) if self.parent else None except AttributeError: return None @@ -357,8 +398,92 @@ def reset(self): for child in self.children: child.reset() -def from_dict_to_set(types:dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set \ No newline at end of file + +def conforms(bag1:TypeBag, bag2:TypeBag): + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) + + bag1.set_conditions(condition_list, conform_list) + return len(bag1.type_set) >= 1 + +def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + ancestor_set = set() + head_list = [] + ordered_set1 = order_set_by_index(bag1.type_set) + ordered_set2 = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + + join_result = TypeBag(ancestor_set, head_list) + return join_result + +def join_list(type_list): + join_result = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + join_result = join(join_result, type_i) + return join_result + +def smart_add(type_set:set, head_list:list, typex:Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex + break + if not there_is: + head_list.append(typex) + return head_list, type_set + +def auto_add(type_set:set, head_list:list, bag:TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head in bag.heads: + ancestor = head_i.least_common_ancestor(head) + if ancestor in type_set: + head_i[i] = ancestor + aux.pop(head) + break + head_list += [typex for typex in aux] + return head_list, type_set + diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index b4f31d8f1..6ce5523b3 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,6 +1,6 @@ import semantics.visitor as visitor from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.tools import SemanticError +from semantics.tools import SemanticError, TypeBag from semantics.tools import ErrorType, SelfType from semantics.tools import Context @@ -65,7 +65,9 @@ def visit(self, node): params_type = [] params_name = [] - for p_name, p_type in node.params: + for var in node.params: + p_name = var.id + p_type = var.type try: params_type.append(self.context.get_type(p_type)) except SemanticError as err: @@ -90,18 +92,23 @@ def build_default_classes(self): Io.set_parent(Object) Bool.set_parent(Object) - Object.define_method("abort", [], [], Object) - Object.define_method("type_name", [], [], String) - Object.define_method("copy", [], [], SelfType()) + p_Object = self.context.get_type("Object") + p_String = self.context.get_type("String") + p_Int = self.context.get_type("Int") + p_Self = TypeBag({SelfType()}) - String.define_method("length", [], [], Int) - String.define_method("concat", ["s"], [String], String) - String.define_method("substr", ["i", "l"], [Int, Int], String) + Object.define_method("abort", [], [], p_Object) + Object.define_method("type_name", [], [], p_String) + Object.define_method("copy", [], [], p_Self) - Io.define_method("out_string", ["x"],[String], SelfType()) - Io.define_method("out_int", ["x"],[Int], SelfType()) - Io.define_method("in_string", [],[], String) - Io.define_method("in_int", [], [], Int) + String.define_method("length", [], [], p_Int) + String.define_method("concat", ["s"], [p_String], p_String) + String.define_method("substr", ["i", "l"], [p_Int, p_Int], p_String) + + Io.define_method("out_string", ["x"],[p_String], p_Self) + Io.define_method("out_int", ["x"],[p_Int], p_Self) + Io.define_method("in_string", [],[], p_String) + Io.define_method("in_int", [], [], p_Int) def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 88c089983..d0375d9e8 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,24 +1,3 @@ -from semantics.tools import Type, TypeBag - -def conforms(bag1:TypeBag, bag2:TypeBag): - ordered_set = order_set_by_index(bag2.type_set) - - condition_list = [] - conform_list = [] - for condition in ordered_set: - conform = conform_to_condition(bag1.type_set, condition) - for i in range(len(condition_list)): - conform_i = conform_list[i] - if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): - condition_list[i].add(condition) - break - else: - condition_list.append({condition}) - conform_list.append(conform) - - bag1.set_conditions(condition_list, conform_list) - return bag1 - def conform_to_condition(type_set, parent) -> set: set_result = set() for typex in type_set: @@ -26,83 +5,18 @@ def conform_to_condition(type_set, parent) -> set: set_result.add(typex) return set_result -def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: - ancestor_set = set() - head_list = [] - ordered_set1 = order_set_by_index(bag1.type_set) - ordered_set2 = order_set_by_index(bag2.type_set) - ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) - for type1 in ordered_set1: - same_branch = False - previous_ancestor = None - previous_type = None - for type2 in ordered_set2: - if same_branch and type2.conforms_to(previous_type): - previous_type = type2 - continue - common_ancestor = type1.least_common_ancestor(type2) - previous_type = type2 - if not previous_ancestor: - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - else: - if previous_ancestor == common_ancestor: - same_branch = True - else: - same_branch = False - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - - join_result = TypeBag(ancestor_set, head_list) - return join_result - -def join_list(type_list): - typex = type_list[0] - for i in range(1, len(type_list)): - type_i = type_list[i] - typex = join(typex, type_i) - return typex - -def smart_add(type_set:set, head_list:list, typex:Type): - if isinstance(typex, TypeBag): - return auto_add(type_set, head_list, typex) - - type_set.add(typex) - there_is = False - for i in range(len(head_list)): - head = head_list[i] - ancestor = typex.least_common_ancestor(head) - if ancestor in type_set: - there_is = True - if ancestor == typex: - head_list[i] = typex - break - if not there_is: - head_list.append(typex) - return head_list, type_set - -def auto_add(type_set:set, head_list:list, bag:TypeBag): - type_set = type_set.union(bag.type_set) - aux = set(bag.heads) - for i in range(len(head_list)): - head_i = head_list[i] - for head in bag.heads: - ancestor = head_i.least_common_ancestor(head) - if ancestor in type_set: - head_i[i] = ancestor - aux.pop(head) - break - head_list += [typex for typex in aux] - return head_list, type_set - def order_set_by_index(type_set): - return sorted(list(type_set), lambda x: x.index) - - + return sorted(list(type_set), key = lambda x: x.index) def set_intersection(parent, type_set) -> set: set_result = set() for typex in type_set: if typex.conforms_to(parent): set_result.add(typex) - return set_result \ No newline at end of file + return set_result + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set \ No newline at end of file diff --git a/src/zTests/Misc/0HelloWorld.txt b/src/zTests/Misc/00HelloRodro.cl similarity index 61% rename from src/zTests/Misc/0HelloWorld.txt rename to src/zTests/Misc/00HelloRodro.cl index 8ab5bd3a5..08352cbc8 100644 --- a/src/zTests/Misc/0HelloWorld.txt +++ b/src/zTests/Misc/00HelloRodro.cl @@ -1,5 +1,5 @@ class Main inherits IO { main(): SELF_TYPE { - out_string("Hello, World.\n") + out_string("Hello, Rodro.\n") }; -}; \ No newline at end of file +}; diff --git a/src/zTests/Misc/0Simple.txt b/src/zTests/Misc/01Simple.cl similarity index 100% rename from src/zTests/Misc/0Simple.txt rename to src/zTests/Misc/01Simple.cl diff --git a/src/zTests/Misc/10.txt b/src/zTests/Misc/02Simple.cl similarity index 69% rename from src/zTests/Misc/10.txt rename to src/zTests/Misc/02Simple.cl index 5cffd4f8c..eea0900fb 100644 --- a/src/zTests/Misc/10.txt +++ b/src/zTests/Misc/02Simple.cl @@ -3,8 +3,7 @@ class Main{ a: A; main(b:Int): A { b <- 3 - a }; }; -class A{}; \ No newline at end of file +class A{}; diff --git a/src/zTests/Misc/9.txt b/src/zTests/Misc/03Simple.cl similarity index 100% rename from src/zTests/Misc/9.txt rename to src/zTests/Misc/03Simple.cl diff --git a/src/zTests/Misc/11.txt b/src/zTests/Misc/04SallySilly.cl similarity index 100% rename from src/zTests/Misc/11.txt rename to src/zTests/Misc/04SallySilly.cl diff --git a/src/zTests/Misc/1Ackerman.txt b/src/zTests/Misc/05Ackerman.cl similarity index 100% rename from src/zTests/Misc/1Ackerman.txt rename to src/zTests/Misc/05Ackerman.cl diff --git a/src/zTests/Misc/5.txt b/src/zTests/Misc/06FooBarRaz.cl similarity index 100% rename from src/zTests/Misc/5.txt rename to src/zTests/Misc/06FooBarRaz.cl diff --git a/src/zTests/Misc/8.txt b/src/zTests/Misc/07MultipleClass.cl similarity index 100% rename from src/zTests/Misc/8.txt rename to src/zTests/Misc/07MultipleClass.cl diff --git a/src/zTests/Misc/3.txt b/src/zTests/Misc/08Cellullar.cl similarity index 100% rename from src/zTests/Misc/3.txt rename to src/zTests/Misc/08Cellullar.cl diff --git a/src/zTests/Misc/6.txt b/src/zTests/Misc/09GameOfLife.cl similarity index 100% rename from src/zTests/Misc/6.txt rename to src/zTests/Misc/09GameOfLife.cl diff --git a/src/zTests/Misc/0SimpleSpaced.txt b/src/zTests/Misc/0SimpleSpaced.txt deleted file mode 100644 index 151be34fe..000000000 --- a/src/zTests/Misc/0SimpleSpaced.txt +++ /dev/null @@ -1,13 +0,0 @@ -class Main { - a : A ; - - main ( ) : A { - a <- new A - } ; -} ; - -class A { - method ( ) : Int { - 1 - } ; -} ; \ No newline at end of file diff --git a/src/zTests/Misc/7.txt b/src/zTests/Misc/10BiG.cl similarity index 100% rename from src/zTests/Misc/7.txt rename to src/zTests/Misc/10BiG.cl From 986e16f333826bafd3295edd495a61985d247ec0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 015/432] Added Type Builder and Type Collector --- src/semantics/autotype_collector.py | 2 +- src/semantics/tools.py | 2 +- src/semantics/utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index c3c0a1265..431a0509a 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -298,4 +298,4 @@ def visit(self, node, scope): # 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 \ No newline at end of file +# todo: Cambiar self.error a que cada error tengo la tupla de localizacion, asi permite organizar los errores diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 5e8c042bf..efd7b43f4 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -2,7 +2,7 @@ from collections import OrderedDict from typing import FrozenSet -from semantics.utils import conform_to_condition, order_set_by_index +from semantics.utils import conform_to_condition, from_dict_to_set, order_set_by_index class InternalError(Exception): @property diff --git a/src/semantics/utils.py b/src/semantics/utils.py index d0375d9e8..3290eebee 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -19,4 +19,4 @@ def from_dict_to_set(types:dict): type_set = set() for typex in types: type_set.add(types[typex]) - return type_set \ No newline at end of file + return type_set From 5a9ac89434617bc54dd0ba1e3765ab7b35f4ac2c Mon Sep 17 00:00:00 2001 From: adrian Date: Fri, 26 Feb 2021 14:53:00 -0500 Subject: [PATCH 016/432] Fix bug in lexer related to comments containig . character --- src/lexing/lexing_rules.py | 2 +- src/parsing/utils.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index b423d24d3..41e146d1c 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -125,7 +125,7 @@ def t_aux_rcomment(t): def t_aux_pass(t): - r'[^.]' + r'[^\*\)]' pass # Rule so we can track line numbers diff --git a/src/parsing/utils.py b/src/parsing/utils.py index 782b4f63b..90d984e19 100644 --- a/src/parsing/utils.py +++ b/src/parsing/utils.py @@ -7,5 +7,3 @@ def __init__(self, token, line, col) -> None: def __str__(self) -> str: return f'({self.line}, {self.col}) - \ SyntacticError: ERROR at or near "{self.token}"' - - From c62da3b452c6b53aa516a9ea959bee3aa15228a5 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 15:10:09 -0500 Subject: [PATCH 017/432] Fixed Bugs Related to Circular Heritage --- src/devdeb.py | 16 +++++--- src/semantics/autotype_collector.py | 2 +- src/semantics/tools.py | 59 ++++++++++++++++++++++------- src/semantics/type_collector.py | 9 +++-- src/zTests/Misc/07MultipleClass.cl | 28 ++++++++++---- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/devdeb.py b/src/devdeb.py index b7c205cd4..372fbd1c9 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -22,7 +22,7 @@ def run_pipeline(program): print('Context\n', context) auto_collector = autotype_collector.AutotypeCollector(context) - auto_collector.visit(ast) + scope = auto_collector.visit(ast) s = "Type Collector Errors:\n" s = format_errors(collector.errors, s) @@ -30,14 +30,20 @@ def run_pipeline(program): s = format_errors(builder.errors, s) s += "Inference Gatherer Errors:\n" s = format_errors(auto_collector.errors, s) - + s += "Scope:\n" + scope.get_all_names() print(s) -folder_path = r'./zTests/Misc' -filenames = os.listdir(folder_path) -filenames.sort() +try: + folder_path = r'./zTests/Misc' + filenames = os.listdir(folder_path) + filenames.sort() +except FileNotFoundError: + print("Error Importing Files") count = 4 +filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/06FooBarRaz.cl'] +filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/07MultipleClass.cl'] + for filename in filenames: if count == 0: print("Reach Count Limit") diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 431a0509a..822f7db61 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -25,7 +25,7 @@ def visit(self, node:ProgramNode) -> Scope: @visitor.when(ClassDeclarationNode) def visit(self, node, scope): self.current_type = self.context.get_type(node.id, unpacked=True) - scope.define_variable("self", self.current_type) + scope.define_variable("self", TypeBag({self.current_type})) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index efd7b43f4..d3732284e 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -76,25 +76,35 @@ def define_attribute(self, name:str, typex): else: raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') - def get_attribute(self, name:str): + def get_attribute(self, name:str, first=None): + if not first: + first = self.name + elif first == self.name: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + try: return next(attr for attr in self.attributes if attr.name == name) except StopIteration: if self.parent is None: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') try: - return self.parent.get_attribute(name) + return self.parent.get_attribute(name, first=first) except SemanticError: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') - def get_method(self, name:str, local:bool = False): + def get_method(self, name:str, local:bool = False, first = None): + if not first: + first = self.name + elif first == self.name: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + try: return next(method for method in self.methods if method.name == name) except StopIteration: if self.parent is None: raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') try: - return self.parent.get_method(name) + return self.parent.get_method(name, first = first) except SemanticError: raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') @@ -108,7 +118,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ parent_method = None if parent_method: error_list = [] - if conforms(return_type, parent_method.return_type): + if not conforms(return_type, parent_method.return_type): error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") @@ -116,7 +126,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ count = 0 err = [] for param_type, parent_param_type in zip(param_types, parent_method.param_types): - if param_type != parent_param_type: + if not conforms(param_type, parent_param_type): err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") count += 1 if err: @@ -130,20 +140,34 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ self.methods.append(method) return method - def all_attributes(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + def all_attributes(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(clean = False, first=first) for attr in self.attributes: plain[attr.name] = (attr, self) return plain.values() if clean else plain - def all_methods(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + def all_methods(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = OrderedDict() if self.parent is None else self.parent.all_methods(clean = False, first=first) for method in self.methods: plain[method.name] = (method, self) return plain.values() if clean else plain - def conforms_to(self, other): - return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + def conforms_to(self, other, first=None): + if not first: + first = self.name + elif self.name == first: + return False + return other.bypass() or self == other or self.parent and self.parent.conforms_to(other, first) def bypass(self): return False @@ -151,8 +175,7 @@ def bypass(self): def least_common_ancestor(self, other): this = self if isinstance(this, ErrorType) or isinstance(other, ErrorType): - return ErrorType() - #raise SemanticError("Error Type detected while perfoming Join. Aborting.") + return ErrorType() while this.index < other.index: other = other.parent @@ -397,6 +420,14 @@ def reset(self): self.current_child = -1 for child in self.children: child.reset() + + def get_all_names(self, s:str = "", level:int = 0): + if self.locals: + s += "\n ".join([x.name + ":" + str([typex.name for typex in x.type.type_set]) for x in self.locals]) + s += "\n\n" + for child in self.children: + s = child.get_all_names(s, level + 1) + return s def conforms(bag1:TypeBag, bag2:TypeBag): diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 77a110147..82327ca93 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -30,8 +30,11 @@ def visit(self, node): def visit(self, node): try: self.context.create_type(node.id) - self.type_graph[node.id] = [] self.node_dict[node.id] = node + try: + self.type_graph[node.id] + except KeyError: + self.type_graph[node.id] = [] if node.parent: if node.parent in {'String', 'Int, Bool'}: raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") @@ -56,7 +59,7 @@ def get_type_hierarchy(self): visited.add(node) path = [node] circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) - new_order = new_order + [self.context.get_type(node) for node in path] + new_order = new_order + [self.node_dict[node] for node in path] if circular_heritage_errors: print(circular_heritage_errors) @@ -82,7 +85,7 @@ def dfs_type_graph(self, root, graph, visited:set, new_order, index): def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: if node in path: - return ' -> '.join(child for child in visited + [visited[0]]) + return ' -> '.join(child for child in path + [path[0]]) visited.add(node) path.append(node) diff --git a/src/zTests/Misc/07MultipleClass.cl b/src/zTests/Misc/07MultipleClass.cl index 51274315c..52464394a 100644 --- a/src/zTests/Misc/07MultipleClass.cl +++ b/src/zTests/Misc/07MultipleClass.cl @@ -1,34 +1,46 @@ +class Main +{ + h:AUTO_TYPE <- new H; + a:AUTO_TYPE <- new A; + main(): Int + { + { + 3; + } + }; +}; + class H { - a:int; + a:Int; }; class Z inherits H { - x:int; + x:Int; }; class A inherits F { - b:int; + b:Int; }; class B inherits A { - c:int; + c:Int; }; class C inherits B { - e:int; + e:Int; }; class D inherits C { - f:int; + f:Int; }; class F inherits D { - g:int; -}; \ No newline at end of file + g:Int; +}; From d516ef876b40a6e6c584fc96026bdc5442fcd1c0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 018/432] Added Type Builder and Type Collector --- src/semantics/autotype_collector.py | 48 ++++++++ src/semantics/tools.py | 177 ++++++++++++++++++++++++++++ src/semantics/type_builder.py | 98 +++++++++++++++ src/semantics/type_collector.py | 108 +++++++++++++++++ src/semantics/utils.py | 47 ++++++++ src/semantics/visitor.py | 80 +++++++++++++ 6 files changed, 558 insertions(+) create mode 100644 src/semantics/autotype_collector.py create mode 100644 src/semantics/tools.py create mode 100644 src/semantics/type_builder.py create mode 100644 src/semantics/type_collector.py create mode 100644 src/semantics/utils.py create mode 100644 src/semantics/visitor.py diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py new file mode 100644 index 000000000..2a74ee36c --- /dev/null +++ b/src/semantics/autotype_collector.py @@ -0,0 +1,48 @@ +import semantics.visitor as visitor +from semantics.tools import Context, Scope +from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode + +class AutotypeCollector: + def __init__(self, context:Context): + self.context = context + self.current_type = None + self.current_method = None + self.current_attrb = None + self.inference_graph = dict() + self.errors = [] + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode) -> Scope: + scope = Scope() + for declaration in node.declarations: + self.visit(declaration, scope.create_child()) + + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + scope.define_variable("self", self.current_type) + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + for feature in node.features: + self.visit(feature, 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) + + if not node.expr: + self.current_attrb = None + node.inferenced_type = node_type + return + + +# todo: Revisar los auto types que me hace falta y que no +# todo: completar de manera acorde el autotype collector \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py new file mode 100644 index 000000000..4b32c2cc2 --- /dev/null +++ b/src/semantics/tools.py @@ -0,0 +1,177 @@ +import itertools as itt +from collections import OrderedDict + +class InternalError(Exception): + @property + def text(self): + return "Internal Error: " + self.args[0] + +class SemanticError(Exception): + @property + def text(self): + return "Semantic Error: " + self.args[0] + +class TypeError(SemanticError): + @property + def text(self): + return "Type Error: " + self.args[0] + +class AttributeError(SemanticError): + @property + def text(self): + return "Attribute Error: " + self.args[0] + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name} : {self.type.name};' + + def __repr__(self): + return str(self) + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + +class Type: + def __init__(self, name:str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + self.index = -1 + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Type \'{self.name}\' already has parent type \'{self.parent.name}\'. Type \'{parent.name}\' cannot be set as parent.') + if parent.name in {"String", "Int", "Bool"}: + raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') + self.parent = parent + + def get_attribute(self, name:str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + +class SelfType(Type): + def __init__(self): + self.name = "SELF_TYPE" + def conforms_to(self, other): + #if isinstance(other, SelfType): + # return True + raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + def bypass(self): + raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + +class AutoType(Type): + pass + +class ErrorType(Type): + pass + +class Context: + def __init__(self) -> None: + self.types = {} + self.num_autotypes = 0 + self.type_graph = None + + def create_type(self, name:str) -> Type: + if name in self.types: + raise SemanticError(f'Type with the same name ({name}) already exists.') + if name[0] != name[0].upper: + raise SemanticError(f'Type name ({name}) must start with upper case') + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name:str, selftype=True, autotype=True) -> Type: + if selftype and name == "SELF_TYPE": + return SelfType() + if autotype and name == "AUTO_TYPE": + self.num_autotypes += 1 + return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + try: + return self.types[name] + except KeyError: + raise TypeError(f'Type "{name}" is not defined.') + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + def __str__(self): + return self.name + ":" + self.type + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + self.current_child = -1 + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + try: + return self.parent.find_variable(vname, self.index)# if self.parent else None + except AttributeError: + return None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) + + def next_child(self): + self.current_child += 1 + return self.children[self.current_child] + + def reset(self): + self.current_child = -1 + for child in self.children: + child.reset() \ No newline at end of file diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py new file mode 100644 index 000000000..9e4b70b3c --- /dev/null +++ b/src/semantics/type_builder.py @@ -0,0 +1,98 @@ +import semantics.visitor as visitor +from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import Context + +class TypeCollector(object): + def __init__(self) -> None: + self.context = Context() + self.errors = [] + + self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context = Context() + self.init_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + new_declarations = self.get_type_hierarchy() + node.declarations = new_declarations + self.context.type_graph = self.type_graph + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id) + self.type_graph[node.id] = [] + if node.parent: + if node.parent in {'String', 'Int, Bool'}: + raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + try: + self.type_graph[node.parent].append(node.id) + except KeyError: + self.type_graph[node.parent] = [node.id] + else: + node.parent = "Object" + self.type_graph["Object"] = [node.id] + except SemanticError as error: + self.add_error(node, error.text) + + def get_type_hierarchy(self): + visited = set(["Object"]) + new_order = [] + self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + + circular_heritage_errors = [] + for node in self.type_graph: + if not node in visited: + visited.add(node) + path = [node] + circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + new_order = new_order + [self.context.get_type(node) for node in path] + + if circular_heritage_errors: + error = "Semantic Error: Circular Heritage:\n" + error += "\n".join(err for err in circular_heritage_errors) + self.add_error(None, error) + + return new_order + + def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + if not root in graph: + return + + for node in graph[root]: + if node in visited: + continue + visited.add(node) + if node not in {"Int", "String", "IO", "Bool", "Object"}: + new_order.append(self.context.get_type(node)) + self.context.get_type(node).index = index + self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + + def check_circular_heritage(self, root, graph, path, visited): + for node in graph[root]: + if node in path: + return ' -> '.join(child for child in visited + [visited[0]]) + + visited.add(node) + path.append(node) + return self.check_circular_heritage(node, graph, path, visited) + + def init_default_classes(self): + self.context.create_type('Object').index = 0 + self.context.create_type('String') + self.context.create_type('Int') + self.context.create_type('IO') + self.context.create_type('Bool') + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py new file mode 100644 index 000000000..450f6844d --- /dev/null +++ b/src/semantics/type_collector.py @@ -0,0 +1,108 @@ +import semantics.visitor as visitor +from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.utils import SemanticError +from semantics.utils import ErrorType, SelfType +from semantics.utils import Context + +class TypeBuilder: + def __init__(self, context: Context): + self.context = context + self.current_type = None + self.errors = [] + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.build_default_classes() + + for class_def in node.declarations: + self.visit(class_def) + + try: + self.context.get_type('Main').get_method('main', local=True) + except SemanticError as err: + self.add_error(node, err.text) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + + if node.parent: + try: + parent_type = self.context.get_type(node.parent) + self.current_type.set_parent(parent_type) + for idx, _ in list(parent_type.all_attributes(True)): + self.current_type.attributes.append(idx) + except SemanticError as err: + self.add_error(node, err.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + try: + attr_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(node, err.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as err: + self.add_error(err.text) + + @visitor.when(MethodDeclarationNode) + def visit(self, node): + try: + ret_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(err.text) + ret_type = ErrorType() + + params_type = [] + params_name = [] + for p_name, p_type in node.params: + try: + params_type.append(self.context.get_type(p_type)) + except SemanticError as err: + params_type.append(ErrorType()) + self.add_error(node, err.text) + params_name.append(p_name) + + try: + self.current_type.define_method(node.id, params_name, params_type, ret_type) + except SemanticError as err: + self.add_error(node, err.text) + + def build_default_classes(self): + Object = self.context.get_type("Object") + String = self.context.get_type("String") + Int = self.context.get_type("Int") + Io = self.context.get_type("IO") + Bool = self.context.get_type("Bool") + + String.set_parent(Object) + Int.set_parent(Object) + Io.set_parent(Object) + Bool.set_parent(Object) + + Object.define_method("abort", [], [], Object) + Object.define_method("type_name", [], [], String) + Object.define_method("copy", [], [], SelfType()) + + String.define_method("length", [], [], Int) + String.define_method("concat", ["s"], [String], String) + String.define_method("substr", ["i", "l"], [Int, Int], String) + + Io.define_method("out_string", ["x"],[String], SelfType()) + Io.define_method("out_int", ["x"],[Int], SelfType()) + Io.define_method("in_string", [],[], String) + Io.define_method("in_int", [], [], Int) + + def add_error(self, node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file diff --git a/src/semantics/utils.py b/src/semantics/utils.py new file mode 100644 index 000000000..953f74326 --- /dev/null +++ b/src/semantics/utils.py @@ -0,0 +1,47 @@ +from semantics.tools import Type, ErrorType, AutoType + +def conforms(type1:Type, type2:Type): + if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): + return ErrorType() + if not isinstance(type1, AutoType) and isinstance(type2, AutoType): + type2.set_upper_limmit([type1]) + return type1 + if not isinstance(type1, AutoType): + type1 = AutoType("TEMP01", [type1], {type1}) + if not isinstance(type2, AutoType): + type2 = AutoType("TEMP02", [type2], {type2}) + + print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) + print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + + condition_set_list, conform_set_list = conforming(type1, type2) + type1.set_new_conditions(condition_set_list, conform_set_list) + + print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) + print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) + print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") + return type1 + +def conforming(auto1:AutoType, auto2:AutoType): + ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) + + condition_set_list = [] + conform_set_list = [] + for type2 in ord_types2: + conforms = conform_intersection(auto1.type_set, type2) + for i in range(len(condition_set_list)): + prev_conform = conform_set_list[i] + if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): + condition_set_list[i].add(type2) + break + else: + condition_set_list.append(set([type2])) + conform_set_list.append(conforms) + return condition_set_list, conform_set_list + +def conform_intersection(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result \ No newline at end of file diff --git a/src/semantics/visitor.py b/src/semantics/visitor.py new file mode 100644 index 000000000..964842836 --- /dev/null +++ b/src/semantics/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) From 4c1f7f3e7f838d9fe97a96d82e6b7494cf9d0a0d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 19:18:53 -0500 Subject: [PATCH 019/432] Added Autotype Collector. --- src/devdeb.py | 2 + src/parsing/ast.py | 2 +- src/semantics/autotype_collector.py | 269 +++++++++++++++++++++++++++- src/semantics/tools.py | 179 +++++++++++++++++- src/semantics/type_builder.py | 6 +- src/semantics/utils.py | 139 ++++++++++---- 6 files changed, 542 insertions(+), 55 deletions(-) create mode 100644 src/devdeb.py diff --git a/src/devdeb.py b/src/devdeb.py new file mode 100644 index 000000000..ef174c7e1 --- /dev/null +++ b/src/devdeb.py @@ -0,0 +1,2 @@ +def run_pipeline(): + pass \ No newline at end of file diff --git a/src/parsing/ast.py b/src/parsing/ast.py index e07038198..53abf401c 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -57,7 +57,7 @@ class VarDeclarationNode(ExpressionNode): def __init__(self, idx, typex, expression=None): Node.__init__(self) self.id = idx - self.typex = typex + self.type = typex self.expr = expression diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 2a74ee36c..da2dcc28a 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -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): @@ -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 \ No newline at end of file +# 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 \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 4b32c2cc2..f0dd3b0af 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,5 +1,7 @@ import itertools as itt from collections import OrderedDict +from typing import FrozenSet +from semantics.utils import from_dict_to_set class InternalError(Exception): @property @@ -73,6 +75,151 @@ def get_attribute(self, name:str): return self.parent.get_attribute(name) except SemanticError: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + + def get_method(self, name:str, local:bool = False): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method \'{name}\' already defined in \'{self.name}\'') + + try: + parent_method = self.get_method(name) + except SemanticError: + parent_method = None + if parent_method: + error_list = [] + if not return_type.conforms_to(parent_method.return_type): + error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") + if len(param_types) != len(parent_method.param_types): + error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") + else: + count = 0 + err = [] + for param_type, parent_param_type in zip(param_types, parent_method.param_types): + if param_type != parent_param_type: + err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") + count += 1 + if err: + s = f" -> Same param types:\n" + "\n".join(child for child in err) + error_list.append(s) + if error_list: + err = f"Redifined method \"{name}\" in class {self.name} does not have:\n" + "\n".join(child for child in error_list) + raise SemanticError(err) + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def least_common_ancestor(self, other): + this = self + if isinstance(this, ErrorType) or isinstance(other, ErrorType): + return ErrorType() + #raise SemanticError("Error Type detected while perfoming Join. Aborting.") + + while this.index < other.index: + other = other.parent + while other.index < this.index: + this = this.parent + if not (this and other): + return None + while this.name != other.name: + this = this.parent + other = other.parent + if this == None: + return None + return this + +class TypeBag: + def __init__(self, type_set, heads = []) -> None: + self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) + self.heads:list = heads + if len(type_set) == 1: + self.heads = list(self.type_set) + self.condition_list = [] + self.conform_list = [] + + def set_conditions(self, condition_list, conform_list): + self.condition_list = condition_list + self.conform_list = conform_list + self.update_type_set_from_conforms() + + def update_type_set_from_conforms(self): + intersect_set = set() + for conform_set in self.conforms_list: + intersect_set = intersect_set.union(conform_set) + self.type_set = self.type_set.intersection(intersect_set) + self.update_heads() + + def update_heads(self): + new_heads = [] + visited = set() + for head in self.upper_limmit: + if head in self.type_set: + new_heads.append(head) + continue + new_heads = [] + lower_index = 2**32 + for typex in self.type_set: + if typex in visited: + continue + if typex.conforms_to(head): + visited.add(typex) + if typex.index < lower_index: + new_heads = [typex] + lower_index = typex.index + elif typex.index == lower_index: + new_heads.append(typex) + new_heads += new_heads + self.upper_limmit = new_heads + + def swap_self_type(self, update_type): + try: + self.type_set.remove(SelfType()) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def swap_types(self, update_type, remove_type): + try: + self.type_set.remove(remove_type) + self.type_set.add(update_type) + except KeyError: + pass + return self + + def clone(self): + clone = TypeBag(self.type_set, self.heads) + clone.condition_list = self.condition_list + clone.conform_list = self.conform_list + return clone class SelfType(Type): def __init__(self): @@ -80,15 +227,17 @@ def __init__(self): def conforms_to(self, other): #if isinstance(other, SelfType): # return True - raise InternalError("SELF_TYPE yet to be assigned, cannot conform.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") def bypass(self): - raise InternalError("SELF_TYPE yet to be assigned, cannot bypass.") + raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") class AutoType(Type): pass class ErrorType(Type): - pass + def __init__(self): + self.name = "" + self.type_set = FrozenSet() class Context: def __init__(self) -> None: @@ -106,15 +255,31 @@ def create_type(self, name:str) -> Type: def get_type(self, name:str, selftype=True, autotype=True) -> Type: if selftype and name == "SELF_TYPE": - return SelfType() + return TypeBag({SelfType()}) #SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 - return AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: - return self.types[name] + return TypeBag({self.types[name]}) except KeyError: raise TypeError(f'Type "{name}" is not defined.') - + + def get_method_by_name(self, name:str, args:int) -> list: + def dfs(root:str, results:list): + try: + for typex in self.type_tree[root]: + for method in self.types[typex].methods: + if name == method.name and args == len(method.param_names): + results.append((method, self.types[typex])) + break + else: + dfs(typex, results) + except KeyError: + pass + results = [] + dfs("Object", results) + return results + def __str__(self): return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 9e4b70b3c..98f53b865 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -47,7 +47,7 @@ def visit(self, node): def get_type_hierarchy(self): visited = set(["Object"]) new_order = [] - self.get_type_hierarchy("Object", self.type_graph, visited, new_order, 1) + self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) circular_heritage_errors = [] for node in self.type_graph: @@ -64,7 +64,7 @@ def get_type_hierarchy(self): return new_order - def get_type_hierarchy(self, root, graph, visited:set, new_order, index): + def dfs_type_graph(self, root, graph, visited:set, new_order, index): if not root in graph: return @@ -75,7 +75,7 @@ def get_type_hierarchy(self, root, graph, visited:set, new_order, index): if node not in {"Int", "String", "IO", "Bool", "Object"}: new_order.append(self.context.get_type(node)) self.context.get_type(node).index = index - self.get_type_hierarchy(node, graph, visited, new_order, index + 1) + self.dfs_type_graph(node, graph, visited, new_order, index + 1) def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 953f74326..2f9d90686 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,45 +1,110 @@ -from semantics.tools import Type, ErrorType, AutoType - -def conforms(type1:Type, type2:Type): - if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): - return ErrorType() - if not isinstance(type1, AutoType) and isinstance(type2, AutoType): - type2.set_upper_limmit([type1]) - return type1 - if not isinstance(type1, AutoType): - type1 = AutoType("TEMP01", [type1], {type1}) - if not isinstance(type2, AutoType): - type2 = AutoType("TEMP02", [type2], {type2}) +from semantics.tools import Type, ErrorType, AutoType, TypeBag + +def conforms(bag1:TypeBag, bag2:TypeBag): + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) - print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) - print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + bag1.set_conditions(condition_list, conform_list) + return bag1 + +def conform_to_condition(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result - condition_set_list, conform_set_list = conforming(type1, type2) - type1.set_new_conditions(condition_set_list, conform_set_list) +def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + ancestor_set = set() + head_list = [] + ordered_set1 = order_set_by_index(bag1.type_set) + ordered_set2 = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor - print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) - print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) - print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") - return type1 - -def conforming(auto1:AutoType, auto2:AutoType): - ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) - - condition_set_list = [] - conform_set_list = [] - for type2 in ord_types2: - conforms = conform_intersection(auto1.type_set, type2) - for i in range(len(condition_set_list)): - prev_conform = conform_set_list[i] - if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): - condition_set_list[i].add(type2) + join_result = TypeBag(ancestor_set, head_list) + return join_result + +def join_list(type_list): + typex = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + typex = join(typex, type_i) + return typex + +def smart_add(type_set:set, head_list:list, typex:Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex break - else: - condition_set_list.append(set([type2])) - conform_set_list.append(conforms) - return condition_set_list, conform_set_list + if not there_is: + head_list.append(typex) + return head_list, type_set + +def auto_add(type_set:set, head_list:list, bag:TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head in bag.heads: + ancestor = head_i.least_common_ancestor(head) + if ancestor in type_set: + head_i[i] = ancestor + aux.pop(head) + break + head_list += [typex for typex in aux] + return head_list, type_set + +def order_set_by_index(type_set): + return sorted(list(type_set), lambda x: x.index) + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set -def conform_intersection(type_set, parent) -> set: +def set_intersection(parent, type_set) -> set: set_result = set() for typex in type_set: if typex.conforms_to(parent): From e718cf5f69e9d1d0cdba30e0869bf31cc2b09130 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 22:04:58 -0500 Subject: [PATCH 020/432] Fixed Bugs. --- src/devdeb.py | 53 +++- src/semantics/tools.py | 36 ++- src/semantics/type_builder.py | 152 ++++++----- src/semantics/type_collector.py | 156 +++++------ src/semantics/utils.py | 8 +- src/zTests/Misc/0HelloWorld.txt | 5 + src/zTests/Misc/0Simple.txt | 13 + src/zTests/Misc/0SimpleSpaced.txt | 13 + src/zTests/Misc/10.txt | 10 + src/zTests/Misc/11.txt | 10 + src/zTests/Misc/1Ackerman.txt | 24 ++ src/zTests/Misc/3.txt | 93 +++++++ src/zTests/Misc/5.txt | 64 +++++ src/zTests/Misc/6.txt | 436 ++++++++++++++++++++++++++++++ src/zTests/Misc/7.txt | 426 +++++++++++++++++++++++++++++ src/zTests/Misc/8.txt | 34 +++ src/zTests/Misc/9.txt | 23 ++ 17 files changed, 1388 insertions(+), 168 deletions(-) create mode 100644 src/zTests/Misc/0HelloWorld.txt create mode 100644 src/zTests/Misc/0Simple.txt create mode 100644 src/zTests/Misc/0SimpleSpaced.txt create mode 100644 src/zTests/Misc/10.txt create mode 100644 src/zTests/Misc/11.txt create mode 100644 src/zTests/Misc/1Ackerman.txt create mode 100644 src/zTests/Misc/3.txt create mode 100644 src/zTests/Misc/5.txt create mode 100644 src/zTests/Misc/6.txt create mode 100644 src/zTests/Misc/7.txt create mode 100644 src/zTests/Misc/8.txt create mode 100644 src/zTests/Misc/9.txt diff --git a/src/devdeb.py b/src/devdeb.py index ef174c7e1..86868597e 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -1,2 +1,51 @@ -def run_pipeline(): - pass \ No newline at end of file +import os +from parsing import parser +from semantics import type_collector, type_builder, autotype_collector + +def format_errors(errors, s = ""): + count = 1 + for error in errors: + s += str(count) + ". " + error + "\n" + count += 1 + return s + +def run_pipeline(program): + ast = parser.parse(program) + + collector = type_collector.TypeCollector() + collector.visit(ast) + context = collector.context + print('Context\n', context) + + builder = type_builder.TypeBuilder(context) + builder.visit(ast) + print('Context\n', context) + + auto_collector = autotype_collector.AutotypeCollector(context) + auto_collector.visit(ast) + + s = "Type Collector Errors:\n" + s = format_errors(collector.errors, s) + s += "Type Builder Errors:\n" + s = format_errors(builder.errors, s) + s += "Inference Gatherer Errors:\n" + s = format_errors(auto_collector.errors, s) + + print(s) + +folder_path = r'./zTests/Misc' +filenames = os.listdir(folder_path) +filenames.sort() + +for filename in filenames: + path = os.path.join(folder_path, filename) + file = open(path, "r") + program = file.read() + file.close() + + print(f"Running {filename}") + run_pipeline(program) + input() + +print("EndOfFiles") + diff --git a/src/semantics/tools.py b/src/semantics/tools.py index f0dd3b0af..4c0a459f6 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,7 +1,7 @@ import itertools as itt from collections import OrderedDict from typing import FrozenSet -from semantics.utils import from_dict_to_set +#from semantics.utils import from_dict_to_set class InternalError(Exception): @property @@ -155,6 +155,22 @@ def least_common_ancestor(self, other): if this == None: return None return this + + def __str__(self): + output = f'type {self.name}' + parent = '' if self.parent is None else f' : {self.parent.name}' + output += parent + output += ' {' + output += '\n\t' if self.attributes or self.methods else '' + output += '\n\t'.join(str(x) for x in self.attributes) + output += '\n\t' if self.attributes else '' + output += '\n\t'.join(str(x) for x in self.methods) + output += '\n' if self.methods else '' + output += '}\n' + return output + + def __repr__(self): + return str(self) class TypeBag: def __init__(self, type_set, heads = []) -> None: @@ -215,6 +231,7 @@ def swap_types(self, update_type, remove_type): pass return self + def clone(self): clone = TypeBag(self.type_set, self.heads) clone.condition_list = self.condition_list @@ -231,9 +248,6 @@ def conforms_to(self, other): def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") -class AutoType(Type): - pass - class ErrorType(Type): def __init__(self): self.name = "" @@ -248,18 +262,20 @@ def __init__(self) -> None: def create_type(self, name:str) -> Type: if name in self.types: raise SemanticError(f'Type with the same name ({name}) already exists.') - if name[0] != name[0].upper: + if name[0] != name[0].upper(): raise SemanticError(f'Type name ({name}) must start with upper case') typex = self.types[name] = Type(name) return typex - def get_type(self, name:str, selftype=True, autotype=True) -> Type: + def get_type(self, name:str, selftype=True, autotype=True, unpacked=False) -> Type: if selftype and name == "SELF_TYPE": return TypeBag({SelfType()}) #SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: + if unpacked: + return self.types[name] return TypeBag({self.types[name]}) except KeyError: raise TypeError(f'Type "{name}" is not defined.') @@ -339,4 +355,10 @@ def next_child(self): def reset(self): self.current_child = -1 for child in self.children: - child.reset() \ No newline at end of file + child.reset() + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set \ No newline at end of file diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 98f53b865..b4f31d8f1 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,14 +1,14 @@ import semantics.visitor as visitor -from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.utils import SemanticError -from semantics.utils import Context +from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from semantics.tools import SemanticError +from semantics.tools import ErrorType, SelfType +from semantics.tools import Context -class TypeCollector(object): - def __init__(self) -> None: - self.context = Context() +class TypeBuilder: + def __init__(self, context: Context): + self.context = context + self.current_type = None self.errors = [] - - self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} @visitor.on('node') def visit(self, node): @@ -16,82 +16,92 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): - self.context = Context() - self.init_default_classes() + self.build_default_classes() for class_def in node.declarations: self.visit(class_def) - new_declarations = self.get_type_hierarchy() - node.declarations = new_declarations - self.context.type_graph = self.type_graph - + try: + self.context.get_type('Main', unpacked=True).get_method('main', local=True) + except SemanticError as err: + self.add_error(node, err.text) + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id, unpacked=True) + + if node.parent: + try: + parent_type = self.context.get_type(node.parent, unpacked=True) + self.current_type.set_parent(parent_type) + for idx, _ in list(parent_type.all_attributes(True)): + self.current_type.attributes.append(idx) + except SemanticError as err: + self.add_error(node, err.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) def visit(self, node): try: - self.context.create_type(node.id) - self.type_graph[node.id] = [] - if node.parent: - if node.parent in {'String', 'Int, Bool'}: - raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") - try: - self.type_graph[node.parent].append(node.id) - except KeyError: - self.type_graph[node.parent] = [node.id] - else: - node.parent = "Object" - self.type_graph["Object"] = [node.id] - except SemanticError as error: - self.add_error(node, error.text) + attr_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(node, err.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as err: + self.add_error(err.text) - def get_type_hierarchy(self): - visited = set(["Object"]) - new_order = [] - self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) + @visitor.when(MethodDeclarationNode) + def visit(self, node): + try: + ret_type = self.context.get_type(node.type) + except SemanticError as err: + self.add_error(err.text) + ret_type = ErrorType() + + params_type = [] + params_name = [] + for p_name, p_type in node.params: + try: + params_type.append(self.context.get_type(p_type)) + except SemanticError as err: + params_type.append(ErrorType()) + self.add_error(node, err.text) + params_name.append(p_name) + + try: + self.current_type.define_method(node.id, params_name, params_type, ret_type) + except SemanticError as err: + self.add_error(node, err.text) - circular_heritage_errors = [] - for node in self.type_graph: - if not node in visited: - visited.add(node) - path = [node] - circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) - new_order = new_order + [self.context.get_type(node) for node in path] - - if circular_heritage_errors: - error = "Semantic Error: Circular Heritage:\n" - error += "\n".join(err for err in circular_heritage_errors) - self.add_error(None, error) + def build_default_classes(self): + Object = self.context.get_type("Object", unpacked=True) + String = self.context.get_type("String", unpacked=True) + Int = self.context.get_type("Int", unpacked=True) + Io = self.context.get_type("IO", unpacked=True) + Bool = self.context.get_type("Bool", unpacked=True) - return new_order + String.set_parent(Object) + Int.set_parent(Object) + Io.set_parent(Object) + Bool.set_parent(Object) - def dfs_type_graph(self, root, graph, visited:set, new_order, index): - if not root in graph: - return - - for node in graph[root]: - if node in visited: - continue - visited.add(node) - if node not in {"Int", "String", "IO", "Bool", "Object"}: - new_order.append(self.context.get_type(node)) - self.context.get_type(node).index = index - self.dfs_type_graph(node, graph, visited, new_order, index + 1) - - def check_circular_heritage(self, root, graph, path, visited): - for node in graph[root]: - if node in path: - return ' -> '.join(child for child in visited + [visited[0]]) + Object.define_method("abort", [], [], Object) + Object.define_method("type_name", [], [], String) + Object.define_method("copy", [], [], SelfType()) - visited.add(node) - path.append(node) - return self.check_circular_heritage(node, graph, path, visited) + String.define_method("length", [], [], Int) + String.define_method("concat", ["s"], [String], String) + String.define_method("substr", ["i", "l"], [Int, Int], String) - def init_default_classes(self): - self.context.create_type('Object').index = 0 - self.context.create_type('String') - self.context.create_type('Int') - self.context.create_type('IO') - self.context.create_type('Bool') + Io.define_method("out_string", ["x"],[String], SelfType()) + Io.define_method("out_int", ["x"],[Int], SelfType()) + Io.define_method("in_string", [],[], String) + Io.define_method("in_int", [], [], Int) def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 450f6844d..77a110147 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,107 +1,99 @@ import semantics.visitor as visitor -from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.utils import SemanticError -from semantics.utils import ErrorType, SelfType -from semantics.utils import Context +from parsing.ast import Node, ProgramNode, ClassDeclarationNode +from semantics.tools import SemanticError +from semantics.tools import Context -class TypeBuilder: - def __init__(self, context: Context): - self.context = context - self.current_type = None +class TypeCollector(object): + def __init__(self) -> None: + self.context = Context() self.errors = [] - + self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + self.node_dict = dict() + @visitor.on('node') def visit(self, node): pass @visitor.when(ProgramNode) def visit(self, node): - self.build_default_classes() + self.context = Context() + self.init_default_classes() for class_def in node.declarations: self.visit(class_def) - try: - self.context.get_type('Main').get_method('main', local=True) - except SemanticError as err: - self.add_error(node, err.text) - - @visitor.when(ClassDeclarationNode) - def visit(self, node): - self.current_type = self.context.get_type(node.id) - - if node.parent: - try: - parent_type = self.context.get_type(node.parent) - self.current_type.set_parent(parent_type) - for idx, _ in list(parent_type.all_attributes(True)): - self.current_type.attributes.append(idx) - except SemanticError as err: - self.add_error(node, err.text) - - for feature in node.features: - self.visit(feature) + new_declarations = self.get_type_hierarchy() + node.declarations = new_declarations + self.context.type_graph = self.type_graph - @visitor.when(AttrDeclarationNode) + @visitor.when(ClassDeclarationNode) def visit(self, node): try: - attr_type = self.context.get_type(node.type) - except SemanticError as err: - self.add_error(node, err.text) - attr_type = ErrorType() - - try: - self.current_type.define_attribute(node.id, attr_type) - except SemanticError as err: - self.add_error(err.text) + self.context.create_type(node.id) + self.type_graph[node.id] = [] + self.node_dict[node.id] = node + if node.parent: + if node.parent in {'String', 'Int, Bool'}: + raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + try: + self.type_graph[node.parent].append(node.id) + except KeyError: + self.type_graph[node.parent] = [node.id] + else: + node.parent = "Object" + self.type_graph["Object"].append(node.id) + except SemanticError as error: + self.add_error(node, error.text) - @visitor.when(MethodDeclarationNode) - def visit(self, node): - try: - ret_type = self.context.get_type(node.type) - except SemanticError as err: - self.add_error(err.text) - ret_type = ErrorType() - - params_type = [] - params_name = [] - for p_name, p_type in node.params: - try: - params_type.append(self.context.get_type(p_type)) - except SemanticError as err: - params_type.append(ErrorType()) - self.add_error(node, err.text) - params_name.append(p_name) - - try: - self.current_type.define_method(node.id, params_name, params_type, ret_type) - except SemanticError as err: - self.add_error(node, err.text) + def get_type_hierarchy(self): + visited = set(["Object"]) + new_order = [] + self.dfs_type_graph("Object", self.type_graph, visited, new_order, 1) - def build_default_classes(self): - Object = self.context.get_type("Object") - String = self.context.get_type("String") - Int = self.context.get_type("Int") - Io = self.context.get_type("IO") - Bool = self.context.get_type("Bool") + circular_heritage_errors = [] + for node in self.type_graph: + if not node in visited: + visited.add(node) + path = [node] + circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + new_order = new_order + [self.context.get_type(node) for node in path] + + if circular_heritage_errors: + print(circular_heritage_errors) + error = "Semantic Error: Circular Heritage:\n" + error += "\n".join(err for err in circular_heritage_errors) + self.add_error(None, error) - String.set_parent(Object) - Int.set_parent(Object) - Io.set_parent(Object) - Bool.set_parent(Object) + return new_order - Object.define_method("abort", [], [], Object) - Object.define_method("type_name", [], [], String) - Object.define_method("copy", [], [], SelfType()) + def dfs_type_graph(self, root, graph, visited:set, new_order, index): + if not root in graph: + return + + for node in graph[root]: + if node in visited: + continue + visited.add(node) + if node not in {"Int", "String", "IO", "Bool", "Object"}: + new_order.append(self.node_dict[node]) + self.context.get_type(node).index = index + self.dfs_type_graph(node, graph, visited, new_order, index + 1) + + def check_circular_heritage(self, root, graph, path, visited): + for node in graph[root]: + if node in path: + return ' -> '.join(child for child in visited + [visited[0]]) - String.define_method("length", [], [], Int) - String.define_method("concat", ["s"], [String], String) - String.define_method("substr", ["i", "l"], [Int, Int], String) + visited.add(node) + path.append(node) + return self.check_circular_heritage(node, graph, path, visited) - Io.define_method("out_string", ["x"],[String], SelfType()) - Io.define_method("out_int", ["x"],[Int], SelfType()) - Io.define_method("in_string", [],[], String) - Io.define_method("in_int", [], [], Int) + def init_default_classes(self): + self.context.create_type('Object').index = 0 + self.context.create_type('String') + self.context.create_type('Int') + self.context.create_type('IO') + self.context.create_type('Bool') def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 2f9d90686..88c089983 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,4 +1,4 @@ -from semantics.tools import Type, ErrorType, AutoType, TypeBag +from semantics.tools import Type, TypeBag def conforms(bag1:TypeBag, bag2:TypeBag): ordered_set = order_set_by_index(bag2.type_set) @@ -98,11 +98,7 @@ def auto_add(type_set:set, head_list:list, bag:TypeBag): def order_set_by_index(type_set): return sorted(list(type_set), lambda x: x.index) -def from_dict_to_set(types:dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set + def set_intersection(parent, type_set) -> set: set_result = set() diff --git a/src/zTests/Misc/0HelloWorld.txt b/src/zTests/Misc/0HelloWorld.txt new file mode 100644 index 000000000..8ab5bd3a5 --- /dev/null +++ b/src/zTests/Misc/0HelloWorld.txt @@ -0,0 +1,5 @@ +class Main inherits IO { + main(): SELF_TYPE { + out_string("Hello, World.\n") + }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/0Simple.txt b/src/zTests/Misc/0Simple.txt new file mode 100644 index 000000000..9046024dc --- /dev/null +++ b/src/zTests/Misc/0Simple.txt @@ -0,0 +1,13 @@ +class Main{ + a: A; + + main(): A { + a <- new A + }; +}; + +class A { + method(): Int{ + 1 + }; +}; diff --git a/src/zTests/Misc/0SimpleSpaced.txt b/src/zTests/Misc/0SimpleSpaced.txt new file mode 100644 index 000000000..151be34fe --- /dev/null +++ b/src/zTests/Misc/0SimpleSpaced.txt @@ -0,0 +1,13 @@ +class Main { + a : A ; + + main ( ) : A { + a <- new A + } ; +} ; + +class A { + method ( ) : Int { + 1 + } ; +} ; \ No newline at end of file diff --git a/src/zTests/Misc/10.txt b/src/zTests/Misc/10.txt new file mode 100644 index 000000000..5cffd4f8c --- /dev/null +++ b/src/zTests/Misc/10.txt @@ -0,0 +1,10 @@ + +class Main{ + a: A; + main(b:Int): A { + b <- 3 + a + }; +}; + +class A{}; \ No newline at end of file diff --git a/src/zTests/Misc/11.txt b/src/zTests/Misc/11.txt new file mode 100644 index 000000000..f4afdca9a --- /dev/null +++ b/src/zTests/Misc/11.txt @@ -0,0 +1,10 @@ +class Silly +{ + capy() : SELF_TYPE { self }; +}; +class Sally inherits Silly { }; + +class Main { + x : Sally <- (new Sally).capy(); + main() : Sally { x }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/1Ackerman.txt b/src/zTests/Misc/1Ackerman.txt new file mode 100644 index 000000000..0ca3e1c7f --- /dev/null +++ b/src/zTests/Misc/1Ackerman.txt @@ -0,0 +1,24 @@ +class Main inherits IO{ + a : Ackermann ; + main(): SELF_TYPE {{ + a <- new Ackermann; + out_int(a.ackermann(1,3)); + } + }; +}; + +class Fact { + fact(n : Int): Int{ + if (n=0) then 1 else n*fact(n-1) fi + }; +}; + +class Ackermann { + ackermann(m:Int, n: Int): Int{ + if (m = 0 ) then n+1 else + if ( n = 0) then ackermann(m-1, 1) else + ackermann(m-1, ackermann(m, n-1)) + fi + fi + }; +}; \ No newline at end of file diff --git a/src/zTests/Misc/3.txt b/src/zTests/Misc/3.txt new file mode 100644 index 000000000..a43e3fa4a --- /dev/null +++ b/src/zTests/Misc/3.txt @@ -0,0 +1,93 @@ +class CellularAutomaton inherits IO { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + self; + } + }; + + print() : SELF_TYPE { + { + out_string(population_map.concat("\n")); + self; + } + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + population_map.substr(position, 1) + }; + + cell_left_neighbor(position : Int) : String { + if position = 0 then + cell(num_cells() - 1) + else + cell(position - 1) + fi + }; + + cell_right_neighbor(position : Int) : String { + if position = num_cells() - 1 then + cell(0) + else + cell(position + 1) + fi + }; + + (* a cell will live if exactly 1 of itself and it's immediate + neighbors are alive *) + cell_at_next_evolution(position : Int) : String { + if ((if cell(position) = "X" then 1 else 0 fi) + + (if cell_left_neighbor(position) = "X" then 1 else 0 fi) + + (if cell_right_neighbor(position) = "X" then 1 else 0 fi) + = 1) + then + "X" + else + "." + fi + }; + + evolve() : SELF_TYPE { + (let position : Int in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; +}; + +class Main { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + cells <- (new CellularAutomaton).init(" X "); + cells.print(); + (let countdown : Int <- 20 in + while 0 < countdown loop + { + cells.evolve(); + cells.print(); + countdown <- countdown - 1; + } + pool + ); + self; + } + }; +}; diff --git a/src/zTests/Misc/5.txt b/src/zTests/Misc/5.txt new file mode 100644 index 000000000..daebec7e6 --- /dev/null +++ b/src/zTests/Misc/5.txt @@ -0,0 +1,64 @@ +(* hairy . . .*) + +class Foo inherits Bazz { + a : Razz <- case self of + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + b : Int <- a.doh() + g.doh() + doh() + printh(); + + doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; + +}; + +class Bar inherits Razz { + + c : Int <- doh(); + + d : Object <- printh(); +}; + + +class Razz inherits Foo { + + e : Bar <- case self of + n : Razz => (new Bar); + n : Bar => n; + esac; + + f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); + +}; + +class Bazz inherits IO { + + h : Int <- 1; + + g : Foo <- case self of + n : Bazz => (new Foo); + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + i : Object <- printh(); + + printh() : Int { { out_int(h); 0; } }; + + doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; +}; + +(* scary . . . *) +class Main inherits IO{ + a : Bazz <- new Bazz; + b : Foo <- new Foo; + c : Razz <- new Razz; + d : Bar <- new Bar; + + main(): String { out_string("do nothing, except this") }; + +}; + + diff --git a/src/zTests/Misc/6.txt b/src/zTests/Misc/6.txt new file mode 100644 index 000000000..25facd526 --- /dev/null +++ b/src/zTests/Misc/6.txt @@ -0,0 +1,436 @@ +(* The Game of Life + Tendo Kayiira, Summer '95 + With code taken from /private/cool/class/examples/cells.cl + + This introduction was taken off the internet. It gives a brief + description of the Game Of Life. It also gives the rules by which + this particular game follows. + + Introduction + + John Conway's Game of Life is a mathematical amusement, but it + is also much more: an insight into how a system of simple + cellualar automata can create complex, odd, and often aesthetically + pleasing patterns. It is played on a cartesian grid of cells + which are either 'on' or 'off' The game gets it's name from the + similarity between the behaviour of these cells and the behaviour + of living organisms. + + The Rules + + The playfield is a cartesian grid of arbitrary size. Each cell in + this grid can be in an 'on' state or an 'off' state. On each 'turn' + (called a generation,) the state of each cell changes simultaneously + depending on it's state and the state of all cells adjacent to it. + + For 'on' cells, + If the cell has 0 or 1 neighbours which are 'on', the cell turns + 'off'. ('dies of loneliness') + If the cell has 2 or 3 neighbours which are 'on', the cell stays + 'on'. (nothing happens to that cell) + If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', + the cell turns 'off'. ('dies of overcrowding') + + For 'off' cells, + If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which + are 'on', the cell stays 'off'. (nothing happens to that cell) + If the cell has 3 neighbours which are 'on', the cell turns + 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) + + Repeat for as many generations as desired. + + *) + + +class Board inherits IO { + + rows : Int; + columns : Int; + board_size : Int; + + size_of_board(initial : String) : Int { + initial.length() + }; + + board_init(start : String) : SELF_TYPE { + (let size :Int <- size_of_board(start) in + { + if size = 15 then + { + rows <- 3; + columns <- 5; + board_size <- size; + } + else if size = 16 then + { + rows <- 4; + columns <- 4; + board_size <- size; + } + else if size = 20 then + { + rows <- 4; + columns <- 5; + board_size <- size; + } + else if size = 21 then + { + rows <- 3; + columns <- 7; + board_size <- size; + } + else if size = 25 then + { + rows <- 5; + columns <- 5; + board_size <- size; + } + else if size = 28 then + { + rows <- 7; + columns <- 4; + board_size <- size; + } + else + { + rows <- 5; + columns <- 5; + board_size <- size; + } + fi fi fi fi fi fi; + self; + } + ) + }; + +}; + + + +class CellularAutomaton inherits Board { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + board_init(map); + self; + } + }; + + + + + print() : SELF_TYPE { + + (let i : Int <- 0 in + (let num : Int <- board_size in + { + out_string("\n"); + while i < num loop + { + out_string(population_map.substr(i,columns)); + out_string("\n"); + i <- i + columns; + } + pool; + out_string("\n"); + self; + } + ) ) + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + if board_size - 1 < position then + " " + else + population_map.substr(position, 1) + fi + }; + + north(position : Int): String { + if (position - columns) < 0 then + " " + else + cell(position - columns) + fi + }; + + south(position : Int): String { + if board_size < (position + columns) then + " " + else + cell(position + columns) + fi + }; + + east(position : Int): String { + if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + cell(position + 1) + fi + }; + + west(position : Int): String { + if position = 0 then + " " + else + if ((position / columns) * columns) = position then + " " + else + cell(position - 1) + fi fi + }; + + northwest(position : Int): String { + if (position - columns) < 0 then + " " + else if ((position / columns) * columns) = position then + " " + else + north(position - 1) + fi fi + }; + + northeast(position : Int): String { + if (position - columns) < 0 then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + north(position + 1) + fi fi + }; + + southeast(position : Int): String { + if board_size < (position + columns) then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + south(position + 1) + fi fi + }; + + southwest(position : Int): String { + if board_size < (position + columns) then + " " + else if ((position / columns) * columns) = position then + " " + else + south(position - 1) + fi fi + }; + + neighbors(position: Int): Int { + { + (if north(position) = "X" then 1 else 0 fi) + + (if south(position) = "X" then 1 else 0 fi) + + (if east(position) = "X" then 1 else 0 fi) + + (if west(position) = "X" then 1 else 0 fi) + + (if northeast(position) = "X" then 1 else 0 fi) + + (if northwest(position) = "X" then 1 else 0 fi) + + (if southeast(position) = "X" then 1 else 0 fi) + + (if southwest(position) = "X" then 1 else 0 fi); + } + }; + + +(* A cell will live if 2 or 3 of it's neighbors are alive. It dies + otherwise. A cell is born if only 3 of it's neighbors are alive. *) + + cell_at_next_evolution(position : Int) : String { + + if neighbors(position) = 3 then + "X" + else + if neighbors(position) = 2 then + if cell(position) = "X" then + "X" + else + "-" + fi + else + "-" + fi fi + }; + + + evolve() : SELF_TYPE { + (let position : Int <- 0 in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; + +(* This is where the background pattern is detremined by the user. More + patterns can be added as long as whoever adds keeps the board either + 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) + option(): String { + { + (let num : Int in + { + out_string("\nPlease chose a number:\n"); + out_string("\t1: A cross\n"); + out_string("\t2: A slash from the upper left to lower right\n"); + out_string("\t3: A slash from the upper right to lower left\n"); + out_string("\t4: An X\n"); + out_string("\t5: A greater than sign \n"); + out_string("\t6: A less than sign\n"); + out_string("\t7: Two greater than signs\n"); + out_string("\t8: Two less than signs\n"); + out_string("\t9: A 'V'\n"); + out_string("\t10: An inverse 'V'\n"); + out_string("\t11: Numbers 9 and 10 combined\n"); + out_string("\t12: A full grid\n"); + out_string("\t13: A 'T'\n"); + out_string("\t14: A plus '+'\n"); + out_string("\t15: A 'W'\n"); + out_string("\t16: An 'M'\n"); + out_string("\t17: An 'E'\n"); + out_string("\t18: A '3'\n"); + out_string("\t19: An 'O'\n"); + out_string("\t20: An '8'\n"); + out_string("\t21: An 'S'\n"); + out_string("Your choice => "); + num <- in_int(); + out_string("\n"); + if num = 1 then + " XX XXXX XXXX XX " + else if num = 2 then + " X X X X X " + else if num = 3 then + "X X X X X" + else if num = 4 then + "X X X X X X X X X" + else if num = 5 then + "X X X X X " + else if num = 6 then + " X X X X X" + else if num = 7 then + "X X X XX X " + else if num = 8 then + " X XX X X X " + else if num = 9 then + "X X X X X " + else if num = 10 then + " X X X X X" + else if num = 11 then + "X X X X X X X X" + else if num = 12 then + "XXXXXXXXXXXXXXXXXXXXXXXXX" + else if num = 13 then + "XXXXX X X X X " + else if num = 14 then + " X X XXXXX X X " + else if num = 15 then + "X X X X X X X " + else if num = 16 then + " X X X X X X X" + else if num = 17 then + "XXXXX X XXXXX X XXXX" + else if num = 18 then + "XXX X X X X XXXX " + else if num = 19 then + " XX X XX X XX " + else if num = 20 then + " XX X XX X XX X XX X XX " + else if num = 21 then + " XXXX X XX X XXXX " + else + " " + fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; + } + ); + } + }; + + + + + prompt() : Bool { + { + (let ans : String in + { + out_string("Would you like to continue with the next generation? \n"); + out_string("Please use lowercase y or n for your answer [y]: "); + ans <- in_string(); + out_string("\n"); + if ans = "n" then + false + else + true + fi; + } + ); + } + }; + + + prompt2() : Bool { + (let ans : String in + { + out_string("\n\n"); + out_string("Would you like to choose a background pattern? \n"); + out_string("Please use lowercase y or n for your answer [n]: "); + ans <- in_string(); + if ans = "y" then + true + else + false + fi; + } + ) + }; + + +}; + +class Main inherits CellularAutomaton { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + (let continue : Bool in + (let choice : String in + { + out_string("Welcome to the Game of Life.\n"); + out_string("There are many initial states to choose from. \n"); + while prompt2() loop + { + continue <- true; + choice <- option(); + cells <- (new CellularAutomaton).init(choice); + cells.print(); + while continue loop + if prompt() then + { + cells.evolve(); + cells.print(); + } + else + continue <- false + fi + pool; + } + pool; + self; + } ) ); } + }; +}; + diff --git a/src/zTests/Misc/7.txt b/src/zTests/Misc/7.txt new file mode 100644 index 000000000..098e965fe --- /dev/null +++ b/src/zTests/Misc/7.txt @@ -0,0 +1,426 @@ + +class VarList inherits IO { + isNil() : Bool { true }; + head() : Variable { { abort(); new Variable; } }; + tail() : VarList { { abort(); new VarList; } }; + add(x : Variable) : VarList { (new VarListNE).init(x, self) }; + print() : SELF_TYPE { out_string("\n") }; +}; + +class VarListNE inherits VarList { + x : Variable; + rest : VarList; + isNil() : Bool { false }; + head() : Variable { x }; + tail() : VarList { rest }; + init(y : Variable, r : VarList) : VarListNE { { x <- y; rest <- r; self; } }; + print() : SELF_TYPE { { x.print_self(); out_string(" "); + rest.print(); self; } }; +}; + +class LambdaList { + isNil() : Bool { true }; + headE() : VarList { { abort(); new VarList; } }; + headC() : Lambda { { abort(); new Lambda; } }; + headN() : Int { { abort(); 0; } }; + tail() : LambdaList { { abort(); new LambdaList; } }; + add(e : VarList, x : Lambda, n : Int) : LambdaList { + (new LambdaListNE).init(e, x, n, self) + }; +}; + +class LambdaListNE inherits LambdaList { + lam : Lambda; + num : Int; + env : VarList; + rest : LambdaList; + isNil() : Bool { false }; + headE() : VarList { env }; + headC() : Lambda { lam }; + headN() : Int { num }; + tail() : LambdaList { rest }; + init(e : VarList, l : Lambda, n : Int, r : LambdaList) : LambdaListNE { + { + env <- e; + lam <- l; + num <- n; + rest <- r; + self; + } + }; +}; + +class LambdaListRef { + nextNum : Int <- 0; + l : LambdaList; + isNil() : Bool { l.isNil() }; + headE() : VarList { l.headE() }; + headC() : Lambda { l.headC() }; + headN() : Int { l.headN() }; + reset() : SELF_TYPE { + { + nextNum <- 0; + l <- new LambdaList; + self; + } + }; + add(env : VarList, c : Lambda) : Int { + { + l <- l.add(env, c, nextNum); + nextNum <- nextNum + 1; + nextNum - 1; + } + }; + removeHead() : SELF_TYPE { + { + l <- l.tail(); + self; + } + }; +}; + + +class Expr inherits IO { + + print_self() : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't print self\n"); + abort(); + self; + } + }; + + beta() : Expr { + { + out_string("\nError: Expr is pure virtual; can't beta-reduce\n"); + abort(); + self; + } + }; + + substitute(x : Variable, e : Expr) : Expr { + { + out_string("\nError: Expr is pure virtual; can't substitute\n"); + abort(); + self; + } + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't gen_code\n"); + abort(); + self; + } + }; +}; + +class Variable inherits Expr { + name : String; + + init(n:String) : Variable { + { + name <- n; + self; + } + }; + + print_self() : SELF_TYPE { + out_string(name) + }; + + beta() : Expr { self }; + + substitute(x : Variable, e : Expr) : Expr { + if x = self then e else self fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + let cur_env : VarList <- env in + { while (if cur_env.isNil() then + false + else + not (cur_env.head() = self) + fi) loop + { out_string("get_parent()."); + cur_env <- cur_env.tail(); + } + pool; + if cur_env.isNil() then + { out_string("Error: free occurrence of "); + print_self(); + out_string("\n"); + abort(); + self; + } + else + out_string("get_x()") + fi; + } + }; +}; + +class Lambda inherits Expr { + arg : Variable; + body : Expr; + + init(a:Variable, b:Expr) : Lambda { + { + arg <- a; + body <- b; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("\\"); + arg.print_self(); + out_string("."); + body.print_self(); + self; + } + }; + + beta() : Expr { self }; + + apply(actual : Expr) : Expr { + body.substitute(arg, actual) + }; + + substitute(x : Variable, e : Expr) : Expr { + if x = arg then + self + else + let new_body : Expr <- body.substitute(x, e), + new_lam : Lambda <- new Lambda in + new_lam.init(arg, new_body) + fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("((new Closure"); + out_int(closures.add(env, self)); + out_string(").init("); + if env.isNil() then + out_string("new Closure))") + else + out_string("self))") fi; + self; + } + }; + + gen_closure_code(n : Int, env : VarList, + closures : LambdaListRef) : SELF_TYPE { + { + out_string("class Closure"); + out_int(n); + out_string(" inherits Closure {\n"); + out_string(" apply(y : EvalObject) : EvalObject {\n"); + out_string(" { out_string(\"Applying closure "); + out_int(n); + out_string("\\n\");\n"); + out_string(" x <- y;\n"); + body.gen_code(env.add(arg), closures); + out_string(";}};\n"); + out_string("};\n"); + } + }; +}; + + +class App inherits Expr { + fun : Expr; + arg : Expr; + + init(f : Expr, a : Expr) : App { + { + fun <- f; + arg <- a; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("(("); + fun.print_self(); + out_string(")@("); + arg.print_self(); + out_string("))"); + self; + } + }; + + beta() : Expr { + case fun of + l : Lambda => l.apply(arg); -- Lazy evaluation + e : Expr => + let new_fun : Expr <- fun.beta(), + new_app : App <- new App in + new_app.init(new_fun, arg); + esac + }; + + substitute(x : Variable, e : Expr) : Expr { + let new_fun : Expr <- fun.substitute(x, e), + new_arg : Expr <- arg.substitute(x, e), + new_app : App <- new App in + new_app.init(new_fun, new_arg) + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("(let x : EvalObject <- "); + fun.gen_code(env, closures); + out_string(",\n"); + out_string(" y : EvalObject <- "); + arg.gen_code(env, closures); + out_string(" in\n"); + out_string(" case x of\n"); + out_string(" c : Closure => c.apply(y);\n"); + out_string(" o : Object => { abort(); new EvalObject; };\n"); + out_string(" esac)"); + } + }; +}; + + + +class Term inherits IO { + + var(x : String) : Variable { + let v : Variable <- new Variable in + v.init(x) + }; + + lam(x : Variable, e : Expr) : Lambda { + let l : Lambda <- new Lambda in + l.init(x, e) + }; + + app(e1 : Expr, e2 : Expr) : App { + let a : App <- new App in + a.init(e1, e2) + }; + + (* + * Some useful terms + *) + i() : Expr { + let x : Variable <- var("x") in + lam(x,x) + }; + + k() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y") in + lam(x,lam(y,x)) + }; + + s() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y"), + z : Variable <- var("z") in + lam(x,lam(y,lam(z,app(app(x,z),app(y,z))))) + }; + +}; + + + +class Main inherits Term { + beta_reduce(e : Expr) : Expr { + { + out_string("beta-reduce: "); + e.print_self(); + let done : Bool <- false, + new_expr : Expr in + { + while (not done) loop + { + new_expr <- e.beta(); + if (new_expr = e) then + done <- true + else + { + e <- new_expr; + out_string(" =>\n"); + e.print_self(); + } + fi; + } + pool; + out_string("\n"); + e; + }; + } + }; + + eval_class() : SELF_TYPE { + { + out_string("class EvalObject inherits IO {\n"); + out_string(" eval() : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + closure_class() : SELF_TYPE { + { + out_string("class Closure inherits EvalObject {\n"); + out_string(" parent : Closure;\n"); + out_string(" x : EvalObject;\n"); + out_string(" get_parent() : Closure { parent };\n"); + out_string(" get_x() : EvalObject { x };\n"); + out_string(" init(p : Closure) : Closure {{ parent <- p; self; }};\n"); + out_string(" apply(y : EvalObject) : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + gen_code(e : Expr) : SELF_TYPE { + let cl : LambdaListRef <- (new LambdaListRef).reset() in + { + out_string("Generating code for "); + e.print_self(); + out_string("\n------------------cut here------------------\n"); + out_string("(*Generated by lam.cl (Jeff Foster, March 2000)*)\n"); + eval_class(); + closure_class(); + out_string("class Main {\n"); + out_string(" main() : EvalObject {\n"); + e.gen_code(new VarList, cl); + out_string("\n};\n};\n"); + while (not (cl.isNil())) loop + let e : VarList <- cl.headE(), + c : Lambda <- cl.headC(), + n : Int <- cl.headN() in + { + cl.removeHead(); + c.gen_closure_code(n, e, cl); + } + pool; + out_string("\n------------------cut here------------------\n"); + } + }; + + main() : Int { + { + i().print_self(); + out_string("\n"); + k().print_self(); + out_string("\n"); + s().print_self(); + out_string("\n"); + beta_reduce(app(app(app(s(), k()), i()), i())); + beta_reduce(app(app(k(),i()),i())); + gen_code(app(i(), i())); + gen_code(app(app(app(s(), k()), i()), i())); + gen_code(app(app(app(app(app(app(app(app(i(), k()), s()), s()), + k()), s()), i()), k()), i())); + gen_code(app(app(i(), app(k(), s())), app(k(), app(s(), s())))); + 0; + } + }; +}; diff --git a/src/zTests/Misc/8.txt b/src/zTests/Misc/8.txt new file mode 100644 index 000000000..51274315c --- /dev/null +++ b/src/zTests/Misc/8.txt @@ -0,0 +1,34 @@ +class H +{ + a:int; +}; + +class Z inherits H +{ + x:int; +}; + +class A inherits F +{ + b:int; +}; + +class B inherits A +{ + c:int; +}; + +class C inherits B +{ + e:int; +}; + +class D inherits C +{ + f:int; +}; + +class F inherits D +{ + g:int; +}; \ No newline at end of file diff --git a/src/zTests/Misc/9.txt b/src/zTests/Misc/9.txt new file mode 100644 index 000000000..978e266e2 --- /dev/null +++ b/src/zTests/Misc/9.txt @@ -0,0 +1,23 @@ + +class Main{ + a: A; + main(): A { + 1 + }; +}; + +class A { + oper(a : Int, b : Int): Int{ + a + b + }; +}; +class B inherits A { + oper(a : Int, b : Int, c : Int) : Int{ + a * b * c + }; +}; +class C inherits A { + oper(a : Int, b : String) : Bool{ + a + b + }; +}; \ No newline at end of file From 4060bc548b1d92a6f952b63c34d429c3783717e1 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 12:27:05 -0500 Subject: [PATCH 021/432] Minor Re-Structuiring and bug fixes --- src/devdeb.py | 8 +- src/parsing/ast.py | 1 - src/semantics/autotype_collector.py | 40 +++-- src/semantics/tools.py | 151 ++++++++++++++++-- src/semantics/type_builder.py | 31 ++-- src/semantics/utils.py | 102 +----------- .../Misc/{0HelloWorld.txt => 00HelloRodro.cl} | 4 +- src/zTests/Misc/{0Simple.txt => 01Simple.cl} | 0 src/zTests/Misc/{10.txt => 02Simple.cl} | 3 +- src/zTests/Misc/{9.txt => 03Simple.cl} | 0 src/zTests/Misc/{11.txt => 04SallySilly.cl} | 0 .../Misc/{1Ackerman.txt => 05Ackerman.cl} | 0 src/zTests/Misc/{5.txt => 06FooBarRaz.cl} | 0 src/zTests/Misc/{8.txt => 07MultipleClass.cl} | 0 src/zTests/Misc/{3.txt => 08Cellullar.cl} | 0 src/zTests/Misc/{6.txt => 09GameOfLife.cl} | 0 src/zTests/Misc/0SimpleSpaced.txt | 13 -- src/zTests/Misc/{7.txt => 10BiG.cl} | 0 18 files changed, 194 insertions(+), 159 deletions(-) rename src/zTests/Misc/{0HelloWorld.txt => 00HelloRodro.cl} (61%) rename src/zTests/Misc/{0Simple.txt => 01Simple.cl} (100%) rename src/zTests/Misc/{10.txt => 02Simple.cl} (69%) rename src/zTests/Misc/{9.txt => 03Simple.cl} (100%) rename src/zTests/Misc/{11.txt => 04SallySilly.cl} (100%) rename src/zTests/Misc/{1Ackerman.txt => 05Ackerman.cl} (100%) rename src/zTests/Misc/{5.txt => 06FooBarRaz.cl} (100%) rename src/zTests/Misc/{8.txt => 07MultipleClass.cl} (100%) rename src/zTests/Misc/{3.txt => 08Cellullar.cl} (100%) rename src/zTests/Misc/{6.txt => 09GameOfLife.cl} (100%) delete mode 100644 src/zTests/Misc/0SimpleSpaced.txt rename src/zTests/Misc/{7.txt => 10BiG.cl} (100%) diff --git a/src/devdeb.py b/src/devdeb.py index 86868597e..b7c205cd4 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -36,8 +36,13 @@ def run_pipeline(program): folder_path = r'./zTests/Misc' filenames = os.listdir(folder_path) filenames.sort() +count = 4 for filename in filenames: + if count == 0: + print("Reach Count Limit") + break + path = os.path.join(folder_path, filename) file = open(path, "r") program = file.read() @@ -45,7 +50,8 @@ def run_pipeline(program): print(f"Running {filename}") run_pipeline(program) - input() + count -= 1 + print("-------------------------------------------------------------------------\n") print("EndOfFiles") diff --git a/src/parsing/ast.py b/src/parsing/ast.py index 53abf401c..8f7b3dd01 100644 --- a/src/parsing/ast.py +++ b/src/parsing/ast.py @@ -23,7 +23,6 @@ def __init__(self, declarations): class DeclarationNode(Node): pass - class ClassDeclarationNode(DeclarationNode): def __init__(self, idx, features, parent=None): Node.__init__(self) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index da2dcc28a..c3c0a1265 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -1,4 +1,4 @@ -from semantics.utils import conforms, join, join_list, smart_add +from semantics.tools import conforms, join, join_list, smart_add import semantics.visitor as visitor 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 @@ -7,8 +7,6 @@ class AutotypeCollector: def __init__(self, context:Context): self.context = context self.current_type = None - self.current_method = None - self.current_attrb = None self.inference_graph = dict() self.errors = [] @@ -26,7 +24,7 @@ def visit(self, node:ProgramNode) -> Scope: @visitor.when(ClassDeclarationNode) def visit(self, node, scope): - self.current_type = self.context.get_type(node.id) + self.current_type = self.context.get_type(node.id, unpacked=True) scope.define_variable("self", self.current_type) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) @@ -36,14 +34,14 @@ def visit(self, node, scope): @visitor.when(AttrDeclarationNode) def visit(self, node, scope): - node_type = self.current_type.get_attribute(node.id).swap_self_type(self.current_type) + node_type = self.current_type.get_attribute(node.id).type.swap_self_type(self.current_type) if not node.expr: node.inferenced_type = node_type return self.visit(node.expr, scope) node_expr = node.expr.inferenced_type - node_expr = conforms(node_expr, node_type) + conforms(node_expr, node_type) var = scope.find_variable(node.id) var.type = node_type @@ -58,9 +56,9 @@ def visit(self, node, scopex): 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_decl = 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) + conforms(ret_type_expr, ret_type_decl) node.body.inferenced_type = ret_type_expr node.inferenced_type = ret_type_decl.clone() @@ -68,20 +66,20 @@ def visit(self, node, scopex): @visitor.when(BlocksNode) def visit(self, node, scope): - for expr in node.body: + for expr in node.expr_list: self.visit(expr, scope) - node.inferenced_type = node.body[-1].inferenced_type + node.inferenced_type = node.expr_list[-1].inferenced_type @visitor.when(ConditionalNode) def visit(self, node, scope): - self.visit(node.condition) + 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.then_body) + self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type - self.visit(node.else_body) + self.visit(node.else_body, scope) else_type = node.else_body.inferenced_type joined_type = join(then_type, else_type) @@ -118,13 +116,13 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") conforms(condition_type, bool_type) - self.visit(node.bodyexpr, scope) + self.visit(node.body, 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: + for var in node.var_decl_list: self.visit(var, child) self.visit(node.in_expr, scope) node.inferenced_type = node.in_expr.inferenced_type @@ -172,12 +170,12 @@ def visit(self, node, scope:Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): if node.expr == None: - caller = self.current_type + caller = TypeBag({self.current_type}) elif node.type == None: - self.visit(node.expr) + self.visit(node.expr, scope) caller = node.expr.inferenced_type else: - self.visit(node.expr) + self.visit(node.expr, scope) bridge = node.expr.inferenced_type caller = self.context.get_type(node.type, selftype=False, autotype=False) conforms(bridge, caller) @@ -194,7 +192,7 @@ def visit(self, node, scope): elif len(caller.type_set) == 1: caller_type = caller.heads[0] try: - methods = [caller_type, caller_type.get_method(node.id)] + methods = [(caller_type, caller_type.get_method(node.id))] except SemanticError: pass #Add Error @@ -241,7 +239,7 @@ def visit(self, node, scope): @visitor.when(VariableNode) def visit(self, node, scope): - var = scope.find_variable(node.expr) + var = scope.find_variable(node.value) if var: node.defined = True var_type = var.type @@ -276,7 +274,7 @@ def visit(self, node, scope): @visitor.when(InstantiateNode) def visit(self, node, scope): try: - node_type = self.context.get_type(node.expr, selftype=False, autotype=False) + node_type = self.context.get_type(node.value, selftype=False, autotype=False) except SemanticError as err: node_type = ErrorType() node.inferenced_type = node_type diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 4c0a459f6..5e8c042bf 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,7 +1,8 @@ import itertools as itt from collections import OrderedDict from typing import FrozenSet -#from semantics.utils import from_dict_to_set + +from semantics.utils import conform_to_condition, order_set_by_index class InternalError(Exception): @property @@ -65,6 +66,16 @@ def set_parent(self, parent): raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') self.parent = parent + def define_attribute(self, name:str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') + def get_attribute(self, name:str): try: return next(attr for attr in self.attributes if attr.name == name) @@ -97,7 +108,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ parent_method = None if parent_method: error_list = [] - if not return_type.conforms_to(parent_method.return_type): + if conforms(return_type, parent_method.return_type): error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") @@ -176,8 +187,10 @@ class TypeBag: def __init__(self, type_set, heads = []) -> None: self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) self.heads:list = heads - if len(type_set) == 1: + if len(self.type_set) == 1: self.heads = list(self.type_set) + + self.name = self.generate_name() self.condition_list = [] self.conform_list = [] @@ -185,10 +198,11 @@ def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list self.update_type_set_from_conforms() + self.name = self.generate_name() def update_type_set_from_conforms(self): intersect_set = set() - for conform_set in self.conforms_list: + for conform_set in self.conform_list: intersect_set = intersect_set.union(conform_set) self.type_set = self.type_set.intersection(intersect_set) self.update_heads() @@ -196,7 +210,7 @@ def update_type_set_from_conforms(self): def update_heads(self): new_heads = [] visited = set() - for head in self.upper_limmit: + for head in self.heads: if head in self.type_set: new_heads.append(head) continue @@ -213,7 +227,7 @@ def update_heads(self): elif typex.index == lower_index: new_heads.append(typex) new_heads += new_heads - self.upper_limmit = new_heads + self.heads = new_heads def swap_self_type(self, update_type): try: @@ -231,6 +245,14 @@ def swap_types(self, update_type, remove_type): pass return self + def generate_name(self): + if len(self.type_set) == 1: + return self.heads[0].name + + s = "{" + s += ', '.join(typex.name for typex in sorted(self.type_set, key = lambda t: t.index)) + s += "}" + return s def clone(self): clone = TypeBag(self.type_set, self.heads) @@ -241,6 +263,7 @@ def clone(self): class SelfType(Type): def __init__(self): self.name = "SELF_TYPE" + self.index = 2**31 def conforms_to(self, other): #if isinstance(other, SelfType): # return True @@ -248,10 +271,28 @@ def conforms_to(self, other): def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") + + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + class ErrorType(Type): def __init__(self): self.name = "" - self.type_set = FrozenSet() + self.index = 2**32 + self.type_set = frozenset() + def conforms_to(self, other): + return True + def bypass(self): + return True + + def swap_self_type(self, update_type): + return self + + def set_conditions(self, *params): + return class Context: def __init__(self) -> None: @@ -338,7 +379,7 @@ def find_variable(self, vname, index=None): return next(x for x in locals if x.name == vname) except StopIteration: try: - return self.parent.find_variable(vname, self.index)# if self.parent else None + return self.parent.find_variable(vname, self.index) if self.parent else None except AttributeError: return None @@ -357,8 +398,92 @@ def reset(self): for child in self.children: child.reset() -def from_dict_to_set(types:dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set \ No newline at end of file + +def conforms(bag1:TypeBag, bag2:TypeBag): + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) + + bag1.set_conditions(condition_list, conform_list) + return len(bag1.type_set) >= 1 + +def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + ancestor_set = set() + head_list = [] + ordered_set1 = order_set_by_index(bag1.type_set) + ordered_set2 = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + + join_result = TypeBag(ancestor_set, head_list) + return join_result + +def join_list(type_list): + join_result = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + join_result = join(join_result, type_i) + return join_result + +def smart_add(type_set:set, head_list:list, typex:Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex + break + if not there_is: + head_list.append(typex) + return head_list, type_set + +def auto_add(type_set:set, head_list:list, bag:TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head in bag.heads: + ancestor = head_i.least_common_ancestor(head) + if ancestor in type_set: + head_i[i] = ancestor + aux.pop(head) + break + head_list += [typex for typex in aux] + return head_list, type_set + diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index b4f31d8f1..6ce5523b3 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,6 +1,6 @@ import semantics.visitor as visitor from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode -from semantics.tools import SemanticError +from semantics.tools import SemanticError, TypeBag from semantics.tools import ErrorType, SelfType from semantics.tools import Context @@ -65,7 +65,9 @@ def visit(self, node): params_type = [] params_name = [] - for p_name, p_type in node.params: + for var in node.params: + p_name = var.id + p_type = var.type try: params_type.append(self.context.get_type(p_type)) except SemanticError as err: @@ -90,18 +92,23 @@ def build_default_classes(self): Io.set_parent(Object) Bool.set_parent(Object) - Object.define_method("abort", [], [], Object) - Object.define_method("type_name", [], [], String) - Object.define_method("copy", [], [], SelfType()) + p_Object = self.context.get_type("Object") + p_String = self.context.get_type("String") + p_Int = self.context.get_type("Int") + p_Self = TypeBag({SelfType()}) - String.define_method("length", [], [], Int) - String.define_method("concat", ["s"], [String], String) - String.define_method("substr", ["i", "l"], [Int, Int], String) + Object.define_method("abort", [], [], p_Object) + Object.define_method("type_name", [], [], p_String) + Object.define_method("copy", [], [], p_Self) - Io.define_method("out_string", ["x"],[String], SelfType()) - Io.define_method("out_int", ["x"],[Int], SelfType()) - Io.define_method("in_string", [],[], String) - Io.define_method("in_int", [], [], Int) + String.define_method("length", [], [], p_Int) + String.define_method("concat", ["s"], [p_String], p_String) + String.define_method("substr", ["i", "l"], [p_Int, p_Int], p_String) + + Io.define_method("out_string", ["x"],[p_String], p_Self) + Io.define_method("out_int", ["x"],[p_Int], p_Self) + Io.define_method("in_string", [],[], p_String) + Io.define_method("in_int", [], [], p_Int) def add_error(self, node, text:str): line, col = node.get_position() if node else 0, 0 diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 88c089983..d0375d9e8 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,24 +1,3 @@ -from semantics.tools import Type, TypeBag - -def conforms(bag1:TypeBag, bag2:TypeBag): - ordered_set = order_set_by_index(bag2.type_set) - - condition_list = [] - conform_list = [] - for condition in ordered_set: - conform = conform_to_condition(bag1.type_set, condition) - for i in range(len(condition_list)): - conform_i = conform_list[i] - if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): - condition_list[i].add(condition) - break - else: - condition_list.append({condition}) - conform_list.append(conform) - - bag1.set_conditions(condition_list, conform_list) - return bag1 - def conform_to_condition(type_set, parent) -> set: set_result = set() for typex in type_set: @@ -26,83 +5,18 @@ def conform_to_condition(type_set, parent) -> set: set_result.add(typex) return set_result -def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: - ancestor_set = set() - head_list = [] - ordered_set1 = order_set_by_index(bag1.type_set) - ordered_set2 = order_set_by_index(bag2.type_set) - ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) - for type1 in ordered_set1: - same_branch = False - previous_ancestor = None - previous_type = None - for type2 in ordered_set2: - if same_branch and type2.conforms_to(previous_type): - previous_type = type2 - continue - common_ancestor = type1.least_common_ancestor(type2) - previous_type = type2 - if not previous_ancestor: - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - else: - if previous_ancestor == common_ancestor: - same_branch = True - else: - same_branch = False - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - - join_result = TypeBag(ancestor_set, head_list) - return join_result - -def join_list(type_list): - typex = type_list[0] - for i in range(1, len(type_list)): - type_i = type_list[i] - typex = join(typex, type_i) - return typex - -def smart_add(type_set:set, head_list:list, typex:Type): - if isinstance(typex, TypeBag): - return auto_add(type_set, head_list, typex) - - type_set.add(typex) - there_is = False - for i in range(len(head_list)): - head = head_list[i] - ancestor = typex.least_common_ancestor(head) - if ancestor in type_set: - there_is = True - if ancestor == typex: - head_list[i] = typex - break - if not there_is: - head_list.append(typex) - return head_list, type_set - -def auto_add(type_set:set, head_list:list, bag:TypeBag): - type_set = type_set.union(bag.type_set) - aux = set(bag.heads) - for i in range(len(head_list)): - head_i = head_list[i] - for head in bag.heads: - ancestor = head_i.least_common_ancestor(head) - if ancestor in type_set: - head_i[i] = ancestor - aux.pop(head) - break - head_list += [typex for typex in aux] - return head_list, type_set - def order_set_by_index(type_set): - return sorted(list(type_set), lambda x: x.index) - - + return sorted(list(type_set), key = lambda x: x.index) def set_intersection(parent, type_set) -> set: set_result = set() for typex in type_set: if typex.conforms_to(parent): set_result.add(typex) - return set_result \ No newline at end of file + return set_result + +def from_dict_to_set(types:dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set \ No newline at end of file diff --git a/src/zTests/Misc/0HelloWorld.txt b/src/zTests/Misc/00HelloRodro.cl similarity index 61% rename from src/zTests/Misc/0HelloWorld.txt rename to src/zTests/Misc/00HelloRodro.cl index 8ab5bd3a5..08352cbc8 100644 --- a/src/zTests/Misc/0HelloWorld.txt +++ b/src/zTests/Misc/00HelloRodro.cl @@ -1,5 +1,5 @@ class Main inherits IO { main(): SELF_TYPE { - out_string("Hello, World.\n") + out_string("Hello, Rodro.\n") }; -}; \ No newline at end of file +}; diff --git a/src/zTests/Misc/0Simple.txt b/src/zTests/Misc/01Simple.cl similarity index 100% rename from src/zTests/Misc/0Simple.txt rename to src/zTests/Misc/01Simple.cl diff --git a/src/zTests/Misc/10.txt b/src/zTests/Misc/02Simple.cl similarity index 69% rename from src/zTests/Misc/10.txt rename to src/zTests/Misc/02Simple.cl index 5cffd4f8c..eea0900fb 100644 --- a/src/zTests/Misc/10.txt +++ b/src/zTests/Misc/02Simple.cl @@ -3,8 +3,7 @@ class Main{ a: A; main(b:Int): A { b <- 3 - a }; }; -class A{}; \ No newline at end of file +class A{}; diff --git a/src/zTests/Misc/9.txt b/src/zTests/Misc/03Simple.cl similarity index 100% rename from src/zTests/Misc/9.txt rename to src/zTests/Misc/03Simple.cl diff --git a/src/zTests/Misc/11.txt b/src/zTests/Misc/04SallySilly.cl similarity index 100% rename from src/zTests/Misc/11.txt rename to src/zTests/Misc/04SallySilly.cl diff --git a/src/zTests/Misc/1Ackerman.txt b/src/zTests/Misc/05Ackerman.cl similarity index 100% rename from src/zTests/Misc/1Ackerman.txt rename to src/zTests/Misc/05Ackerman.cl diff --git a/src/zTests/Misc/5.txt b/src/zTests/Misc/06FooBarRaz.cl similarity index 100% rename from src/zTests/Misc/5.txt rename to src/zTests/Misc/06FooBarRaz.cl diff --git a/src/zTests/Misc/8.txt b/src/zTests/Misc/07MultipleClass.cl similarity index 100% rename from src/zTests/Misc/8.txt rename to src/zTests/Misc/07MultipleClass.cl diff --git a/src/zTests/Misc/3.txt b/src/zTests/Misc/08Cellullar.cl similarity index 100% rename from src/zTests/Misc/3.txt rename to src/zTests/Misc/08Cellullar.cl diff --git a/src/zTests/Misc/6.txt b/src/zTests/Misc/09GameOfLife.cl similarity index 100% rename from src/zTests/Misc/6.txt rename to src/zTests/Misc/09GameOfLife.cl diff --git a/src/zTests/Misc/0SimpleSpaced.txt b/src/zTests/Misc/0SimpleSpaced.txt deleted file mode 100644 index 151be34fe..000000000 --- a/src/zTests/Misc/0SimpleSpaced.txt +++ /dev/null @@ -1,13 +0,0 @@ -class Main { - a : A ; - - main ( ) : A { - a <- new A - } ; -} ; - -class A { - method ( ) : Int { - 1 - } ; -} ; \ No newline at end of file diff --git a/src/zTests/Misc/7.txt b/src/zTests/Misc/10BiG.cl similarity index 100% rename from src/zTests/Misc/7.txt rename to src/zTests/Misc/10BiG.cl From 1acca39e368c6027cafae72639f856350c3e24fd Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 022/432] Added Type Builder and Type Collector --- src/semantics/autotype_collector.py | 2 +- src/semantics/tools.py | 2 +- src/semantics/utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index c3c0a1265..431a0509a 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -298,4 +298,4 @@ def visit(self, node, scope): # 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 \ No newline at end of file +# todo: Cambiar self.error a que cada error tengo la tupla de localizacion, asi permite organizar los errores diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 5e8c042bf..efd7b43f4 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -2,7 +2,7 @@ from collections import OrderedDict from typing import FrozenSet -from semantics.utils import conform_to_condition, order_set_by_index +from semantics.utils import conform_to_condition, from_dict_to_set, order_set_by_index class InternalError(Exception): @property diff --git a/src/semantics/utils.py b/src/semantics/utils.py index d0375d9e8..3290eebee 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -19,4 +19,4 @@ def from_dict_to_set(types:dict): type_set = set() for typex in types: type_set.add(types[typex]) - return type_set \ No newline at end of file + return type_set From 6ec0a66f6aabe09a3dd8b13639f4fd90cecc765d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 25 Feb 2021 11:11:49 -0500 Subject: [PATCH 023/432] Added Type Builder and Type Collector --- src/semantics/utils.py | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 3290eebee..84a1ca0c3 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,3 +1,4 @@ +<<<<<<< HEAD def conform_to_condition(type_set, parent) -> set: set_result = set() for typex in type_set: @@ -9,10 +10,55 @@ def order_set_by_index(type_set): return sorted(list(type_set), key = lambda x: x.index) def set_intersection(parent, type_set) -> set: +======= +from semantics.tools import Type, ErrorType, AutoType + +def conforms(type1:Type, type2:Type): + if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): + return ErrorType() + if not isinstance(type1, AutoType) and isinstance(type2, AutoType): + type2.set_upper_limmit([type1]) + return type1 + if not isinstance(type1, AutoType): + type1 = AutoType("TEMP01", [type1], {type1}) + if not isinstance(type2, AutoType): + type2 = AutoType("TEMP02", [type2], {type2}) + + print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) + print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) + + condition_set_list, conform_set_list = conforming(type1, type2) + type1.set_new_conditions(condition_set_list, conform_set_list) + + print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) + print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) + print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") + return type1 + +def conforming(auto1:AutoType, auto2:AutoType): + ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) + + condition_set_list = [] + conform_set_list = [] + for type2 in ord_types2: + conforms = conform_intersection(auto1.type_set, type2) + for i in range(len(condition_set_list)): + prev_conform = conform_set_list[i] + if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): + condition_set_list[i].add(type2) + break + else: + condition_set_list.append(set([type2])) + conform_set_list.append(conforms) + return condition_set_list, conform_set_list + +def conform_intersection(type_set, parent) -> set: +>>>>>>> Added Type Builder and Type Collector set_result = set() for typex in type_set: if typex.conforms_to(parent): set_result.add(typex) +<<<<<<< HEAD return set_result def from_dict_to_set(types:dict): @@ -20,3 +66,6 @@ def from_dict_to_set(types:dict): for typex in types: type_set.add(types[typex]) return type_set +======= + return set_result +>>>>>>> Added Type Builder and Type Collector From 51d7e38e7a263ce5f037325ee45eed7a876c0b89 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 15:10:09 -0500 Subject: [PATCH 024/432] Fixed Bugs Related to Circular Heritage --- src/devdeb.py | 16 +++++--- src/semantics/autotype_collector.py | 2 +- src/semantics/tools.py | 59 ++++++++++++++++++++++------- src/semantics/type_collector.py | 9 +++-- src/zTests/Misc/07MultipleClass.cl | 28 ++++++++++---- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/devdeb.py b/src/devdeb.py index b7c205cd4..372fbd1c9 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -22,7 +22,7 @@ def run_pipeline(program): print('Context\n', context) auto_collector = autotype_collector.AutotypeCollector(context) - auto_collector.visit(ast) + scope = auto_collector.visit(ast) s = "Type Collector Errors:\n" s = format_errors(collector.errors, s) @@ -30,14 +30,20 @@ def run_pipeline(program): s = format_errors(builder.errors, s) s += "Inference Gatherer Errors:\n" s = format_errors(auto_collector.errors, s) - + s += "Scope:\n" + scope.get_all_names() print(s) -folder_path = r'./zTests/Misc' -filenames = os.listdir(folder_path) -filenames.sort() +try: + folder_path = r'./zTests/Misc' + filenames = os.listdir(folder_path) + filenames.sort() +except FileNotFoundError: + print("Error Importing Files") count = 4 +filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/06FooBarRaz.cl'] +filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/07MultipleClass.cl'] + for filename in filenames: if count == 0: print("Reach Count Limit") diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 431a0509a..822f7db61 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -25,7 +25,7 @@ def visit(self, node:ProgramNode) -> Scope: @visitor.when(ClassDeclarationNode) def visit(self, node, scope): self.current_type = self.context.get_type(node.id, unpacked=True) - scope.define_variable("self", self.current_type) + scope.define_variable("self", TypeBag({self.current_type})) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index efd7b43f4..d3732284e 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -76,25 +76,35 @@ def define_attribute(self, name:str, typex): else: raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') - def get_attribute(self, name:str): + def get_attribute(self, name:str, first=None): + if not first: + first = self.name + elif first == self.name: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + try: return next(attr for attr in self.attributes if attr.name == name) except StopIteration: if self.parent is None: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') try: - return self.parent.get_attribute(name) + return self.parent.get_attribute(name, first=first) except SemanticError: raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') - def get_method(self, name:str, local:bool = False): + def get_method(self, name:str, local:bool = False, first = None): + if not first: + first = self.name + elif first == self.name: + raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + try: return next(method for method in self.methods if method.name == name) except StopIteration: if self.parent is None: raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') try: - return self.parent.get_method(name) + return self.parent.get_method(name, first = first) except SemanticError: raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') @@ -108,7 +118,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ parent_method = None if parent_method: error_list = [] - if conforms(return_type, parent_method.return_type): + if not conforms(return_type, parent_method.return_type): error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") @@ -116,7 +126,7 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ count = 0 err = [] for param_type, parent_param_type in zip(param_types, parent_method.param_types): - if param_type != parent_param_type: + if not conforms(param_type, parent_param_type): err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") count += 1 if err: @@ -130,20 +140,34 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ self.methods.append(method) return method - def all_attributes(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + def all_attributes(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(clean = False, first=first) for attr in self.attributes: plain[attr.name] = (attr, self) return plain.values() if clean else plain - def all_methods(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + def all_methods(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = OrderedDict() if self.parent is None else self.parent.all_methods(clean = False, first=first) for method in self.methods: plain[method.name] = (method, self) return plain.values() if clean else plain - def conforms_to(self, other): - return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + def conforms_to(self, other, first=None): + if not first: + first = self.name + elif self.name == first: + return False + return other.bypass() or self == other or self.parent and self.parent.conforms_to(other, first) def bypass(self): return False @@ -151,8 +175,7 @@ def bypass(self): def least_common_ancestor(self, other): this = self if isinstance(this, ErrorType) or isinstance(other, ErrorType): - return ErrorType() - #raise SemanticError("Error Type detected while perfoming Join. Aborting.") + return ErrorType() while this.index < other.index: other = other.parent @@ -397,6 +420,14 @@ def reset(self): self.current_child = -1 for child in self.children: child.reset() + + def get_all_names(self, s:str = "", level:int = 0): + if self.locals: + s += "\n ".join([x.name + ":" + str([typex.name for typex in x.type.type_set]) for x in self.locals]) + s += "\n\n" + for child in self.children: + s = child.get_all_names(s, level + 1) + return s def conforms(bag1:TypeBag, bag2:TypeBag): diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 77a110147..82327ca93 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -30,8 +30,11 @@ def visit(self, node): def visit(self, node): try: self.context.create_type(node.id) - self.type_graph[node.id] = [] self.node_dict[node.id] = node + try: + self.type_graph[node.id] + except KeyError: + self.type_graph[node.id] = [] if node.parent: if node.parent in {'String', 'Int, Bool'}: raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") @@ -56,7 +59,7 @@ def get_type_hierarchy(self): visited.add(node) path = [node] circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) - new_order = new_order + [self.context.get_type(node) for node in path] + new_order = new_order + [self.node_dict[node] for node in path] if circular_heritage_errors: print(circular_heritage_errors) @@ -82,7 +85,7 @@ def dfs_type_graph(self, root, graph, visited:set, new_order, index): def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: if node in path: - return ' -> '.join(child for child in visited + [visited[0]]) + return ' -> '.join(child for child in path + [path[0]]) visited.add(node) path.append(node) diff --git a/src/zTests/Misc/07MultipleClass.cl b/src/zTests/Misc/07MultipleClass.cl index 51274315c..52464394a 100644 --- a/src/zTests/Misc/07MultipleClass.cl +++ b/src/zTests/Misc/07MultipleClass.cl @@ -1,34 +1,46 @@ +class Main +{ + h:AUTO_TYPE <- new H; + a:AUTO_TYPE <- new A; + main(): Int + { + { + 3; + } + }; +}; + class H { - a:int; + a:Int; }; class Z inherits H { - x:int; + x:Int; }; class A inherits F { - b:int; + b:Int; }; class B inherits A { - c:int; + c:Int; }; class C inherits B { - e:int; + e:Int; }; class D inherits C { - f:int; + f:Int; }; class F inherits D { - g:int; -}; \ No newline at end of file + g:Int; +}; From 82c4e617e9fe33a72101934f8dd9c2c08e27f32b Mon Sep 17 00:00:00 2001 From: adrian Date: Fri, 26 Feb 2021 16:33:14 -0500 Subject: [PATCH 025/432] Change regex for multiline comments --- src/lexing/lexing_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index 41e146d1c..2cd749b1f 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -125,7 +125,7 @@ def t_aux_rcomment(t): def t_aux_pass(t): - r'[^\*\)]' + r'.|\n' pass # Rule so we can track line numbers From d1c603f7c18eb6dc3bc89fe77636c191f3c2732a Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 18:31:21 -0500 Subject: [PATCH 026/432] Minor Bug Fixes --- src/semantics/autotype_inferencer.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/semantics/autotype_inferencer.py diff --git a/src/semantics/autotype_inferencer.py b/src/semantics/autotype_inferencer.py new file mode 100644 index 000000000..e1d01e676 --- /dev/null +++ b/src/semantics/autotype_inferencer.py @@ -0,0 +1,28 @@ +import semantics.visitor as visitor +from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode +from semantics.tools import Context, Scope + +class AutotypeInferencer: + def __init__(self, context:Context) -> None: + self.context = context + self.current_type = None + self.errors = [] + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode, scope:Scope): + for declaration in node.declarations: + self.visit(declaration, scope.next_child()) + + scope.reset() + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id, unpacked=True) + for feature in node.features: + self.visit(feature, scope) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + + self.visit(node.expr, scope) + node_expr = node.expr.inferenced_type \ No newline at end of file From 31322b61c5fefc3b0d29ec62e37f97eac96e0369 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 18:31:54 -0500 Subject: [PATCH 027/432] Minor Bug Fixes --- src/devdeb.py | 3 +- src/semantics/autotype_collector.py | 5 ++- src/semantics/type_collector.py | 2 +- src/semantics/utils.py | 49 ----------------------------- 4 files changed, 4 insertions(+), 55 deletions(-) diff --git a/src/devdeb.py b/src/devdeb.py index 372fbd1c9..ef6567043 100644 --- a/src/devdeb.py +++ b/src/devdeb.py @@ -41,8 +41,7 @@ def run_pipeline(program): print("Error Importing Files") count = 4 -filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/06FooBarRaz.cl'] -filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/07MultipleClass.cl'] +filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/10BiG.cl'] for filename in filenames: if count == 0: diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index 822f7db61..aa8d329f0 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -7,7 +7,6 @@ class AutotypeCollector: def __init__(self, context:Context): self.context = context self.current_type = None - self.inference_graph = dict() self.errors = [] @visitor.on('node') @@ -87,10 +86,10 @@ def visit(self, node, scope): @visitor.when(CaseNode) def visit(self, node, scope:Scope): - self.visit(node.expr, scope) + self.visit(node.case_expr, scope) type_list = [] - for var in node.casevars: + for var in node.options: child = scope.create_child() self.visit(var, child) type_list.append(var.inferenced_type) diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 82327ca93..8f18be753 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -79,7 +79,7 @@ def dfs_type_graph(self, root, graph, visited:set, new_order, index): visited.add(node) if node not in {"Int", "String", "IO", "Bool", "Object"}: new_order.append(self.node_dict[node]) - self.context.get_type(node).index = index + self.context.get_type(node, unpacked=True).index = index self.dfs_type_graph(node, graph, visited, new_order, index + 1) def check_circular_heritage(self, root, graph, path, visited): diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 84a1ca0c3..3290eebee 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD def conform_to_condition(type_set, parent) -> set: set_result = set() for typex in type_set: @@ -10,55 +9,10 @@ def order_set_by_index(type_set): return sorted(list(type_set), key = lambda x: x.index) def set_intersection(parent, type_set) -> set: -======= -from semantics.tools import Type, ErrorType, AutoType - -def conforms(type1:Type, type2:Type): - if isinstance(type1, ErrorType) or isinstance(type2, ErrorType): - return ErrorType() - if not isinstance(type1, AutoType) and isinstance(type2, AutoType): - type2.set_upper_limmit([type1]) - return type1 - if not isinstance(type1, AutoType): - type1 = AutoType("TEMP01", [type1], {type1}) - if not isinstance(type2, AutoType): - type2 = AutoType("TEMP02", [type2], {type2}) - - print("type 1 set:", ", ".join(typex.name for typex in type1.type_set)) - print("type 2 set:", ", ".join(typex.name for typex in type2.type_set)) - - condition_set_list, conform_set_list = conforming(type1, type2) - type1.set_new_conditions(condition_set_list, conform_set_list) - - print("Conditions obtained", [[typex.name for typex in type_set] for type_set in condition_set_list]) - print("Conforms obtained", [[typex.name for typex in type_set] for type_set in conform_set_list]) - print("Updated set:", ", ".join(typex.name for typex in type1.type_set),"\n") - return type1 - -def conforming(auto1:AutoType, auto2:AutoType): - ord_types2 = sorted(list(auto2.type_set), lambda x: x.index) - - condition_set_list = [] - conform_set_list = [] - for type2 in ord_types2: - conforms = conform_intersection(auto1.type_set, type2) - for i in range(len(condition_set_list)): - prev_conform = conform_set_list[i] - if len(prev_conform) == len(conforms) and len(conforms.intersection(prev_conform)) == len(conforms): - condition_set_list[i].add(type2) - break - else: - condition_set_list.append(set([type2])) - conform_set_list.append(conforms) - return condition_set_list, conform_set_list - -def conform_intersection(type_set, parent) -> set: ->>>>>>> Added Type Builder and Type Collector set_result = set() for typex in type_set: if typex.conforms_to(parent): set_result.add(typex) -<<<<<<< HEAD return set_result def from_dict_to_set(types:dict): @@ -66,6 +20,3 @@ def from_dict_to_set(types:dict): for typex in types: type_set.add(types[typex]) return type_set -======= - return set_result ->>>>>>> Added Type Builder and Type Collector From e894229f449cce48036bd5e1253fed1298344628 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 18:34:34 -0500 Subject: [PATCH 028/432] Eliminated unnecesary scripts --- src/devdeb.py | 62 ---- src/zTests/Misc/00HelloRodro.cl | 5 - src/zTests/Misc/01Simple.cl | 13 - src/zTests/Misc/02Simple.cl | 9 - src/zTests/Misc/03Simple.cl | 23 -- src/zTests/Misc/04SallySilly.cl | 10 - src/zTests/Misc/05Ackerman.cl | 24 -- src/zTests/Misc/06FooBarRaz.cl | 64 ----- src/zTests/Misc/07MultipleClass.cl | 46 --- src/zTests/Misc/08Cellullar.cl | 93 ------ src/zTests/Misc/09GameOfLife.cl | 436 ----------------------------- src/zTests/Misc/10BiG.cl | 426 ---------------------------- 12 files changed, 1211 deletions(-) delete mode 100644 src/devdeb.py delete mode 100644 src/zTests/Misc/00HelloRodro.cl delete mode 100644 src/zTests/Misc/01Simple.cl delete mode 100644 src/zTests/Misc/02Simple.cl delete mode 100644 src/zTests/Misc/03Simple.cl delete mode 100644 src/zTests/Misc/04SallySilly.cl delete mode 100644 src/zTests/Misc/05Ackerman.cl delete mode 100644 src/zTests/Misc/06FooBarRaz.cl delete mode 100644 src/zTests/Misc/07MultipleClass.cl delete mode 100644 src/zTests/Misc/08Cellullar.cl delete mode 100644 src/zTests/Misc/09GameOfLife.cl delete mode 100644 src/zTests/Misc/10BiG.cl diff --git a/src/devdeb.py b/src/devdeb.py deleted file mode 100644 index ef6567043..000000000 --- a/src/devdeb.py +++ /dev/null @@ -1,62 +0,0 @@ -import os -from parsing import parser -from semantics import type_collector, type_builder, autotype_collector - -def format_errors(errors, s = ""): - count = 1 - for error in errors: - s += str(count) + ". " + error + "\n" - count += 1 - return s - -def run_pipeline(program): - ast = parser.parse(program) - - collector = type_collector.TypeCollector() - collector.visit(ast) - context = collector.context - print('Context\n', context) - - builder = type_builder.TypeBuilder(context) - builder.visit(ast) - print('Context\n', context) - - auto_collector = autotype_collector.AutotypeCollector(context) - scope = auto_collector.visit(ast) - - s = "Type Collector Errors:\n" - s = format_errors(collector.errors, s) - s += "Type Builder Errors:\n" - s = format_errors(builder.errors, s) - s += "Inference Gatherer Errors:\n" - s = format_errors(auto_collector.errors, s) - s += "Scope:\n" + scope.get_all_names() - print(s) - -try: - folder_path = r'./zTests/Misc' - filenames = os.listdir(folder_path) - filenames.sort() -except FileNotFoundError: - print("Error Importing Files") -count = 4 - -filenames = [r'/home/rodro/Aarka/Complementos de Compilacion/cool-compiler-2022/src/zTests/Misc/10BiG.cl'] - -for filename in filenames: - if count == 0: - print("Reach Count Limit") - break - - path = os.path.join(folder_path, filename) - file = open(path, "r") - program = file.read() - file.close() - - print(f"Running {filename}") - run_pipeline(program) - count -= 1 - print("-------------------------------------------------------------------------\n") - -print("EndOfFiles") - diff --git a/src/zTests/Misc/00HelloRodro.cl b/src/zTests/Misc/00HelloRodro.cl deleted file mode 100644 index 08352cbc8..000000000 --- a/src/zTests/Misc/00HelloRodro.cl +++ /dev/null @@ -1,5 +0,0 @@ -class Main inherits IO { - main(): SELF_TYPE { - out_string("Hello, Rodro.\n") - }; -}; diff --git a/src/zTests/Misc/01Simple.cl b/src/zTests/Misc/01Simple.cl deleted file mode 100644 index 9046024dc..000000000 --- a/src/zTests/Misc/01Simple.cl +++ /dev/null @@ -1,13 +0,0 @@ -class Main{ - a: A; - - main(): A { - a <- new A - }; -}; - -class A { - method(): Int{ - 1 - }; -}; diff --git a/src/zTests/Misc/02Simple.cl b/src/zTests/Misc/02Simple.cl deleted file mode 100644 index eea0900fb..000000000 --- a/src/zTests/Misc/02Simple.cl +++ /dev/null @@ -1,9 +0,0 @@ - -class Main{ - a: A; - main(b:Int): A { - b <- 3 - }; -}; - -class A{}; diff --git a/src/zTests/Misc/03Simple.cl b/src/zTests/Misc/03Simple.cl deleted file mode 100644 index 978e266e2..000000000 --- a/src/zTests/Misc/03Simple.cl +++ /dev/null @@ -1,23 +0,0 @@ - -class Main{ - a: A; - main(): A { - 1 - }; -}; - -class A { - oper(a : Int, b : Int): Int{ - a + b - }; -}; -class B inherits A { - oper(a : Int, b : Int, c : Int) : Int{ - a * b * c - }; -}; -class C inherits A { - oper(a : Int, b : String) : Bool{ - a + b - }; -}; \ No newline at end of file diff --git a/src/zTests/Misc/04SallySilly.cl b/src/zTests/Misc/04SallySilly.cl deleted file mode 100644 index f4afdca9a..000000000 --- a/src/zTests/Misc/04SallySilly.cl +++ /dev/null @@ -1,10 +0,0 @@ -class Silly -{ - capy() : SELF_TYPE { self }; -}; -class Sally inherits Silly { }; - -class Main { - x : Sally <- (new Sally).capy(); - main() : Sally { x }; -}; \ No newline at end of file diff --git a/src/zTests/Misc/05Ackerman.cl b/src/zTests/Misc/05Ackerman.cl deleted file mode 100644 index 0ca3e1c7f..000000000 --- a/src/zTests/Misc/05Ackerman.cl +++ /dev/null @@ -1,24 +0,0 @@ -class Main inherits IO{ - a : Ackermann ; - main(): SELF_TYPE {{ - a <- new Ackermann; - out_int(a.ackermann(1,3)); - } - }; -}; - -class Fact { - fact(n : Int): Int{ - if (n=0) then 1 else n*fact(n-1) fi - }; -}; - -class Ackermann { - ackermann(m:Int, n: Int): Int{ - if (m = 0 ) then n+1 else - if ( n = 0) then ackermann(m-1, 1) else - ackermann(m-1, ackermann(m, n-1)) - fi - fi - }; -}; \ No newline at end of file diff --git a/src/zTests/Misc/06FooBarRaz.cl b/src/zTests/Misc/06FooBarRaz.cl deleted file mode 100644 index daebec7e6..000000000 --- a/src/zTests/Misc/06FooBarRaz.cl +++ /dev/null @@ -1,64 +0,0 @@ -(* hairy . . .*) - -class Foo inherits Bazz { - a : Razz <- case self of - n : Razz => (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - b : Int <- a.doh() + g.doh() + doh() + printh(); - - doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; - -}; - -class Bar inherits Razz { - - c : Int <- doh(); - - d : Object <- printh(); -}; - - -class Razz inherits Foo { - - e : Bar <- case self of - n : Razz => (new Bar); - n : Bar => n; - esac; - - f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); - -}; - -class Bazz inherits IO { - - h : Int <- 1; - - g : Foo <- case self of - n : Bazz => (new Foo); - n : Razz => (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - i : Object <- printh(); - - printh() : Int { { out_int(h); 0; } }; - - doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; -}; - -(* scary . . . *) -class Main inherits IO{ - a : Bazz <- new Bazz; - b : Foo <- new Foo; - c : Razz <- new Razz; - d : Bar <- new Bar; - - main(): String { out_string("do nothing, except this") }; - -}; - - diff --git a/src/zTests/Misc/07MultipleClass.cl b/src/zTests/Misc/07MultipleClass.cl deleted file mode 100644 index 52464394a..000000000 --- a/src/zTests/Misc/07MultipleClass.cl +++ /dev/null @@ -1,46 +0,0 @@ -class Main -{ - h:AUTO_TYPE <- new H; - a:AUTO_TYPE <- new A; - main(): Int - { - { - 3; - } - }; -}; - -class H -{ - a:Int; -}; - -class Z inherits H -{ - x:Int; -}; - -class A inherits F -{ - b:Int; -}; - -class B inherits A -{ - c:Int; -}; - -class C inherits B -{ - e:Int; -}; - -class D inherits C -{ - f:Int; -}; - -class F inherits D -{ - g:Int; -}; diff --git a/src/zTests/Misc/08Cellullar.cl b/src/zTests/Misc/08Cellullar.cl deleted file mode 100644 index a43e3fa4a..000000000 --- a/src/zTests/Misc/08Cellullar.cl +++ /dev/null @@ -1,93 +0,0 @@ -class CellularAutomaton inherits IO { - population_map : String; - - init(map : String) : SELF_TYPE { - { - population_map <- map; - self; - } - }; - - print() : SELF_TYPE { - { - out_string(population_map.concat("\n")); - self; - } - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - population_map.substr(position, 1) - }; - - cell_left_neighbor(position : Int) : String { - if position = 0 then - cell(num_cells() - 1) - else - cell(position - 1) - fi - }; - - cell_right_neighbor(position : Int) : String { - if position = num_cells() - 1 then - cell(0) - else - cell(position + 1) - fi - }; - - (* a cell will live if exactly 1 of itself and it's immediate - neighbors are alive *) - cell_at_next_evolution(position : Int) : String { - if ((if cell(position) = "X" then 1 else 0 fi) - + (if cell_left_neighbor(position) = "X" then 1 else 0 fi) - + (if cell_right_neighbor(position) = "X" then 1 else 0 fi) - = 1) - then - "X" - else - "." - fi - }; - - evolve() : SELF_TYPE { - (let position : Int in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; -}; - -class Main { - cells : CellularAutomaton; - - main() : SELF_TYPE { - { - cells <- (new CellularAutomaton).init(" X "); - cells.print(); - (let countdown : Int <- 20 in - while 0 < countdown loop - { - cells.evolve(); - cells.print(); - countdown <- countdown - 1; - } - pool - ); - self; - } - }; -}; diff --git a/src/zTests/Misc/09GameOfLife.cl b/src/zTests/Misc/09GameOfLife.cl deleted file mode 100644 index 25facd526..000000000 --- a/src/zTests/Misc/09GameOfLife.cl +++ /dev/null @@ -1,436 +0,0 @@ -(* The Game of Life - Tendo Kayiira, Summer '95 - With code taken from /private/cool/class/examples/cells.cl - - This introduction was taken off the internet. It gives a brief - description of the Game Of Life. It also gives the rules by which - this particular game follows. - - Introduction - - John Conway's Game of Life is a mathematical amusement, but it - is also much more: an insight into how a system of simple - cellualar automata can create complex, odd, and often aesthetically - pleasing patterns. It is played on a cartesian grid of cells - which are either 'on' or 'off' The game gets it's name from the - similarity between the behaviour of these cells and the behaviour - of living organisms. - - The Rules - - The playfield is a cartesian grid of arbitrary size. Each cell in - this grid can be in an 'on' state or an 'off' state. On each 'turn' - (called a generation,) the state of each cell changes simultaneously - depending on it's state and the state of all cells adjacent to it. - - For 'on' cells, - If the cell has 0 or 1 neighbours which are 'on', the cell turns - 'off'. ('dies of loneliness') - If the cell has 2 or 3 neighbours which are 'on', the cell stays - 'on'. (nothing happens to that cell) - If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', - the cell turns 'off'. ('dies of overcrowding') - - For 'off' cells, - If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which - are 'on', the cell stays 'off'. (nothing happens to that cell) - If the cell has 3 neighbours which are 'on', the cell turns - 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) - - Repeat for as many generations as desired. - - *) - - -class Board inherits IO { - - rows : Int; - columns : Int; - board_size : Int; - - size_of_board(initial : String) : Int { - initial.length() - }; - - board_init(start : String) : SELF_TYPE { - (let size :Int <- size_of_board(start) in - { - if size = 15 then - { - rows <- 3; - columns <- 5; - board_size <- size; - } - else if size = 16 then - { - rows <- 4; - columns <- 4; - board_size <- size; - } - else if size = 20 then - { - rows <- 4; - columns <- 5; - board_size <- size; - } - else if size = 21 then - { - rows <- 3; - columns <- 7; - board_size <- size; - } - else if size = 25 then - { - rows <- 5; - columns <- 5; - board_size <- size; - } - else if size = 28 then - { - rows <- 7; - columns <- 4; - board_size <- size; - } - else - { - rows <- 5; - columns <- 5; - board_size <- size; - } - fi fi fi fi fi fi; - self; - } - ) - }; - -}; - - - -class CellularAutomaton inherits Board { - population_map : String; - - init(map : String) : SELF_TYPE { - { - population_map <- map; - board_init(map); - self; - } - }; - - - - - print() : SELF_TYPE { - - (let i : Int <- 0 in - (let num : Int <- board_size in - { - out_string("\n"); - while i < num loop - { - out_string(population_map.substr(i,columns)); - out_string("\n"); - i <- i + columns; - } - pool; - out_string("\n"); - self; - } - ) ) - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - if board_size - 1 < position then - " " - else - population_map.substr(position, 1) - fi - }; - - north(position : Int): String { - if (position - columns) < 0 then - " " - else - cell(position - columns) - fi - }; - - south(position : Int): String { - if board_size < (position + columns) then - " " - else - cell(position + columns) - fi - }; - - east(position : Int): String { - if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - cell(position + 1) - fi - }; - - west(position : Int): String { - if position = 0 then - " " - else - if ((position / columns) * columns) = position then - " " - else - cell(position - 1) - fi fi - }; - - northwest(position : Int): String { - if (position - columns) < 0 then - " " - else if ((position / columns) * columns) = position then - " " - else - north(position - 1) - fi fi - }; - - northeast(position : Int): String { - if (position - columns) < 0 then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - north(position + 1) - fi fi - }; - - southeast(position : Int): String { - if board_size < (position + columns) then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - south(position + 1) - fi fi - }; - - southwest(position : Int): String { - if board_size < (position + columns) then - " " - else if ((position / columns) * columns) = position then - " " - else - south(position - 1) - fi fi - }; - - neighbors(position: Int): Int { - { - (if north(position) = "X" then 1 else 0 fi) - + (if south(position) = "X" then 1 else 0 fi) - + (if east(position) = "X" then 1 else 0 fi) - + (if west(position) = "X" then 1 else 0 fi) - + (if northeast(position) = "X" then 1 else 0 fi) - + (if northwest(position) = "X" then 1 else 0 fi) - + (if southeast(position) = "X" then 1 else 0 fi) - + (if southwest(position) = "X" then 1 else 0 fi); - } - }; - - -(* A cell will live if 2 or 3 of it's neighbors are alive. It dies - otherwise. A cell is born if only 3 of it's neighbors are alive. *) - - cell_at_next_evolution(position : Int) : String { - - if neighbors(position) = 3 then - "X" - else - if neighbors(position) = 2 then - if cell(position) = "X" then - "X" - else - "-" - fi - else - "-" - fi fi - }; - - - evolve() : SELF_TYPE { - (let position : Int <- 0 in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; - -(* This is where the background pattern is detremined by the user. More - patterns can be added as long as whoever adds keeps the board either - 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) - option(): String { - { - (let num : Int in - { - out_string("\nPlease chose a number:\n"); - out_string("\t1: A cross\n"); - out_string("\t2: A slash from the upper left to lower right\n"); - out_string("\t3: A slash from the upper right to lower left\n"); - out_string("\t4: An X\n"); - out_string("\t5: A greater than sign \n"); - out_string("\t6: A less than sign\n"); - out_string("\t7: Two greater than signs\n"); - out_string("\t8: Two less than signs\n"); - out_string("\t9: A 'V'\n"); - out_string("\t10: An inverse 'V'\n"); - out_string("\t11: Numbers 9 and 10 combined\n"); - out_string("\t12: A full grid\n"); - out_string("\t13: A 'T'\n"); - out_string("\t14: A plus '+'\n"); - out_string("\t15: A 'W'\n"); - out_string("\t16: An 'M'\n"); - out_string("\t17: An 'E'\n"); - out_string("\t18: A '3'\n"); - out_string("\t19: An 'O'\n"); - out_string("\t20: An '8'\n"); - out_string("\t21: An 'S'\n"); - out_string("Your choice => "); - num <- in_int(); - out_string("\n"); - if num = 1 then - " XX XXXX XXXX XX " - else if num = 2 then - " X X X X X " - else if num = 3 then - "X X X X X" - else if num = 4 then - "X X X X X X X X X" - else if num = 5 then - "X X X X X " - else if num = 6 then - " X X X X X" - else if num = 7 then - "X X X XX X " - else if num = 8 then - " X XX X X X " - else if num = 9 then - "X X X X X " - else if num = 10 then - " X X X X X" - else if num = 11 then - "X X X X X X X X" - else if num = 12 then - "XXXXXXXXXXXXXXXXXXXXXXXXX" - else if num = 13 then - "XXXXX X X X X " - else if num = 14 then - " X X XXXXX X X " - else if num = 15 then - "X X X X X X X " - else if num = 16 then - " X X X X X X X" - else if num = 17 then - "XXXXX X XXXXX X XXXX" - else if num = 18 then - "XXX X X X X XXXX " - else if num = 19 then - " XX X XX X XX " - else if num = 20 then - " XX X XX X XX X XX X XX " - else if num = 21 then - " XXXX X XX X XXXX " - else - " " - fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; - } - ); - } - }; - - - - - prompt() : Bool { - { - (let ans : String in - { - out_string("Would you like to continue with the next generation? \n"); - out_string("Please use lowercase y or n for your answer [y]: "); - ans <- in_string(); - out_string("\n"); - if ans = "n" then - false - else - true - fi; - } - ); - } - }; - - - prompt2() : Bool { - (let ans : String in - { - out_string("\n\n"); - out_string("Would you like to choose a background pattern? \n"); - out_string("Please use lowercase y or n for your answer [n]: "); - ans <- in_string(); - if ans = "y" then - true - else - false - fi; - } - ) - }; - - -}; - -class Main inherits CellularAutomaton { - cells : CellularAutomaton; - - main() : SELF_TYPE { - { - (let continue : Bool in - (let choice : String in - { - out_string("Welcome to the Game of Life.\n"); - out_string("There are many initial states to choose from. \n"); - while prompt2() loop - { - continue <- true; - choice <- option(); - cells <- (new CellularAutomaton).init(choice); - cells.print(); - while continue loop - if prompt() then - { - cells.evolve(); - cells.print(); - } - else - continue <- false - fi - pool; - } - pool; - self; - } ) ); } - }; -}; - diff --git a/src/zTests/Misc/10BiG.cl b/src/zTests/Misc/10BiG.cl deleted file mode 100644 index 098e965fe..000000000 --- a/src/zTests/Misc/10BiG.cl +++ /dev/null @@ -1,426 +0,0 @@ - -class VarList inherits IO { - isNil() : Bool { true }; - head() : Variable { { abort(); new Variable; } }; - tail() : VarList { { abort(); new VarList; } }; - add(x : Variable) : VarList { (new VarListNE).init(x, self) }; - print() : SELF_TYPE { out_string("\n") }; -}; - -class VarListNE inherits VarList { - x : Variable; - rest : VarList; - isNil() : Bool { false }; - head() : Variable { x }; - tail() : VarList { rest }; - init(y : Variable, r : VarList) : VarListNE { { x <- y; rest <- r; self; } }; - print() : SELF_TYPE { { x.print_self(); out_string(" "); - rest.print(); self; } }; -}; - -class LambdaList { - isNil() : Bool { true }; - headE() : VarList { { abort(); new VarList; } }; - headC() : Lambda { { abort(); new Lambda; } }; - headN() : Int { { abort(); 0; } }; - tail() : LambdaList { { abort(); new LambdaList; } }; - add(e : VarList, x : Lambda, n : Int) : LambdaList { - (new LambdaListNE).init(e, x, n, self) - }; -}; - -class LambdaListNE inherits LambdaList { - lam : Lambda; - num : Int; - env : VarList; - rest : LambdaList; - isNil() : Bool { false }; - headE() : VarList { env }; - headC() : Lambda { lam }; - headN() : Int { num }; - tail() : LambdaList { rest }; - init(e : VarList, l : Lambda, n : Int, r : LambdaList) : LambdaListNE { - { - env <- e; - lam <- l; - num <- n; - rest <- r; - self; - } - }; -}; - -class LambdaListRef { - nextNum : Int <- 0; - l : LambdaList; - isNil() : Bool { l.isNil() }; - headE() : VarList { l.headE() }; - headC() : Lambda { l.headC() }; - headN() : Int { l.headN() }; - reset() : SELF_TYPE { - { - nextNum <- 0; - l <- new LambdaList; - self; - } - }; - add(env : VarList, c : Lambda) : Int { - { - l <- l.add(env, c, nextNum); - nextNum <- nextNum + 1; - nextNum - 1; - } - }; - removeHead() : SELF_TYPE { - { - l <- l.tail(); - self; - } - }; -}; - - -class Expr inherits IO { - - print_self() : SELF_TYPE { - { - out_string("\nError: Expr is pure virtual; can't print self\n"); - abort(); - self; - } - }; - - beta() : Expr { - { - out_string("\nError: Expr is pure virtual; can't beta-reduce\n"); - abort(); - self; - } - }; - - substitute(x : Variable, e : Expr) : Expr { - { - out_string("\nError: Expr is pure virtual; can't substitute\n"); - abort(); - self; - } - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("\nError: Expr is pure virtual; can't gen_code\n"); - abort(); - self; - } - }; -}; - -class Variable inherits Expr { - name : String; - - init(n:String) : Variable { - { - name <- n; - self; - } - }; - - print_self() : SELF_TYPE { - out_string(name) - }; - - beta() : Expr { self }; - - substitute(x : Variable, e : Expr) : Expr { - if x = self then e else self fi - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - let cur_env : VarList <- env in - { while (if cur_env.isNil() then - false - else - not (cur_env.head() = self) - fi) loop - { out_string("get_parent()."); - cur_env <- cur_env.tail(); - } - pool; - if cur_env.isNil() then - { out_string("Error: free occurrence of "); - print_self(); - out_string("\n"); - abort(); - self; - } - else - out_string("get_x()") - fi; - } - }; -}; - -class Lambda inherits Expr { - arg : Variable; - body : Expr; - - init(a:Variable, b:Expr) : Lambda { - { - arg <- a; - body <- b; - self; - } - }; - - print_self() : SELF_TYPE { - { - out_string("\\"); - arg.print_self(); - out_string("."); - body.print_self(); - self; - } - }; - - beta() : Expr { self }; - - apply(actual : Expr) : Expr { - body.substitute(arg, actual) - }; - - substitute(x : Variable, e : Expr) : Expr { - if x = arg then - self - else - let new_body : Expr <- body.substitute(x, e), - new_lam : Lambda <- new Lambda in - new_lam.init(arg, new_body) - fi - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("((new Closure"); - out_int(closures.add(env, self)); - out_string(").init("); - if env.isNil() then - out_string("new Closure))") - else - out_string("self))") fi; - self; - } - }; - - gen_closure_code(n : Int, env : VarList, - closures : LambdaListRef) : SELF_TYPE { - { - out_string("class Closure"); - out_int(n); - out_string(" inherits Closure {\n"); - out_string(" apply(y : EvalObject) : EvalObject {\n"); - out_string(" { out_string(\"Applying closure "); - out_int(n); - out_string("\\n\");\n"); - out_string(" x <- y;\n"); - body.gen_code(env.add(arg), closures); - out_string(";}};\n"); - out_string("};\n"); - } - }; -}; - - -class App inherits Expr { - fun : Expr; - arg : Expr; - - init(f : Expr, a : Expr) : App { - { - fun <- f; - arg <- a; - self; - } - }; - - print_self() : SELF_TYPE { - { - out_string("(("); - fun.print_self(); - out_string(")@("); - arg.print_self(); - out_string("))"); - self; - } - }; - - beta() : Expr { - case fun of - l : Lambda => l.apply(arg); -- Lazy evaluation - e : Expr => - let new_fun : Expr <- fun.beta(), - new_app : App <- new App in - new_app.init(new_fun, arg); - esac - }; - - substitute(x : Variable, e : Expr) : Expr { - let new_fun : Expr <- fun.substitute(x, e), - new_arg : Expr <- arg.substitute(x, e), - new_app : App <- new App in - new_app.init(new_fun, new_arg) - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("(let x : EvalObject <- "); - fun.gen_code(env, closures); - out_string(",\n"); - out_string(" y : EvalObject <- "); - arg.gen_code(env, closures); - out_string(" in\n"); - out_string(" case x of\n"); - out_string(" c : Closure => c.apply(y);\n"); - out_string(" o : Object => { abort(); new EvalObject; };\n"); - out_string(" esac)"); - } - }; -}; - - - -class Term inherits IO { - - var(x : String) : Variable { - let v : Variable <- new Variable in - v.init(x) - }; - - lam(x : Variable, e : Expr) : Lambda { - let l : Lambda <- new Lambda in - l.init(x, e) - }; - - app(e1 : Expr, e2 : Expr) : App { - let a : App <- new App in - a.init(e1, e2) - }; - - (* - * Some useful terms - *) - i() : Expr { - let x : Variable <- var("x") in - lam(x,x) - }; - - k() : Expr { - let x : Variable <- var("x"), - y : Variable <- var("y") in - lam(x,lam(y,x)) - }; - - s() : Expr { - let x : Variable <- var("x"), - y : Variable <- var("y"), - z : Variable <- var("z") in - lam(x,lam(y,lam(z,app(app(x,z),app(y,z))))) - }; - -}; - - - -class Main inherits Term { - beta_reduce(e : Expr) : Expr { - { - out_string("beta-reduce: "); - e.print_self(); - let done : Bool <- false, - new_expr : Expr in - { - while (not done) loop - { - new_expr <- e.beta(); - if (new_expr = e) then - done <- true - else - { - e <- new_expr; - out_string(" =>\n"); - e.print_self(); - } - fi; - } - pool; - out_string("\n"); - e; - }; - } - }; - - eval_class() : SELF_TYPE { - { - out_string("class EvalObject inherits IO {\n"); - out_string(" eval() : EvalObject { { abort(); self; } };\n"); - out_string("};\n"); - } - }; - - closure_class() : SELF_TYPE { - { - out_string("class Closure inherits EvalObject {\n"); - out_string(" parent : Closure;\n"); - out_string(" x : EvalObject;\n"); - out_string(" get_parent() : Closure { parent };\n"); - out_string(" get_x() : EvalObject { x };\n"); - out_string(" init(p : Closure) : Closure {{ parent <- p; self; }};\n"); - out_string(" apply(y : EvalObject) : EvalObject { { abort(); self; } };\n"); - out_string("};\n"); - } - }; - - gen_code(e : Expr) : SELF_TYPE { - let cl : LambdaListRef <- (new LambdaListRef).reset() in - { - out_string("Generating code for "); - e.print_self(); - out_string("\n------------------cut here------------------\n"); - out_string("(*Generated by lam.cl (Jeff Foster, March 2000)*)\n"); - eval_class(); - closure_class(); - out_string("class Main {\n"); - out_string(" main() : EvalObject {\n"); - e.gen_code(new VarList, cl); - out_string("\n};\n};\n"); - while (not (cl.isNil())) loop - let e : VarList <- cl.headE(), - c : Lambda <- cl.headC(), - n : Int <- cl.headN() in - { - cl.removeHead(); - c.gen_closure_code(n, e, cl); - } - pool; - out_string("\n------------------cut here------------------\n"); - } - }; - - main() : Int { - { - i().print_self(); - out_string("\n"); - k().print_self(); - out_string("\n"); - s().print_self(); - out_string("\n"); - beta_reduce(app(app(app(s(), k()), i()), i())); - beta_reduce(app(app(k(),i()),i())); - gen_code(app(i(), i())); - gen_code(app(app(app(s(), k()), i()), i())); - gen_code(app(app(app(app(app(app(app(app(i(), k()), s()), s()), - k()), s()), i()), k()), i())); - gen_code(app(app(i(), app(k(), s())), app(k(), app(s(), s())))); - 0; - } - }; -}; From f4cf51a130ce0d63db200cb29234906d5644965b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 26 Feb 2021 18:41:08 -0500 Subject: [PATCH 029/432] Added git ignoe --- .gitignore | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d568784ec..de0bc8a81 100644 --- a/.gitignore +++ b/.gitignore @@ -410,4 +410,19 @@ dmypy.json src/__pycache__ src/cool_example.cl -src/testing.py \ No newline at end of file +src/testing.py +src/devdeb.py +src/zTests/Misc/00HelloRodro.cl +src/zTests/Misc/01Simple.cl +src/zTests/Misc/02Simple.cl +src/zTests/Misc/03Simple.cl +src/zTests/Misc/04SallySilly.cl +src/zTests/Misc/05Ackerman.cl +src/zTests/Misc/06FooBarRaz.cl +src/zTests/Misc/07MultipleClass.cl +src/zTests/Misc/08Cellullar.cl +src/zTests/Misc/09GameOfLife.cl +src/zTests/Misc/10BiG.cl +.gitignore +./gitignore +.gitignore From 0f69226320ab582d85958cb0391dc5d65968044b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 27 Feb 2021 17:25:10 -0500 Subject: [PATCH 030/432] Added error detection to AutotypeCollector --- src/semantics/autotype_collector.py | 115 ++++++++++++++++++++-------- src/semantics/tools.py | 38 ++++++--- src/semantics/type_builder.py | 10 +-- src/semantics/type_collector.py | 4 +- 4 files changed, 117 insertions(+), 50 deletions(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index aa8d329f0..dfba23fb9 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -1,13 +1,13 @@ from semantics.tools import conforms, join, join_list, smart_add import semantics.visitor as visitor 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 +from parsing.ast import ArithmeticNode, AssignNode, AttrDeclarationNode, BlocksNode, BooleanNode, CaseNode, CaseOptionNode, ClassDeclarationNode, ComparerNode, ComplementNode, ConditionalNode, InstantiateNode, IntNode, IsVoidNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, Node, NotNode, ProgramNode, StringNode, VarDeclarationNode, VariableNode class AutotypeCollector: - def __init__(self, context:Context): + def __init__(self, context:Context, errors): self.context = context self.current_type = None - self.errors = [] + self.errors = errors @visitor.on('node') def visit(self, node, scope): @@ -57,11 +57,15 @@ def visit(self, node, scopex): self.visit(node.body, scope) ret_type_decl = current_method.return_type.swap_self_type(self.current_type) ret_type_expr = node.body.inferenced_type - conforms(ret_type_expr, ret_type_decl) + + ret_expr_clone = ret_type_expr.clone() + if not conforms(ret_expr_clone, ret_type_decl): + self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_type_expr.name} does not conforms to declared return type ({ret_type_decl.name}))") + node.body.inferenced_type = ret_type_expr node.inferenced_type = ret_type_decl.clone() - ret_type_decl.swap_types(SelfType(), self.current_type) + ret_type_decl.swap_self_type(self.current_type, back = True) @visitor.when(BlocksNode) def visit(self, node, scope): @@ -74,7 +78,10 @@ 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) + + condition_clone = condition_type.clone() + if not conforms(condition_clone, bool_type): + self.add_error(node, f"Type Error: If's condition type({condition_type.name} does not conforms to Bool type") self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type @@ -89,10 +96,14 @@ def visit(self, node, scope:Scope): self.visit(node.case_expr, scope) type_list = [] - for var in node.options: + types_visited = set() + for option in node.options: child = scope.create_child() - self.visit(var, child) - type_list.append(var.inferenced_type) + self.visit(option, child) + type_list.append(option.inferenced_type) + var_type = child.find_variable(option.id).type + if var_type in types_visited: + self.add_error(node, f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})") joined_type = join_list(type_list) node.inferenced_type = joined_type @@ -102,6 +113,7 @@ def visit(self, node, scope): try: node_type = self.context.get_type(node.type, selftype=False, autotype=False) except SemanticError as err: + self.add_error(node, err) node_type = ErrorType() scope.define_variable(node.id, node_type) @@ -113,7 +125,10 @@ 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) + + condition_clone = condition_type.clone() + if not conforms(condition_clone, bool_type): + self.add_error(node, f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.") self.visit(node.body, scope) node.inferenced_type = self.context.get_type("Object") @@ -137,13 +152,17 @@ def visit(self, node, scope): scope.define_variable(node.id, node_type) node.defined = True else: - #add error + self.add_error(node, f"Semantic Error: Variable \'{node.id}\' already defined in current scope.") node.defined = False if node.expr: self.visit(node.expr, scope) expr_type = node.expr.inferenced_type - conforms(expr_type, node_type) + expr_clone = expr_type.clone() + if not conforms(expr_clone, node_type): + self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({expr_type.name}) does not conforms to declared type({node_type.name}).") + else: + expr_type = expr_clone node.expr.inferenced_type = expr_type node.inferenced_type = node_type @@ -162,8 +181,13 @@ def visit(self, node, scope:Scope): node_expr = node.expr.inferenced_type if var and var.name != 'self': - conforms(node_expr, var_type) + if not conforms(node_expr, var_type): + self.add_error(node, "") var.type = var_type + elif var.name =='self': + self.add_error(node, "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.") + var_type = ErrorType() + node.inferenced_type = var_type @visitor.when(MethodCallNode) @@ -177,7 +201,11 @@ def visit(self, node, scope): self.visit(node.expr, scope) bridge = node.expr.inferenced_type caller = self.context.get_type(node.type, selftype=False, autotype=False) - conforms(bridge, caller) + + bridge_clone = bridge.clone() + if not conforms(bridge, caller): + self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") + caller = ErrorType() methods = None if len(caller.type_set) > 1: @@ -187,13 +215,13 @@ def visit(self, node, scope): if len(caller.type_set): methods = [(t, t.get_method) for t in caller.heads] else: - pass #Add Error + self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Types {caller.name}.") 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 + self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Type \'{caller.name}\'.") if methods: type_set = set() @@ -206,7 +234,9 @@ def visit(self, node, scope): arg, param_type = node.args[i], method.param_types[i] self.visit(arg, scope) arg_type = arg.inferenced_type - conforms(arg_type, param_type) + arg_clone = arg_type.clone() + conforms(arg_clone, param_type) + node.inferenced_type = TypeBag(type_set, heads) else: node.inferenced_type = ErrorType() @@ -215,13 +245,20 @@ def visit(self, node, scope): def visit(self, node, scope): self.visit(node.left, scope) left_type = node.left.inferenced_type + left_clone = left_type.clone() self.visit(node.right, scope) right_type = node.right.inferenced_type + right_clone = right_type.clone() int_type = self.context.get_type("Int") - conforms(left_type, int_type) - conforms(right_type, int_type) + if not conforms(left_type, int_type): + self.add_error(node, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") + int_type = ErrorType() + if not conforms(right_type, int_type): + self.add_error(node, f"Type Error: Arithmetic Error: Left member type({right_clone.name}) does not conforms to Int type.") + int_type = ErrorType() + node.inferenced_type = int_type @visitor.when(ComparerNode) @@ -232,9 +269,17 @@ def visit(self, node, scope): 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") + node_type = self.context.get_type("Bool") + left_clone = left_type.clone() + right_clone = right_type.clone() + if not conforms(left_clone, right_type) and not conforms(right_clone, left_type): + self.add_error(node, f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})") + node_type = ErrorType() + + #node.left.inferenced_type = left_clone + #node.right.inferenced_type = right_clone + + node.inferenced_type = node_type @visitor.when(VariableNode) def visit(self, node, scope): @@ -245,25 +290,32 @@ def visit(self, node, scope): else: node.defined = False var_type = ErrorType() + self.add_error(node, f"Semantic Error: Variable '{node.id}' is not defined.") 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) + expr_clone = expr_type.clone() + node_type = self.context.get_type("Bool") + if not conforms(expr_clone, node_type): + self.add_error(node, f"Type Error: Not's expresion type({expr_type.name} does not conforms to Bool type") + node_type = ErrorType() - node.inferenced_type = bool_type + node.inferenced_type = node_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 + node_type = self.context.get_type("Int") + + if not conforms(expr_type, node_type): + self.add_error(node, f"Type Error: Not's expresion type({expr_type.name} does not conforms to Int type") + node_type = ErrorType() + + node.inferenced_type = node_type @visitor.when(IsVoidNode) def visit(self, node, scope): @@ -290,8 +342,9 @@ def visit(self, node, scope): def visit(self, node, scope): node.inferenced_type = self.context.get_type("Bool") - - + def add_error(self, node:Node, text:str): + line, col = node.get_position() if node else 0, 0 + self.errors.append(f"({line}, {col}) - " + text) # todo: Revisar los auto types que me hace falta y que no # todo: completar de manera acorde el autotype collector # todo: Annadir error en VarDeclarationNode diff --git a/src/semantics/tools.py b/src/semantics/tools.py index d3732284e..0ae8909f1 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -118,6 +118,8 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ parent_method = None if parent_method: error_list = [] + return_type.swap_self_type(self) + parent_method.return_type.swap_self_type(self) if not conforms(return_type, parent_method.return_type): error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): @@ -132,6 +134,8 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ if err: s = f" -> Same param types:\n" + "\n".join(child for child in err) error_list.append(s) + return_type.swap_self_type(self, back = True) + parent_method.return_type.swap_self_type(self, back = True) if error_list: err = f"Redifined method \"{name}\" in class {self.name} does not have:\n" + "\n".join(child for child in error_list) raise SemanticError(err) @@ -252,20 +256,25 @@ def update_heads(self): new_heads += new_heads self.heads = new_heads - def swap_self_type(self, update_type): - try: - self.type_set.remove(SelfType()) - self.type_set.add(update_type) - except KeyError: - pass - return self - - def swap_types(self, update_type, remove_type): + def swap_self_type(self, swap_type, back = False): + if not back: + remove_type = SelfType() + add_type = swap_type + else: + remove_type = swap_type + add_type = SelfType() + try: self.type_set.remove(remove_type) - self.type_set.add(update_type) + self.type_set.add(add_type) except KeyError: - pass + return self + + for i in range(len(self.heads)): + typex = self.heads[i] + if typex.name == remove_type.name: + self.heads[i] = add_type + break return self def generate_name(self): @@ -294,6 +303,11 @@ def conforms_to(self, other): def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") + def __hash__(self) -> int: + return hash(self.name) + + def __eq__(self, o: object) -> bool: + return isinstance(o, SelfType) def __str__(self): return self.name @@ -311,7 +325,7 @@ def conforms_to(self, other): def bypass(self): return True - def swap_self_type(self, update_type): + def swap_self_type(self, swap_type): return self def set_conditions(self, *params): diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 6ce5523b3..54ee3939e 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,14 +1,14 @@ import semantics.visitor as visitor -from parsing.ast import ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode from semantics.tools import SemanticError, TypeBag from semantics.tools import ErrorType, SelfType from semantics.tools import Context class TypeBuilder: - def __init__(self, context: Context): + def __init__(self, context: Context, errors): self.context = context self.current_type = None - self.errors = [] + self.errors = errors @visitor.on('node') def visit(self, node): @@ -110,6 +110,6 @@ def build_default_classes(self): Io.define_method("in_string", [],[], p_String) Io.define_method("in_int", [], [], p_Int) - def add_error(self, node, text:str): + def add_error(self, node:Node, text:str): line, col = node.get_position() if node else 0, 0 - self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file + self.errors.append(f"({line}, {col}) - " + text) \ No newline at end of file diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 8f18be753..91b5ce25a 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -98,6 +98,6 @@ def init_default_classes(self): self.context.create_type('IO') self.context.create_type('Bool') - def add_error(self, node, text:str): + def add_error(self, node:Node, text:str): line, col = node.get_position() if node else 0, 0 - self.errors.append(f"Line: {line} Col: {col} " + text) \ No newline at end of file + self.errors.append(f"({line}, {col}) - " + text) \ No newline at end of file From 56625758d1f6ed61505234d3542ad332f8289615 Mon Sep 17 00:00:00 2001 From: adrian Date: Sat, 27 Feb 2021 18:30:58 -0500 Subject: [PATCH 031/432] Fix bug in expression--> variable production --- src/lexing/lexing_rules.py | 4 ++-- src/parsing/parsing_rules.py | 11 +++++++---- src/semantics/type_builder.py | 2 +- tests/parser_test.py | 2 +- tests/semantic_test.py | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index 2cd749b1f..9da043226 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -117,7 +117,7 @@ def t_aux_rcomment(t): r'\*\)' t.lexer.level -= 1 if t.lexer.level == 0: - t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos+1] + t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos] t.type = "COMMENT" t.lexer.lineno += t.value.count('\n') t.lexer.begin('INITIAL') @@ -131,7 +131,7 @@ def t_aux_pass(t): # Rule so we can track line numbers -def t_ANY_newline(t): +def t_newline(t): r'\n+' t.lexer.lineno += len(t.value) t.lexer.col = 1 diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index a7c4bdb8f..81ba3a31f 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -6,7 +6,7 @@ InstantiateNode, IntNode, IsVoidNode, LessNode, LessOrEqualNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, MinusNode, NotNode, PlusNode, ProgramNode, StarNode, - StringNode, VarDeclarationNode) + StringNode, VarDeclarationNode, VariableNode) def p_program(p): @@ -30,6 +30,9 @@ def p_class(p): p[0] = ClassDeclarationNode(p[2], p[6], p[4]) elif len(p) == 6: p[0] = ClassDeclarationNode(p[2], p[4]) + + p[0].set_position(p.slice[1].lineno, p.slice[1].col) + def p_feature_list(p): @@ -238,7 +241,7 @@ def p_expression_string(p): def p_expression_variable(p): """expression : ID""" - p[0] = InstantiateNode(p[1]) + p[0] = VariableNode(p[1]) def p_expression_true(p): @@ -261,8 +264,8 @@ def p_empty(p): p[0] = [] -def p_error(p): - print(f"Syntax error in input! {p} ")#line:{p.lineno} col:{p.col}") +def p_error(t): + print(f"Syntax error in input! {t} ")#line:{p.lineno} col:{p.col}") diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 6ce5523b3..810ab1da3 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -11,7 +11,7 @@ def __init__(self, context: Context): self.errors = [] @visitor.on('node') - def visit(self, node): + def visit(self, node): pass @visitor.when(ProgramNode) diff --git a/tests/parser_test.py b/tests/parser_test.py index 129c0f20a..d34c23bcf 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -1,6 +1,6 @@ import pytest import os -from utils import compare_errors +from .utils import compare_errors tests_dir = __file__.rpartition('/')[0] + '/parser/' tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] diff --git a/tests/semantic_test.py b/tests/semantic_test.py index cac9cd78b..62be0be16 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -1,6 +1,6 @@ import pytest import os -from utils import compare_errors, first_error_only_line +from .utils import compare_errors, first_error_only_line tests_dir = __file__.rpartition('/')[0] + '/semantic/' tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] From 930c9e74bc14f4114d4158e35174a75964a4a5ae Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 27 Feb 2021 20:42:43 -0500 Subject: [PATCH 032/432] Fixed bugs and improved error detection in AutotypeCollectors -The list containig errors, their elements are now a tuple of ((line:int, col:int), error:str). -Added error detection while analizing Instantiate Node in AutotypeCollector. -Other small bug fixes. --- src/semantics/autotype_collector.py | 42 +++++++++++++---------------- src/semantics/tools.py | 30 +++++++++++++-------- src/semantics/type_builder.py | 4 +-- src/semantics/type_collector.py | 4 +-- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index dfba23fb9..e6181f032 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -54,13 +54,13 @@ def visit(self, node, scopex): 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 = current_method.return_type.swap_self_type(self.current_type) + self.visit(node.body, scope) ret_type_expr = node.body.inferenced_type ret_expr_clone = ret_type_expr.clone() if not conforms(ret_expr_clone, ret_type_decl): - self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_type_expr.name} does not conforms to declared return type ({ret_type_decl.name}))") + self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_type_expr.name}) does not conforms to declared return type ({ret_type_decl.name})") node.body.inferenced_type = ret_type_expr @@ -81,7 +81,7 @@ def visit(self, node, scope): condition_clone = condition_type.clone() if not conforms(condition_clone, bool_type): - self.add_error(node, f"Type Error: If's condition type({condition_type.name} does not conforms to Bool type") + self.add_error(node, f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.") self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type @@ -138,7 +138,7 @@ def visit(self, node, scope): child = scope.create_child() for var in node.var_decl_list: self.visit(var, child) - self.visit(node.in_expr, scope) + self.visit(node.in_expr, child) node.inferenced_type = node.in_expr.inferenced_type @visitor.when(VarDeclarationNode) @@ -229,13 +229,13 @@ def visit(self, node, scope): 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 - arg_clone = arg_type.clone() - conforms(arg_clone, param_type) + type_set = 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 + # arg_clone = arg_type.clone() + # conforms(arg_clone, param_type) node.inferenced_type = TypeBag(type_set, heads) else: @@ -256,7 +256,7 @@ def visit(self, node, scope): self.add_error(node, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") int_type = ErrorType() if not conforms(right_type, int_type): - self.add_error(node, f"Type Error: Arithmetic Error: Left member type({right_clone.name}) does not conforms to Int type.") + self.add_error(node, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") int_type = ErrorType() node.inferenced_type = int_type @@ -276,13 +276,10 @@ def visit(self, node, scope): self.add_error(node, f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})") node_type = ErrorType() - #node.left.inferenced_type = left_clone - #node.right.inferenced_type = right_clone - node.inferenced_type = node_type @visitor.when(VariableNode) - def visit(self, node, scope): + def visit(self, node, scope:Scope): var = scope.find_variable(node.value) if var: node.defined = True @@ -290,7 +287,7 @@ def visit(self, node, scope): else: node.defined = False var_type = ErrorType() - self.add_error(node, f"Semantic Error: Variable '{node.id}' is not defined.") + self.add_error(node, f"Semantic Error: Variable '{node.value}' is not defined.") node.inferenced_type = var_type @visitor.when(NotNode) @@ -327,6 +324,7 @@ def visit(self, node, scope): try: node_type = self.context.get_type(node.value, selftype=False, autotype=False) except SemanticError as err: + self.add_error(f"Semantic Error: Could not instantiate type '{node.value}'.") node_type = ErrorType() node.inferenced_type = node_type @@ -343,11 +341,7 @@ def visit(self, node, scope): node.inferenced_type = self.context.get_type("Bool") def add_error(self, node:Node, text:str): - line, col = node.get_position() if node else 0, 0 - self.errors.append(f"({line}, {col}) - " + text) -# todo: Revisar los auto types que me hace falta y que no -# 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 + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line,col), f"({line}, {col}) - " + text)) + # todo: Cambiar self.error a que cada error tengo la tupla de localizacion, asi permite organizar los errores diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 0ae8909f1..47dcb82b9 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -111,7 +111,7 @@ def get_method(self, name:str, local:bool = False, first = None): def define_method(self, name:str, param_names:list, param_types:list, return_type): if name in (method.name for method in self.methods): raise SemanticError(f'Method \'{name}\' already defined in \'{self.name}\'') - + try: parent_method = self.get_method(name) except SemanticError: @@ -119,17 +119,19 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ if parent_method: error_list = [] return_type.swap_self_type(self) + return_clone = return_type.clone() parent_method.return_type.swap_self_type(self) if not conforms(return_type, parent_method.return_type): - error_list.append(f" -> Same return type: Redefined method has \'{return_type.name}\' as return type instead of \'{parent_method.return_type.name}\'.") + error_list.append(f" -> Same return type: Redefined method has \'{return_clone.name}\' as return type instead of \'{parent_method.return_type.name}\'.") if len(param_types) != len(parent_method.param_types): error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") else: count = 0 err = [] for param_type, parent_param_type in zip(param_types, parent_method.param_types): + param_clone = param_type.clone() if not conforms(param_type, parent_param_type): - err.append(f" -Param number {count} has {param_type.name} as type instead of {parent_param_type.name}") + err.append(f" -Param number {count} has {param_clone.name} as type instead of {parent_param_type.name}") count += 1 if err: s = f" -> Same param types:\n" + "\n".join(child for child in err) @@ -137,11 +139,12 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ return_type.swap_self_type(self, back = True) parent_method.return_type.swap_self_type(self, back = True) if error_list: - err = f"Redifined method \"{name}\" in class {self.name} does not have:\n" + "\n".join(child for child in error_list) + err = f"Redifined method \'{name}\' in class \'{self.name}\' does not have:\n" + "\n".join(child for child in error_list) raise SemanticError(err) - + method = Method(name, param_names, param_types, return_type) self.methods.append(method) + return method def all_attributes(self, clean=True, first=None): @@ -275,6 +278,8 @@ def swap_self_type(self, swap_type, back = False): if typex.name == remove_type.name: self.heads[i] = add_type break + + self.name = self.generate_name() return self def generate_name(self): @@ -287,9 +292,9 @@ def generate_name(self): return s def clone(self): - clone = TypeBag(self.type_set, self.heads) - clone.condition_list = self.condition_list - clone.conform_list = self.conform_list + clone = TypeBag(self.type_set.copy(), self.heads.copy()) + clone.condition_list = self.condition_list.copy() + clone.conform_list = self.conform_list.copy() return clone class SelfType(Type): @@ -330,6 +335,9 @@ def swap_self_type(self, swap_type): def set_conditions(self, *params): return + + def clone(self): + return self class Context: def __init__(self) -> None: @@ -416,7 +424,7 @@ def find_variable(self, vname, index=None): return next(x for x in locals if x.name == vname) except StopIteration: try: - return self.parent.find_variable(vname, self.index) if self.parent else None + return self.parent.find_variable(vname, self.index) if self.parent is not None else None except AttributeError: return None @@ -516,7 +524,7 @@ def smart_add(type_set:set, head_list:list, typex:Type): break if not there_is: head_list.append(typex) - return head_list, type_set + return type_set def auto_add(type_set:set, head_list:list, bag:TypeBag): type_set = type_set.union(bag.type_set) @@ -530,5 +538,5 @@ def auto_add(type_set:set, head_list:list, bag:TypeBag): aux.pop(head) break head_list += [typex for typex in aux] - return head_list, type_set + return type_set diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 3e2c7b8b8..4fd74f215 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -111,5 +111,5 @@ def build_default_classes(self): Io.define_method("in_int", [], [], p_Int) def add_error(self, node:Node, text:str): - line, col = node.get_position() if node else 0, 0 - self.errors.append(f"({line}, {col}) - " + text) \ No newline at end of file + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 91b5ce25a..4a1104564 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -99,5 +99,5 @@ def init_default_classes(self): self.context.create_type('Bool') def add_error(self, node:Node, text:str): - line, col = node.get_position() if node else 0, 0 - self.errors.append(f"({line}, {col}) - " + text) \ No newline at end of file + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file From d98b7b35f7b759bdcc20844377f12dcfeb85e0c0 Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 28 Feb 2021 00:09:55 -0500 Subject: [PATCH 033/432] Commit before merge --- src/semantics/autotype_collector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index dfba23fb9..343912c1f 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -343,7 +343,7 @@ def visit(self, node, scope): node.inferenced_type = self.context.get_type("Bool") def add_error(self, node:Node, text:str): - line, col = node.get_position() if node else 0, 0 + line, col = node.get_position() if node else (0, 0) self.errors.append(f"({line}, {col}) - " + text) # todo: Revisar los auto types que me hace falta y que no # todo: completar de manera acorde el autotype collector From 14d95054be53da49207e1d0d5f4ec68d5795056e Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 28 Feb 2021 02:00:20 -0500 Subject: [PATCH 034/432] Add line and col for each AST-node --- src/lexing/lexing_rules.py | 15 +++++---- src/lexing/utils.py | 1 + src/parsing/parsing_rules.py | 61 ++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index 9da043226..b1d11b087 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -1,6 +1,3 @@ -# Lexer rules -######################################################################################### - from lexing.utils import LexicographicError, set_pos literals = [ @@ -139,7 +136,10 @@ def t_newline(t): def t_WHITESPACE(t): r'\s' - t.lexer.col += len(t.value) + if t.value == '\t': + t.lexer.col += 4 + else: + t.lexer.col += len(t.value) def t_plus(t): @@ -264,8 +264,11 @@ def t_dollar(t): def t_ANY_error(t): - # print("Illegal character '%s'" % t.value[0]) set_pos(t) t.lexer.errors.append(LexicographicError(t.lineno, t.col, t.value[0])) t.lexer.skip(1) -######################################################################################### + + +# TODO: Add separate tokens for class (types) names and identifiers +# TODO: Fix bug related to (line, col)-setting when program contains comments +# TODO: Handle errors inside comments (unbalanced multiline comments delimeters) diff --git a/src/lexing/utils.py b/src/lexing/utils.py index b6db182e3..7ef56284f 100644 --- a/src/lexing/utils.py +++ b/src/lexing/utils.py @@ -14,4 +14,5 @@ def __repr__(self) -> str: def set_pos(token): token.col = token.lexer.col + token.line = token.lexer.lineno token.lexer.col += len(token.value) \ No newline at end of file diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 81ba3a31f..a4f3796c6 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -31,7 +31,7 @@ def p_class(p): elif len(p) == 6: p[0] = ClassDeclarationNode(p[2], p[4]) - p[0].set_position(p.slice[1].lineno, p.slice[1].col) + p[0].set_position(p.slice[1].line, p.slice[1].col) @@ -53,10 +53,13 @@ def p_attribute(p): else: p[0] = AttrDeclarationNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_method(p): """method : ID '(' params_list ')' ':' ID '{' expression '}'""" p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) + p[0].set_position(p.slice[1].line, p.slice[1].col) def p_params_list(p): @@ -75,6 +78,8 @@ def p_params_list_empty(p): def p_param(p): """param : ID ':' ID""" p[0] = VarDeclarationNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_list(p): @@ -89,26 +94,36 @@ def p_expression_list(p): def p_expression_assigment(p): """expression : ID ASSIGN expression""" p[0] = AssignNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_if_then_else(p): """expression : IF expression THEN expression ELSE expression FI""" p[0] = ConditionalNode(p[2], p[4], p[6]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_while(p): """expression : WHILE expression LOOP expression POOL""" p[0] = LoopNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_block(p): """expression : '{' expression_list '}'""" p[0] = BlocksNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_let_in(p): """expression : LET let_list IN expression""" p[0] = LetNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_let_list(p): @@ -127,11 +142,15 @@ def p_let_single(p): p[0] = VarDeclarationNode(p[1], p[3], p[5]) else: p[0] = VarDeclarationNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_case(p): """expression : CASE expression OF case_list ESAC""" p[0] = CaseNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_case_list(p): @@ -145,7 +164,9 @@ def p_case_list(p): def p_case_single(p): """case_single : ID ':' ID RET expression ';'""" - p[0] = CaseOptionNode(p[1],p[3],p[5]) + p[0] = CaseOptionNode(p[1],p[3],p[5]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + @@ -155,10 +176,16 @@ def p_expression_dispatch(p): | ID '(' args_list ')'""" if len(p) == 9: p[0] = MethodCallNode(p[1],p[3],p[5],p[7]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + elif len(p) == 7: p[0] = MethodCallNode(p[1], None, p[3], p[5]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + else: p[0]= MethodCallNode(None, None, p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_args_list(p): @@ -177,86 +204,114 @@ def p_args_list_empty(p): def p_expression_instatiate(p): """expression : NEW ID""" p[0] = InstantiateNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_isvoid(p): """expression : ISVOID expression""" p[0] = IsVoidNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) def p_expression_not(p): """expression : NOT expression""" p[0] = NotNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_complement(p): """expression : '~' expression""" p[0] = ComplementNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_plus(p): """expression : expression '+' expression""" p[0] = PlusNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + def p_expression_minus(p): """expression : expression '-' expression""" p[0] = MinusNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + def p_expression_div(p): """expression : expression '/' expression""" p[0] = DivNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_star(p): """expression : expression '*' expression""" p[0] = StarNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_less(p): """expression : expression '<' expression""" p[0] = LessNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_lesseq(p): """expression : expression LESSEQ expression""" p[0] = LessOrEqualNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_equals(p): """expression : expression '=' expression""" p[0] = EqualsNode(p[1],p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_parentheses(p): """expression : '(' expression ')'""" p[0] = p[2] + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_string(p): """expression : STRING""" p[0] = StringNode(p[1]) + p[0].set_position(p.slice[1].lineno, p.slice[1].col) + def p_expression_variable(p): """expression : ID""" p[0] = VariableNode(p[1]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_true(p): """expression : TRUE""" p[0] = BooleanNode(True) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_false(p): """expression : FALSE""" p[0] = BooleanNode(False) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_int(p): """expression : INT""" p[0] = IntNode(p[1]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_empty(p): @@ -265,7 +320,7 @@ def p_empty(p): def p_error(t): - print(f"Syntax error in input! {t} ")#line:{p.lineno} col:{p.col}") + print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") From 62b1426d6cf513b8aedc103e7c07d33f3b349edc Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 28 Feb 2021 02:12:10 -0500 Subject: [PATCH 035/432] Fix bug related to (line, col)-setting when the program contains comments --- src/lexing/lexing_rules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index b1d11b087..eb774fe39 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -117,6 +117,7 @@ def t_aux_rcomment(t): t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos] t.type = "COMMENT" t.lexer.lineno += t.value.count('\n') + t.lexer.col = len(t.value) - t.value.rfind('\n') t.lexer.begin('INITIAL') # return t @@ -270,5 +271,5 @@ def t_ANY_error(t): # TODO: Add separate tokens for class (types) names and identifiers -# TODO: Fix bug related to (line, col)-setting when program contains comments +# TODO: Fix bug related to (line, col)-setting when the program contains comments # TODO: Handle errors inside comments (unbalanced multiline comments delimeters) From db0fb341b3e547f818c0b6af49ecb550320e2e80 Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 28 Feb 2021 03:01:06 -0500 Subject: [PATCH 036/432] Add separate tokens for class (types) names and identifiers --- src/lexing/lexing_rules.py | 17 ++++-- src/parsing/parsetab.py | 108 +++++++++++++++++------------------ src/parsing/parsing_rules.py | 22 +++---- 3 files changed, 76 insertions(+), 71 deletions(-) diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index eb774fe39..9448ad586 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -32,6 +32,7 @@ 'ASSIGN', 'RET', 'ID', + 'TYPE', 'STRING', 'INT', 'COMMENT', @@ -60,14 +61,19 @@ def t_RET(t): set_pos(t) return t - -def t_ID(t): - r'[a-zA-Z_][a-zA-Z_0-9]*' +def t_TYPE(t): + r'[A-Z][a-zA-Z_0-9]*' set_pos(t) lower_case = t.value.lower() - if lower_case in ('true', 'false') and t.value[0].isupper(): - t.type = 'ID' + if lower_case in ('true', 'false'): + t.type = 'TYPE' return t + t.type = reserved.get(lower_case, 'TYPE') + return t + +def t_ID(t): + r'[a-z_][a-zA-Z_0-9]*' + set_pos(t) t.type = reserved.get(t.value.lower(), 'ID') return t @@ -271,5 +277,4 @@ def t_ANY_error(t): # TODO: Add separate tokens for class (types) names and identifiers -# TODO: Fix bug related to (line, col)-setting when the program contains comments # TODO: Handle errors inside comments (unbalanced multiline comments delimeters) diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index a1d8b3310..31ccd530d 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,9 +6,9 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS ID INHERITS ID '{' feature_list '}'\n | CLASS ID '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' ID ASSIGN expression\n | ID ':' ID method : ID '(' params_list ')' ':' ID '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' IDexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' ID ASSIGN expression\n | ID ':' IDexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' ID RET expression ';'expression : expression '@' ID '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW IDexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPE method : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " -_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,13,14,19,23,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,20,21,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'ID':([4,8,9,16,17,18,20,21,31,32,34,37,38,39,40,41,42,43,44,45,46,52,54,55,56,57,58,59,60,61,62,63,64,92,93,95,96,97,98,99,101,103,104,105,113,119,121,124,126,133,136,],[6,10,11,11,23,24,11,11,35,51,24,35,35,35,71,35,35,74,35,35,35,78,35,35,83,84,35,35,35,35,35,35,35,35,35,35,35,71,111,114,35,35,117,35,114,35,35,130,35,35,-30,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'}':([9,12,15,16,20,21,22,28,29,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,19,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([11,24,33,71,114,],[17,32,52,98,124,]),'(':([11,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[18,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([18,25,26,27,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([23,35,111,],[31,54,121,]),',':([26,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} _lr_action = {} for _k, _v in _lr_action_items.items(): @@ -17,7 +17,7 @@ _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,20,21,],[12,22,28,29,]),'attribute':([9,16,20,21,],[13,13,13,13,]),'method':([9,16,20,21,],[14,14,14,14,]),'empty':([9,16,18,20,21,34,55,103,105,126,],[15,15,27,15,15,27,82,82,82,82,]),'params_list':([18,34,],[25,53,]),'param':([18,34,],[26,26,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,68,109,115,81,81,128,129,81,135,]),'expression_list':([39,95,],[67,108,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,18,19,],[11,22,23,24,]),'attribute':([9,16,18,19,],[12,12,12,12,]),'method':([9,16,18,19,],[13,13,13,13,]),'empty':([9,16,18,19,21,34,55,103,105,126,],[14,14,14,14,29,29,82,82,82,82,]),'params_list':([21,34,],[27,53,]),'param':([21,34,],[28,28,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,68,109,115,81,81,128,129,81,135,]),'expression_list':([39,95,],[67,108,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} _lr_goto = {} for _k, _v in _lr_goto_items.items(): @@ -30,55 +30,55 @@ ('program -> class_list','program',1,'p_program','parsing_rules.py',13), ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',18), ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',19), - ('class -> CLASS ID INHERITS ID { feature_list }','class',7,'p_class','parsing_rules.py',27), - ('class -> CLASS ID { feature_list }','class',5,'p_class','parsing_rules.py',28), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',36), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',37), - ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',38), - ('attribute -> ID : ID ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',46), - ('attribute -> ID : ID','attribute',3,'p_attribute','parsing_rules.py',47), - ('method -> ID ( params_list ) : ID { expression }','method',9,'p_method','parsing_rules.py',55), - ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',60), - ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',61), - ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',68), - ('param -> ID : ID','param',3,'p_param','parsing_rules.py',73), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',78), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',79), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',87), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',92), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',97), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',102), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',107), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',112), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',113), - ('let_single -> ID : ID ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',121), - ('let_single -> ID : ID','let_single',3,'p_let_single','parsing_rules.py',122), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',130), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',135), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',136), - ('case_single -> ID : ID RET expression ;','case_single',6,'p_case_single','parsing_rules.py',144), - ('expression -> expression @ ID . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',150), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',151), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',152), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',162), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',163), - ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',171), - ('expression -> NEW ID','expression',2,'p_expression_instatiate','parsing_rules.py',175), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',180), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',185), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',190), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',195), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',200), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',205), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',210), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',215), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',220), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',225), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',230), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',235), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',240), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',245), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',250), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',255), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',260), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',27), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',28), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',39), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',40), + ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',41), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',49), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',50), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',60), + ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',66), + ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',67), + ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',74), + ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',79), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',86), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',87), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',95), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',102), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',109), + ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',116), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',123), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',130), + ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',131), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',139), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',140), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',150), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',157), + ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',158), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',166), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',174), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',175), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',176), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',192), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',193), + ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',201), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',205), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',212), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',218), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',225), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',232), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',239), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',246), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',252), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',258), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',264), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',270), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',276), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',283), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',290), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',297), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',304), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',311), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',318), ] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index a4f3796c6..600519b9b 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -24,8 +24,8 @@ def p_class_list(p): def p_class(p): - """class : CLASS ID INHERITS ID '{' feature_list '}' - | CLASS ID '{' feature_list '}'""" + """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' + | CLASS TYPE '{' feature_list '}'""" if len(p) == 8: p[0] = ClassDeclarationNode(p[2], p[6], p[4]) elif len(p) == 6: @@ -46,8 +46,8 @@ def p_feature_list(p): def p_attribute(p): - """attribute : ID ':' ID ASSIGN expression - | ID ':' ID """ + """attribute : ID ':' TYPE ASSIGN expression + | ID ':' TYPE """ if len(p) == 6: p[0] = AttrDeclarationNode(p[1], p[3], p[5]) else: @@ -57,7 +57,7 @@ def p_attribute(p): def p_method(p): - """method : ID '(' params_list ')' ':' ID '{' expression '}'""" + """method : ID '(' params_list ')' ':' TYPE '{' expression '}'""" p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) p[0].set_position(p.slice[1].line, p.slice[1].col) @@ -76,7 +76,7 @@ def p_params_list_empty(p): def p_param(p): - """param : ID ':' ID""" + """param : ID ':' TYPE""" p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) @@ -136,8 +136,8 @@ def p_let_list(p): def p_let_single(p): - """let_single : ID ':' ID ASSIGN expression - | ID ':' ID""" + """let_single : ID ':' TYPE ASSIGN expression + | ID ':' TYPE""" if len(p) == 6: p[0] = VarDeclarationNode(p[1], p[3], p[5]) else: @@ -163,7 +163,7 @@ def p_case_list(p): def p_case_single(p): - """case_single : ID ':' ID RET expression ';'""" + """case_single : ID ':' TYPE RET expression ';'""" p[0] = CaseOptionNode(p[1],p[3],p[5]) p[0].set_position(p.slice[1].line, p.slice[1].col) @@ -171,7 +171,7 @@ def p_case_single(p): def p_expression_dispatch(p): - """expression : expression '@' ID '.' ID '(' args_list ')' + """expression : expression '@' TYPE '.' ID '(' args_list ')' | expression '.' ID '(' args_list ')' | ID '(' args_list ')'""" if len(p) == 9: @@ -202,7 +202,7 @@ def p_args_list_empty(p): p[0] = [] def p_expression_instatiate(p): - """expression : NEW ID""" + """expression : NEW TYPE""" p[0] = InstantiateNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) From 0403f3ee13c69b853a7034de6472dd35b1e93363 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 28 Feb 2021 11:36:21 -0500 Subject: [PATCH 037/432] Removed checking type first letter is uppercase --- src/semantics/tools.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 47dcb82b9..55eb61124 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -348,8 +348,6 @@ def __init__(self) -> None: def create_type(self, name:str) -> Type: if name in self.types: raise SemanticError(f'Type with the same name ({name}) already exists.') - if name[0] != name[0].upper(): - raise SemanticError(f'Type name ({name}) must start with upper case') typex = self.types[name] = Type(name) return typex From 59aa0824958053e09a8e9a0a55ac0ba87b0f89c4 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 28 Feb 2021 19:08:50 -0500 Subject: [PATCH 038/432] Minor changes in AutotypeCollector --- .gitignore | 3 ++ src/semantics/autotype_collector.py | 74 +++++++++++++++-------------- src/semantics/tools.py | 7 ++- 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index de0bc8a81..f3c16e09f 100644 --- a/.gitignore +++ b/.gitignore @@ -426,3 +426,6 @@ src/zTests/Misc/10BiG.cl .gitignore ./gitignore .gitignore +src/type_logger.py +src/zTests/Auto/00Simple.cl +src/zTests/Auto/01Assign.cl diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index e6181f032..f7ae41ce6 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -40,7 +40,10 @@ def visit(self, node, scope): self.visit(node.expr, scope) node_expr = node.expr.inferenced_type - conforms(node_expr, node_type) + expr_clone = node_expr.clone() + if not conforms(node_expr, node_type): + self.add_error(node, f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({expr_clone.name}) does not conforms to declared type ({node_type.name}).") + # What is made error type here!!! var = scope.find_variable(node.id) var.type = node_type @@ -59,12 +62,11 @@ def visit(self, node, scopex): ret_type_expr = node.body.inferenced_type ret_expr_clone = ret_type_expr.clone() - if not conforms(ret_expr_clone, ret_type_decl): - self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_type_expr.name}) does not conforms to declared return type ({ret_type_decl.name})") + if not conforms(ret_type_expr, ret_type_decl): + self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})") + ret_type_expr = ErrorType() - node.body.inferenced_type = ret_type_expr - - node.inferenced_type = ret_type_decl.clone() + node.inferenced_type = ret_type_expr ret_type_decl.swap_self_type(self.current_type, back = True) @visitor.when(BlocksNode) @@ -154,16 +156,14 @@ def visit(self, node, scope): else: self.add_error(node, f"Semantic Error: Variable \'{node.id}\' already defined in current scope.") node.defined = False + node_type = ErrorType() if node.expr: self.visit(node.expr, scope) expr_type = node.expr.inferenced_type expr_clone = expr_type.clone() - if not conforms(expr_clone, node_type): - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({expr_type.name}) does not conforms to declared type({node_type.name}).") - else: - expr_type = expr_clone - node.expr.inferenced_type = expr_type + if not conforms(expr_type, node_type): + self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).") node.inferenced_type = node_type @@ -179,16 +179,19 @@ def visit(self, node, scope:Scope): self.visit(node.expr, scope) node_expr = node.expr.inferenced_type + node_type = var_type if var and var.name != 'self': + node_expr_clone = node.expr.inferenced_type.clone() if not conforms(node_expr, var_type): - self.add_error(node, "") + self.add_error(node, f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).") + node_type = ErrorType() var.type = var_type elif var.name =='self': self.add_error(node, "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.") - var_type = ErrorType() + node_type = ErrorType() - node.inferenced_type = var_type + node.inferenced_type = node_type @visitor.when(MethodCallNode) def visit(self, node, scope): @@ -207,22 +210,26 @@ def visit(self, node, scope): self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") caller = ErrorType() + + 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))) + conforms(caller, TypeBag(set(types), types)) if len(caller.type_set): methods = [(t, t.get_method) for t in caller.heads] else: self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Types {caller.name}.") + caller = ErrorType() elif len(caller.type_set) == 1: caller_type = caller.heads[0] try: methods = [(caller_type, caller_type.get_method(node.id))] except SemanticError: self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Type \'{caller.name}\'.") - + caller = ErrorType() + if methods: type_set = set() heads = [] @@ -230,16 +237,16 @@ def visit(self, node, scope): ret_type = method.return_type.clone() ret_type.swap_self_type(typex) type_set = 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) + for i in range(len(node.args)): + arg = node.args[i] + self.visit(arg, scope) # arg_type = arg.inferenced_type # arg_clone = arg_type.clone() # conforms(arg_clone, param_type) - node.inferenced_type = TypeBag(type_set, heads) else: node.inferenced_type = ErrorType() + node.inferenced_caller = caller @visitor.when(ArithmeticNode) def visit(self, node, scope): @@ -253,11 +260,9 @@ def visit(self, node, scope): int_type = self.context.get_type("Int") if not conforms(left_type, int_type): - self.add_error(node, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") - int_type = ErrorType() + self.add_error(node.left, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") if not conforms(right_type, int_type): - self.add_error(node, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") - int_type = ErrorType() + self.add_error(node.right, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") node.inferenced_type = int_type @@ -269,14 +274,13 @@ def visit(self, node, scope): self.visit(node.right, scope) right_type = node.right.inferenced_type - node_type = self.context.get_type("Bool") + bool_type = self.context.get_type("Bool") left_clone = left_type.clone() right_clone = right_type.clone() if not conforms(left_clone, right_type) and not conforms(right_clone, left_type): self.add_error(node, f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})") - node_type = ErrorType() - node.inferenced_type = node_type + node.inferenced_type = bool_type @visitor.when(VariableNode) def visit(self, node, scope:Scope): @@ -295,21 +299,21 @@ def visit(self, node, scope): self.visit(node.expr, scope) expr_type = node.expr.inferenced_type expr_clone = expr_type.clone() - node_type = self.context.get_type("Bool") - if not conforms(expr_clone, node_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_type.name} does not conforms to Bool type") - node_type = ErrorType() + bool_type = self.context.get_type("Bool") + if not conforms(expr_type, bool_type): + self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type") - node.inferenced_type = node_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 + expr_clone = expr_type.clone() node_type = self.context.get_type("Int") if not conforms(expr_type, node_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_type.name} does not conforms to Int type") + self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type") node_type = ErrorType() node.inferenced_type = node_type @@ -342,6 +346,4 @@ def visit(self, node, scope): def add_error(self, node:Node, text:str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) - -# todo: Cambiar self.error a que cada error tengo la tupla de localizacion, asi permite organizar los errores + self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 55eb61124..e664c6a22 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -74,7 +74,7 @@ def define_attribute(self, name:str, typex): self.attributes.append(attribute) return attribute else: - raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') + raise SemanticError(f'Attribute "{name}" is already defined in "{self.name}".') def get_attribute(self, name:str, first=None): if not first: @@ -506,6 +506,11 @@ def join_list(type_list): join_result = join(join_result, type_i) return join_result +def equal(bag1:TypeBag, bag2:TypeBag): + set1 = bag1.type_set + set2 = bag2.type_set + return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) + def smart_add(type_set:set, head_list:list, typex:Type): if isinstance(typex, TypeBag): return auto_add(type_set, head_list, typex) From 718f962a647dc62be8562c946cf76fad419c08c5 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 28 Feb 2021 19:09:34 -0500 Subject: [PATCH 039/432] Added AutotypeInferencer --- src/semantics/autotype_inferencer.py | 315 ++++++++++++++++++++++++++- 1 file changed, 310 insertions(+), 5 deletions(-) diff --git a/src/semantics/autotype_inferencer.py b/src/semantics/autotype_inferencer.py index e1d01e676..7f04dbdcd 100644 --- a/src/semantics/autotype_inferencer.py +++ b/src/semantics/autotype_inferencer.py @@ -1,12 +1,17 @@ +from parsing.parsing_rules import p_param import semantics.visitor as visitor -from parsing.ast import AttrDeclarationNode, ClassDeclarationNode, ProgramNode -from semantics.tools import Context, Scope +from parsing.ast import ArithmeticNode, AssignNode, AttrDeclarationNode, BlocksNode, CaseNode, CaseOptionNode, ClassDeclarationNode, ComparerNode, ComplementNode, ConditionalNode, EqualsNode, IsVoidNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, Node, NotNode, ProgramNode, VarDeclarationNode, VariableNode +from semantics.tools import Context, ErrorType, Scope, TypeBag, conforms, equal, join, join_list, smart_add class AutotypeInferencer: - def __init__(self, context:Context) -> None: + def __init__(self, context:Context, errors) -> None: self.context = context self.current_type = None - self.errors = [] + self.errors = errors + + @visitor.on('node') + def visit(self, node, scope): + pass @visitor.when(ProgramNode) def visit(self, node:ProgramNode, scope:Scope): @@ -23,6 +28,306 @@ def visit(self, node, scope): @visitor.when(AttrDeclarationNode) def visit(self, node, scope): + if not node.expr: + return + + node_infered = node.inferenced_type + expr_infered = node.expr.inferenced_type.clone() + + self.visit(node.expr, scope) + new_expr_infered = node.expr.inferenced_type + + if equal(expr_infered, new_expr_infered): + return + + new_clone_inferred = new_expr_infered.clone() + if not conforms(new_expr_infered, node_infered): + self.add_error(node, f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({new_clone_inferred.name}) does not conforms to declared type ({node_infered.name}).") + # What is made error type here!!! + + @visitor.when(MethodDeclarationNode) + def visit(self, node, scopex:Scope): + scope = scopex.next_child() + + ret_type_infered = node.body.inferenced_type.clone() + self.visit(node.body, scope) + new_type_infered = node.body.inferenced_type + + if equal(ret_type_infered, new_type_infered): + return + + current_method = self.current_type.get_method(node.id) + ret_type_decl = current_method.return_type.swap_self_type(self.current_type) + new_clone_infered = new_type_infered.clone() + + if not conforms(new_type_infered, ret_type_decl): + self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({new_clone_infered.name}) does not conforms to declared return type ({ret_type_decl.name})") + ret_type_expr = ErrorType() + + node.inferenced_type = ret_type_expr + ret_type_decl.swap_self_type(self.current_type, back = True) + + @visitor.when(BlocksNode) + def visit(self, node, scope): + for expr in node.expr_list: + self.visit(expr, scope) + node.inferenced_type = node.expr_list[-1].inferenced_type + + @visitor.when(ConditionalNode) + def visit(self, node, scope): + condition_infered = node.condition.inferenced_type.clone() + then_infered = node.then_body.inferenced_type.clone() + else_infered = node.else_body.inferenced_type.clone() + + self.visit(node.condition, scope) + self.visit(node.then_body, scope) + self.visit(node.else_body, scope) + + new_condition_infered = node.condition.inferenced_type + new_then_infered = node.then_body.inferenced_type + new_else_infered = node.else_body.inferenced_type + + if not equal(condition_infered, new_condition_infered): + self.add_error(node, f"Type Error: If's condition type({new_condition_infered.name}) does not conforms to Bool type.") + if equal(then_infered, new_then_infered) and equal(else_infered, new_else_infered): + return + + joined_type = join(new_then_infered, new_else_infered) + node.inferenced_type = joined_type + + @visitor.when(CaseNode) + def visit(self, node, scope:Scope): + self.visit(node.case_expr, scope) + + type_list = [] + change = False + for option in node.options: + child = scope.next_child() + option_infered = option.inferenced_type.clone() + self.visit(option, child) + new_option_infered = option.inferenced_type + type_list.append(new_option_infered) + change = change or not equal(option_infered, new_option_infered) + + if change: + joined_type = join_list(type_list) + node.inferenced_type = joined_type + + @visitor.when(CaseOptionNode) + def visit(self, node, scope:Scope): + self.visit(node.expr, scope) + + @visitor.when(LoopNode) + def visit(self, node, scope): + condition_infered = node.condition.inferenced_type.clone() + self.visit(node.condition, scope) + new_cond_infered = node.condition.inferenced_type + + if not equal(condition_infered, new_cond_infered): + self.add_error(node, f"Type Error: Loop's condition type({new_cond_infered.name}) does not conforms to Bool type.") + + self.visit(node.body, scope) + + @visitor.when(LetNode) + def visit(self, node, scope): + child = scope.next_child() + for var in node.var_decl_list: + self.visit(var, child) + self.visit(node.in_expr, child) + node.inferenced_type = node.in_expr.inferenced_type + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope:Scope): + if not node.expr: + return + + expr_infered = node.expr.inferenced_type.clone() + self.visit(node.expr, scope) + new_expr_inferred = node.expr.inferenced_type + + if equal(expr_infered, new_expr_inferred): + return + + node_infered = node.inferenced_type + new_clone_infered = new_expr_inferred.clone() + if not conforms(new_expr_inferred, node_infered): + self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({new_clone_infered.name}) does not conforms to declared type({node_infered.name}).") + + @visitor.when(AssignNode) + def visit(self, node, scope:Scope): + if not node.defined and node.id != "self": + return + + expr_infered = node.expr.inferenced_type.clone() self.visit(node.expr, scope) - node_expr = node.expr.inferenced_type \ No newline at end of file + new_expr_infered = node.expr.inferenced_type + + if equal(expr_infered, new_expr_infered): + return + + var_type = scope.find_variable(node.id).type + new_clone_infered = new_expr_infered.clone() + if not conforms(new_expr_infered, var_type): + self.add_error(node, f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({new_clone_infered.name}) does not conforms to declared type ({var_type.name}).") + var_type = ErrorType() + + node.inferenced_type = var_type + + @visitor.when(MethodCallNode) + def visit(self, node, scope): + caller = node.inferenced_caller + if node.type and node.expr: + bridge_infered = node.expr.inferenced_type.clone() + self.visit(node.expr, scope) + bridge = node.expr.inferenced_type + if not equal(bridge_infered, bridge): + bridge_clone = bridge.clone() + if not conforms(bridge, caller): + self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") + caller = ErrorType() + elif node.expr: + self.visit(node.expr, scope) + caller = node.expr.inferenced_type + + 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), types)) + if len(caller.heads) > 1: + error = f"Semantic Error: Method \"{node.id}\" found in {len(caller.heads)} unrelated types:\n" + error += " -Found in: " + error += ", ".join(typex.name for typex in caller.heads) + self.add_error(node, error) + caller = ErrorType() + elif len(caller.heads) == 0: + self.add_error(node, f"There is no method called {node.id} which takes {len(node.args)} paramters.") + caller = ErrorType() + + if len(caller.heads) == 1: + caller_type = caller.heads[0] + method = caller_type.get_method(node.id) + + if len(node.args) != len(method.param_types): + self.add_error(node, f"Semantic Error: Method '{node.id}' from class '{caller_type.name}' takes {len(node.args)} arguments but {method.param_types} were given.'") + node.inferenced_type = ErrorType() + + decl_return_type = method.return_type.clone() + decl_return_type.swap_self_type(caller_type) + + type_set = set() + heads = [] + type_set = smart_add(type_set, heads, decl_return_type) + for i in range(len(node.args)): + arg = node.args[i] + p_type = method.param_types[i] + arg_infered = arg.inferenced_type.clone() + self.visit(arg, scope) + new_arg_infered = arg.inferenced_type + new_clone_infered = new_arg_infered.clone() + if not conforms(new_arg_infered, p_type): + self.add_error(node.arg, f"Type Error: Argument expression type ({new_clone_infered.name}) does not conforms parameter declared type({p_type.name})") + node.inferenced_type = TypeBag(type_set, heads) + else: + node.inferenced_type = ErrorType() + node.inferenced_caller = caller + + @visitor.when(ArithmeticNode) + def visit(self, node, scope): + left_infered = node.left.inferenced_type#.clone() + right_infered = node.right.inferenced_type#.clone() + + self.visit(node.left, scope) + self.visit(node.right, scope) + + new_left = node.left.inferenced_type + new_right = node.right.inferenced_type + + int_type = self.context.get_type("Int") + if not equal(left_infered, new_left): + left_clone = new_left.clone() + if not conforms(left_infered, int_type): + self.add_error(node.left, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") + + if not equal(right_infered, new_right): + right_clone = new_left.clone() + if not conforms(right_infered, int_type): + self.add_error(node.right, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") + + @visitor.when(ComparerNode) + def visit(self, node, scope): + left_infered = node.left.inferenced_type#.clone() + right_infered = node.right.inferenced_type#.clone() + + self.visit(node.left, scope) + self.visit(node.right, scope) + + new_left = node.left.inferenced_type + new_right = node.right.inferenced_type + left_clone = new_left.clone() + right_clone = new_right.clone() + + if equal(left_infered, new_left) and equal(right_infered, new_right): + return + + if not conforms(left_clone, new_right) and not conforms(right_clone, new_left): + self.add_error(node, f"Type Error: Left expression type({new_left.name}) does not conforms to right expression type({new_right.name})") + + @visitor.when(VariableNode) + def visit(self, node, scope:Scope): + if node.defined: + node.inferenced_type = scope.find_variable(node.value).type + + @visitor.when(NotNode) + def visit(self, node, scope): + expr_infered = node.expr.inferenced_type#.clone() + self.visit(node.expr, scope) + new_expr = node.expr.inferenced_type + expr_clone = new_expr.clone() + bool_type = self.context.get_type("Bool") + if equal(expr_infered, new_expr): + return + if not conforms(new_expr, bool_type): + self.add_error(node.value, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type") + + @visitor.when(ComplementNode) + def visit(self, node, scope): + expr_infered = node.expr.inferenced_type#.clone() + self.visit(node.expr, scope) + new_expr = node.expr.inferenced_type + expr_clone = new_expr.clone() + int_type = self.context.get_type("Int") + if equal(expr_infered, new_expr): + return + if not conforms(new_expr, int_type): + self.add_error(node.value, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type") + + @visitor.when(IsVoidNode) + def visit(self, node, scope): + self.visit(node.expr, scope) + + def add_error(self, node:Node, text:str): + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line,col), f"({line}, {col}) - " + text)) + + #todo: los .clone detras de los old_infered_types puede eliminarse, me parece q no son necesarios + #todo: para no tener los .clone en todas las visitas en todos los casos posibles debe actualizarse el + #todo: .inferenced_type + + + #todo: Para pensar: + #todo: que hacer si expr_type no conforma con decl_type + #todo: Convierto expr en error_type si se me queda vacio, si es error ahora va a ser despues + #todo: ademas le pone ya una condicion al bolsa, en caso de que sea AUTO_TYPE + #todo: si lo mantengo igual que puedo ganar? + + #todo: Es necesario agregar una propiedad Autotype a los TypeBag que indiquen quien es quien? + + #todo: En el caso donde Auto1 se conforma de Auto2, y Auto1, nada mas puede ser Int o Object, y el + #todo: otro puede ser de todo, de que manera y cuando achicar Auto2. + #todo: Una manera puede ser cuando no se hayan hecho mas cambios sobre Auto1 y Auto2 + + #todo: AutoType checking for later: + #todo: Redefined methods with params and return type are autotypes + #todo: Check use of self types inside auto types, how does it affects, etc... + #todo: \ No newline at end of file From a2bed1bfaccd04f87270aa12324a6dad8a91903e Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Wed, 14 Apr 2021 17:50:52 -0400 Subject: [PATCH 040/432] Modify coolc.sh for tests --- src/coolc.sh | 4 +++- src/lexing/lexing_rules.py | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coolc.sh b/src/coolc.sh index 4fe55f7f4..34811cc42 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -8,4 +8,6 @@ echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar echo "Copyright (c) 2021: Adrian, Rodrigo" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +# echo "Compiling $INPUT_FILE into $OUTPUT_FILE" + +exec python3 __main__.py $INPUT_FILE \ No newline at end of file diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py index 9448ad586..00b301763 100644 --- a/src/lexing/lexing_rules.py +++ b/src/lexing/lexing_rules.py @@ -276,5 +276,4 @@ def t_ANY_error(t): t.lexer.skip(1) -# TODO: Add separate tokens for class (types) names and identifiers -# TODO: Handle errors inside comments (unbalanced multiline comments delimeters) +# TODO: Handle errors inside comments (unbalanced multiline comments delimeters) \ No newline at end of file From 5089d1e8d42f0d1d4a65bfe68590febdfac02ebc Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Wed, 14 Apr 2021 22:04:00 -0400 Subject: [PATCH 041/432] Added ast module The ast module has all the ast used by the compiler in every phase --- src/ast/__init__.py | 0 src/ast/builder_ast.py | 0 src/ast/checker_ast.py | 0 src/ast/collector_ast.py | 0 src/ast/inferencer_ast.py | 0 src/ast/parser_ast.py | 214 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 214 insertions(+) create mode 100644 src/ast/__init__.py create mode 100644 src/ast/builder_ast.py create mode 100644 src/ast/checker_ast.py create mode 100644 src/ast/collector_ast.py create mode 100644 src/ast/inferencer_ast.py create mode 100644 src/ast/parser_ast.py diff --git a/src/ast/__init__.py b/src/ast/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast/builder_ast.py b/src/ast/builder_ast.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast/checker_ast.py b/src/ast/checker_ast.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast/collector_ast.py b/src/ast/collector_ast.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast/parser_ast.py b/src/ast/parser_ast.py new file mode 100644 index 000000000..a17b358d7 --- /dev/null +++ b/src/ast/parser_ast.py @@ -0,0 +1,214 @@ +from typing import List, Tuple + + +class Node: + def __init__(self) -> None: + self.line = 0 + self.col = 0 + + def get_position(self) -> Tuple[int, int]: + return self.line, self.col + + def set_position(self, line: int, col: int) -> None: + self.line = line + self.col = col + + +class ProgramNode(Node): + def __init__(self, declarations): + Node.__init__(self) + self.declarations = declarations + + +class DeclarationNode(Node): + pass + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, idx, features, parent=None): + Node.__init__(self) + self.id = idx + self.parent = parent + self.features = features + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx, typex, expression=None): + Node.__init__(self) + self.id = idx + self.type = typex + self.expr = expression + + +class MethodDeclarationNode(DeclarationNode): + def __init__(self, idx, params, return_type, body): + Node.__init__(self) + self.id = idx + self.params: List[VarDeclarationNode] = params + self.type = return_type + self.body = body + + +class ExpressionNode(Node): + pass + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, idx, typex, expression=None): + Node.__init__(self) + self.id = idx + self.type = typex + self.expr = expression + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr): + Node.__init__(self) + self.id = idx + self.expr = expr + + +class MethodCallNode(ExpressionNode): + def __init__(self, expr=None, typex=None, idx=None, args=None): + Node.__init__(self) + self.expr = expr + self.type = typex + self.id = idx + self.args = args + + +class ConditionalNode(ExpressionNode): + def __init__( + self, + condition: ExpressionNode, + then_body: ExpressionNode, + else_body: ExpressionNode, + ): + Node.__init__(self) + self.condition = condition + self.then_body = then_body + self.else_body = else_body + + +class LoopNode(ExpressionNode): + def __init__(self, condition: ExpressionNode, body: ExpressionNode): + Node.__init__(self) + self.condition = condition + self.body = body + + +class LetNode(ExpressionNode): + def __init__( + self, var_decl_list: List[VarDeclarationNode], in_expr: ExpressionNode + ): + Node.__init__(self) + self.var_decl_list = var_decl_list + self.in_expr = in_expr + + +class CaseNode(ExpressionNode): + def __init__(self, case_expr, options): + Node.__init__(self) + self.case_expr = case_expr + self.options: List[CaseOptionNode] = options + + +class CaseOptionNode(ExpressionNode): + def __init__(self, idx, typex, ret_expr): + Node.__init__(self) + self.id = idx + self.type = typex + self.expr = ret_expr + + +class BlocksNode(ExpressionNode): + def __init__(self, expr_list): + Node.__init__(self) + self.expr_list = expr_list + + +class UnaryNode(ExpressionNode): + def __init__(self, expr): + Node.__init__(self) + self.expr = expr + + +class IsVoidNode(UnaryNode): + pass + + +class NotNode(UnaryNode): + pass + + +class ComplementNode(UnaryNode): + pass + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right): + Node.__init__(self) + self.left = left + self.right = right + + +class ComparerNode(BinaryNode): + pass + + +class LessNode(ComparerNode): + pass + + +class LessOrEqualNode(ComparerNode): + pass + + +class EqualsNode(ComparerNode): + pass + + +class ArithmeticNode(BinaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class AtomicNode(ExpressionNode): + def __init__(self, value): + Node.__init__(self) + self.value = value + + +class BooleanNode(AtomicNode): + pass + + +class IntNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + pass + + +class InstantiateNode(AtomicNode): + pass From 9bf0de1b1d5c170808ce367a0631e7647676f98f Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Wed, 14 Apr 2021 22:05:39 -0400 Subject: [PATCH 042/432] Updated parsing_rules.py to work with new ast module --- src/parsing/ast.py | 206 ----------------------------------- src/parsing/parsing_rules.py | 133 +++++++++++----------- 2 files changed, 66 insertions(+), 273 deletions(-) delete mode 100644 src/parsing/ast.py diff --git a/src/parsing/ast.py b/src/parsing/ast.py deleted file mode 100644 index 8f7b3dd01..000000000 --- a/src/parsing/ast.py +++ /dev/null @@ -1,206 +0,0 @@ -from typing import List, Tuple - - -class Node: - def __init__(self) -> None: - self.line = 0 - self.col = 0 - - def get_position(self) -> Tuple[int, int]: - return self.line, self.col - - def set_position(self, line: int, col: int) -> None: - self.line = line - self.col = col - - -class ProgramNode(Node): - def __init__(self, declarations): - Node.__init__(self) - self.declarations = declarations - - -class DeclarationNode(Node): - pass - -class ClassDeclarationNode(DeclarationNode): - def __init__(self, idx, features, parent=None): - Node.__init__(self) - self.id = idx - self.parent = parent - self.features = features - - -class AttrDeclarationNode(DeclarationNode): - def __init__(self, idx, typex, expression=None): - Node.__init__(self) - self.id = idx - self.type = typex - self.expr = expression - - -class MethodDeclarationNode(DeclarationNode): - def __init__(self, idx, params, return_type, body): - Node.__init__(self) - self.id = idx - self.params: List[VarDeclarationNode] = params - self.type = return_type - self.body = body - - -class ExpressionNode(Node): - pass - - -class VarDeclarationNode(ExpressionNode): - def __init__(self, idx, typex, expression=None): - Node.__init__(self) - self.id = idx - self.type = typex - self.expr = expression - - -class AssignNode(ExpressionNode): - def __init__(self, idx, expr): - Node.__init__(self) - self.id = idx - self.expr = expr - - -class MethodCallNode(ExpressionNode): - def __init__(self, expr=None, typex=None, idx=None, args=None): - Node.__init__(self) - self.expr = expr - self.type = typex - self.id = idx - self.args = args - - -class ConditionalNode(ExpressionNode): - def __init__(self, condition: ExpressionNode, then_body: ExpressionNode, else_body: ExpressionNode): - Node.__init__(self) - self.condition = condition - self.then_body = then_body - self.else_body = else_body - - -class LoopNode(ExpressionNode): - def __init__(self, condition: ExpressionNode, body: ExpressionNode): - Node.__init__(self) - self.condition = condition - self.body = body - - -class LetNode(ExpressionNode): - def __init__(self, var_decl_list: List[VarDeclarationNode], in_expr: ExpressionNode): - Node.__init__(self) - self.var_decl_list = var_decl_list - self.in_expr = in_expr - - -class CaseNode(ExpressionNode): - def __init__(self, case_expr, options): - Node.__init__(self) - self.case_expr = case_expr - self.options: List[CaseOptionNode] = options - - -class CaseOptionNode(ExpressionNode): - def __init__(self, idx, typex, ret_expr): - Node.__init__(self) - self.id = idx - self.type = typex - self.expr = ret_expr - - -class BlocksNode(ExpressionNode): - def __init__(self, expr_list): - Node.__init__(self) - self.expr_list = expr_list - - -class UnaryNode(ExpressionNode): - def __init__(self, expr): - Node.__init__(self) - self.expr = expr - - -class IsVoidNode(UnaryNode): - pass - - -class NotNode(UnaryNode): - pass - - -class ComplementNode(UnaryNode): - pass - - -class BinaryNode(ExpressionNode): - def __init__(self, left, right): - Node.__init__(self) - self.left = left - self.right = right - - -class ComparerNode(BinaryNode): - pass - - -class LessNode(ComparerNode): - pass - - -class LessOrEqualNode(ComparerNode): - pass - - -class EqualsNode(ComparerNode): - pass - - -class ArithmeticNode(BinaryNode): - pass - - -class PlusNode(ArithmeticNode): - pass - - -class MinusNode(ArithmeticNode): - pass - - -class StarNode(ArithmeticNode): - pass - - -class DivNode(ArithmeticNode): - pass - - -class AtomicNode(ExpressionNode): - def __init__(self, value): - Node.__init__(self) - self.value = value - - -class BooleanNode(AtomicNode): - pass - - -class IntNode(AtomicNode): - pass - - -class StringNode(AtomicNode): - pass - - -class VariableNode(AtomicNode): - pass - - -class InstantiateNode(AtomicNode): - pass diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 600519b9b..c10d0684c 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -1,12 +1,33 @@ -from lexing.lexing_rules import tokens - -from .ast import (AssignNode, AttrDeclarationNode, BlocksNode, BooleanNode, - CaseNode, CaseOptionNode, ClassDeclarationNode, - ComplementNode, ConditionalNode, DivNode, EqualsNode, - InstantiateNode, IntNode, IsVoidNode, LessNode, - LessOrEqualNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, - MinusNode, NotNode, PlusNode, ProgramNode, StarNode, - StringNode, VarDeclarationNode, VariableNode) +from ast.parser_ast import ( + AssignNode, + AttrDeclarationNode, + BlocksNode, + BooleanNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComplementNode, + ConditionalNode, + DivNode, + EqualsNode, + InstantiateNode, + IntNode, + IsVoidNode, + LessNode, + LessOrEqualNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + MinusNode, + NotNode, + PlusNode, + ProgramNode, + StarNode, + StringNode, + VarDeclarationNode, + VariableNode, +) def p_program(p): @@ -16,7 +37,7 @@ def p_program(p): def p_class_list(p): """class_list : class ';' class_list - | class ';'""" + | class ';'""" if len(p) == 4: p[0] = [p[1]] + p[3] elif len(p) == 3: @@ -25,20 +46,19 @@ def p_class_list(p): def p_class(p): """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' - | CLASS TYPE '{' feature_list '}'""" + | CLASS TYPE '{' feature_list '}'""" if len(p) == 8: p[0] = ClassDeclarationNode(p[2], p[6], p[4]) elif len(p) == 6: p[0] = ClassDeclarationNode(p[2], p[4]) - + p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_feature_list(p): """feature_list : attribute ';' feature_list - | method ';' feature_list - | empty""" + | method ';' feature_list + | empty""" if len(p) == 4: p[0] = [p[1]] + p[3] elif len(p) == 2: @@ -47,7 +67,7 @@ def p_feature_list(p): def p_attribute(p): """attribute : ID ':' TYPE ASSIGN expression - | ID ':' TYPE """ + | ID ':' TYPE""" if len(p) == 6: p[0] = AttrDeclarationNode(p[1], p[3], p[5]) else: @@ -64,12 +84,13 @@ def p_method(p): def p_params_list(p): """params_list : param ',' params_list - | param""" + | param""" if len(p) == 4: p[0] = [p[1]] + p[3] else: p[0] = [p[1]] + def p_params_list_empty(p): """params_list : empty""" p[0] = [] @@ -81,13 +102,12 @@ def p_param(p): p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_list(p): """expression_list : expression ';' expression_list - | expression ';' """ + | expression ';'""" if len(p) == 4: p[0] = [p[1]] + p[3] - elif len(p) == 3: + elif len(p) == 3: p[0] = [p[1]] @@ -97,38 +117,33 @@ def p_expression_assigment(p): p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_if_then_else(p): """expression : IF expression THEN expression ELSE expression FI""" p[0] = ConditionalNode(p[2], p[4], p[6]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_while(p): """expression : WHILE expression LOOP expression POOL""" p[0] = LoopNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_block(p): """expression : '{' expression_list '}'""" p[0] = BlocksNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_let_in(p): """expression : LET let_list IN expression""" p[0] = LetNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_let_list(p): """let_list : let_single ',' let_list - | let_single""" + | let_single""" if len(p) == 4: p[0] = [p[1]] + p[3] else: @@ -137,13 +152,12 @@ def p_let_list(p): def p_let_single(p): """let_single : ID ':' TYPE ASSIGN expression - | ID ':' TYPE""" + | ID ':' TYPE""" if len(p) == 6: p[0] = VarDeclarationNode(p[1], p[3], p[5]) else: p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_case(p): @@ -152,10 +166,9 @@ def p_expression_case(p): p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_case_list(p): """case_list : case_single case_list - | case_single""" + | case_single""" if len(p) == 3: p[0] = [p[1]] + p[2] else: @@ -164,18 +177,16 @@ def p_case_list(p): def p_case_single(p): """case_single : ID ':' TYPE RET expression ';'""" - p[0] = CaseOptionNode(p[1],p[3],p[5]) + p[0] = CaseOptionNode(p[1], p[3], p[5]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_dispatch(p): """expression : expression '@' TYPE '.' ID '(' args_list ')' - | expression '.' ID '(' args_list ')' - | ID '(' args_list ')'""" + | expression '.' ID '(' args_list ')' + | ID '(' args_list ')'""" if len(p) == 9: - p[0] = MethodCallNode(p[1],p[3],p[5],p[7]) + p[0] = MethodCallNode(p[1], p[3], p[5], p[7]) p[0].set_position(p.slice[2].line, p.slice[2].col) elif len(p) == 7: @@ -183,14 +194,13 @@ def p_expression_dispatch(p): p[0].set_position(p.slice[2].line, p.slice[2].col) else: - p[0]= MethodCallNode(None, None, p[1], p[3]) + p[0] = MethodCallNode(None, None, p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_args_list(p): """args_list : expression ',' args_list - | expression""" + | expression""" if len(p) == 4: p[0] = [p[1]] + p[3] else: @@ -201,13 +211,13 @@ def p_args_list_empty(p): """args_list : empty""" p[0] = [] + def p_expression_instatiate(p): """expression : NEW TYPE""" p[0] = InstantiateNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_isvoid(p): """expression : ISVOID expression""" p[0] = IsVoidNode(p[2]) @@ -220,55 +230,51 @@ def p_expression_not(p): p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_complement(p): """expression : '~' expression""" p[0] = ComplementNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_plus(p): """expression : expression '+' expression""" - p[0] = PlusNode(p[1],p[3]) + p[0] = PlusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - def p_expression_minus(p): """expression : expression '-' expression""" - p[0] = MinusNode(p[1],p[3]) + p[0] = MinusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - def p_expression_div(p): """expression : expression '/' expression""" - p[0] = DivNode(p[1],p[3]) + p[0] = DivNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_star(p): """expression : expression '*' expression""" - p[0] = StarNode(p[1],p[3]) + p[0] = StarNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_less(p): """expression : expression '<' expression""" - p[0] = LessNode(p[1],p[3]) + p[0] = LessNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_lesseq(p): """expression : expression LESSEQ expression""" - p[0] = LessOrEqualNode(p[1],p[3]) + p[0] = LessOrEqualNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) def p_expression_equals(p): """expression : expression '=' expression""" - p[0] = EqualsNode(p[1],p[3]) + p[0] = EqualsNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) @@ -278,42 +284,36 @@ def p_expression_parentheses(p): p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_string(p): """expression : STRING""" p[0] = StringNode(p[1]) p[0].set_position(p.slice[1].lineno, p.slice[1].col) - def p_expression_variable(p): """expression : ID""" p[0] = VariableNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_true(p): """expression : TRUE""" p[0] = BooleanNode(True) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_false(p): """expression : FALSE""" p[0] = BooleanNode(False) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_expression_int(p): """expression : INT""" p[0] = IntNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_empty(p): """empty : """ p[0] = [] @@ -323,15 +323,14 @@ def p_error(t): print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") - precedence = ( - ('right', 'ASSIGN'), - ('right', 'NOT'), - ('nonassoc', 'LESSEQ', '<', '='), - ('left', '+','-'), - ('left', '*', '/'), - ('right', 'ISVOID'), - ('left', '~'), - ('left', '@'), - ('left', '.') + ("right", "ASSIGN"), + ("right", "NOT"), + ("nonassoc", "LESSEQ", "<", "="), + ("left", "+", "-"), + ("left", "*", "/"), + ("right", "ISVOID"), + ("left", "~"), + ("left", "@"), + ("left", "."), ) From d65183695177bcf7340044d1d7698ca5f505307b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 09:12:33 -0400 Subject: [PATCH 043/432] Added TypeFunc class --- src/semantics/tools.py | 298 ++++++++++++++++++++++---------- src/semantics/type_builder.py | 45 +++-- src/semantics/type_collector.py | 51 +++--- 3 files changed, 259 insertions(+), 135 deletions(-) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index e664c6a22..d9a9070f7 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,40 +1,46 @@ import itertools as itt from collections import OrderedDict -from typing import FrozenSet +from typing import FrozenSet, List, Set from semantics.utils import conform_to_condition, from_dict_to_set, order_set_by_index + class InternalError(Exception): @property def text(self): return "Internal Error: " + self.args[0] + class SemanticError(Exception): @property def text(self): return "Semantic Error: " + self.args[0] + class TypeError(SemanticError): @property def text(self): return "Type Error: " + self.args[0] + class AttributeError(SemanticError): @property def text(self): return "Attribute Error: " + self.args[0] + class Attribute: def __init__(self, name, typex): self.name = name self.type = typex def __str__(self): - return f'[attrib] {self.name} : {self.type.name};' + return f"[attrib] {self.name} : {self.type.name};" def __repr__(self): return str(self) + class Method: def __init__(self, name, param_names, params_types, return_type): self.name = name @@ -43,16 +49,21 @@ def __init__(self, name, param_names, params_types, return_type): self.return_type = return_type def __str__(self): - params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) - return f'[method] {self.name}({params}): {self.return_type.name};' + params = ", ".join( + f"{n}:{t.name}" for n, t in zip(self.param_names, self.param_types) + ) + return f"[method] {self.name}({params}): {self.return_type.name};" def __eq__(self, other): - return other.name == self.name and \ - other.return_type == self.return_type and \ - other.param_types == self.param_types + return ( + other.name == self.name + and other.return_type == self.return_type + and other.param_types == self.param_types + ) + class Type: - def __init__(self, name:str): + def __init__(self, name: str): self.name = name self.attributes = [] self.methods = [] @@ -61,12 +72,16 @@ def __init__(self, name:str): def set_parent(self, parent): if self.parent is not None: - raise SemanticError(f'Type \'{self.name}\' already has parent type \'{self.parent.name}\'. Type \'{parent.name}\' cannot be set as parent.') + raise SemanticError( + f"Type '{self.name}' already has parent type '{self.parent.name}'. Type '{parent.name}' cannot be set as parent." + ) if parent.name in {"String", "Int", "Bool"}: - raise SemanticError(f'Cannot set \'{self.name}\' parent, \'{parent.name}\' type cannot be inherited.') + raise SemanticError( + f"Cannot set '{self.name}' parent, '{parent.name}' type cannot be inherited." + ) self.parent = parent - def define_attribute(self, name:str, typex): + def define_attribute(self, name: str, typex): try: self.get_attribute(name) except SemanticError: @@ -74,9 +89,11 @@ def define_attribute(self, name:str, typex): self.attributes.append(attribute) return attribute else: - raise SemanticError(f'Attribute "{name}" is already defined in "{self.name}".') + raise SemanticError( + f'Attribute "{name}" is already defined in "{self.name}".' + ) - def get_attribute(self, name:str, first=None): + def get_attribute(self, name: str, first=None): if not first: first = self.name elif first == self.name: @@ -86,13 +103,17 @@ def get_attribute(self, name:str, first=None): return next(attr for attr in self.attributes if attr.name == name) except StopIteration: if self.parent is None: - raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + raise AttributeError( + f'Attribute "{name}" is not defined in {self.name}.' + ) try: return self.parent.get_attribute(name, first=first) except SemanticError: - raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') - - def get_method(self, name:str, local:bool = False, first = None): + raise AttributeError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + + def get_method(self, name: str, local: bool = False, first=None): if not first: first = self.name elif first == self.name: @@ -102,16 +123,22 @@ def get_method(self, name:str, local:bool = False, first = None): return next(method for method in self.methods if method.name == name) except StopIteration: if self.parent is None: - raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + raise SemanticError( + f'Method "{name}" is not defined in class {self.name}.' + ) try: - return self.parent.get_method(name, first = first) + return self.parent.get_method(name, first=first) except SemanticError: - raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + raise SemanticError( + f'Method "{name}" is not defined in class {self.name}.' + ) - def define_method(self, name:str, param_names:list, param_types:list, return_type): + def define_method( + self, name: str, param_names: list, param_types: list, return_type + ): if name in (method.name for method in self.methods): - raise SemanticError(f'Method \'{name}\' already defined in \'{self.name}\'') - + raise SemanticError(f"Method '{name}' already defined in '{self.name}'") + try: parent_method = self.get_method(name) except SemanticError: @@ -122,26 +149,39 @@ def define_method(self, name:str, param_names:list, param_types:list, return_typ return_clone = return_type.clone() parent_method.return_type.swap_self_type(self) if not conforms(return_type, parent_method.return_type): - error_list.append(f" -> Same return type: Redefined method has \'{return_clone.name}\' as return type instead of \'{parent_method.return_type.name}\'.") + error_list.append( + f" -> Same return type: Redefined method has '{return_clone.name}' as return type instead of '{parent_method.return_type.name}'." + ) if len(param_types) != len(parent_method.param_types): - error_list.append(f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}.") + error_list.append( + f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}." + ) else: count = 0 err = [] - for param_type, parent_param_type in zip(param_types, parent_method.param_types): + for param_type, parent_param_type in zip( + param_types, parent_method.param_types + ): param_clone = param_type.clone() if not conforms(param_type, parent_param_type): - err.append(f" -Param number {count} has {param_clone.name} as type instead of {parent_param_type.name}") + err.append( + f" -Param number {count} has {param_clone.name} as type instead of {parent_param_type.name}" + ) count += 1 if err: - s = f" -> Same param types:\n" + "\n".join(child for child in err) + s = f" -> Same param types:\n" + "\n".join( + child for child in err + ) error_list.append(s) - return_type.swap_self_type(self, back = True) - parent_method.return_type.swap_self_type(self, back = True) + return_type.swap_self_type(self, back=True) + parent_method.return_type.swap_self_type(self, back=True) if error_list: - err = f"Redifined method \'{name}\' in class \'{self.name}\' does not have:\n" + "\n".join(child for child in error_list) + err = ( + f"Redifined method '{name}' in class '{self.name}' does not have:\n" + + "\n".join(child for child in error_list) + ) raise SemanticError(err) - + method = Method(name, param_names, param_types, return_type) self.methods.append(method) @@ -153,7 +193,11 @@ def all_attributes(self, clean=True, first=None): elif first == self.name: return OrderedDict.values() if clean else OrderedDict() - plain = OrderedDict() if self.parent is None else self.parent.all_attributes(clean = False, first=first) + plain = ( + OrderedDict() + if self.parent is None + else self.parent.all_attributes(clean=False, first=first) + ) for attr in self.attributes: plain[attr.name] = (attr, self) return plain.values() if clean else plain @@ -164,7 +208,11 @@ def all_methods(self, clean=True, first=None): elif first == self.name: return OrderedDict.values() if clean else OrderedDict() - plain = OrderedDict() if self.parent is None else self.parent.all_methods(clean = False, first=first) + plain = ( + OrderedDict() + if self.parent is None + else self.parent.all_methods(clean=False, first=first) + ) for method in self.methods: plain[method.name] = (method, self) return plain.values() if clean else plain @@ -174,7 +222,12 @@ def conforms_to(self, other, first=None): first = self.name elif self.name == first: return False - return other.bypass() or self == other or self.parent and self.parent.conforms_to(other, first) + return ( + other.bypass() + or self == other + or self.parent + and self.parent.conforms_to(other, first) + ) def bypass(self): return False @@ -182,7 +235,7 @@ def bypass(self): def least_common_ancestor(self, other): this = self if isinstance(this, ErrorType) or isinstance(other, ErrorType): - return ErrorType() + return ErrorType() while this.index < other.index: other = other.parent @@ -196,34 +249,37 @@ def least_common_ancestor(self, other): if this == None: return None return this - + def __str__(self): - output = f'type {self.name}' - parent = '' if self.parent is None else f' : {self.parent.name}' + output = f"type {self.name}" + parent = "" if self.parent is None else f" : {self.parent.name}" output += parent - output += ' {' - output += '\n\t' if self.attributes or self.methods else '' - output += '\n\t'.join(str(x) for x in self.attributes) - output += '\n\t' if self.attributes else '' - output += '\n\t'.join(str(x) for x in self.methods) - output += '\n' if self.methods else '' - output += '}\n' + output += " {" + output += "\n\t" if self.attributes or self.methods else "" + output += "\n\t".join(str(x) for x in self.attributes) + output += "\n\t" if self.attributes else "" + output += "\n\t".join(str(x) for x in self.methods) + output += "\n" if self.methods else "" + output += "}\n" return output def __repr__(self): return str(self) + class TypeBag: - def __init__(self, type_set, heads = []) -> None: - self.type_set:set = type_set if isinstance(type_set, set) else from_dict_to_set(type_set) - self.heads:list = heads + def __init__(self, type_set, heads=[]) -> None: + self.type_set: set = ( + type_set if isinstance(type_set, set) else from_dict_to_set(type_set) + ) + self.heads: list = heads if len(self.type_set) == 1: self.heads = list(self.type_set) - + self.name = self.generate_name() self.condition_list = [] self.conform_list = [] - + def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list @@ -245,7 +301,7 @@ def update_heads(self): new_heads.append(head) continue new_heads = [] - lower_index = 2**32 + lower_index = 2 ** 32 for typex in self.type_set: if typex in visited: continue @@ -259,7 +315,7 @@ def update_heads(self): new_heads += new_heads self.heads = new_heads - def swap_self_type(self, swap_type, back = False): + def swap_self_type(self, swap_type, back=False): if not back: remove_type = SelfType() add_type = swap_type @@ -272,22 +328,24 @@ def swap_self_type(self, swap_type, back = False): self.type_set.add(add_type) except KeyError: return self - + for i in range(len(self.heads)): - typex = self.heads[i] - if typex.name == remove_type.name: - self.heads[i] = add_type - break - + typex = self.heads[i] + if typex.name == remove_type.name: + self.heads[i] = add_type + break + self.name = self.generate_name() return self - + def generate_name(self): if len(self.type_set) == 1: return self.heads[0].name s = "{" - s += ', '.join(typex.name for typex in sorted(self.type_set, key = lambda t: t.index)) + s += ", ".join( + typex.name for typex in sorted(self.type_set, key=lambda t: t.index) + ) s += "}" return s @@ -297,14 +355,15 @@ def clone(self): clone.conform_list = self.conform_list.copy() return clone + class SelfType(Type): def __init__(self): self.name = "SELF_TYPE" - self.index = 2**31 + self.index = 2 ** 31 + def conforms_to(self, other): - #if isinstance(other, SelfType): - # return True raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") + def bypass(self): raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") @@ -320,13 +379,32 @@ def __str__(self): def __repr__(self): return str(self) + +class FuncType(Type): + def __init__(self, name: str, params: List[Type], ret_type: Type) -> None: + self.name = name + self.params = params + self.ret_type = ret_type + + def conforms_to(self, other, first): + if not isinstance(other, FuncType): + raise InternalError( + ( + "A Function Type can only conform to other Function" + f"Type, not to {other.__class__.__name__}" + ) + ) + + class ErrorType(Type): def __init__(self): self.name = "" - self.index = 2**32 + self.index = 2 ** 32 self.type_set = frozenset() + def conforms_to(self, other): return True + def bypass(self): return True @@ -335,28 +413,31 @@ def swap_self_type(self, swap_type): def set_conditions(self, *params): return - + def clone(self): return self + class Context: def __init__(self) -> None: self.types = {} self.num_autotypes = 0 self.type_graph = None - - def create_type(self, name:str) -> Type: + + def create_type(self, name: str) -> Type: if name in self.types: - raise SemanticError(f'Type with the same name ({name}) already exists.') + raise SemanticError(f"Type with the same name ({name}) already exists.") typex = self.types[name] = Type(name) return typex - - def get_type(self, name:str, selftype=True, autotype=True, unpacked=False) -> Type: + + def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> Type: if selftype and name == "SELF_TYPE": - return TypeBag({SelfType()}) #SelfType() + return TypeBag({SelfType()}) # SelfType() if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 - return TypeBag(self.types, [self.types['Object']]) #AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + return TypeBag( + self.types, [self.types["Object"]] + ) # AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) try: if unpacked: return self.types[name] @@ -364,8 +445,8 @@ def get_type(self, name:str, selftype=True, autotype=True, unpacked=False) -> Ty except KeyError: raise TypeError(f'Type "{name}" is not defined.') - def get_method_by_name(self, name:str, args:int) -> list: - def dfs(root:str, results:list): + def get_method_by_name(self, name: str, args: int) -> list: + def dfs(root: str, results: list): try: for typex in self.type_tree[root]: for method in self.types[typex].methods: @@ -376,21 +457,27 @@ def dfs(root:str, results:list): dfs(typex, results) except KeyError: pass + results = [] dfs("Object", results) return results def __str__(self): - return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + return ( + "{\n\t" + + "\n\t".join(y for x in self.types.values() for y in str(x).split("\n")) + + "\n}" + ) def __repr__(self): return str(self) + class VariableInfo: def __init__(self, name, vtype): self.name = name self.type = vtype - + def __str__(self): return self.name + ":" + self.type @@ -422,7 +509,11 @@ def find_variable(self, vname, index=None): return next(x for x in locals if x.name == vname) except StopIteration: try: - return self.parent.find_variable(vname, self.index) if self.parent is not None else None + return ( + self.parent.find_variable(vname, self.index) + if self.parent is not None + else None + ) except AttributeError: return None @@ -431,26 +522,31 @@ def is_defined(self, vname): def is_local(self, vname): return any(True for x in self.locals if x.name == vname) - + def next_child(self): self.current_child += 1 return self.children[self.current_child] - + def reset(self): self.current_child = -1 for child in self.children: child.reset() - - def get_all_names(self, s:str = "", level:int = 0): + + def get_all_names(self, s: str = "", level: int = 0): if self.locals: - s += "\n ".join([x.name + ":" + str([typex.name for typex in x.type.type_set]) for x in self.locals]) + s += "\n ".join( + [ + x.name + ":" + str([typex.name for typex in x.type.type_set]) + for x in self.locals + ] + ) s += "\n\n" - for child in self.children: + for child in self.children: s = child.get_all_names(s, level + 1) return s -def conforms(bag1:TypeBag, bag2:TypeBag): +def conforms(bag1: TypeBag, bag2: TypeBag): ordered_set = order_set_by_index(bag2.type_set) condition_list = [] @@ -459,22 +555,29 @@ def conforms(bag1:TypeBag, bag2:TypeBag): conform = conform_to_condition(bag1.type_set, condition) for i in range(len(condition_list)): conform_i = conform_list[i] - if len(conform_i) == len(conform) and len(conform.intersection(conform_i)) == len(conform): + if len(conform_i) == len(conform) and len( + conform.intersection(conform_i) + ) == len(conform): condition_list[i].add(condition) break else: condition_list.append({condition}) conform_list.append(conform) - + bag1.set_conditions(condition_list, conform_list) return len(bag1.type_set) >= 1 -def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: + +def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: ancestor_set = set() head_list = [] - ordered_set1 = order_set_by_index(bag1.type_set) - ordered_set2 = order_set_by_index(bag2.type_set) - ordered_set1, ordered_set2 = (ordered_set1, ordered_set2) if len(ordered_set1) < len(ordered_set2) else (ordered_set2, ordered_set1) + ordered_set1: Set[Type] = order_set_by_index(bag1.type_set) + ordered_set2: Set[Type] = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = ( + (ordered_set1, ordered_set2) + if len(ordered_set1) < len(ordered_set2) + else (ordered_set2, ordered_set1) + ) for type1 in ordered_set1: same_branch = False previous_ancestor = None @@ -495,10 +598,11 @@ def join(bag1:TypeBag, bag2:TypeBag) -> TypeBag: same_branch = False smart_add(ancestor_set, head_list, common_ancestor) previous_ancestor = common_ancestor - + join_result = TypeBag(ancestor_set, head_list) return join_result + def join_list(type_list): join_result = type_list[0] for i in range(1, len(type_list)): @@ -506,12 +610,14 @@ def join_list(type_list): join_result = join(join_result, type_i) return join_result -def equal(bag1:TypeBag, bag2:TypeBag): + +def equal(bag1: TypeBag, bag2: TypeBag): set1 = bag1.type_set set2 = bag2.type_set return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) -def smart_add(type_set:set, head_list:list, typex:Type): + +def smart_add(type_set: set, head_list: list, typex: Type): if isinstance(typex, TypeBag): return auto_add(type_set, head_list, typex) @@ -529,7 +635,8 @@ def smart_add(type_set:set, head_list:list, typex:Type): head_list.append(typex) return type_set -def auto_add(type_set:set, head_list:list, bag:TypeBag): + +def auto_add(type_set: set, head_list: list, bag: TypeBag): type_set = type_set.union(bag.type_set) aux = set(bag.heads) for i in range(len(head_list)): @@ -542,4 +649,3 @@ def auto_add(type_set:set, head_list:list, bag:TypeBag): break head_list += [typex for typex in aux] return type_set - diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 4fd74f215..f347f07c0 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,17 +1,24 @@ import semantics.visitor as visitor -from parsing.ast import Node, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, AttrDeclarationNode +from ast.parser_ast import ( + Node, + ProgramNode, + ClassDeclarationNode, + MethodDeclarationNode, + AttrDeclarationNode, +) from semantics.tools import SemanticError, TypeBag from semantics.tools import ErrorType, SelfType from semantics.tools import Context + class TypeBuilder: def __init__(self, context: Context, errors): self.context = context self.current_type = None - self.errors = errors - - @visitor.on('node') - def visit(self, node): + self.errors: list = errors + + @visitor.on("node") + def visit(self, node): pass @visitor.when(ProgramNode) @@ -22,12 +29,12 @@ def visit(self, node): self.visit(class_def) try: - self.context.get_type('Main', unpacked=True).get_method('main', local=True) + self.context.get_type("Main", unpacked=True).get_method("main", local=True) except SemanticError as err: self.add_error(node, err.text) - + @visitor.when(ClassDeclarationNode) - def visit(self, node): + def visit(self, node: ClassDeclarationNode): self.current_type = self.context.get_type(node.id, unpacked=True) if node.parent: @@ -38,7 +45,7 @@ def visit(self, node): self.current_type.attributes.append(idx) except SemanticError as err: self.add_error(node, err.text) - + for feature in node.features: self.visit(feature) @@ -49,12 +56,12 @@ def visit(self, node): except SemanticError as err: self.add_error(node, err.text) attr_type = ErrorType() - + try: self.current_type.define_attribute(node.id, attr_type) except SemanticError as err: self.add_error(err.text) - + @visitor.when(MethodDeclarationNode) def visit(self, node): try: @@ -62,7 +69,7 @@ def visit(self, node): except SemanticError as err: self.add_error(err.text) ret_type = ErrorType() - + params_type = [] params_name = [] for var in node.params: @@ -74,7 +81,7 @@ def visit(self, node): params_type.append(ErrorType()) self.add_error(node, err.text) params_name.append(p_name) - + try: self.current_type.define_method(node.id, params_name, params_type, ret_type) except SemanticError as err: @@ -105,11 +112,11 @@ def build_default_classes(self): String.define_method("concat", ["s"], [p_String], p_String) String.define_method("substr", ["i", "l"], [p_Int, p_Int], p_String) - Io.define_method("out_string", ["x"],[p_String], p_Self) - Io.define_method("out_int", ["x"],[p_Int], p_Self) - Io.define_method("in_string", [],[], p_String) + Io.define_method("out_string", ["x"], [p_String], p_Self) + Io.define_method("out_int", ["x"], [p_Int], p_Self) + Io.define_method("in_string", [], [], p_String) Io.define_method("in_int", [], [], p_Int) - - def add_error(self, node:Node, text:str): + + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 4a1104564..e7d2a1a01 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,16 +1,23 @@ import semantics.visitor as visitor -from parsing.ast import Node, ProgramNode, ClassDeclarationNode +from ast.parser_ast import Node, ProgramNode, ClassDeclarationNode from semantics.tools import SemanticError from semantics.tools import Context + class TypeCollector(object): def __init__(self) -> None: self.context = Context() self.errors = [] - self.type_graph = {"Object":["IO", "String", "Int", "Bool"], "IO":[], "String":[], "Int":[], "Bool":[]} + self.type_graph = { + "Object": ["IO", "String", "Int", "Bool"], + "IO": [], + "String": [], + "Int": [], + "Bool": [], + } self.node_dict = dict() - @visitor.on('node') + @visitor.on("node") def visit(self, node): pass @@ -36,8 +43,10 @@ def visit(self, node): except KeyError: self.type_graph[node.id] = [] if node.parent: - if node.parent in {'String', 'Int, Bool'}: - raise SemanticError(f"Type \'{node.id}\' cannot inherit from \'{node.parent}\' beacuse is forbidden.") + if node.parent in {"String", "Int, Bool"}: + raise SemanticError( + f"Type '{node.id}' cannot inherit from '{node.parent}' beacuse is forbidden." + ) try: self.type_graph[node.parent].append(node.id) except KeyError: @@ -47,7 +56,7 @@ def visit(self, node): self.type_graph["Object"].append(node.id) except SemanticError as error: self.add_error(node, error.text) - + def get_type_hierarchy(self): visited = set(["Object"]) new_order = [] @@ -58,9 +67,11 @@ def get_type_hierarchy(self): if not node in visited: visited.add(node) path = [node] - circular_heritage_errors.append(self.check_circular_heritage(node, self.type_graph, path, visited)) + circular_heritage_errors.append( + self.check_circular_heritage(node, self.type_graph, path, visited) + ) new_order = new_order + [self.node_dict[node] for node in path] - + if circular_heritage_errors: print(circular_heritage_errors) error = "Semantic Error: Circular Heritage:\n" @@ -69,10 +80,10 @@ def get_type_hierarchy(self): return new_order - def dfs_type_graph(self, root, graph, visited:set, new_order, index): + def dfs_type_graph(self, root, graph, visited: set, new_order, index): if not root in graph: return - + for node in graph[root]: if node in visited: continue @@ -81,23 +92,23 @@ def dfs_type_graph(self, root, graph, visited:set, new_order, index): new_order.append(self.node_dict[node]) self.context.get_type(node, unpacked=True).index = index self.dfs_type_graph(node, graph, visited, new_order, index + 1) - + def check_circular_heritage(self, root, graph, path, visited): for node in graph[root]: if node in path: - return ' -> '.join(child for child in path + [path[0]]) + return " -> ".join(child for child in path + [path[0]]) visited.add(node) path.append(node) return self.check_circular_heritage(node, graph, path, visited) def init_default_classes(self): - self.context.create_type('Object').index = 0 - self.context.create_type('String') - self.context.create_type('Int') - self.context.create_type('IO') - self.context.create_type('Bool') - - def add_error(self, node:Node, text:str): + self.context.create_type("Object").index = 0 + self.context.create_type("String") + self.context.create_type("Int") + self.context.create_type("IO") + self.context.create_type("Bool") + + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) From 6de6fedab91d3aa9ea5202b1cd2a58707cbe5b0c Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 16:53:58 -0400 Subject: [PATCH 044/432] Added ast for inferencer Removed builder and collector ast because they were not necesary --- src/ast/builder_ast.py | 0 src/ast/collector_ast.py | 0 src/ast/inferencer_ast.py | 213 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) delete mode 100644 src/ast/builder_ast.py delete mode 100644 src/ast/collector_ast.py diff --git a/src/ast/builder_ast.py b/src/ast/builder_ast.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/ast/collector_ast.py b/src/ast/collector_ast.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index e69de29bb..6a18c36b4 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -0,0 +1,213 @@ +from typing import List, Tuple + + +class Node: + def __init__(self, node) -> None: + self.line = node.line + self.col = node.col + self.inferenced_type = None + + def get_position(self) -> Tuple[int, int]: + return self.line, self.col + + +class ProgramNode(Node): + def __init__(self, declarations, scope, node: Node): + Node.__init__(self, node) + self.declarations = declarations + self.scope = scope + + +class DeclarationNode(Node): + pass + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, features, node): + Node.__init__(self, node) + self.features = features + self.id = node.id + # For debbuging purposses + self.parent = node.parent + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, node): + Node.__init__(self, node) + self.id = node.id + self.expr = None # expression is set later if it exists + # for debbugin purposes + self.type = node.type + + +class MethodDeclarationNode(DeclarationNode): + def __init__(self, return_type, body, node): + Node.__init__(self, node) + self.id = node.id + self.type = return_type + self.body = body + # for debbugin purposes + self.params = node.params + + +class ExpressionNode(Node): + pass + + +class BlocksNode(ExpressionNode): + def __init__(self, expr_list, node): + Node.__init__(self, node) + self.expr_list = expr_list + + +class ConditionalNode(ExpressionNode): + def __init__(self, condition, then_node, else_node, node): + Node.__init__(self, node) + self.condition = condition + self.then_body = then_node + self.else_body = else_node + + +class CaseNode(ExpressionNode): + def __init__(self, case_expr, options, node): + Node.__init__(self, node) + self.case_expr = case_expr + self.options: List[CaseOptionNode] = options + + +class CaseOptionNode(ExpressionNode): + def __init__(self, ret_expr, node): + Node.__init__(self, node) + self.id = node.id + self.expr = ret_expr + # For debbuging purposes + self.type = node.type + + +class LoopNode(ExpressionNode): + def __init__(self, condition, body, node): + Node.__init__(self, node) + self.condition = condition + self.body = body + + +class LetNode(ExpressionNode): + def __init__(self, var_decl_list, in_expr, node): + Node.__init__(self, node) + self.var_decl_list = var_decl_list + self.in_expr = in_expr + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, node): + Node.__init__(self, node) + self.id = node.id + self.expr = None # Expression is set later if it exists + self.defined = False + # For debbugi purposes + self.type = node.type + + +class AssignNode(ExpressionNode): + def __init__(self, expr, node): + Node.__init__(self, node) + self.id = node.id + self.expr = expr + self.defined = False + + +class MethodCallNode(ExpressionNode): + def __init__(self, caller_type, args, node): + Node.__init__(self, node) + self.caller_type = caller_type + self.args = args + self.id = node.id + + +class UnaryNode(ExpressionNode): + def __init__(self, expr, node): + Node.__init__(self, node) + self.expr = expr + + +class IsVoidNode(UnaryNode): + pass + + +class NotNode(UnaryNode): + pass + + +class ComplementNode(UnaryNode): + pass + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right, node): + Node.__init__(self, node) + self.left = left + self.right = right + + +class ComparerNode(BinaryNode): + pass + + +class LessNode(ComparerNode): + pass + + +class LessOrEqualNode(ComparerNode): + pass + + +class EqualsNode(ComparerNode): + pass + + +class ArithmeticNode(BinaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class AtomicNode(ExpressionNode): + def __init__(self, node): + Node.__init__(self, node) + self.value = node.value + + +class BooleanNode(AtomicNode): + pass + + +class IntNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + def __init__(self, node): + super().__init__(node) + self.defined = False + + +class InstantiateNode(AtomicNode): + pass From 8e0b388254b1fd08d01da1906d2387bb28660b87 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 16:56:03 -0400 Subject: [PATCH 045/432] Fixed parsing rules --- src/parsing/parsetab.py | 110 +++++++++++++++++------------------ src/parsing/parsing_rules.py | 1 + 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 31ccd530d..1eae9561b 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,7 +6,7 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPE method : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';' expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " _lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} @@ -27,58 +27,58 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parsing_rules.py',13), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',18), - ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',19), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',27), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',28), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',39), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',40), - ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',41), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',49), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',50), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',60), - ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',66), - ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',67), - ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',74), - ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',79), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',86), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',87), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',95), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',102), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',109), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',116), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',123), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',130), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',131), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',139), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',140), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',150), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',157), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',158), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',166), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',174), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',175), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',176), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',192), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',193), - ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',201), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',205), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',212), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',218), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',225), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',232), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',239), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',246), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',252), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',258), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',264), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',270), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',276), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',283), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',290), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',297), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',304), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',311), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',318), + ('program -> class_list','program',1,'p_program','parsing_rules.py',35), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',40), + ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',41), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',49), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',50), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',60), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',61), + ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',62), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',70), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',71), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',81), + ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',87), + ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',88), + ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',96), + ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',101), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',107), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',108), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',116), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',122), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',128), + ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',134), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',140), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',146), + ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',147), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',155), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',156), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',165), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',171), + ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',172), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',180), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',186), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',187), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',188), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',203), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',204), + ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',212), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',217), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',223), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',229), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',235), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',241), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',247), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',253), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',259), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',265), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',271), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',277), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',283), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',289), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',295), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',301), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',307), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',313), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',319), ] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index c10d0684c..80ecc57e9 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -1,3 +1,4 @@ +from lexing.lexing_rules import tokens from ast.parser_ast import ( AssignNode, AttrDeclarationNode, From 0c152f13c9bee3ac3476a842891eba8961da4f03 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 16:56:40 -0400 Subject: [PATCH 046/432] Added soft inferencer and small changes in tools.py Soft Inferencer is an improved verstion of AutotypeCollector. It recieves an ast and returns another Added try_conform() method --- src/semantics/soft_inferencer.py | 578 +++++++++++++++++++++++++++++++ src/semantics/tools.py | 13 + 2 files changed, 591 insertions(+) create mode 100644 src/semantics/soft_inferencer.py diff --git a/src/semantics/soft_inferencer.py b/src/semantics/soft_inferencer.py new file mode 100644 index 000000000..ffdbae32d --- /dev/null +++ b/src/semantics/soft_inferencer.py @@ -0,0 +1,578 @@ +import ast.inferencer_ast as inf_ast +from ast.parser_ast import ( + ArithmeticNode, + AssignNode, + AttrDeclarationNode, + BlocksNode, + BooleanNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComparerNode, + ComplementNode, + ConditionalNode, + InstantiateNode, + IntNode, + IsVoidNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + Node, + NotNode, + ProgramNode, + StringNode, + VarDeclarationNode, + VariableNode, +) + +import semantics.visitor as visitor +from semantics.tools import ( + Context, + ErrorType, + Scope, + SemanticError, + TypeBag, + conforms, + join, + join_list, + smart_add, +) + + +class SoftInferencer: + def __init__(self, context: Context) -> None: + self.context = context + self.errors = [] + self.current_type = None + + @visitor.on("node") + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode) -> inf_ast.ProgramNode: + scope = Scope() + new_declaration = [] + for declaration in node.declarations: + new_declaration.append(self.visit(declaration, scope.create_child())) + + program = inf_ast.ProgramNode(new_declaration, scope, node) + return program + + @visitor.when(ClassDeclarationNode) + def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: + self.current_type = self.context.get_type(node.id, unpacked=True) + scope.define_variable("self", TypeBag({self.current_type})) + + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + new_features = [] + for feature in node.features: + new_features.append(self.visit(feature, scope)) + + class_node = inf_ast.ClassDeclarationNode(new_features, node) + return class_node + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + node_type = self.current_type.get_attribute(node.id).type.swap_self_type( + self.current_type + ) + + attr_node = inf_ast.AttrDeclarationNode(node) + if not node.expr: + attr_node.inferenced_type = node_type + return attr_node + + expr_node = self.visit(node.expr, scope) + + node_expr = expr_node.inferenced_type + expr_clone = node_expr.clone() + + if not conforms(node_expr, node_type): + self.add_error( + node, + ( + f"Type Error: In class '{self.current_type.name}' attribue" + f"'{node.id}' expression type({expr_clone.name}) does not conforms" + f"to declared type ({node_type.name})." + ), + ) + expr_node.inferenced_type = ErrorType() + attr_node.expr = expr_node + attr_node.inferenced_type = node_type + return attr_node + + @visitor.when(MethodDeclarationNode) + def visit(self, node, scopex: Scope): + 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) + + ret_type_decl = current_method.return_type.swap_self_type(self.current_type) + body_node = self.visit(node.body, scope) + + ret_type_expr = body_node.inferenced_type + ret_expr_clone = ret_type_expr.clone() + if not conforms(ret_type_expr, ret_type_decl): + self.add_error( + node, + ( + f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}'" + f"return expression type({ret_expr_clone.name}) does not conforms to" + f"declared return type ({ret_type_decl.name})" + ), + ) + body_node.inferenced_type = ErrorType() + + ret_type_decl.swap_self_type(self.current_type, back=True) + + method_node = inf_ast.MethodDeclarationNode(ret_type_decl, body_node, node) + method_node.inferenced_type = ret_type_decl + return method_node + + @visitor.when(BlocksNode) + def visit(self, node, scope): + new_expr_list = [] + for expr in node.expr_list: + new_expr_list.append(self.visit(expr, scope)) + + block_node = inf_ast.BlocksNode(new_expr_list, node) + block_node.inferenced_type = block_node.expr_list[-1].inferenced_type + return block_node + + @visitor.when(ConditionalNode) + def visit(self, node, scope): + condition_node = self.visit(node.condition, scope) + + condition_type = condition_node.inferenced_type + bool_type = self.context.get_type("Bool") + + condition_clone = condition_type.clone() + if not conforms(condition_type, bool_type): + self.add_error( + node, + ( + f"Type Error: If's condition type({condition_clone.name})" + "does not conforms to Bool type.", + ), + ) + condition_node.inferenced_type = ErrorType() + + then_node = self.visit(node.then_body, scope) + else_node = self.visit(node.else_body, scope) + + if_node = inf_ast.ConditionalNode(condition_node, then_node, else_node, node) + + then_type = then_node.inferenced_type + else_type = else_node.inferenced_type + joined_type = join(then_type, else_type) + + if_node.inferenced_type = joined_type + return if_node + + @visitor.when(CaseNode) + def visit(self, node, scope: Scope): + expr_node = self.visit(node.case_expr, scope) + + types_visited = set() + type_list = [] + new_options = [] + for option in node.options: + child = scope.create_child() + new_options.append(self.visit(option, child)) + type_list.append(new_options[-1].inferenced_type) + var_type = child.find_variable(option.id).type + if var_type in types_visited: + self.add_error( + node, + ( + "Semantic Error: Case Expression can't have branches" + f"with same case type({var_type.name})", + ), + ) + + joined_type = join_list(type_list) + + case_node = inf_ast.CaseNode(expr_node, new_options, node) + case_node.inferenced_type = joined_type + return case_node + + @visitor.when(CaseOptionNode) + def visit(self, node, scope: Scope): + try: + node_type = self.context.get_type(node.type, selftype=False, autotype=False) + except SemanticError as err: + self.add_error(node, err) + node_type = ErrorType() + + scope.define_variable(node.id, node_type) + expr_node = self.visit(node.expr, scope) + + case_opt_node = inf_ast.CaseOptionNode(expr_node, node) + case_opt_node.inferenced_type = expr_node.inferenced_type + return case_opt_node + + @visitor.when(LoopNode) + def visit(self, node, scope): + condition_node = self.visit(node.condition, scope) + condition_type = condition_node.inferenced_type + + bool_type = self.context.get_type("Bool") + condition_clone = condition_type.clone() + if not conforms(condition_type, bool_type): + self.add_error( + node, + ( + f"Type Error: Loop condition type({condition_clone.name})" + "does not conforms to Bool type.", + ), + ) + condition_node.inferenced_type = ErrorType() + + body_node = self.visit(node.body, scope) + loop_node = inf_ast.LoopNode(condition_node, body_node, node) + loop_node.inferenced_type = self.context.get_type("Object") + return loop_node + + @visitor.when(LetNode) + def visit(self, node, scope: Scope): + child = scope.create_child() + + new_decl_list = [] + for var in node.var_decl_list: + new_decl_list.append(self.visit(var, child)) + + in_expr_node = self.visit(node.in_expr, child) + + let_node = inf_ast.LetNode(new_decl_list, in_expr_node, node) + let_node.inferenced_type = in_expr_node.inferenced_type + return let_node + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope: Scope): + var_decl_node = inf_ast.VarDeclarationNode(node) + + try: + node_type = self.context.get_type(node.type).swap_self_type( + self.current_type + ) + except SemanticError as err: + node_type = ErrorType() + self.add_error(node, err) + + if not scope.is_local(node.id): + scope.define_variable(node.id, node_type) + var_decl_node.defined = True + else: + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' already defined in current scope.", + ) + node_type = ErrorType() + + var_decl_node.inferenced_type = node_type + + if node.expr: + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + expr_clone = expr_type.clone() + if not conforms(expr_type, node_type): + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).", + ) + expr_node.inferenced_type = ErrorType() + var_decl_node.expr = expr_node + + return var_decl_node + + @visitor.when(AssignNode) + def visit(self, node, scope: Scope): + + expr_node = self.visit(node.expr, scope) + assign_node = inf_ast.AssignNode(expr_node, node) + + var = scope.find_variable(node.id) + if not var: + self.add_error( + ( + f"Scope Error: Cannot assign new value to" + f"{node.id} beacuse it is not defined in the current scope" + ) + ) + decl_type = ErrorType() + else: + # decl type should not have selftype .swap_self_type(self.current_type) + decl_type = var.type + assign_node.defined = True + + if var is not None: + if var.name == "self": + self.add_error( + node, + "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.", + ) + decl_type = ErrorType() + + expr_type = expr_node.inferenced_type + expr_clone = expr_type.clone() + if not conforms(expr_type, decl_type): + self.add_error( + node, + ( + f"Type Error: Cannot assign new value to variable '{node.id}'." + f"Expression type({expr_clone.name}) does not conforms to" + f"declared type ({decl_type.name}).", + ), + ) + expr_node.inferenced_type = ErrorType() + + assign_node.inferenced_type = decl_type + return assign_node + + @visitor.when(MethodCallNode) + def visit(self, node, scope): + if node.expr == None: + caller_type = TypeBag({self.current_type}) + elif node.type == None: + caller_node = self.visit(node.expr, scope) + caller_type = caller_node.inferenced_type + else: + bridge_node = self.visit(node.expr, scope) + bridge_type = bridge_node.inferenced_type + caller_type = self.context.get_type( + node.type, selftype=False, autotype=False + ) + + bridge_clone = bridge_type.clone() + if not conforms(bridge_type, caller_type): + self.add_error( + node, + ( + f"Semantic Error: Cannot effect dispatch because expression" + f"type({bridge_clone.name}) does not conforms to " + f"caller type({caller_type.name}).", + ), + ) + caller_type = ErrorType() + + methods = None + if len(caller_type.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_type, TypeBag(set(types), types)) + if len(caller_type.type_set): + methods = [(typex, typex.get_method) for typex in caller_type.heads] + else: + self.add_error( + node, + ( + f"Semantic Error: There is no method '{node.id}'" + f"that recieves {len(node.params)} arguments in" + f"types {caller_type.name}.", + ), + ) + caller_type = ErrorType() + elif len(caller_type.type_set) == 1: + caller_type = caller_type.heads[0] + try: + methods = [(caller_type, caller_type.get_method(node.id))] + except SemanticError: + self.add_error( + node, + ( + f"Semantic Error: There is no method '{node.id}'" + f"that recieves {len(node.params)} arguments in" + f"Type '{caller_type.name}'.", + ), + ) + caller_type = ErrorType() + + new_args = [] + for i in range(len(node.args)): + new_args.append(self.visit(node.args[i], scope)) + + method_call_node = inf_ast.MethodCallNode(caller_type, new_args, node) + + if methods: + type_set = set() + heads = [] + for typex, method in methods: + ret_type = method.return_type.clone() + ret_type.swap_self_type(typex) + type_set = smart_add(type_set, heads, ret_type) + method_call_node.inferenced_type = TypeBag(type_set, heads) + else: + # Errors already notified previuosly + method_call_node.inferenced_type = ErrorType() + + return method_call_node + + @visitor.when(ArithmeticNode) + def visit(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + left_clone = left_type.clone() + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + right_clone = right_type.clone() + + int_type = self.context.get_type("Int") + if not conforms(left_type, int_type): + self.add_error( + node.left, + f"Type Error: Arithmetic Error: Left member type({left_clone.name})" + "does not conforms to Int type.", + ) + left_node.inferenced_type = ErrorType() + if not conforms(right_type, int_type): + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member type({right_clone.name})" + "does not conforms to Int type.", + ) + + arith_node = inf_ast.ArithmeticNode(left_node, right_node, node) + arith_node.inferenced_type = int_type + return arith_node + + @visitor.when(ComparerNode) + def visit(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + left_clone = left_type.clone() + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + right_clone = right_type.clone() + + bool_type = self.context.get_type("Bool") + if not conforms(left_type, right_type): + self.add_error( + node, + ( + f"Type Error: Left expression type({left_clone.name})" + f"does not conforms to right expression type({right_type.name})", + ), + ) + left_node.inferenced_type = ErrorType() + elif not conforms(right_type, left_type): + self.add_error( + node, + ( + f"Type Error: Right expression type({right_clone.name})" + f"does not conforms to left expression type({left_type.name})", + ), + ) + right_node.inferenced_type = ErrorType() + + comparer_node = inf_ast.ComparerNode(left_node, right_node, node) + comparer_node.inferenced_type = bool_type + return comparer_node + + @visitor.when(VariableNode) + def visit(self, node, scope: Scope): + var_node = inf_ast.VariableNode(node) + + var = scope.find_variable(node.value) + if var: + node.defined = True + var_type = var.type + else: + var_type = ErrorType() + self.add_error( + node, f"Semantic Error: Variable '{node.value}' is not defined." + ) + var_node.inferenced_type = var_type + return var_node + + @visitor.when(NotNode) + def visit(self, node, scope): + expr_node = self.visit(node.expr, scope) + + expr_type = expr_node.inferenced_type + expr_clone = expr_type.clone() + bool_type = self.context.get_type("Bool") + if not conforms(expr_type, bool_type): + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not" + " conforms to Bool type", + ) + expr_node.inferenced_type = ErrorType() + + not_node = inf_ast.NotNode(expr_node, node) + not_node.inferenced_type = bool_type + return not_node + + @visitor.when(ComplementNode) + def visit(self, node, scope): + expr_node = self.visit(node.expr, scope) + + expr_type = expr_node.inferenced_type + expr_clone = expr_type.clone() + node_type = self.context.get_type("Int") + if not conforms(expr_type, node_type): + self.add_error( + node, + ( + f"Type Error: ~ expresion type({expr_clone.name} does not" + " conforms to Int type", + ), + ) + node_type = ErrorType() + + complement_node = inf_ast.ComplementNode(expr_node, node) + complement_node.inferenced_type = node_type + return complement_node + + @visitor.when(IsVoidNode) + def visit(self, node, scope): + node_expr = self.visit(node.expr, scope) + is_void_node = IsVoidNode(node_expr, node) + is_void_node.inferenced_type = self.context.get_type("Bool") + return is_void_node + + @visitor.when(InstantiateNode) + def visit(self, node, scope): + instantiate_node = inf_ast.InstantiateNode(node) + try: + node_type = self.context.get_type( + node.value, selftype=False, autotype=False + ) + except SemanticError as err: + self.add_error( + node, + err + f"\nSemantic Error: Could not instantiate type '{node.value}'.", + ) + node_type = ErrorType() + instantiate_node.inferenced_type = node_type + return instantiate_node + + @visitor.when(IntNode) + def visit(self, node, scope): + int_node = inf_ast.IntNode(node) + int_node.inferenced_type = self.context.get_type("Int") + return int_node + + @visitor.when(StringNode) + def visit(self, node, scope): + str_node = inf_ast.StringNode(node) + str_node.inferenced_type = self.context.get_type("String") + return str_node + + @visitor.when(BooleanNode) + def visit(self, node, scope): + bool_node = inf_ast.BooleanNode(node) + bool_node.inferenced_type = self.context.get_type("Bool") + return bool_node + + def add_error(self, node: Node, text: str): + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index d9a9070f7..62569bec8 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -355,6 +355,12 @@ def clone(self): clone.conform_list = self.conform_list.copy() return clone + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + class SelfType(Type): def __init__(self): @@ -568,6 +574,13 @@ def conforms(bag1: TypeBag, bag2: TypeBag): return len(bag1.type_set) >= 1 +def try_conform(bag1: TypeBag, bag2: TypeBag): + clone1 = bag1.clone() + if not conforms(bag1, bag2): + return clone1 + return bag2 + + def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: ancestor_set = set() head_list = [] From 089fe6e77282a95301c3c8642d17a5a11b00709d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 17:00:27 -0400 Subject: [PATCH 047/432] Added new debbuging module Debbuging module has several test cases to check compilers performance debdev.py has a pipeline executing different parts of the compilers TypeLogger recieves an ast and returns a string representing the values of the ast and the variables in the scope. --- src/debbuging/__init__.py | 0 src/debbuging/tests/Auto/00Simple.cl | 5 + src/debbuging/tests/Auto/01Assign.cl | 6 + src/debbuging/tests/Misc/00HelloRodro.cl | 5 + src/debbuging/tests/Misc/01Simple.cl | 13 + src/debbuging/tests/Misc/02Simple.cl | 9 + src/debbuging/tests/Misc/03Simple.cl | 23 + src/debbuging/tests/Misc/04SallySilly.cl | 10 + src/debbuging/tests/Misc/05Ackerman.cl | 24 + src/debbuging/tests/Misc/06FooBarRaz.cl | 67 +++ src/debbuging/tests/Misc/07MultipleClass.cl | 46 ++ src/debbuging/tests/Misc/08Cellullar.cl | 93 ++++ src/debbuging/tests/Misc/09GameOfLife.cl | 436 ++++++++++++++++++ src/debbuging/tests/Misc/10BiG.cl | 477 ++++++++++++++++++++ src/debbuging/type_logger.py | 280 ++++++++++++ src/debdev.py | 81 ++++ 16 files changed, 1575 insertions(+) create mode 100644 src/debbuging/__init__.py create mode 100644 src/debbuging/tests/Auto/00Simple.cl create mode 100644 src/debbuging/tests/Auto/01Assign.cl create mode 100644 src/debbuging/tests/Misc/00HelloRodro.cl create mode 100644 src/debbuging/tests/Misc/01Simple.cl create mode 100644 src/debbuging/tests/Misc/02Simple.cl create mode 100644 src/debbuging/tests/Misc/03Simple.cl create mode 100644 src/debbuging/tests/Misc/04SallySilly.cl create mode 100644 src/debbuging/tests/Misc/05Ackerman.cl create mode 100644 src/debbuging/tests/Misc/06FooBarRaz.cl create mode 100644 src/debbuging/tests/Misc/07MultipleClass.cl create mode 100644 src/debbuging/tests/Misc/08Cellullar.cl create mode 100644 src/debbuging/tests/Misc/09GameOfLife.cl create mode 100644 src/debbuging/tests/Misc/10BiG.cl create mode 100644 src/debbuging/type_logger.py create mode 100644 src/debdev.py diff --git a/src/debbuging/__init__.py b/src/debbuging/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/debbuging/tests/Auto/00Simple.cl b/src/debbuging/tests/Auto/00Simple.cl new file mode 100644 index 000000000..ca2ffb704 --- /dev/null +++ b/src/debbuging/tests/Auto/00Simple.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main(n : AUTO_TYPE) : AUTO_TYPE { + n + 1 + }; +}; diff --git a/src/debbuging/tests/Auto/01Assign.cl b/src/debbuging/tests/Auto/01Assign.cl new file mode 100644 index 000000000..79d75a0bd --- /dev/null +++ b/src/debbuging/tests/Auto/01Assign.cl @@ -0,0 +1,6 @@ +class Main inherits IO { + a : AUTO_TYPE; + main(n : AUTO_TYPE) : AUTO_TYPE { + a <- n + 1 + }; +}; diff --git a/src/debbuging/tests/Misc/00HelloRodro.cl b/src/debbuging/tests/Misc/00HelloRodro.cl new file mode 100644 index 000000000..08352cbc8 --- /dev/null +++ b/src/debbuging/tests/Misc/00HelloRodro.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main(): SELF_TYPE { + out_string("Hello, Rodro.\n") + }; +}; diff --git a/src/debbuging/tests/Misc/01Simple.cl b/src/debbuging/tests/Misc/01Simple.cl new file mode 100644 index 000000000..9046024dc --- /dev/null +++ b/src/debbuging/tests/Misc/01Simple.cl @@ -0,0 +1,13 @@ +class Main{ + a: A; + + main(): A { + a <- new A + }; +}; + +class A { + method(): Int{ + 1 + }; +}; diff --git a/src/debbuging/tests/Misc/02Simple.cl b/src/debbuging/tests/Misc/02Simple.cl new file mode 100644 index 000000000..eea0900fb --- /dev/null +++ b/src/debbuging/tests/Misc/02Simple.cl @@ -0,0 +1,9 @@ + +class Main{ + a: A; + main(b:Int): A { + b <- 3 + }; +}; + +class A{}; diff --git a/src/debbuging/tests/Misc/03Simple.cl b/src/debbuging/tests/Misc/03Simple.cl new file mode 100644 index 000000000..978e266e2 --- /dev/null +++ b/src/debbuging/tests/Misc/03Simple.cl @@ -0,0 +1,23 @@ + +class Main{ + a: A; + main(): A { + 1 + }; +}; + +class A { + oper(a : Int, b : Int): Int{ + a + b + }; +}; +class B inherits A { + oper(a : Int, b : Int, c : Int) : Int{ + a * b * c + }; +}; +class C inherits A { + oper(a : Int, b : String) : Bool{ + a + b + }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/04SallySilly.cl b/src/debbuging/tests/Misc/04SallySilly.cl new file mode 100644 index 000000000..f4afdca9a --- /dev/null +++ b/src/debbuging/tests/Misc/04SallySilly.cl @@ -0,0 +1,10 @@ +class Silly +{ + capy() : SELF_TYPE { self }; +}; +class Sally inherits Silly { }; + +class Main { + x : Sally <- (new Sally).capy(); + main() : Sally { x }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/05Ackerman.cl b/src/debbuging/tests/Misc/05Ackerman.cl new file mode 100644 index 000000000..0ca3e1c7f --- /dev/null +++ b/src/debbuging/tests/Misc/05Ackerman.cl @@ -0,0 +1,24 @@ +class Main inherits IO{ + a : Ackermann ; + main(): SELF_TYPE {{ + a <- new Ackermann; + out_int(a.ackermann(1,3)); + } + }; +}; + +class Fact { + fact(n : Int): Int{ + if (n=0) then 1 else n*fact(n-1) fi + }; +}; + +class Ackermann { + ackermann(m:Int, n: Int): Int{ + if (m = 0 ) then n+1 else + if ( n = 0) then ackermann(m-1, 1) else + ackermann(m-1, ackermann(m, n-1)) + fi + fi + }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/06FooBarRaz.cl b/src/debbuging/tests/Misc/06FooBarRaz.cl new file mode 100644 index 000000000..ec38a7766 --- /dev/null +++ b/src/debbuging/tests/Misc/06FooBarRaz.cl @@ -0,0 +1,67 @@ +(* hairy . . .*) + +class Foo inherits Bazz { + a : Razz <- case self of + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + b : Int <- a.doh() + g.doh() + doh() + printh(); + + doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; + +}; + +class Bar inherits Razz { + + c : Int <- doh(); + + d : Object <- printh(); +}; + + +class Razz inherits Foo { + + e : Bar <- case self of + n : Razz => (new Bar); + n : Bar => n; + esac; + + f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); + +}; + +class Bazz inherits IO { + + h : Int <- 1; + + g : Foo <- case self of + n : Bazz => (new Foo); + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + i : Object <- printh(); + + printh() : Int { { out_int(h); 0; } }; + + doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; +}; + +(* scary . . . *) +class Main { + a : Bazz <- new Bazz; + b : Foo <- new Foo; + c : Razz <- new Razz; + d : Bar <- new Bar; + + main(): String { "do nothing" }; + +}; + + + + + diff --git a/src/debbuging/tests/Misc/07MultipleClass.cl b/src/debbuging/tests/Misc/07MultipleClass.cl new file mode 100644 index 000000000..52464394a --- /dev/null +++ b/src/debbuging/tests/Misc/07MultipleClass.cl @@ -0,0 +1,46 @@ +class Main +{ + h:AUTO_TYPE <- new H; + a:AUTO_TYPE <- new A; + main(): Int + { + { + 3; + } + }; +}; + +class H +{ + a:Int; +}; + +class Z inherits H +{ + x:Int; +}; + +class A inherits F +{ + b:Int; +}; + +class B inherits A +{ + c:Int; +}; + +class C inherits B +{ + e:Int; +}; + +class D inherits C +{ + f:Int; +}; + +class F inherits D +{ + g:Int; +}; diff --git a/src/debbuging/tests/Misc/08Cellullar.cl b/src/debbuging/tests/Misc/08Cellullar.cl new file mode 100644 index 000000000..a43e3fa4a --- /dev/null +++ b/src/debbuging/tests/Misc/08Cellullar.cl @@ -0,0 +1,93 @@ +class CellularAutomaton inherits IO { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + self; + } + }; + + print() : SELF_TYPE { + { + out_string(population_map.concat("\n")); + self; + } + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + population_map.substr(position, 1) + }; + + cell_left_neighbor(position : Int) : String { + if position = 0 then + cell(num_cells() - 1) + else + cell(position - 1) + fi + }; + + cell_right_neighbor(position : Int) : String { + if position = num_cells() - 1 then + cell(0) + else + cell(position + 1) + fi + }; + + (* a cell will live if exactly 1 of itself and it's immediate + neighbors are alive *) + cell_at_next_evolution(position : Int) : String { + if ((if cell(position) = "X" then 1 else 0 fi) + + (if cell_left_neighbor(position) = "X" then 1 else 0 fi) + + (if cell_right_neighbor(position) = "X" then 1 else 0 fi) + = 1) + then + "X" + else + "." + fi + }; + + evolve() : SELF_TYPE { + (let position : Int in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; +}; + +class Main { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + cells <- (new CellularAutomaton).init(" X "); + cells.print(); + (let countdown : Int <- 20 in + while 0 < countdown loop + { + cells.evolve(); + cells.print(); + countdown <- countdown - 1; + } + pool + ); + self; + } + }; +}; diff --git a/src/debbuging/tests/Misc/09GameOfLife.cl b/src/debbuging/tests/Misc/09GameOfLife.cl new file mode 100644 index 000000000..25facd526 --- /dev/null +++ b/src/debbuging/tests/Misc/09GameOfLife.cl @@ -0,0 +1,436 @@ +(* The Game of Life + Tendo Kayiira, Summer '95 + With code taken from /private/cool/class/examples/cells.cl + + This introduction was taken off the internet. It gives a brief + description of the Game Of Life. It also gives the rules by which + this particular game follows. + + Introduction + + John Conway's Game of Life is a mathematical amusement, but it + is also much more: an insight into how a system of simple + cellualar automata can create complex, odd, and often aesthetically + pleasing patterns. It is played on a cartesian grid of cells + which are either 'on' or 'off' The game gets it's name from the + similarity between the behaviour of these cells and the behaviour + of living organisms. + + The Rules + + The playfield is a cartesian grid of arbitrary size. Each cell in + this grid can be in an 'on' state or an 'off' state. On each 'turn' + (called a generation,) the state of each cell changes simultaneously + depending on it's state and the state of all cells adjacent to it. + + For 'on' cells, + If the cell has 0 or 1 neighbours which are 'on', the cell turns + 'off'. ('dies of loneliness') + If the cell has 2 or 3 neighbours which are 'on', the cell stays + 'on'. (nothing happens to that cell) + If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', + the cell turns 'off'. ('dies of overcrowding') + + For 'off' cells, + If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which + are 'on', the cell stays 'off'. (nothing happens to that cell) + If the cell has 3 neighbours which are 'on', the cell turns + 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) + + Repeat for as many generations as desired. + + *) + + +class Board inherits IO { + + rows : Int; + columns : Int; + board_size : Int; + + size_of_board(initial : String) : Int { + initial.length() + }; + + board_init(start : String) : SELF_TYPE { + (let size :Int <- size_of_board(start) in + { + if size = 15 then + { + rows <- 3; + columns <- 5; + board_size <- size; + } + else if size = 16 then + { + rows <- 4; + columns <- 4; + board_size <- size; + } + else if size = 20 then + { + rows <- 4; + columns <- 5; + board_size <- size; + } + else if size = 21 then + { + rows <- 3; + columns <- 7; + board_size <- size; + } + else if size = 25 then + { + rows <- 5; + columns <- 5; + board_size <- size; + } + else if size = 28 then + { + rows <- 7; + columns <- 4; + board_size <- size; + } + else + { + rows <- 5; + columns <- 5; + board_size <- size; + } + fi fi fi fi fi fi; + self; + } + ) + }; + +}; + + + +class CellularAutomaton inherits Board { + population_map : String; + + init(map : String) : SELF_TYPE { + { + population_map <- map; + board_init(map); + self; + } + }; + + + + + print() : SELF_TYPE { + + (let i : Int <- 0 in + (let num : Int <- board_size in + { + out_string("\n"); + while i < num loop + { + out_string(population_map.substr(i,columns)); + out_string("\n"); + i <- i + columns; + } + pool; + out_string("\n"); + self; + } + ) ) + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + if board_size - 1 < position then + " " + else + population_map.substr(position, 1) + fi + }; + + north(position : Int): String { + if (position - columns) < 0 then + " " + else + cell(position - columns) + fi + }; + + south(position : Int): String { + if board_size < (position + columns) then + " " + else + cell(position + columns) + fi + }; + + east(position : Int): String { + if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + cell(position + 1) + fi + }; + + west(position : Int): String { + if position = 0 then + " " + else + if ((position / columns) * columns) = position then + " " + else + cell(position - 1) + fi fi + }; + + northwest(position : Int): String { + if (position - columns) < 0 then + " " + else if ((position / columns) * columns) = position then + " " + else + north(position - 1) + fi fi + }; + + northeast(position : Int): String { + if (position - columns) < 0 then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + north(position + 1) + fi fi + }; + + southeast(position : Int): String { + if board_size < (position + columns) then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + south(position + 1) + fi fi + }; + + southwest(position : Int): String { + if board_size < (position + columns) then + " " + else if ((position / columns) * columns) = position then + " " + else + south(position - 1) + fi fi + }; + + neighbors(position: Int): Int { + { + (if north(position) = "X" then 1 else 0 fi) + + (if south(position) = "X" then 1 else 0 fi) + + (if east(position) = "X" then 1 else 0 fi) + + (if west(position) = "X" then 1 else 0 fi) + + (if northeast(position) = "X" then 1 else 0 fi) + + (if northwest(position) = "X" then 1 else 0 fi) + + (if southeast(position) = "X" then 1 else 0 fi) + + (if southwest(position) = "X" then 1 else 0 fi); + } + }; + + +(* A cell will live if 2 or 3 of it's neighbors are alive. It dies + otherwise. A cell is born if only 3 of it's neighbors are alive. *) + + cell_at_next_evolution(position : Int) : String { + + if neighbors(position) = 3 then + "X" + else + if neighbors(position) = 2 then + if cell(position) = "X" then + "X" + else + "-" + fi + else + "-" + fi fi + }; + + + evolve() : SELF_TYPE { + (let position : Int <- 0 in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; + +(* This is where the background pattern is detremined by the user. More + patterns can be added as long as whoever adds keeps the board either + 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) + option(): String { + { + (let num : Int in + { + out_string("\nPlease chose a number:\n"); + out_string("\t1: A cross\n"); + out_string("\t2: A slash from the upper left to lower right\n"); + out_string("\t3: A slash from the upper right to lower left\n"); + out_string("\t4: An X\n"); + out_string("\t5: A greater than sign \n"); + out_string("\t6: A less than sign\n"); + out_string("\t7: Two greater than signs\n"); + out_string("\t8: Two less than signs\n"); + out_string("\t9: A 'V'\n"); + out_string("\t10: An inverse 'V'\n"); + out_string("\t11: Numbers 9 and 10 combined\n"); + out_string("\t12: A full grid\n"); + out_string("\t13: A 'T'\n"); + out_string("\t14: A plus '+'\n"); + out_string("\t15: A 'W'\n"); + out_string("\t16: An 'M'\n"); + out_string("\t17: An 'E'\n"); + out_string("\t18: A '3'\n"); + out_string("\t19: An 'O'\n"); + out_string("\t20: An '8'\n"); + out_string("\t21: An 'S'\n"); + out_string("Your choice => "); + num <- in_int(); + out_string("\n"); + if num = 1 then + " XX XXXX XXXX XX " + else if num = 2 then + " X X X X X " + else if num = 3 then + "X X X X X" + else if num = 4 then + "X X X X X X X X X" + else if num = 5 then + "X X X X X " + else if num = 6 then + " X X X X X" + else if num = 7 then + "X X X XX X " + else if num = 8 then + " X XX X X X " + else if num = 9 then + "X X X X X " + else if num = 10 then + " X X X X X" + else if num = 11 then + "X X X X X X X X" + else if num = 12 then + "XXXXXXXXXXXXXXXXXXXXXXXXX" + else if num = 13 then + "XXXXX X X X X " + else if num = 14 then + " X X XXXXX X X " + else if num = 15 then + "X X X X X X X " + else if num = 16 then + " X X X X X X X" + else if num = 17 then + "XXXXX X XXXXX X XXXX" + else if num = 18 then + "XXX X X X X XXXX " + else if num = 19 then + " XX X XX X XX " + else if num = 20 then + " XX X XX X XX X XX X XX " + else if num = 21 then + " XXXX X XX X XXXX " + else + " " + fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; + } + ); + } + }; + + + + + prompt() : Bool { + { + (let ans : String in + { + out_string("Would you like to continue with the next generation? \n"); + out_string("Please use lowercase y or n for your answer [y]: "); + ans <- in_string(); + out_string("\n"); + if ans = "n" then + false + else + true + fi; + } + ); + } + }; + + + prompt2() : Bool { + (let ans : String in + { + out_string("\n\n"); + out_string("Would you like to choose a background pattern? \n"); + out_string("Please use lowercase y or n for your answer [n]: "); + ans <- in_string(); + if ans = "y" then + true + else + false + fi; + } + ) + }; + + +}; + +class Main inherits CellularAutomaton { + cells : CellularAutomaton; + + main() : SELF_TYPE { + { + (let continue : Bool in + (let choice : String in + { + out_string("Welcome to the Game of Life.\n"); + out_string("There are many initial states to choose from. \n"); + while prompt2() loop + { + continue <- true; + choice <- option(); + cells <- (new CellularAutomaton).init(choice); + cells.print(); + while continue loop + if prompt() then + { + cells.evolve(); + cells.print(); + } + else + continue <- false + fi + pool; + } + pool; + self; + } ) ); } + }; +}; + diff --git a/src/debbuging/tests/Misc/10BiG.cl b/src/debbuging/tests/Misc/10BiG.cl new file mode 100644 index 000000000..775589cce --- /dev/null +++ b/src/debbuging/tests/Misc/10BiG.cl @@ -0,0 +1,477 @@ +(* A program for + + 1. Representing lambda terms + 2. Interpreting lambda terms + 3. Compiling lambda calculus programs to Cool + + The lambda calculus is described by the following grammar: + + e ::= x a variable + | \x.e a function with argument x + | e1@e2 apply function e1 to argument e2 + + Jeff Foster (jfoster@cs.berkeley.edu) + March 24, 2000 +*) + +(* + * A list of variables. We use this to do de Bruijn numbering + * + *) +class VarList inherits IO { + isNil() : Bool { true }; + head() : Variable { { abort(); new Variable; } }; + tail() : VarList { { abort(); new VarList; } }; + add(x : Variable) : VarList { (new VarListNE).init(x, self) }; + print() : SELF_TYPE { out_string("\n") }; +}; + +class VarListNE inherits VarList { + x : Variable; + rest : VarList; + isNil() : Bool { false }; + head() : Variable { x }; + tail() : VarList { rest }; + init(y : Variable, r : VarList) : VarListNE { { x <- y; rest <- r; self; } }; + print() : SELF_TYPE { { x.print_self(); out_string(" "); + rest.print(); self; } }; +}; + +(* + * A list of closures we need to build. We need to number (well, name) + * the closures uniquely. + *) +class LambdaList { + isNil() : Bool { true }; + headE() : VarList { { abort(); new VarList; } }; + headC() : Lambda { { abort(); new Lambda; } }; + headN() : Int { { abort(); 0; } }; + tail() : LambdaList { { abort(); new LambdaList; } }; + add(e : VarList, x : Lambda, n : Int) : LambdaList { + (new LambdaListNE).init(e, x, n, self) + }; +}; + +class LambdaListNE inherits LambdaList { + lam : Lambda; + num : Int; + env : VarList; + rest : LambdaList; + isNil() : Bool { false }; + headE() : VarList { env }; + headC() : Lambda { lam }; + headN() : Int { num }; + tail() : LambdaList { rest }; + init(e : VarList, l : Lambda, n : Int, r : LambdaList) : LambdaListNE { + { + env <- e; + lam <- l; + num <- n; + rest <- r; + self; + } + }; +}; + +class LambdaListRef { + nextNum : Int <- 0; + l : LambdaList; + isNil() : Bool { l.isNil() }; + headE() : VarList { l.headE() }; + headC() : Lambda { l.headC() }; + headN() : Int { l.headN() }; + reset() : SELF_TYPE { + { + nextNum <- 0; + l <- new LambdaList; + self; + } + }; + add(env : VarList, c : Lambda) : Int { + { + l <- l.add(env, c, nextNum); + nextNum <- nextNum + 1; + nextNum - 1; + } + }; + removeHead() : SELF_TYPE { + { + l <- l.tail(); + self; + } + }; +}; + +(* + * Lambda expressions + * + *) + +-- A pure virtual class representing any expression +class Expr inherits IO { + + -- Print this lambda term + print_self() : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't print self\n"); + abort(); + self; + } + }; + + -- Do one step of (outermost) beta reduction to this term + beta() : Expr { + { + out_string("\nError: Expr is pure virtual; can't beta-reduce\n"); + abort(); + self; + } + }; + + -- Replace all occurrences of x by e + substitute(x : Variable, e : Expr) : Expr { + { + out_string("\nError: Expr is pure virtual; can't substitute\n"); + abort(); + self; + } + }; + + -- Generate Cool code to evaluate this expression + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("\nError: Expr is pure virtual; can't gen_code\n"); + abort(); + self; + } + }; +}; + +(* + * Variables + *) +class Variable inherits Expr { + name : String; + + init(n:String) : Variable { + { + name <- n; + self; + } + }; + + print_self() : SELF_TYPE { + out_string(name) + }; + + beta() : Expr { self }; + + substitute(x : Variable, e : Expr) : Expr { + if x = self then e else self fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + let cur_env : VarList <- env in + { while (if cur_env.isNil() then + false + else + not (cur_env.head() = self) + fi) loop + { out_string("get_parent()."); + cur_env <- cur_env.tail(); + } + pool; + if cur_env.isNil() then + { out_string("Error: free occurrence of "); + print_self(); + out_string("\n"); + abort(); + self; + } + else + out_string("get_x()") + fi; + } + }; +}; + +(* + * Functions + *) +class Lambda inherits Expr { + arg : Variable; + body : Expr; + + init(a:Variable, b:Expr) : Lambda { + { + arg <- a; + body <- b; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("\\"); + arg.print_self(); + out_string("."); + body.print_self(); + self; + } + }; + + beta() : Expr { self }; + + apply(actual : Expr) : Expr { + body.substitute(arg, actual) + }; + + -- We allow variables to be reused + substitute(x : Variable, e : Expr) : Expr { + if x = arg then + self + else + let new_body : Expr <- body.substitute(x, e), + new_lam : Lambda <- new Lambda in + new_lam.init(arg, new_body) + fi + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("((new Closure"); + out_int(closures.add(env, self)); + out_string(").init("); + if env.isNil() then + out_string("new Closure))") + else + out_string("self))") fi; + self; + } + }; + + gen_closure_code(n : Int, env : VarList, + closures : LambdaListRef) : SELF_TYPE { + { + out_string("class Closure"); + out_int(n); + out_string(" inherits Closure {\n"); + out_string(" apply(y : EvalObject) : EvalObject {\n"); + out_string(" { out_string(\"Applying closure "); + out_int(n); + out_string("\\n\");\n"); + out_string(" x <- y;\n"); + body.gen_code(env.add(arg), closures); + out_string(";}};\n"); + out_string("};\n"); + } + }; +}; + +(* + * Applications + *) +class App inherits Expr { + fun : Expr; + arg : Expr; + + init(f : Expr, a : Expr) : App { + { + fun <- f; + arg <- a; + self; + } + }; + + print_self() : SELF_TYPE { + { + out_string("(("); + fun.print_self(); + out_string(")@("); + arg.print_self(); + out_string("))"); + self; + } + }; + + beta() : Expr { + case fun of + l : Lambda => l.apply(arg); -- Lazy evaluation + e : Expr => + let new_fun : Expr <- fun.beta(), + new_app : App <- new App in + new_app.init(new_fun, arg); + esac + }; + + substitute(x : Variable, e : Expr) : Expr { + let new_fun : Expr <- fun.substitute(x, e), + new_arg : Expr <- arg.substitute(x, e), + new_app : App <- new App in + new_app.init(new_fun, new_arg) + }; + + gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { + { + out_string("(let x : EvalObject <- "); + fun.gen_code(env, closures); + out_string(",\n"); + out_string(" y : EvalObject <- "); + arg.gen_code(env, closures); + out_string(" in\n"); + out_string(" case x of\n"); + out_string(" c : Closure => c.apply(y);\n"); + out_string(" o : Object => { abort(); new EvalObject; };\n"); + out_string(" esac)"); + } + }; +}; + +(* + * Term: A class for building up terms + * + *) + +class Term inherits IO { + (* + * The basics + *) + var(x : String) : Variable { + let v : Variable <- new Variable in + v.init(x) + }; + + lam(x : Variable, e : Expr) : Lambda { + let l : Lambda <- new Lambda in + l.init(x, e) + }; + + app(e1 : Expr, e2 : Expr) : App { + let a : App <- new App in + a.init(e1, e2) + }; + + (* + * Some useful terms + *) + i() : Expr { + let x : Variable <- var("x") in + lam(x,x) + }; + + k() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y") in + lam(x,lam(y,x)) + }; + + s() : Expr { + let x : Variable <- var("x"), + y : Variable <- var("y"), + z : Variable <- var("z") in + lam(x,lam(y,lam(z,app(app(x,z),app(y,z))))) + }; + +}; + +(* + * + * The main method -- build up some lambda terms and try things out + * + *) + +class Main inherits Term { + -- Beta-reduce an expression, printing out the term at each step + beta_reduce(e : Expr) : Expr { + { + out_string("beta-reduce: "); + e.print_self(); + let done : Bool <- false, + new_expr : Expr in + { + while (not done) loop + { + new_expr <- e.beta(); + if (new_expr = e) then + done <- true + else + { + e <- new_expr; + out_string(" =>\n"); + e.print_self(); + } + fi; + } + pool; + out_string("\n"); + e; + }; + } + }; + + eval_class() : SELF_TYPE { + { + out_string("class EvalObject inherits IO {\n"); + out_string(" eval() : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + closure_class() : SELF_TYPE { + { + out_string("class Closure inherits EvalObject {\n"); + out_string(" parent : Closure;\n"); + out_string(" x : EvalObject;\n"); + out_string(" get_parent() : Closure { parent };\n"); + out_string(" get_x() : EvalObject { x };\n"); + out_string(" init(p : Closure) : Closure {{ parent <- p; self; }};\n"); + out_string(" apply(y : EvalObject) : EvalObject { { abort(); self; } };\n"); + out_string("};\n"); + } + }; + + gen_code(e : Expr) : SELF_TYPE { + let cl : LambdaListRef <- (new LambdaListRef).reset() in + { + out_string("Generating code for "); + e.print_self(); + out_string("\n------------------cut here------------------\n"); + out_string("(*Generated by lam.cl (Jeff Foster, March 2000)*)\n"); + eval_class(); + closure_class(); + out_string("class Main {\n"); + out_string(" main() : EvalObject {\n"); + e.gen_code(new VarList, cl); + out_string("\n};\n};\n"); + while (not (cl.isNil())) loop + let e : VarList <- cl.headE(), + c : Lambda <- cl.headC(), + n : Int <- cl.headN() in + { + cl.removeHead(); + c.gen_closure_code(n, e, cl); + } + pool; + out_string("\n------------------cut here------------------\n"); + } + }; + + main() : Int { + { + i().print_self(); + out_string("\n"); + k().print_self(); + out_string("\n"); + s().print_self(); + out_string("\n"); + beta_reduce(app(app(app(s(), k()), i()), i())); + beta_reduce(app(app(k(),i()),i())); + gen_code(app(i(), i())); + gen_code(app(app(app(s(), k()), i()), i())); + gen_code(app(app(app(app(app(app(app(app(i(), k()), s()), s()), + k()), s()), i()), k()), i())); + gen_code(app(app(i(), app(k(), s())), app(k(), app(s(), s())))); + 0; + } + }; +}; diff --git a/src/debbuging/type_logger.py b/src/debbuging/type_logger.py new file mode 100644 index 000000000..2ca58e0a6 --- /dev/null +++ b/src/debbuging/type_logger.py @@ -0,0 +1,280 @@ +import semantics.visitor as visitor +from ast.inferencer_ast import ( + AssignNode, + AtomicNode, + AttrDeclarationNode, + BinaryNode, + BlocksNode, + CaseOptionNode, + MethodCallNode, + CaseNode, + ClassDeclarationNode, + MethodDeclarationNode, + ComplementNode, + ConditionalNode, + InstantiateNode, + IsVoidNode, + LetNode, + NotNode, + ProgramNode, + VarDeclarationNode, + LoopNode, +) +from semantics.tools import Context, Scope + + +class TypeLogger(object): + def __init__(self, context) -> None: + self.context: Context = context + + @visitor.on("node") + def visit(self, node, scope, tabs): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope: Scope, tabs=0): + ans = "\t" * tabs + f"\\__ProgramNode [ ... ]" + statements = "\n".join( + self.visit(child, scope.next_child(), tabs + 1) + for child in node.declarations + ) + return f"{ans}\n{statements}" + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope, tabs=0): + parent = "" if node.parent is None else f": {node.parent}" + attr_list = self.context.get_type(node.id, unpacked=True).attributes + name_list = ["self"] + for attr in attr_list: + name_list.append(attr.name) + format_scope = defined_format(name_list, scope, tabs) + ans = ( + "\t" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + ans += format_scope + features = "\n".join( + str(self.visit(child, scope, tabs + 1)) for child in node.features + ) + return f"{ans}\n{features}" + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope: Scope, tabs=0): + extra = computed_info(node) + ans = "\t" * tabs + f"\\__AttrDeclarationNode: {node.id} : {node.type}" + extra + if node.expr != None: + ans += f"\n{self.visit(node.expr, scope, tabs +1)}" + return f"{ans}" + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans = ( + "\t" * tabs + + f"\\__VarDeclarationNode: {node.id} : {node.type} = " + + extra + ) + if node.expr != None: + ans += f"\n{self.visit(node.expr, scope, tabs + 1)}" + return f"{ans}" + + @visitor.when(BlocksNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans = "\t" * tabs + "\\__BlocksNode: { ; ... ; }" + extra + body = "\n".join(self.visit(child, scope, tabs + 1) for child in node.expr_list) + return f"{ans}\n{body}" + + @visitor.when(ConditionalNode) + def visit(self, node, scope, tabs=0): + ifexpr = self.visit(node.condition, scope, tabs + 1) + thenexpr = self.visit(node.then_body, scope, tabs + 1) + elseexpr = self.visit(node.else_body, scope, tabs + 1) + extra = computed_info(node) + ans = ( + "\t" * tabs + + f"\\ConditionalNode: if then else {extra}\n" + ) + ifs = "\t" * (tabs + 1) + f"if:\n{ifexpr}\n" + ths = "\t" * (tabs + 1) + f"then:\n{thenexpr}\n" + els = "\t" * (tabs + 1) + f"else:\n{elseexpr}" + ans = ans + ifs + ths + els + return ans + + @visitor.when(CaseNode) + def visit(self, node, scope: Scope, tabs=0): + extra = computed_info(node) + header = ( + "\t" * tabs + f"\\CaseNode: case of ( => ...){extra}\n" + ) + caseexpr = self.visit(node.case_expr, scope, tabs + 1) + case = "\t" * (tabs + 1) + f"case:\n{caseexpr}\n" + # casevars = '\n'.join([self.visit(child, scope.next_child(), tabs + 1) for child in node.options]) + casevars = "\n".join( + [self.visit(child, scope.next_child(), tabs + 1) for child in node.options] + ) + of = "\t" * (tabs + 1) + f"of:\n{casevars}" + return header + case + of + + @visitor.when(CaseOptionNode) + def visit(self, node, scope: Scope, tabs=0): + type_info = computed_info(node) + return "\t" * (tabs) + "\\_" + node.id + ":" + node.type + type_info + + @visitor.when(LetNode) + def visit(self, node, scopex, tabs=0): + scope = scopex.next_child() + extra = computed_info(node) + header = ( + "\t" * tabs + f"\\LetNode: Let ( <- ...) in {extra}\n" + ) + name_list = [] + for name_var in node.var_decl_list: + name_list.append(name_var.id) + format_scope = defined_format(name_list, scope, tabs) + letvars = "\n".join( + self.visit(child, scope, tabs + 1) for child in node.var_decl_list + ) + expr = self.visit(node.in_expr, scope, tabs + 1) + let = "\t" * (tabs + 1) + f"let: \n{letvars}\n" + inx = "\t" * (tabs + 1) + f"in: \n{expr}" + return header + let + inx + + @visitor.when(LoopNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + header = "\t" * tabs + f"\\__LoopNode: while loop ( ){extra}\n" + body = self.visit(node.body, scope, tabs + 1) + whilex = self.visit(node.condition, scope, tabs + 1) + "\n" + text1 = "\t" * (tabs + 1) + f"while:\n {whilex}" + text2 = "\t" * (tabs + 1) + f"loop:\n {body}" + return header + text1 + text2 + + @visitor.when(AssignNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans = "\t" * tabs + f"\\__AssignNode: {node.id} = " + extra + expr = self.visit(node.expr, scope, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(MethodDeclarationNode) + def visit(self, node: MethodDeclarationNode, scopex, tabs=0): + scope = scopex.next_child() + extra = computed_info(node) + params = ", ".join([f"{param.id}:{param.type}" for param in node.params]) + ans = ( + "\t" * tabs + + f"\\__MethodDeclarationNode: {node.id}({params}) : {node.type}" + + extra + ) + name_list = [] + for param in node.params: + name_list.append(param.id) + format_scope = defined_format(name_list, scope, tabs) + ans += format_scope + body = "\n" + self.visit(node.body, scope, tabs + 1) + return f"{ans}{body}" + + @visitor.when(IsVoidNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans1 = "\t" * tabs + f"\\__IsVoidNode: isvoid " + extra + ans2 = self.visit(node.expr, scope, tabs + 1) + return ans1 + "\n" + ans2 + + @visitor.when(ComplementNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans1 = "\t" * tabs + f"\\ComplementNode: ~ " + extra + ans2 = self.visit(node.expr, scope, tabs + 1) + return ans1 + "\n" + ans2 + + @visitor.when(NotNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans1 = "\t" * tabs + f"\\__NotNode: not " + extra + ans2 = self.visit(node.expr, scope, tabs + 1) + return ans1 + "\n" + ans2 + + # @visitor.when(IsVoidDeclarationNode) + # def visit(self, node, scope, tabs=0): + # extra = computed_info(node) + # ans1 = '\t' * tabs + f'\\__IsVoidNode: isvoid ' + extra + # ans2 = self.visit(node.lex, scope, tabs+1) + # return ans1 + "\n" + ans2 + + @visitor.when(BinaryNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + extra + left = self.visit(node.left, scope, tabs + 1) + right = self.visit(node.right, scope, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.value}" + extra + + @visitor.when(MethodCallNode) + def visit(self, node, scope, tabs=0): + extra = computed_info(node) + extra2 = "" + if node.caller_type: + extra2 = node.caller_type.name + "." + ans = ( + "\t" * tabs + + f"\\__MethodCallNode: {extra2}{node.id}(, ..., )" + + extra + ) + args = "\n".join(self.visit(arg, scope, tabs + 1) for arg in node.args) + if len(node.args) > 0: + return f"{ans}\n{args}" + return f"{ans}" + + @visitor.when(InstantiateNode) + def visit(self, node, scope, tabs=0): + return "\t" * tabs + f"\\__ InstantiateNode: new {node.value}()" + + +def defined_format(name_list: list, scope: Scope, tabs=0): + if len(name_list) == 0: + return "" + + header = "\n" + "\t" * tabs + f" Variables Defined:" + "\n" + "\t" * tabs + " | " + defined = str("\n" + "\t" * tabs + f" | ").join( + [defined_info(name, scope) for name in name_list] + ) + end = "\n" + "\t" * tabs + f" -----------------------------------" + return header + defined + end + + +def defined_info(name: str, scope: Scope, only_local=True): + if only_local and not scope.is_local(name): + return f'' + var = scope.find_variable(name) + if not only_local and not var: + return f'' + try: + return f"{var.name}:{var.type.name}" + except AttributeError: + return f'' + + +def computed_info(node): + return " -> " + node.inferenced_type.name + try: + if node.type != "AUTO_TYPE": + return "" + except AttributeError: + pass + try: + node.computed_type + try: + return f" -> {node.computed_type.name}" + except AttributeError: + return ( + f" -> " + ) + except AttributeError: + return " -> " diff --git a/src/debdev.py b/src/debdev.py new file mode 100644 index 000000000..6a2fbe426 --- /dev/null +++ b/src/debdev.py @@ -0,0 +1,81 @@ +import os + +from debbuging import type_logger +from parsing import parser +from semantics import type_collector, type_builder, soft_inferencer + + +def format_errors(errors, s=""): + count = 1 + errors.sort(key=lambda x: x[0]) + for error in errors: + num = str(count) if count > 9 else "0" + str(count) + s += num + ". " + error[1] + "\n" + count += 1 + return s + + +def run_pipeline(program): + ast = parser.parse(program) + + collector = type_collector.TypeCollector() + collector.visit(ast) + context = collector.context + errors = collector.errors + # print('Context\n', context) + + builder = type_builder.TypeBuilder(context, errors) + builder.visit(ast) + # print('Context\n', context) + + soft = soft_inferencer.SoftInferencer(context) + soft_ast = soft.visit(ast) + + # auto_inferencer = autotype_inferencer.AutotypeInferencer(context, errors) + # auto_inferencer.visit(ast, scope) + + logger = type_logger.TypeLogger(context) + log = logger.visit(soft_ast, soft_ast.scope) + print(log) + s = "Semantic Errors:\n" + s = format_errors(errors, s) + print(s) + + +try: + misc = r"./tests/Misc" + auto = r"./tests/Auto" + folder_path = auto + filenames = os.listdir(folder_path) + filenames.sort() +except FileNotFoundError: + print("Error Importing Files") +count = 100 + +filenames = [ + r"/home/rodro/Aarka/Complementos de Compilacion/cool-cows/src/debbuging/tests/Auto/" + r"01Assign.cl" +] + +for filename in filenames: + if count == 0: + print("Reach Count Limit") + break + + path = os.path.join(folder_path, filename) + file = open(path, "r") + program = file.read() + file.close() + + print(f"Running {filename}") + run_pipeline(program) + count -= 1 + print("-------------------------------------------------------------------------\n") + if len(filenames) > 1: + # input() + pass + +print("EndOfFiles") + + +# todo: Manejar los self types dentro de los type bags correctamente (acualizar metodo swap swlf types) \ No newline at end of file From a6ee42db8a494836573f01f878dd63c615591418 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 17:04:27 -0400 Subject: [PATCH 048/432] Added back_inferencer, the last stage of inferencing --- src/semantics/back_inferencer.py | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/semantics/back_inferencer.py diff --git a/src/semantics/back_inferencer.py b/src/semantics/back_inferencer.py new file mode 100644 index 000000000..9e46d6029 --- /dev/null +++ b/src/semantics/back_inferencer.py @@ -0,0 +1,78 @@ +from ast.inferencer_ast import ( + ClassDeclarationNode, + ProgramNode, + AttrDeclarationNode, + Node, +) +from semantics.tools import Context, Scope, try_conform +import semantics.visitor as visitor + +# Reducir los AUTO_TYPE declarados a base de el tipo de sus expresiones: + +# No te debe hacer falta tirar ningun metodo nuevo, es solo ensamblar. + +# Si te hace falta algo en tools.py al final hay varios metodos para trabajar con +# tipos, si no entiendes me escribes o me llamas. Si crees que te hace falta realizar +# una operacion que esos metodos no satisfacen la annades al repertorio, pero avisame +# tambien xq puede estar tirado por una esquina algo que haga algo parecido + + +class BackInferencer: + def __init__(self, context: Context) -> None: + self.context = context + self.errors = [] + self.current_type = None + + @visitor.on("node") + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode) -> ProgramNode: + scope: Scope = node.scope + new_declaration = [] + for declaration in node.declarations: + new_declaration.append(self.visit(declaration, scope.next_child())) + + program = ProgramNode(new_declaration, scope, node) + return program + + @visitor.when(ClassDeclarationNode) + def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: + self.current_type = self.context.get_type(node.id, unpacked=True) + + new_features = [] + for feature in node.features: + new_features.append(self.visit(feature, scope)) + + class_node = ClassDeclarationNode(new_features, node) + return class_node + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + attr_node = AttrDeclarationNode(node) + + if not node.expr: + return attr_node + + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + + decl_type = node.inferenced_type + # try conforms trata de disminuir la bolsa de tipos de decl_type a base de los que tiene + # expr_type, en caso de que se quede vacio, se mantiene sin cambios en la bolsa grande + decl_type = try_conform(decl_type, expr_type) + + attr_node.expr = expr_node + attr_node.inferenced_type = decl_type + return attr_node + + # Ten ojo con los selftype dentro de los typebags ... Antes de trabajar con los selftypes + # tienes que cambiarlo por el tipo determinado segun el contexo, utiliza el metodo + # swap_self_type de los objetos TypeBag para realizar esto. Si se te escapa un selftype cuando + # se intente realizar una operacion con el se lanza error + + # Este metodo deberia ser innecesario pues ya todos los errores han sido recogidos previamente + def add_error(self, node: Node, text: str): + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line, col), f"({line}, {col}) - " + text)) \ No newline at end of file From 137399ff725be80859ecfb42cabdae4439415aba Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 15 Apr 2021 23:17:38 -0400 Subject: [PATCH 049/432] Minor fixes ... Added expression property to MethodCallNode from inferencer_ast.py Change comments in back_inferencer to satisfy flake8 Fixed error reporting in soft_inferencer Added heads properties to ErrorType --- src/ast/inferencer_ast.py | 5 +- src/semantics/back_inferencer.py | 19 ++--- src/semantics/soft_inferencer.py | 119 +++++++++++++------------------ src/semantics/tools.py | 1 + 4 files changed, 65 insertions(+), 79 deletions(-) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 6a18c36b4..508479aab 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -104,7 +104,7 @@ def __init__(self, node): self.id = node.id self.expr = None # Expression is set later if it exists self.defined = False - # For debbugi purposes + # For debbugin purposes self.type = node.type @@ -117,9 +117,10 @@ def __init__(self, expr, node): class MethodCallNode(ExpressionNode): - def __init__(self, caller_type, args, node): + def __init__(self, caller_type, expression, args, node): Node.__init__(self, node) self.caller_type = caller_type + self.expression = expression self.args = args self.id = node.id diff --git a/src/semantics/back_inferencer.py b/src/semantics/back_inferencer.py index 9e46d6029..6133f6771 100644 --- a/src/semantics/back_inferencer.py +++ b/src/semantics/back_inferencer.py @@ -59,20 +59,21 @@ def visit(self, node, scope): expr_type = expr_node.inferenced_type decl_type = node.inferenced_type - # try conforms trata de disminuir la bolsa de tipos de decl_type a base de los que tiene - # expr_type, en caso de que se quede vacio, se mantiene sin cambios en la bolsa grande + # try conforms trata de disminuir la bolsa de tipos de decl_type a base de los + # que tiene expr_type, en caso de que se quede vacio, se mantiene sin cambios + # en la bolsa decl_type decl_type = try_conform(decl_type, expr_type) attr_node.expr = expr_node attr_node.inferenced_type = decl_type return attr_node - # Ten ojo con los selftype dentro de los typebags ... Antes de trabajar con los selftypes - # tienes que cambiarlo por el tipo determinado segun el contexo, utiliza el metodo - # swap_self_type de los objetos TypeBag para realizar esto. Si se te escapa un selftype cuando - # se intente realizar una operacion con el se lanza error + # Ten ojo con los selftype dentro de los typebags ... Antes de trabajar con los + # selftypes tienes que cambiarlo por el tipo determinado segun el contexo, utiliza + # el metodo swap_self_type de los objetos TypeBag para realizar esto. Si se te + # escapa un selftype cuando se intente realizar una operacion con el se lanza error - # Este metodo deberia ser innecesario pues ya todos los errores han sido recogidos previamente + # Este metodo deber ser innecesario pues todos los errores son recogidos previamente def add_error(self, node: Node, text: str): - line, col = node.get_position() if node else (0, 0) - self.errors.append(((line, col), f"({line}, {col}) - " + text)) \ No newline at end of file + line, col = node.get_position() if node is not None else (0, 0) + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/soft_inferencer.py b/src/semantics/soft_inferencer.py index ffdbae32d..e84d86312 100644 --- a/src/semantics/soft_inferencer.py +++ b/src/semantics/soft_inferencer.py @@ -89,8 +89,8 @@ def visit(self, node, scope): expr_node = self.visit(node.expr, scope) node_expr = expr_node.inferenced_type - expr_clone = node_expr.clone() + expr_clone = node_expr.clone() if not conforms(node_expr, node_type): self.add_error( node, @@ -121,17 +121,15 @@ def visit(self, node, scopex: Scope): if not conforms(ret_type_expr, ret_type_decl): self.add_error( node, - ( - f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}'" - f"return expression type({ret_expr_clone.name}) does not conforms to" - f"declared return type ({ret_type_decl.name})" - ), + f"Type Error: In Class '{self.current_type.name}' method " + f"'{current_method.name}' return expression type({ret_expr_clone.name})" + f" does not conforms todeclared return type ({ret_type_decl.name})", ) body_node.inferenced_type = ErrorType() ret_type_decl.swap_self_type(self.current_type, back=True) - method_node = inf_ast.MethodDeclarationNode(ret_type_decl, body_node, node) + method_node = inf_ast.MethodDeclarationNode(node.type, body_node, node) method_node.inferenced_type = ret_type_decl return method_node @@ -156,10 +154,8 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - ( - f"Type Error: If's condition type({condition_clone.name})" - "does not conforms to Bool type.", - ), + f"Type Error: If's condition type({condition_clone.name})" + " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -190,10 +186,8 @@ def visit(self, node, scope: Scope): if var_type in types_visited: self.add_error( node, - ( - "Semantic Error: Case Expression can't have branches" - f"with same case type({var_type.name})", - ), + "Semantic Error: Case Expression can't have branches" + f"with same case type({var_type.name})", ) joined_type = join_list(type_list) @@ -227,10 +221,8 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - ( - f"Type Error: Loop condition type({condition_clone.name})" - "does not conforms to Bool type.", - ), + f"Type Error: Loop condition type({condition_clone.name})" + " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -271,7 +263,8 @@ def visit(self, node, scope: Scope): else: self.add_error( node, - f"Semantic Error: Variable '{node.id}' already defined in current scope.", + f"Semantic Error: Variable '{node.id}' already defined" + " in current scope.", ) node_type = ErrorType() @@ -284,7 +277,9 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, node_type): self.add_error( node, - f"Semantic Error: Variable '{node.id}' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).", + f"Semantic Error: Variable '{node.id}' expressiontype" + f"({expr_clone.name}) does not conforms to declared" + f"type({node_type.name}).", ) expr_node.inferenced_type = ErrorType() var_decl_node.expr = expr_node @@ -293,29 +288,27 @@ def visit(self, node, scope: Scope): @visitor.when(AssignNode) def visit(self, node, scope: Scope): - expr_node = self.visit(node.expr, scope) assign_node = inf_ast.AssignNode(expr_node, node) var = scope.find_variable(node.id) if not var: self.add_error( - ( - f"Scope Error: Cannot assign new value to" - f"{node.id} beacuse it is not defined in the current scope" - ) + node, + f"Scope Error: Cannot assign new value to" + f"{node.id} beacuse it is not defined in the current scope", ) decl_type = ErrorType() else: - # decl type should not have selftype .swap_self_type(self.current_type) - decl_type = var.type + decl_type = var.type.swap_self_type(self.current_type) assign_node.defined = True if var is not None: if var.name == "self": self.add_error( node, - "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.", + "Semantic Error: Cannot assign new value. " + "Variable 'self' is Read-Only.", ) decl_type = ErrorType() @@ -324,11 +317,9 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, decl_type): self.add_error( node, - ( - f"Type Error: Cannot assign new value to variable '{node.id}'." - f"Expression type({expr_clone.name}) does not conforms to" - f"declared type ({decl_type.name}).", - ), + f"Type Error: Cannot assign new value to variable '{node.id}'." + f" Expression type({expr_clone.name}) does not conforms to" + f" declared type ({decl_type.name}).", ) expr_node.inferenced_type = ErrorType() @@ -337,14 +328,15 @@ def visit(self, node, scope: Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): - if node.expr == None: + if node.expr is None: + expr_node = None caller_type = TypeBag({self.current_type}) - elif node.type == None: - caller_node = self.visit(node.expr, scope) - caller_type = caller_node.inferenced_type + elif node.type is None: + expr_node = self.visit(node.expr, scope) + caller_type = expr_node.inferenced_type else: - bridge_node = self.visit(node.expr, scope) - bridge_type = bridge_node.inferenced_type + expr_node = self.visit(node.expr, scope) + bridge_type = expr_node.inferenced_type caller_type = self.context.get_type( node.type, selftype=False, autotype=False ) @@ -353,11 +345,9 @@ def visit(self, node, scope): if not conforms(bridge_type, caller_type): self.add_error( node, - ( - f"Semantic Error: Cannot effect dispatch because expression" - f"type({bridge_clone.name}) does not conforms to " - f"caller type({caller_type.name}).", - ), + f"Semantic Error: Cannot effect dispatch because expression" + f"type({bridge_clone.name}) does not conforms to " + f"caller type({caller_type.name}).", ) caller_type = ErrorType() @@ -371,11 +361,9 @@ def visit(self, node, scope): else: self.add_error( node, - ( - f"Semantic Error: There is no method '{node.id}'" - f"that recieves {len(node.params)} arguments in" - f"types {caller_type.name}.", - ), + f"Semantic Error: There is no method '{node.id}'" + f"that recieves {len(node.params)} arguments in" + f"types {caller_type.name}.", ) caller_type = ErrorType() elif len(caller_type.type_set) == 1: @@ -385,11 +373,9 @@ def visit(self, node, scope): except SemanticError: self.add_error( node, - ( - f"Semantic Error: There is no method '{node.id}'" - f"that recieves {len(node.params)} arguments in" - f"Type '{caller_type.name}'.", - ), + f"Semantic Error: There is no method '{node.id}'" + f"that recieves {len(node.params)} arguments in" + f"Type '{caller_type.name}'.", ) caller_type = ErrorType() @@ -397,7 +383,9 @@ def visit(self, node, scope): for i in range(len(node.args)): new_args.append(self.visit(node.args[i], scope)) - method_call_node = inf_ast.MethodCallNode(caller_type, new_args, node) + method_call_node = inf_ast.MethodCallNode( + caller_type, expr_node, new_args, node + ) if methods: type_set = set() @@ -437,6 +425,7 @@ def visit(self, node, scope): f"Type Error: Arithmetic Error: Right member type({right_clone.name})" "does not conforms to Int type.", ) + right_node.inferenced_type = ErrorType() arith_node = inf_ast.ArithmeticNode(left_node, right_node, node) arith_node.inferenced_type = int_type @@ -456,19 +445,15 @@ def visit(self, node, scope): if not conforms(left_type, right_type): self.add_error( node, - ( - f"Type Error: Left expression type({left_clone.name})" - f"does not conforms to right expression type({right_type.name})", - ), + f"Type Error: Left expression type({left_clone.name})" + f"does not conforms to right expression type({right_type.name})", ) left_node.inferenced_type = ErrorType() elif not conforms(right_type, left_type): self.add_error( node, - ( - f"Type Error: Right expression type({right_clone.name})" - f"does not conforms to left expression type({left_type.name})", - ), + f"Type Error: Right expression type({right_clone.name})" + f"does not conforms to left expression type({left_type.name})", ) right_node.inferenced_type = ErrorType() @@ -521,10 +506,8 @@ def visit(self, node, scope): if not conforms(expr_type, node_type): self.add_error( node, - ( - f"Type Error: ~ expresion type({expr_clone.name} does not" - " conforms to Int type", - ), + f"Type Error: ~ expresion type({expr_clone.name} does not" + " conforms to Int type", ) node_type = ErrorType() diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 62569bec8..f1ad940bb 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -407,6 +407,7 @@ def __init__(self): self.name = "" self.index = 2 ** 32 self.type_set = frozenset() + self.heads = frozenset() def conforms_to(self, other): return True From 2c5a7f08926a468336ca3afcead87727d7628e86 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 16 Apr 2021 16:28:55 -0400 Subject: [PATCH 050/432] Refactor some code --- src/__main__.py | 22 ++ src/debbuging/type_logger.py | 2 +- src/debdev.py | 7 +- src/semantics/errors.py | 22 ++ src/semantics/inference/__init__.py | 4 + .../{ => inference}/autotype_collector.py | 240 ++++++++++++------ .../{ => inference}/autotype_inferencer.py | 18 +- .../{ => inference}/back_inferencer.py | 2 +- .../{ => inference}/soft_inferencer.py | 4 +- src/semantics/tools.py | 53 ++-- src/semantics/type_builder.py | 6 +- src/semantics/type_collector.py | 9 +- src/semantics/utils.py | 22 -- src/utils/__init__.py | 1 + src/{semantics => utils}/visitor.py | 0 tests/codegen_test.py | 30 +-- tests/lexer/iis1_error.txt | 2 +- tests/lexer_test.py | 11 +- tests/parser_test.py | 22 +- tests/semantic_test.py | 24 +- tests/utils/utils.py | 6 + 21 files changed, 328 insertions(+), 179 deletions(-) create mode 100644 src/__main__.py create mode 100644 src/semantics/errors.py create mode 100644 src/semantics/inference/__init__.py rename src/semantics/{ => inference}/autotype_collector.py (66%) rename src/semantics/{ => inference}/autotype_inferencer.py (95%) rename src/semantics/{ => inference}/back_inferencer.py (98%) rename src/semantics/{ => inference}/soft_inferencer.py (99%) delete mode 100644 src/semantics/utils.py create mode 100644 src/utils/__init__.py rename src/{semantics => utils}/visitor.py (100%) diff --git a/src/__main__.py b/src/__main__.py new file mode 100644 index 000000000..bd3fe9258 --- /dev/null +++ b/src/__main__.py @@ -0,0 +1,22 @@ +import sys + +from lexing import lexer + + +def main(): + + if len(sys.argv) > 1: + input_file = sys.argv[1] + else: + raise Exception("Incorrect number of arguments") + + program = open(input_file).read() + lexer.input(program) + for token in lexer: + a = token + if lexer.errors: + print(lexer.errors[0]) + exit(1) + + +main() diff --git a/src/debbuging/type_logger.py b/src/debbuging/type_logger.py index 2ca58e0a6..e0424e109 100644 --- a/src/debbuging/type_logger.py +++ b/src/debbuging/type_logger.py @@ -1,4 +1,4 @@ -import semantics.visitor as visitor +from utils import visitor from ast.inferencer_ast import ( AssignNode, AtomicNode, diff --git a/src/debdev.py b/src/debdev.py index 6a2fbe426..8e46ff5b3 100644 --- a/src/debdev.py +++ b/src/debdev.py @@ -2,7 +2,8 @@ from debbuging import type_logger from parsing import parser -from semantics import type_collector, type_builder, soft_inferencer +from semantics import type_collector, type_builder +from semantics.inference import soft_inferencer def format_errors(errors, s=""): @@ -53,8 +54,8 @@ def run_pipeline(program): count = 100 filenames = [ - r"/home/rodro/Aarka/Complementos de Compilacion/cool-cows/src/debbuging/tests/Auto/" - r"01Assign.cl" + r"/home/adrian/Desktop/4to/PrimerSemestre/ComplementosCompilacion/cool-compiler-2021/src/cool_example.cl" + # r"01Assign.cl" ] for filename in filenames: diff --git a/src/semantics/errors.py b/src/semantics/errors.py new file mode 100644 index 000000000..08fc80eeb --- /dev/null +++ b/src/semantics/errors.py @@ -0,0 +1,22 @@ +class InternalError(Exception): + @property + def text(self): + return "Internal Error: " + self.args[0] + + +class SemanticError(Exception): + @property + def text(self): + return "Semantic Error: " + self.args[0] + + +class TypeError(SemanticError): + @property + def text(self): + return "Type Error: " + self.args[0] + + +class AttributeError(SemanticError): + @property + def text(self): + return "Attribute Error: " + self.args[0] \ No newline at end of file diff --git a/src/semantics/inference/__init__.py b/src/semantics/inference/__init__.py new file mode 100644 index 000000000..273ae535a --- /dev/null +++ b/src/semantics/inference/__init__.py @@ -0,0 +1,4 @@ +from .autotype_collector import AutotypeCollector +from .autotype_inferencer import AutotypeInferencer +from .soft_inferencer import SoftInferencer +from .back_inferencer import BackInferencer diff --git a/src/semantics/autotype_collector.py b/src/semantics/inference/autotype_collector.py similarity index 66% rename from src/semantics/autotype_collector.py rename to src/semantics/inference/autotype_collector.py index f7ae41ce6..2dc23b7e3 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/inference/autotype_collector.py @@ -1,24 +1,61 @@ -from semantics.tools import conforms, join, join_list, smart_add -import semantics.visitor as visitor -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, Node, NotNode, ProgramNode, StringNode, VarDeclarationNode, VariableNode +from ast.parser_ast import ( + ArithmeticNode, + AssignNode, + AttrDeclarationNode, + BlocksNode, + BooleanNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComparerNode, + ComplementNode, + ConditionalNode, + InstantiateNode, + IntNode, + IsVoidNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + Node, + NotNode, + ProgramNode, + StringNode, + VarDeclarationNode, + VariableNode, +) + +from utils import visitor +from semantics.tools import ( + Context, + ErrorType, + Scope, + SelfType, + SemanticError, + TypeBag, + conforms, + join, + join_list, + smart_add, +) + class AutotypeCollector: - def __init__(self, context:Context, errors): + def __init__(self, context: Context, errors): self.context = context self.current_type = None self.errors = errors - - @visitor.on('node') + + @visitor.on("node") def visit(self, node, scope): pass @visitor.when(ProgramNode) - def visit(self, node:ProgramNode) -> Scope: + def visit(self, node: ProgramNode) -> Scope: scope = Scope() for declaration in node.declarations: self.visit(declaration, scope.create_child()) - + return scope @visitor.when(ClassDeclarationNode) @@ -27,63 +64,74 @@ def visit(self, node, scope): scope.define_variable("self", TypeBag({self.current_type})) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) - + for feature in node.features: self.visit(feature, scope) - + @visitor.when(AttrDeclarationNode) def visit(self, node, scope): - node_type = self.current_type.get_attribute(node.id).type.swap_self_type(self.current_type) + node_type = self.current_type.get_attribute(node.id).type.swap_self_type( + self.current_type + ) if not node.expr: node.inferenced_type = node_type return - + self.visit(node.expr, scope) node_expr = node.expr.inferenced_type expr_clone = node_expr.clone() if not conforms(node_expr, node_type): - self.add_error(node, f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({expr_clone.name}) does not conforms to declared type ({node_type.name}).") + self.add_error( + node, + f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({expr_clone.name}) does not conforms to declared type ({node_type.name}).", + ) # What is made error type here!!! 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) - + ret_type_decl = current_method.return_type.swap_self_type(self.current_type) self.visit(node.body, scope) ret_type_expr = node.body.inferenced_type ret_expr_clone = ret_type_expr.clone() if not conforms(ret_type_expr, ret_type_decl): - self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})") + self.add_error( + node, + f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})", + ) ret_type_expr = ErrorType() node.inferenced_type = ret_type_expr - ret_type_decl.swap_self_type(self.current_type, back = True) - + ret_type_decl.swap_self_type(self.current_type, back=True) + @visitor.when(BlocksNode) def visit(self, node, scope): for expr in node.expr_list: self.visit(expr, scope) node.inferenced_type = node.expr_list[-1].inferenced_type - + @visitor.when(ConditionalNode) def visit(self, node, scope): self.visit(node.condition, scope) condition_type = node.condition.inferenced_type bool_type = self.context.get_type("Bool") - + condition_clone = condition_type.clone() if not conforms(condition_clone, bool_type): - self.add_error(node, f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.") + self.add_error( + node, + f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.", + ) self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type @@ -92,9 +140,9 @@ def visit(self, node, scope): joined_type = join(then_type, else_type) node.inferenced_type = joined_type - + @visitor.when(CaseNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): self.visit(node.case_expr, scope) type_list = [] @@ -105,11 +153,14 @@ def visit(self, node, scope:Scope): type_list.append(option.inferenced_type) var_type = child.find_variable(option.id).type if var_type in types_visited: - self.add_error(node, f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})") - + self.add_error( + node, + f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})", + ) + joined_type = join_list(type_list) node.inferenced_type = joined_type - + @visitor.when(CaseOptionNode) def visit(self, node, scope): try: @@ -117,7 +168,7 @@ def visit(self, node, scope): except SemanticError as err: self.add_error(node, err) node_type = ErrorType() - + scope.define_variable(node.id, node_type) self.visit(node.expr, scope) node.inferenced_type = node.expr.inferenced_type @@ -127,14 +178,17 @@ def visit(self, node, scope): self.visit(node.condition, scope) condition_type = node.condition.inferenced_type bool_type = self.context.get_type("Bool") - + condition_clone = condition_type.clone() if not conforms(condition_clone, bool_type): - self.add_error(node, f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.") + self.add_error( + node, + f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.", + ) self.visit(node.body, scope) node.inferenced_type = self.context.get_type("Object") - + @visitor.when(LetNode) def visit(self, node, scope): child = scope.create_child() @@ -142,33 +196,41 @@ def visit(self, node, scope): self.visit(var, child) self.visit(node.in_expr, child) 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) + 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: - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' already defined in current scope.") + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' already defined in current scope.", + ) node.defined = False node_type = ErrorType() - + if node.expr: self.visit(node.expr, scope) expr_type = node.expr.inferenced_type expr_clone = expr_type.clone() if not conforms(expr_type, node_type): - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).") - + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).", + ) + node.inferenced_type = node_type @visitor.when(AssignNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): var = scope.find_variable(node.id) if not var: var_type = ErrorType() @@ -176,19 +238,25 @@ def visit(self, node, scope:Scope): 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 node_type = var_type - if var and var.name != 'self': + if var and var.name != "self": node_expr_clone = node.expr.inferenced_type.clone() if not conforms(node_expr, var_type): - self.add_error(node, f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).") + self.add_error( + node, + f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).", + ) node_type = ErrorType() var.type = var_type - elif var.name =='self': - self.add_error(node, "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.") + elif var.name == "self": + self.add_error( + node, + "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.", + ) node_type = ErrorType() node.inferenced_type = node_type @@ -207,10 +275,11 @@ def visit(self, node, scope): bridge_clone = bridge.clone() if not conforms(bridge, caller): - self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") + self.add_error( + node, + f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).", + ) caller = ErrorType() - - methods = None if len(caller.type_set) > 1: @@ -220,14 +289,20 @@ def visit(self, node, scope): if len(caller.type_set): methods = [(t, t.get_method) for t in caller.heads] else: - self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Types {caller.name}.") + self.add_error( + node, + f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Types {caller.name}.", + ) caller = ErrorType() elif len(caller.type_set) == 1: caller_type = caller.heads[0] try: methods = [(caller_type, caller_type.get_method(node.id))] except SemanticError: - self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Type \'{caller.name}\'.") + self.add_error( + node, + f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Type '{caller.name}'.", + ) caller = ErrorType() if methods: @@ -247,7 +322,7 @@ def visit(self, node, scope): else: node.inferenced_type = ErrorType() node.inferenced_caller = caller - + @visitor.when(ArithmeticNode) def visit(self, node, scope): self.visit(node.left, scope) @@ -260,10 +335,16 @@ def visit(self, node, scope): int_type = self.context.get_type("Int") if not conforms(left_type, int_type): - self.add_error(node.left, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") + self.add_error( + node.left, + f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.", + ) if not conforms(right_type, int_type): - self.add_error(node.right, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") - + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.", + ) + node.inferenced_type = int_type @visitor.when(ComparerNode) @@ -277,13 +358,18 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") left_clone = left_type.clone() right_clone = right_type.clone() - if not conforms(left_clone, right_type) and not conforms(right_clone, left_type): - self.add_error(node, f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})") + if not conforms(left_clone, right_type) and not conforms( + right_clone, left_type + ): + self.add_error( + node, + f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})", + ) node.inferenced_type = bool_type - + @visitor.when(VariableNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): var = scope.find_variable(node.value) if var: node.defined = True @@ -291,7 +377,9 @@ def visit(self, node, scope:Scope): else: node.defined = False var_type = ErrorType() - self.add_error(node, f"Semantic Error: Variable '{node.value}' is not defined.") + self.add_error( + node, f"Semantic Error: Variable '{node.value}' is not defined." + ) node.inferenced_type = var_type @visitor.when(NotNode) @@ -301,49 +389,59 @@ def visit(self, node, scope): expr_clone = expr_type.clone() bool_type = self.context.get_type("Bool") if not conforms(expr_type, bool_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type") + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to 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 expr_clone = expr_type.clone() node_type = self.context.get_type("Int") - + if not conforms(expr_type, node_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type") + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type", + ) node_type = ErrorType() - + node.inferenced_type = node_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.value, selftype=False, autotype=False) + node_type = self.context.get_type( + node.value, selftype=False, autotype=False + ) except SemanticError as err: - self.add_error(f"Semantic Error: Could not instantiate type '{node.value}'.") + self.add_error( + f"Semantic Error: Could not instantiate type '{node.value}'." + ) 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") - def add_error(self, node:Node, text:str): + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/autotype_inferencer.py b/src/semantics/inference/autotype_inferencer.py similarity index 95% rename from src/semantics/autotype_inferencer.py rename to src/semantics/inference/autotype_inferencer.py index 7f04dbdcd..6e5984953 100644 --- a/src/semantics/autotype_inferencer.py +++ b/src/semantics/inference/autotype_inferencer.py @@ -1,7 +1,15 @@ -from parsing.parsing_rules import p_param -import semantics.visitor as visitor -from parsing.ast import ArithmeticNode, AssignNode, AttrDeclarationNode, BlocksNode, CaseNode, CaseOptionNode, ClassDeclarationNode, ComparerNode, ComplementNode, ConditionalNode, EqualsNode, IsVoidNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, Node, NotNode, ProgramNode, VarDeclarationNode, VariableNode -from semantics.tools import Context, ErrorType, Scope, TypeBag, conforms, equal, join, join_list, smart_add +from ast.parser_ast import (ArithmeticNode, AssignNode, AttrDeclarationNode, + BlocksNode, CaseNode, CaseOptionNode, + ClassDeclarationNode, ComparerNode, ComplementNode, + ConditionalNode, EqualsNode, IsVoidNode, LetNode, + LoopNode, MethodCallNode, MethodDeclarationNode, + Node, NotNode, ProgramNode, VarDeclarationNode, + VariableNode) + +from utils import visitor +from semantics.tools import (Context, ErrorType, Scope, TypeBag, conforms, + equal, join, join_list, smart_add) + class AutotypeInferencer: def __init__(self, context:Context, errors) -> None: @@ -330,4 +338,4 @@ def add_error(self, node:Node, text:str): #todo: AutoType checking for later: #todo: Redefined methods with params and return type are autotypes #todo: Check use of self types inside auto types, how does it affects, etc... - #todo: \ No newline at end of file + #todo: diff --git a/src/semantics/back_inferencer.py b/src/semantics/inference/back_inferencer.py similarity index 98% rename from src/semantics/back_inferencer.py rename to src/semantics/inference/back_inferencer.py index 6133f6771..4dc86c4f5 100644 --- a/src/semantics/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -5,7 +5,7 @@ Node, ) from semantics.tools import Context, Scope, try_conform -import semantics.visitor as visitor +from utils import visitor # Reducir los AUTO_TYPE declarados a base de el tipo de sus expresiones: diff --git a/src/semantics/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py similarity index 99% rename from src/semantics/soft_inferencer.py rename to src/semantics/inference/soft_inferencer.py index e84d86312..e5322d2b3 100644 --- a/src/semantics/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -26,12 +26,12 @@ VariableNode, ) -import semantics.visitor as visitor +from utils import visitor +from semantics.errors import SemanticError from semantics.tools import ( Context, ErrorType, Scope, - SemanticError, TypeBag, conforms, join, diff --git a/src/semantics/tools.py b/src/semantics/tools.py index f1ad940bb..48bd1867e 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -2,31 +2,7 @@ from collections import OrderedDict from typing import FrozenSet, List, Set -from semantics.utils import conform_to_condition, from_dict_to_set, order_set_by_index - - -class InternalError(Exception): - @property - def text(self): - return "Internal Error: " + self.args[0] - - -class SemanticError(Exception): - @property - def text(self): - return "Semantic Error: " + self.args[0] - - -class TypeError(SemanticError): - @property - def text(self): - return "Type Error: " + self.args[0] - - -class AttributeError(SemanticError): - @property - def text(self): - return "Attribute Error: " + self.args[0] +from semantics.errors import * class Attribute: @@ -663,3 +639,30 @@ def auto_add(type_set: set, head_list: list, bag: TypeBag): break head_list += [typex for typex in aux] return type_set + + +def conform_to_condition(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result + + +def order_set_by_index(type_set): + return sorted(list(type_set), key=lambda x: x.index) + + +def set_intersection(parent, type_set) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result + + +def from_dict_to_set(types: dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index f347f07c0..fd9c02a27 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,4 +1,4 @@ -import semantics.visitor as visitor +from utils import visitor from ast.parser_ast import ( Node, ProgramNode, @@ -6,8 +6,8 @@ MethodDeclarationNode, AttrDeclarationNode, ) -from semantics.tools import SemanticError, TypeBag -from semantics.tools import ErrorType, SelfType +from semantics.errors import SemanticError +from semantics.tools import SelfType,TypeBag,ErrorType from semantics.tools import Context diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index e7d2a1a01..6653bf579 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,10 +1,11 @@ -import semantics.visitor as visitor -from ast.parser_ast import Node, ProgramNode, ClassDeclarationNode -from semantics.tools import SemanticError +from ast.parser_ast import ClassDeclarationNode, Node, ProgramNode + +from semantics.errors import SemanticError from semantics.tools import Context +from utils import visitor -class TypeCollector(object): +class TypeCollector: def __init__(self) -> None: self.context = Context() self.errors = [] diff --git a/src/semantics/utils.py b/src/semantics/utils.py deleted file mode 100644 index 3290eebee..000000000 --- a/src/semantics/utils.py +++ /dev/null @@ -1,22 +0,0 @@ -def conform_to_condition(type_set, parent) -> set: - set_result = set() - for typex in type_set: - if typex.conforms_to(parent): - set_result.add(typex) - return set_result - -def order_set_by_index(type_set): - return sorted(list(type_set), key = lambda x: x.index) - -def set_intersection(parent, type_set) -> set: - set_result = set() - for typex in type_set: - if typex.conforms_to(parent): - set_result.add(typex) - return set_result - -def from_dict_to_set(types:dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 000000000..100cda756 --- /dev/null +++ b/src/utils/__init__.py @@ -0,0 +1 @@ +from .visitor import * \ No newline at end of file diff --git a/src/semantics/visitor.py b/src/utils/visitor.py similarity index 100% rename from src/semantics/visitor.py rename to src/utils/visitor.py diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 48df768ff..598d7da01 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -1,17 +1,17 @@ -import pytest -import os -from utils import compare_outputs +# import pytest +# import os +# from utils import compare_outputs -tests_dir = __file__.rpartition('/')[0] + '/codegen/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +# tests_dir = __file__.rpartition('/')[0] + '/codegen/' +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -# @pytest.mark.lexer -# @pytest.mark.parser -# @pytest.mark.semantic -@pytest.mark.codegen -@pytest.mark.ok -@pytest.mark.run(order=4) -@pytest.mark.parametrize("cool_file", tests) -def test_codegen(compiler_path, cool_file): - compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ - tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file +# # @pytest.mark.lexer +# # @pytest.mark.parser +# # @pytest.mark.semantic +# @pytest.mark.codegen +# @pytest.mark.ok +# @pytest.mark.run(order=4) +# @pytest.mark.parametrize("cool_file", tests) +# def test_codegen(compiler_path, cool_file): +# compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ +# tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file diff --git a/tests/lexer/iis1_error.txt b/tests/lexer/iis1_error.txt index 9e6d66cac..8a81a2472 100644 --- a/tests/lexer/iis1_error.txt +++ b/tests/lexer/iis1_error.txt @@ -1 +1 @@ -(4, 2) - LexicographicError: ERROR "!" +(4,2) - LexicographicError: ERROR "!" diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 2a27223d3..e105f16db 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -2,12 +2,17 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/lexer/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests_dir = __file__.rpartition("/")[0] + "/lexer/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] + @pytest.mark.lexer @pytest.mark.error @pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + print(compiler_path) + print(cool_file) + compare_errors( + compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" + ) diff --git a/tests/parser_test.py b/tests/parser_test.py index d34c23bcf..67b74ed54 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -1,13 +1,13 @@ -import pytest -import os -from .utils import compare_errors +# import pytest +# import os +# from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/parser/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +# tests_dir = __file__.rpartition('/')[0] + '/parser/' +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.parser -@pytest.mark.error -@pytest.mark.run(order=2) -@pytest.mark.parametrize("cool_file", tests) -def test_parser_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file +# @pytest.mark.parser +# @pytest.mark.error +# @pytest.mark.run(order=2) +# @pytest.mark.parametrize("cool_file", tests) +# def test_parser_errors(compiler_path, cool_file): +# compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file diff --git a/tests/semantic_test.py b/tests/semantic_test.py index 62be0be16..b4bf38b1f 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -1,14 +1,14 @@ -import pytest -import os -from .utils import compare_errors, first_error_only_line +# import pytest +# import os +# from utils import compare_errors, first_error_only_line -tests_dir = __file__.rpartition('/')[0] + '/semantic/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +# tests_dir = __file__.rpartition('/')[0] + '/semantic/' +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -@pytest.mark.semantic -@pytest.mark.error -@pytest.mark.run(order=3) -@pytest.mark.parametrize("cool_file", tests) -def test_semantic_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ - cmp=first_error_only_line) \ No newline at end of file +# @pytest.mark.semantic +# @pytest.mark.error +# @pytest.mark.run(order=3) +# @pytest.mark.parametrize("cool_file", tests) +# def test_semantic_errors(compiler_path, cool_file): +# compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ +# cmp=first_error_only_line) \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 961cf7cbc..74d2f28db 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -14,7 +14,10 @@ ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' def parse_error(error: str): + print("ESTE ES EL ERROR") + print(error) merror = re.fullmatch(ERROR_FORMAT, error) + assert merror, BAD_ERROR_FORMAT % error return (t(x) for t, x in zip([int, int, str, str], merror.groups())) @@ -47,6 +50,9 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str try: sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() + print(sp.stderr) + print(f"code:{return_code}") + print(output) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From be6da1d64f5df79166607a04555b490340124b77 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 16 Apr 2021 20:34:24 -0400 Subject: [PATCH 051/432] Find problem in lexer --- .vscode/launch.json | 16 +++++++++++ src/__main__.py | 50 ++++++++++++++++++++++++++++++----- src/coolc.sh | 2 +- src/parsing/parsing_rules.py | 40 +++++++--------------------- src/semantics/__init__.py | 3 +++ src/semantics/tools.py | 8 +++--- src/semantics/type_checker.py | 13 +++++++++ src/test.cl | 1 + tests/utils/utils.py | 3 --- 9 files changed, 92 insertions(+), 44 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 src/semantics/type_checker.py create mode 100644 src/test.cl diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..63bc6be37 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + // "args": ["/home/adrian/Desktop/4to/PrimerSemestre/ComplementosCompilacion/cool-compiler-2021/src/debbuging/tests/Auto/00Simple.cl"] + } + ] +} \ No newline at end of file diff --git a/src/__main__.py b/src/__main__.py index bd3fe9258..6ee55af79 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,22 +1,60 @@ import sys from lexing import lexer +from parsing import parser +from semantics import TypeBuilder, TypeCollector, TypeChecker +from semantics.inference import ( + AutotypeCollector, + AutotypeInferencer, + BackInferencer, + SoftInferencer, +) +def run_pipeline(program_ast): + + collector = TypeCollector() + collector.visit(program_ast) + context = collector.context + errors = collector.errors + + builder = TypeBuilder(context, errors) + builder.visit(program_ast) + + soft = SoftInferencer(context) + soft_ast = soft.visit(program_ast) + + # auto_inferencer = autotype_inferencer.AutotypeInferencer(context, errors) + # auto_inferencer.visit(ast, scope) + + # logger = type_logger.TypeLogger(context) + # log = logger.visit(soft_ast, soft_ast.scope) + # print(log) + # s = "Semantic Errors:\n" + # s = format_errors(errors, s) + # print(s) + +input_file = "src/test.cl" + def main(): - - if len(sys.argv) > 1: - input_file = sys.argv[1] - else: - raise Exception("Incorrect number of arguments") + + # if len(sys.argv) > 1: + # input_file = sys.argv[1] + # else: + # raise Exception("Incorrect number of arguments") program = open(input_file).read() lexer.input(program) + tokens = [] for token in lexer: - a = token + tokens.append(token) if lexer.errors: print(lexer.errors[0]) exit(1) + # ast = parser.parse(program) + + # run_pipeline(ast) + main() diff --git a/src/coolc.sh b/src/coolc.sh index 34811cc42..0bfe5ff13 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,7 +4,7 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas +echo "CoolCow 0.1" # TODO: Recuerde cambiar estas echo "Copyright (c) 2021: Adrian, Rodrigo" # TODO: líneas a los valores correctos # Llamar al compilador diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py index 80ecc57e9..4f78e0c6b 100644 --- a/src/parsing/parsing_rules.py +++ b/src/parsing/parsing_rules.py @@ -1,34 +1,14 @@ +from ast.parser_ast import (AssignNode, AttrDeclarationNode, BlocksNode, + BooleanNode, CaseNode, CaseOptionNode, + ClassDeclarationNode, ComplementNode, + ConditionalNode, DivNode, EqualsNode, + InstantiateNode, IntNode, IsVoidNode, LessNode, + LessOrEqualNode, LetNode, LoopNode, MethodCallNode, + MethodDeclarationNode, MinusNode, NotNode, + PlusNode, ProgramNode, StarNode, StringNode, + VarDeclarationNode, VariableNode) + from lexing.lexing_rules import tokens -from ast.parser_ast import ( - AssignNode, - AttrDeclarationNode, - BlocksNode, - BooleanNode, - CaseNode, - CaseOptionNode, - ClassDeclarationNode, - ComplementNode, - ConditionalNode, - DivNode, - EqualsNode, - InstantiateNode, - IntNode, - IsVoidNode, - LessNode, - LessOrEqualNode, - LetNode, - LoopNode, - MethodCallNode, - MethodDeclarationNode, - MinusNode, - NotNode, - PlusNode, - ProgramNode, - StarNode, - StringNode, - VarDeclarationNode, - VariableNode, -) def p_program(p): diff --git a/src/semantics/__init__.py b/src/semantics/__init__.py index e69de29bb..f01080613 100644 --- a/src/semantics/__init__.py +++ b/src/semantics/__init__.py @@ -0,0 +1,3 @@ +from .type_checker import TypeChecker +from .type_builder import TypeBuilder +from .type_collector import TypeCollector \ No newline at end of file diff --git a/src/semantics/tools.py b/src/semantics/tools.py index 48bd1867e..a318ab0a5 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -1,6 +1,6 @@ import itertools as itt from collections import OrderedDict -from typing import FrozenSet, List, Set +from typing import FrozenSet, List, Set, Tuple from semantics.errors import * @@ -363,16 +363,16 @@ def __repr__(self): class FuncType(Type): - def __init__(self, name: str, params: List[Type], ret_type: Type) -> None: + def __init__(self, name: str, params: Tuple[Type, ...], ret_type: Type) -> None: self.name = name self.params = params self.ret_type = ret_type - def conforms_to(self, other, first): + def conforms_to(self, other): if not isinstance(other, FuncType): raise InternalError( ( - "A Function Type can only conform to other Function" + "A FunctionType can only conform to other Function" f"Type, not to {other.__class__.__name__}" ) ) diff --git a/src/semantics/type_checker.py b/src/semantics/type_checker.py new file mode 100644 index 000000000..553176aa3 --- /dev/null +++ b/src/semantics/type_checker.py @@ -0,0 +1,13 @@ +from utils import visitor + + +class TypeChecker: + def __init__(self) -> None: + pass + + @visitor.on("node") + def visit(self, node): + pass + + + \ No newline at end of file diff --git a/src/test.cl b/src/test.cl new file mode 100644 index 000000000..667f5006e --- /dev/null +++ b/src/test.cl @@ -0,0 +1 @@ +(*a \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 74d2f28db..87d6584b1 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -50,9 +50,6 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str try: sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() - print(sp.stderr) - print(f"code:{return_code}") - print(output) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From 8db04328bccf7290b643402cea6d0b5e1f0159ed Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 16 Apr 2021 23:09:23 -0400 Subject: [PATCH 052/432] Convert lexer to a class --- src/__main__.py | 32 ++- src/lexing/__init__.py | 7 +- src/lexing/{utils.py => errors.py} | 8 +- src/lexing/lexer.py | 287 ++++++++++++++++++++++++ src/lexing/lexing_rules.py | 279 ----------------------- src/parsing/__init__.py | 6 +- src/parsing/{utils.py => errors.py} | 0 src/parsing/parser.py | 328 ++++++++++++++++++++++++++++ src/parsing/parsetab.py | 110 +++++----- src/parsing/parsing_rules.py | 317 --------------------------- src/test.cl | 2 +- 11 files changed, 699 insertions(+), 677 deletions(-) rename src/lexing/{utils.py => errors.py} (71%) create mode 100644 src/lexing/lexer.py delete mode 100644 src/lexing/lexing_rules.py rename src/parsing/{utils.py => errors.py} (100%) create mode 100644 src/parsing/parser.py delete mode 100644 src/parsing/parsing_rules.py diff --git a/src/__main__.py b/src/__main__.py index 6ee55af79..72e96e270 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,7 +1,11 @@ import sys -from lexing import lexer -from parsing import parser +from ply.lex import lex + +from lexing import Lexer + +# from parsing import Parser +from parsing import Parser from semantics import TypeBuilder, TypeCollector, TypeChecker from semantics.inference import ( AutotypeCollector, @@ -34,8 +38,10 @@ def run_pipeline(program_ast): # s = format_errors(errors, s) # print(s) + input_file = "src/test.cl" + def main(): # if len(sys.argv) > 1: @@ -44,12 +50,24 @@ def main(): # raise Exception("Incorrect number of arguments") program = open(input_file).read() - lexer.input(program) - tokens = [] - for token in lexer: - tokens.append(token) + + lexer = Lexer() + + # parser = Parser(lexer) + # ast = parser.parse(program) + # print(ast) + + tokens = list(lexer.tokenize(program)) + # print(tokens) + # print(lexer.errors) + + # lexer.input(program) + # tokens = [] + # for token in lexer: + # # tokens.append(token) if lexer.errors: - print(lexer.errors[0]) + for error in lexer.errors: + print(error) exit(1) # ast = parser.parse(program) diff --git a/src/lexing/__init__.py b/src/lexing/__init__.py index 6259d314d..380c448d2 100644 --- a/src/lexing/__init__.py +++ b/src/lexing/__init__.py @@ -1,7 +1,2 @@ -from . import lexing_rules -from ply import lex +from .lexer import Lexer -lexer = lex.lex(module=lexing_rules) -# Set starting col -lexer.col = 1 -lexer.errors = [] diff --git a/src/lexing/utils.py b/src/lexing/errors.py similarity index 71% rename from src/lexing/utils.py rename to src/lexing/errors.py index 7ef56284f..04630810e 100644 --- a/src/lexing/utils.py +++ b/src/lexing/errors.py @@ -9,10 +9,4 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - - - -def set_pos(token): - token.col = token.lexer.col - token.line = token.lexer.lineno - token.lexer.col += len(token.value) \ No newline at end of file + \ No newline at end of file diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py new file mode 100644 index 000000000..332428f94 --- /dev/null +++ b/src/lexing/lexer.py @@ -0,0 +1,287 @@ +from .errors import LexicographicError +from ply import lex + + +class Lexer: + def __init__(self) -> None: + self.errors = [] + self.literals = [ + "+", + "-", + "*", + "/", + "~", + "=", + "<", + ":", + "{", + "}", + "@", + ",", + ".", + "(", + ")", + ";", + ] + # keywords + self.reserved = { + "true": "TRUE", + "false": "FALSE", + "if": "IF", + "then": "THEN", + "else": "ELSE", + "fi": "FI", + "class": "CLASS", + "inherits": "INHERITS", + "while": "WHILE", + "loop": "LOOP", + "pool": "POOL", + "let": "LET", + "in": "IN", + "case": "CASE", + "of": "OF", + "esac": "ESAC", + "new": "NEW", + "isvoid": "ISVOID", + "not": "NOT", + } + + self.tokens = [ + "LESSEQ", + "ASSIGN", + "RET", + "ID", + "TYPE", + "STRING", + "INT", + "COMMENT", + ] + self.tokens = self.tokens + list(self.reserved.values()) + self.states = (("aux", "exclusive"),) + self._end_comment = True + self._build() + + def _build(self): + self._lexer = lex.lex(module=self) + self._lexer.col = 0 + + def tokenize(self, data): + self._lexer.input(data) + while True: + tok = self._lexer.token() + if not self._end_comment: + line, col = self._get_current_pos(data) + self.errors.append(LexicographicError(line, col, "INVALID COMMENT")) + break + if not tok: + break + yield tok + + def _get_current_pos(self, data: str): + data = data[: self._lexer.lexpos] + line = data.count("\n") + 1 + col = len(data) - data.rfind("\n") + return line, col + + def _set_pos(self, token): + token.col = token.lexer.col + token.line = token.lexer.lineno + token.lexer.col += len(token.value) + + def t_LESSEQ(self, t): + r"\<=" + self._set_pos(t) + return t + + def t_ASSIGN(self, t): + r"\<-" + self._set_pos(t) + return t + + def t_RET(self, t): + r"\=>" + self._set_pos(t) + return t + + def t_TYPE(self, t): + r"[A-Z][a-zA-Z_0-9]*" + self._set_pos(t) + lower_case = t.value.lower() + if lower_case in ("true", "false"): + t.type = "TYPE" + return t + t.type = self.reserved.get(lower_case, "TYPE") + return t + + def t_ID(self, t): + r"[a-z_][a-zA-Z_0-9]*" + self._set_pos(t) + t.type = self.reserved.get(t.value.lower(), "ID") + return t + + def t_STRING(self, t): + r"\"([^\\\n]|(\\.))*?\"" + self._set_pos(t) + t.value = str(t.value) + return t + + def t_INT(self, t): + r"\d+" + self._set_pos(t) + t.value = int(t.value) + return t + + # One-line comments rule + def t_COMMENT(self, t): + r"(--.*(\n | $))" + t.lexer.lineno += 1 + t.col = t.lexer.col + t.lexer.col = 1 + + # Multiline comments rules + def t_aux(self, t): + r"\(\*" + t.lexer.comm_start = t.lexer.lexpos - 2 + t.lexer.level = 1 + t.lexer.begin("aux") + + def t_aux_lcomment(self, t): + r"\(\*" + t.lexer.level += 1 + + def t_aux_rcomment(self, t): + r"\*\)" + t.lexer.level -= 1 + if t.lexer.level == 0: + t.value = t.lexer.lexdata[t.lexer.comm_start : t.lexer.lexpos] + t.type = "COMMENT" + t.lexer.lineno += t.value.count("\n") + t.lexer.col = len(t.value) - t.value.rfind("\n") + self._end_comment = True + t.lexer.begin("INITIAL") + + def t_aux_pass(self, t): + r".|\n" + self._end_comment = False + pass + + # Rule so we can track line numbers + def t_newline(self, t): + r"\n+" + t.lexer.lineno += len(t.value) + t.lexer.col = 1 + + def t_WHITESPACE(self, t): + r"\s" + if t.value == "\t": + t.lexer.col += 4 + else: + t.lexer.col += len(t.value) + + def t_plus(self, t): + r"\+" + t.type = "+" + self._set_pos(t) + return t + + def t_minus(self, t): + r"-" + t.type = "-" + self._set_pos(t) + return t + + def t_star(self, t): + r"\*" + t.type = "*" + self._set_pos(t) + return t + + def t_slash(self, t): + r"/" + t.type = "/" + self._set_pos(t) + return t + + def t_neg(self, t): + r"~" + t.type = "~" + self._set_pos(t) + return t + + def t_equal(self, t): + r"=" + t.type = "=" + self._set_pos(t) + return t + + def t_less(self, t): + r"<" + t.type = "<" + self._set_pos(t) + return t + + def t_colon(self, t): + r":" + t.type = ":" + self._set_pos(t) + return t + + def t_ocur(self, t): + r"\{" + t.type = "{" + self._set_pos(t) + return t + + def t_ccur(self, t): + r"\}" + t.type = "}" + self._set_pos(t) + return t + + def t_at(self, t): + r"@" + t.type = "@" + self._set_pos(t) + return t + + def t_comma(self, t): + r"," + t.type = "," + self._set_pos(t) + return t + + def t_dot(self, t): + r"\." + t.type = "." + self._set_pos(t) + return t + + def t_opar(self, t): + r"\(" + t.type = "(" + self._set_pos(t) + return t + + def t_cpar(self, t): + r"\)" + t.type = ")" + self._set_pos(t) + return t + + def t_semicolon(self, t): + r";" + t.type = ";" + self._set_pos(t) + return t + + # Error handling rule + def t_ANY_error(self, t): + self._set_pos(t) + line = t.lineno + col = t.col + # it's an unterminated string + if t.value[0] == '"': + col = len(t.value) + self.errors.append(LexicographicError(line, col, t.value[0])) + t.lexer.skip(1) + return None diff --git a/src/lexing/lexing_rules.py b/src/lexing/lexing_rules.py deleted file mode 100644 index 00b301763..000000000 --- a/src/lexing/lexing_rules.py +++ /dev/null @@ -1,279 +0,0 @@ -from lexing.utils import LexicographicError, set_pos - -literals = [ - '+', '-', '*', '/', '~', '=', '<', ':', '{', - '}', '@', ',', '.', '(', ')', ';', '$' -] -# keywords -reserved = { - 'true': 'TRUE', - 'false': 'FALSE', - 'if': 'IF', - 'then': 'THEN', - 'else': 'ELSE', - 'fi': 'FI', - 'class': 'CLASS', - 'inherits': 'INHERITS', - 'while': 'WHILE', - 'loop': 'LOOP', - 'pool': 'POOL', - 'let': 'LET', - 'in': 'IN', - 'case': 'CASE', - 'of': 'OF', - 'esac': 'ESAC', - 'new': 'NEW', - 'isvoid': 'ISVOID', - 'not': 'NOT' -} - -tokens = [ - 'LESSEQ', - 'ASSIGN', - 'RET', - 'ID', - 'TYPE', - 'STRING', - 'INT', - 'COMMENT', -] -tokens = tokens + list(reserved.values()) - -states = ( - ('aux', 'exclusive'), -) - - -def t_LESSEQ(t): - r'\<=' - set_pos(t) - return t - - -def t_ASSIGN(t): - r'\<-' - set_pos(t) - return t - - -def t_RET(t): - r'\=>' - set_pos(t) - return t - -def t_TYPE(t): - r'[A-Z][a-zA-Z_0-9]*' - set_pos(t) - lower_case = t.value.lower() - if lower_case in ('true', 'false'): - t.type = 'TYPE' - return t - t.type = reserved.get(lower_case, 'TYPE') - return t - -def t_ID(t): - r'[a-z_][a-zA-Z_0-9]*' - set_pos(t) - t.type = reserved.get(t.value.lower(), 'ID') - return t - - -def t_STRING(t): - r'\"([^\\\n]|(\\.))*?\"' - set_pos(t) - t.value = str(t.value) - return t - - -def t_INT(t): - r'\d+' - set_pos(t) - t.value = int(t.value) - return t - -# One-line comments rule - - -def t_COMMENT(t): - r'(--.*(\n | $))' - t.lexer.lineno += 1 - t.col = t.lexer.col - t.lexer.col = 1 - # return t - -# Multiline comments rules - - -def t_aux(t): - r'\(\*' - t.lexer.comm_start = t.lexer.lexpos - 2 - t.lexer.level = 1 - t.lexer.begin('aux') - - -def t_aux_lcomment(t): - r'\(\*' - t.lexer.level += 1 - - -def t_aux_rcomment(t): - r'\*\)' - t.lexer.level -= 1 - if t.lexer.level == 0: - t.value = t.lexer.lexdata[t.lexer.comm_start:t.lexer.lexpos] - t.type = "COMMENT" - t.lexer.lineno += t.value.count('\n') - t.lexer.col = len(t.value) - t.value.rfind('\n') - t.lexer.begin('INITIAL') - # return t - - -def t_aux_pass(t): - r'.|\n' - pass - -# Rule so we can track line numbers - - -def t_newline(t): - r'\n+' - t.lexer.lineno += len(t.value) - t.lexer.col = 1 - - -def t_WHITESPACE(t): - r'\s' - if t.value == '\t': - t.lexer.col += 4 - else: - t.lexer.col += len(t.value) - - -def t_plus(t): - r'\+' - t.type = '+' - set_pos(t) - return t - - -def t_minus(t): - r'-' - t.type = '-' - set_pos(t) - return t - - -def t_star(t): - r'\*' - t.type = '*' - set_pos(t) - return t - - -def t_slash(t): - r'/' - t.type = '/' - set_pos(t) - return t - - -def t_neg(t): - r'~' - t.type = '~' - set_pos(t) - return t - - -def t_equal(t): - r'=' - t.type = '=' - set_pos(t) - return t - - -def t_less(t): - r'<' - t.type = '<' - set_pos(t) - return t - - -def t_colon(t): - r':' - t.type = ':' - set_pos(t) - return t - - -def t_ocur(t): - r'\{' - t.type = '{' - set_pos(t) - return t - - -def t_ccur(t): - r'\}' - t.type = '}' - set_pos(t) - return t - - -def t_at(t): - r'@' - t.type = '@' - set_pos(t) - return t - - -def t_comma(t): - r',' - t.type = ',' - set_pos(t) - return t - - -def t_dot(t): - r'\.' - t.type = '.' - set_pos(t) - return t - - -def t_opar(t): - r'\(' - t.type = '(' - set_pos(t) - return t - - -def t_cpar(t): - r'\)' - t.type = ')' - set_pos(t) - return t - - -def t_semicolon(t): - r';' - t.type = ';' - set_pos(t) - return t - - -def t_dollar(t): - r'\$' - t.type = '$' - set_pos(t) - return t - -# Error handling rule - - -def t_ANY_error(t): - set_pos(t) - t.lexer.errors.append(LexicographicError(t.lineno, t.col, t.value[0])) - t.lexer.skip(1) - - -# TODO: Handle errors inside comments (unbalanced multiline comments delimeters) \ No newline at end of file diff --git a/src/parsing/__init__.py b/src/parsing/__init__.py index 39f5bd97f..b8d5ea31a 100644 --- a/src/parsing/__init__.py +++ b/src/parsing/__init__.py @@ -1,5 +1 @@ -from ply import yacc -from . import parsing_rules - -parser = yacc.yacc(module=parsing_rules) -parser.errors = [] \ No newline at end of file +from .parser import Parser \ No newline at end of file diff --git a/src/parsing/utils.py b/src/parsing/errors.py similarity index 100% rename from src/parsing/utils.py rename to src/parsing/errors.py diff --git a/src/parsing/parser.py b/src/parsing/parser.py new file mode 100644 index 000000000..0ae06b83b --- /dev/null +++ b/src/parsing/parser.py @@ -0,0 +1,328 @@ +from ply.yacc import yacc +from ast.parser_ast import (AssignNode, AttrDeclarationNode, BlocksNode, + BooleanNode, CaseNode, CaseOptionNode, + ClassDeclarationNode, ComplementNode, + ConditionalNode, DivNode, EqualsNode, + InstantiateNode, IntNode, IsVoidNode, LessNode, + LessOrEqualNode, LetNode, LoopNode, MethodCallNode, + MethodDeclarationNode, MinusNode, NotNode, + PlusNode, ProgramNode, StarNode, StringNode, + VarDeclarationNode, VariableNode) + + +class Parser: + def __init__(self, lexer) -> None: + self.errors = [] + self.lexer = lexer + self.tokens = lexer.tokens + + self.precedence = ( + ("right", "ASSIGN"), + ("right", "NOT"), + ("nonassoc", "LESSEQ", "<", "="), + ("left", "+", "-"), + ("left", "*", "/"), + ("right", "ISVOID"), + ("left", "~"), + ("left", "@"), + ("left", "."), + ) + self._build() + + def _build(self): + self._parser = yacc(module=self) + + def parse(self,program): + return self._parser.parse(program) + + def p_program(self,p): + """program : class_list""" + p[0] = ProgramNode(p[1]) + + + def p_class_list(self,p): + """class_list : class ';' class_list + | class ';'""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + elif len(p) == 3: + p[0] = [p[1]] + + + def p_class(self,p): + """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' + | CLASS TYPE '{' feature_list '}'""" + if len(p) == 8: + p[0] = ClassDeclarationNode(p[2], p[6], p[4]) + elif len(p) == 6: + p[0] = ClassDeclarationNode(p[2], p[4]) + + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_feature_list(self,p): + """feature_list : attribute ';' feature_list + | method ';' feature_list + | empty""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + elif len(p) == 2: + p[0] = [] + + + def p_attribute(self,p): + """attribute : ID ':' TYPE ASSIGN expression + | ID ':' TYPE""" + if len(p) == 6: + p[0] = AttrDeclarationNode(p[1], p[3], p[5]) + else: + p[0] = AttrDeclarationNode(p[1], p[3]) + + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_method(self,p): + """method : ID '(' params_list ')' ':' TYPE '{' expression '}'""" + p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_params_list(self,p): + """params_list : param ',' params_list + | param""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + + def p_params_list_empty(self,p): + """params_list : empty""" + p[0] = [] + + + def p_param(self,p): + """param : ID ':' TYPE""" + p[0] = VarDeclarationNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_list(self,p): + """expression_list : expression ';' expression_list + | expression ';'""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + elif len(p) == 3: + p[0] = [p[1]] + + + def p_expression_assigment(self,p): + """expression : ID ASSIGN expression""" + p[0] = AssignNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_if_then_else(self,p): + """expression : IF expression THEN expression ELSE expression FI""" + p[0] = ConditionalNode(p[2], p[4], p[6]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_while(self,p): + """expression : WHILE expression LOOP expression POOL""" + p[0] = LoopNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_block(self,p): + """expression : '{' expression_list '}'""" + p[0] = BlocksNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_let_in(self,p): + """expression : LET let_list IN expression""" + p[0] = LetNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_let_list(self,p): + """let_list : let_single ',' let_list + | let_single""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + + def p_let_single(self,p): + """let_single : ID ':' TYPE ASSIGN expression + | ID ':' TYPE""" + if len(p) == 6: + p[0] = VarDeclarationNode(p[1], p[3], p[5]) + else: + p[0] = VarDeclarationNode(p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_case(self,p): + """expression : CASE expression OF case_list ESAC""" + p[0] = CaseNode(p[2], p[4]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_case_list(self,p): + """case_list : case_single case_list + | case_single""" + if len(p) == 3: + p[0] = [p[1]] + p[2] + else: + p[0] = [p[1]] + + + def p_case_single(self,p): + """case_single : ID ':' TYPE RET expression ';'""" + p[0] = CaseOptionNode(p[1], p[3], p[5]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_dispatch(self,p): + """expression : expression '@' TYPE '.' ID '(' args_list ')' + | expression '.' ID '(' args_list ')' + | ID '(' args_list ')'""" + if len(p) == 9: + p[0] = MethodCallNode(p[1], p[3], p[5], p[7]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + elif len(p) == 7: + p[0] = MethodCallNode(p[1], None, p[3], p[5]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + else: + p[0] = MethodCallNode(None, None, p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_args_list(self,p): + """args_list : expression ',' args_list + | expression""" + if len(p) == 4: + p[0] = [p[1]] + p[3] + else: + p[0] = [p[1]] + + + def p_args_list_empty(self,p): + """args_list : empty""" + p[0] = [] + + + def p_expression_instatiate(self,p): + """expression : NEW TYPE""" + p[0] = InstantiateNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_isvoid(self,p): + """expression : ISVOID expression""" + p[0] = IsVoidNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_not(self,p): + """expression : NOT expression""" + p[0] = NotNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_complement(self,p): + """expression : '~' expression""" + p[0] = ComplementNode(p[2]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_plus(self,p): + """expression : expression '+' expression""" + p[0] = PlusNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_minus(self,p): + """expression : expression '-' expression""" + p[0] = MinusNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_div(self,p): + """expression : expression '/' expression""" + p[0] = DivNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_star(self,p): + """expression : expression '*' expression""" + p[0] = StarNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_less(self,p): + """expression : expression '<' expression""" + p[0] = LessNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_lesseq(self,p): + """expression : expression LESSEQ expression""" + p[0] = LessOrEqualNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_equals(self,p): + """expression : expression '=' expression""" + p[0] = EqualsNode(p[1], p[3]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + + def p_expression_parentheses(self,p): + """expression : '(' expression ')'""" + p[0] = p[2] + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_string(self,p): + """expression : STRING""" + p[0] = StringNode(p[1]) + p[0].set_position(p.slice[1].lineno, p.slice[1].col) + + + def p_expression_variable(self,p): + """expression : ID""" + p[0] = VariableNode(p[1]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_true(self,p): + """expression : TRUE""" + p[0] = BooleanNode(True) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_false(self,p): + """expression : FALSE""" + p[0] = BooleanNode(False) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_expression_int(self,p): + """expression : INT""" + p[0] = IntNode(p[1]) + p[0].set_position(p.slice[1].line, p.slice[1].col) + + + def p_empty(self,p): + """empty : """ + p[0] = [] + + + def p_error(self,t): + print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 1eae9561b..4ca3752b3 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,7 +6,7 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " _lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} @@ -27,58 +27,58 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parsing_rules.py',35), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',40), - ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',41), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',49), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',50), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',60), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',61), - ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',62), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',70), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',71), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',81), - ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',87), - ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',88), - ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',96), - ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',101), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',107), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',108), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',116), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',122), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',128), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',134), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',140), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',146), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',147), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',155), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',156), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',165), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',171), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',172), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',180), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',186), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',187), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',188), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',203), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',204), - ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',212), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',217), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',223), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',229), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',235), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',241), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',247), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',253), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',259), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',265), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',271), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',277), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',283), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',289), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',295), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',301), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',307), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',313), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',319), + ('program -> class_list','program',1,'p_program','parsing_rules.py',39), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',44), + ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',45), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',53), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',54), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',64), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',65), + ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',66), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',74), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',75), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',85), + ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',91), + ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',92), + ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',100), + ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',105), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',111), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',112), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',120), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',126), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',132), + ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',138), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',144), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',150), + ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',151), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',159), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',160), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',169), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',175), + ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',176), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',184), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',190), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',191), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',192), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',207), + ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',208), + ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',216), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',221), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',227), + ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',233), + ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',239), + ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',245), + ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',251), + ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',257), + ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',263), + ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',269), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',275), + ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',281), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',287), + ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',293), + ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',299), + ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',305), + ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',311), + ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',317), + ('empty -> ','empty',0,'p_empty','parsing_rules.py',323), ] diff --git a/src/parsing/parsing_rules.py b/src/parsing/parsing_rules.py deleted file mode 100644 index 4f78e0c6b..000000000 --- a/src/parsing/parsing_rules.py +++ /dev/null @@ -1,317 +0,0 @@ -from ast.parser_ast import (AssignNode, AttrDeclarationNode, BlocksNode, - BooleanNode, CaseNode, CaseOptionNode, - ClassDeclarationNode, ComplementNode, - ConditionalNode, DivNode, EqualsNode, - InstantiateNode, IntNode, IsVoidNode, LessNode, - LessOrEqualNode, LetNode, LoopNode, MethodCallNode, - MethodDeclarationNode, MinusNode, NotNode, - PlusNode, ProgramNode, StarNode, StringNode, - VarDeclarationNode, VariableNode) - -from lexing.lexing_rules import tokens - - -def p_program(p): - """program : class_list""" - p[0] = ProgramNode(p[1]) - - -def p_class_list(p): - """class_list : class ';' class_list - | class ';'""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - elif len(p) == 3: - p[0] = [p[1]] - - -def p_class(p): - """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' - | CLASS TYPE '{' feature_list '}'""" - if len(p) == 8: - p[0] = ClassDeclarationNode(p[2], p[6], p[4]) - elif len(p) == 6: - p[0] = ClassDeclarationNode(p[2], p[4]) - - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_feature_list(p): - """feature_list : attribute ';' feature_list - | method ';' feature_list - | empty""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - elif len(p) == 2: - p[0] = [] - - -def p_attribute(p): - """attribute : ID ':' TYPE ASSIGN expression - | ID ':' TYPE""" - if len(p) == 6: - p[0] = AttrDeclarationNode(p[1], p[3], p[5]) - else: - p[0] = AttrDeclarationNode(p[1], p[3]) - - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_method(p): - """method : ID '(' params_list ')' ':' TYPE '{' expression '}'""" - p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_params_list(p): - """params_list : param ',' params_list - | param""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - else: - p[0] = [p[1]] - - -def p_params_list_empty(p): - """params_list : empty""" - p[0] = [] - - -def p_param(p): - """param : ID ':' TYPE""" - p[0] = VarDeclarationNode(p[1], p[3]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_list(p): - """expression_list : expression ';' expression_list - | expression ';'""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - elif len(p) == 3: - p[0] = [p[1]] - - -def p_expression_assigment(p): - """expression : ID ASSIGN expression""" - p[0] = AssignNode(p[1], p[3]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_if_then_else(p): - """expression : IF expression THEN expression ELSE expression FI""" - p[0] = ConditionalNode(p[2], p[4], p[6]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_while(p): - """expression : WHILE expression LOOP expression POOL""" - p[0] = LoopNode(p[2], p[4]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_block(p): - """expression : '{' expression_list '}'""" - p[0] = BlocksNode(p[2]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_let_in(p): - """expression : LET let_list IN expression""" - p[0] = LetNode(p[2], p[4]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_let_list(p): - """let_list : let_single ',' let_list - | let_single""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - else: - p[0] = [p[1]] - - -def p_let_single(p): - """let_single : ID ':' TYPE ASSIGN expression - | ID ':' TYPE""" - if len(p) == 6: - p[0] = VarDeclarationNode(p[1], p[3], p[5]) - else: - p[0] = VarDeclarationNode(p[1], p[3]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_case(p): - """expression : CASE expression OF case_list ESAC""" - p[0] = CaseNode(p[2], p[4]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_case_list(p): - """case_list : case_single case_list - | case_single""" - if len(p) == 3: - p[0] = [p[1]] + p[2] - else: - p[0] = [p[1]] - - -def p_case_single(p): - """case_single : ID ':' TYPE RET expression ';'""" - p[0] = CaseOptionNode(p[1], p[3], p[5]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_dispatch(p): - """expression : expression '@' TYPE '.' ID '(' args_list ')' - | expression '.' ID '(' args_list ')' - | ID '(' args_list ')'""" - if len(p) == 9: - p[0] = MethodCallNode(p[1], p[3], p[5], p[7]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - elif len(p) == 7: - p[0] = MethodCallNode(p[1], None, p[3], p[5]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - else: - p[0] = MethodCallNode(None, None, p[1], p[3]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_args_list(p): - """args_list : expression ',' args_list - | expression""" - if len(p) == 4: - p[0] = [p[1]] + p[3] - else: - p[0] = [p[1]] - - -def p_args_list_empty(p): - """args_list : empty""" - p[0] = [] - - -def p_expression_instatiate(p): - """expression : NEW TYPE""" - p[0] = InstantiateNode(p[2]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_isvoid(p): - """expression : ISVOID expression""" - p[0] = IsVoidNode(p[2]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_not(p): - """expression : NOT expression""" - p[0] = NotNode(p[2]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_complement(p): - """expression : '~' expression""" - p[0] = ComplementNode(p[2]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_plus(p): - """expression : expression '+' expression""" - p[0] = PlusNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_minus(p): - """expression : expression '-' expression""" - p[0] = MinusNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_div(p): - """expression : expression '/' expression""" - p[0] = DivNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_star(p): - """expression : expression '*' expression""" - p[0] = StarNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_less(p): - """expression : expression '<' expression""" - p[0] = LessNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_lesseq(p): - """expression : expression LESSEQ expression""" - p[0] = LessOrEqualNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_equals(p): - """expression : expression '=' expression""" - p[0] = EqualsNode(p[1], p[3]) - p[0].set_position(p.slice[2].line, p.slice[2].col) - - -def p_expression_parentheses(p): - """expression : '(' expression ')'""" - p[0] = p[2] - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_string(p): - """expression : STRING""" - p[0] = StringNode(p[1]) - p[0].set_position(p.slice[1].lineno, p.slice[1].col) - - -def p_expression_variable(p): - """expression : ID""" - p[0] = VariableNode(p[1]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_true(p): - """expression : TRUE""" - p[0] = BooleanNode(True) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_false(p): - """expression : FALSE""" - p[0] = BooleanNode(False) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_expression_int(p): - """expression : INT""" - p[0] = IntNode(p[1]) - p[0].set_position(p.slice[1].line, p.slice[1].col) - - -def p_empty(p): - """empty : """ - p[0] = [] - - -def p_error(t): - print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") - - -precedence = ( - ("right", "ASSIGN"), - ("right", "NOT"), - ("nonassoc", "LESSEQ", "<", "="), - ("left", "+", "-"), - ("left", "*", "/"), - ("right", "ISVOID"), - ("left", "~"), - ("left", "@"), - ("left", "."), -) diff --git a/src/test.cl b/src/test.cl index 667f5006e..c9cdc63b0 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1 +1 @@ -(*a \ No newline at end of file +_ \ No newline at end of file From d039ca2c0841398ff8ac7ce3a1a8d503c2fa7307 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 22 Apr 2021 01:01:19 -0400 Subject: [PATCH 053/432] Change lexer rstata name from 'aux' to 'comment' --- src/__main__.py | 8 ++++---- src/lexing/lexer.py | 25 +++++++++++++++---------- src/test.cl | 5 ++++- tests/utils/utils.py | 1 + 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 72e96e270..b10852899 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -44,10 +44,10 @@ def run_pipeline(program_ast): def main(): - # if len(sys.argv) > 1: - # input_file = sys.argv[1] - # else: - # raise Exception("Incorrect number of arguments") + if len(sys.argv) > 1: + input_file = sys.argv[1] + else: + raise Exception("Incorrect number of arguments") program = open(input_file).read() diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index 332428f94..a719772b3 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -54,11 +54,12 @@ def __init__(self) -> None: "TYPE", "STRING", "INT", - "COMMENT", + "ONELINECOMMENT", ] self.tokens = self.tokens + list(self.reserved.values()) - self.states = (("aux", "exclusive"),) + self.states = (("comment", "exclusive"),("string", "exclusive")) self._end_comment = True + self._end_string = True self._build() def _build(self): @@ -114,7 +115,7 @@ def t_TYPE(self, t): return t def t_ID(self, t): - r"[a-z_][a-zA-Z_0-9]*" + r"[a-z][a-zA-Z_0-9]*" self._set_pos(t) t.type = self.reserved.get(t.value.lower(), "ID") return t @@ -132,35 +133,39 @@ def t_INT(self, t): return t # One-line comments rule - def t_COMMENT(self, t): + def t_ONELINECOMMENT(self, t): r"(--.*(\n | $))" t.lexer.lineno += 1 t.col = t.lexer.col t.lexer.col = 1 + # String rules + def t_string(): + pass + # Multiline comments rules - def t_aux(self, t): + def t_comment(self, t): r"\(\*" t.lexer.comm_start = t.lexer.lexpos - 2 t.lexer.level = 1 - t.lexer.begin("aux") + t.lexer.begin("comment") - def t_aux_lcomment(self, t): + def t_comment_lcomment(self, t): r"\(\*" t.lexer.level += 1 - def t_aux_rcomment(self, t): + def t_comment_rcomment(self, t): r"\*\)" t.lexer.level -= 1 if t.lexer.level == 0: t.value = t.lexer.lexdata[t.lexer.comm_start : t.lexer.lexpos] - t.type = "COMMENT" + t.type = "ONELINECOMMENT" t.lexer.lineno += t.value.count("\n") t.lexer.col = len(t.value) - t.value.rfind("\n") self._end_comment = True t.lexer.begin("INITIAL") - def t_aux_pass(self, t): + def t_comment_pass(self, t): r".|\n" self._end_comment = False pass diff --git a/src/test.cl b/src/test.cl index c9cdc63b0..55bf63886 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1 +1,4 @@ -_ \ No newline at end of file +"This \ +is OK" +"This is not +OK" \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 87d6584b1..dd1b370b6 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -50,6 +50,7 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str try: sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() + print(sp.stderr) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From fdc56aeba72223e3fa9ccff77ef4c617d6bbbfe3 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 22 Apr 2021 04:16:22 -0400 Subject: [PATCH 054/432] Lexer's tests passed --- src/lexing/lexer.py | 94 +++++++++++++++++++++++++++++++++++--------- src/test.cl | Bin 31 -> 233 bytes 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index a719772b3..f77f21b67 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -57,23 +57,34 @@ def __init__(self) -> None: "ONELINECOMMENT", ] self.tokens = self.tokens + list(self.reserved.values()) - self.states = (("comment", "exclusive"),("string", "exclusive")) - self._end_comment = True + self.states = (("comment", "exclusive"), ("string", "exclusive")) + + self._string_value = "" + self._string_start = -1 + self._string_col = -1 + self._string_line = -1 + self._string_slash = False self._end_string = True + + self._end_comment = True self._build() def _build(self): self._lexer = lex.lex(module=self) - self._lexer.col = 0 + self._lexer.col = 1 def tokenize(self, data): self._lexer.input(data) while True: tok = self._lexer.token() - if not self._end_comment: + if not self._end_comment and self._lexer.lexpos - 1 <= len(data): line, col = self._get_current_pos(data) self.errors.append(LexicographicError(line, col, "INVALID COMMENT")) break + if not self._end_string and self._lexer.lexpos -1 <= len(data) : + line = self._lexer.lineno + col = self._lexer.col + 1 + self.errors.append(LexicographicError(line, col, "UNTERMINATED STRING")) if not tok: break yield tok @@ -120,11 +131,6 @@ def t_ID(self, t): t.type = self.reserved.get(t.value.lower(), "ID") return t - def t_STRING(self, t): - r"\"([^\\\n]|(\\.))*?\"" - self._set_pos(t) - t.value = str(t.value) - return t def t_INT(self, t): r"\d+" @@ -140,14 +146,63 @@ def t_ONELINECOMMENT(self, t): t.lexer.col = 1 # String rules - def t_string(): - pass + def t_string(self, t): + r'"' + self._string_value = '"' + t.lexer.col += 1 + self._string_value += t.value + self._string_line = t.lexer.lineno + self._string_col = t.lexer.col - 1 + self._end_string = False + t.lexer.begin("string") + + + def t_string_end(self, t): + r'(?0}_xSe_!a!lI8Q=+1H%WBjvdG2^$^o zAwvhBY4OPO2){F<(KAKTd5ln9dqM9HgrY|L1yPTO5sTNno6!^i`aM3kLP%bnNn}^9 zgRN70SE^FAzndeQK1R06CqvFEiNaJ Date: Fri, 23 Apr 2021 10:23:12 -0400 Subject: [PATCH 055/432] Fixed bugs in tools.py --- src/semantics/tools.py | 37 ++++++++++++++++++++++--------------- src/semantics/utils.py | 7 +++++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index f1ad940bb..a01cfa1fd 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -2,6 +2,8 @@ from collections import OrderedDict from typing import FrozenSet, List, Set +from ply.yacc import errok + from semantics.utils import conform_to_condition, from_dict_to_set, order_set_by_index @@ -300,7 +302,7 @@ def update_heads(self): if head in self.type_set: new_heads.append(head) continue - new_heads = [] + pos_new_head = [] lower_index = 2 ** 32 for typex in self.type_set: if typex in visited: @@ -308,11 +310,11 @@ def update_heads(self): if typex.conforms_to(head): visited.add(typex) if typex.index < lower_index: - new_heads = [typex] + pos_new_head = [typex] lower_index = typex.index elif typex.index == lower_index: - new_heads.append(typex) - new_heads += new_heads + pos_new_head.append(typex) + new_heads += pos_new_head self.heads = new_heads def swap_self_type(self, swap_type, back=False): @@ -455,10 +457,10 @@ def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> T def get_method_by_name(self, name: str, args: int) -> list: def dfs(root: str, results: list): try: - for typex in self.type_tree[root]: + for typex in self.type_graph[root]: for method in self.types[typex].methods: if name == method.name and args == len(method.param_names): - results.append((method, self.types[typex])) + results.append((self.types[typex], method)) break else: dfs(typex, results) @@ -481,9 +483,14 @@ def __repr__(self): class VariableInfo: - def __init__(self, name, vtype): - self.name = name - self.type = vtype + def __init__(self, name, vtype) -> None: + self.name: str = name + self.type: TypeBag = vtype + + def get_type(self) -> TypeBag or ErrorType: + if isinstance(self.type, ErrorType): + self.type = ErrorType() + return self.type def __str__(self): return self.name + ":" + self.type @@ -553,7 +560,7 @@ def get_all_names(self, s: str = "", level: int = 0): return s -def conforms(bag1: TypeBag, bag2: TypeBag): +def conforms(bag1: TypeBag, bag2: TypeBag) -> bool: ordered_set = order_set_by_index(bag2.type_set) condition_list = [] @@ -575,7 +582,7 @@ def conforms(bag1: TypeBag, bag2: TypeBag): return len(bag1.type_set) >= 1 -def try_conform(bag1: TypeBag, bag2: TypeBag): +def try_conform(bag1: TypeBag, bag2: TypeBag) -> TypeBag: clone1 = bag1.clone() if not conforms(bag1, bag2): return clone1 @@ -655,11 +662,11 @@ def auto_add(type_set: set, head_list: list, bag: TypeBag): aux = set(bag.heads) for i in range(len(head_list)): head_i = head_list[i] - for head in bag.heads: - ancestor = head_i.least_common_ancestor(head) + for head_j in bag.heads: + ancestor = head_i.least_common_ancestor(head_j) if ancestor in type_set: - head_i[i] = ancestor - aux.pop(head) + head_list[i] = ancestor + aux.remove(head_j) break head_list += [typex for typex in aux] return type_set diff --git a/src/semantics/utils.py b/src/semantics/utils.py index 3290eebee..18e746c8f 100644 --- a/src/semantics/utils.py +++ b/src/semantics/utils.py @@ -5,8 +5,10 @@ def conform_to_condition(type_set, parent) -> set: set_result.add(typex) return set_result + def order_set_by_index(type_set): - return sorted(list(type_set), key = lambda x: x.index) + return sorted(list(type_set), key=lambda x: x.index) + def set_intersection(parent, type_set) -> set: set_result = set() @@ -15,7 +17,8 @@ def set_intersection(parent, type_set) -> set: set_result.add(typex) return set_result -def from_dict_to_set(types:dict): + +def from_dict_to_set(types: dict): type_set = set() for typex in types: type_set.add(types[typex]) From 016cbc0aacf5f81b16b5caed11cb49c9d04c4155 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:23:43 -0400 Subject: [PATCH 056/432] Added new AUTO_TYPE examples --- src/debbuging/tests/Auto/02Many.cl | 77 ++++++++++++++++++++++++++++++ src/debbuging/tests/Auto/03Many.cl | 71 +++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/debbuging/tests/Auto/02Many.cl create mode 100644 src/debbuging/tests/Auto/03Many.cl diff --git a/src/debbuging/tests/Auto/02Many.cl b/src/debbuging/tests/Auto/02Many.cl new file mode 100644 index 000000000..431484e89 --- /dev/null +++ b/src/debbuging/tests/Auto/02Many.cl @@ -0,0 +1,77 @@ +class Main inherits IO { + a : AUTO_TYPE; + b : AUTO_TYPE; + c : AUTO_TYPE; + d : AUTO_TYPE; + main(n : AUTO_TYPE) : AUTO_TYPE { + { + a.a(); + b.a(); + c.a(); + d.a(); + b.b(); + c.b(); + d.b(); + c.c(); + d.c(); + d.d(); + } + }; +}; + +class A +{ + a() : SELF_TYPE + { + self + }; +}; + +class B +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; +}; + +class C +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; + c() : SELF_TYPE + { + self + } ; +}; + +class D +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; + c() : SELF_TYPE + { + self + }; + d() : SELF_TYPE + { + self + }; +}; + diff --git a/src/debbuging/tests/Auto/03Many.cl b/src/debbuging/tests/Auto/03Many.cl new file mode 100644 index 000000000..0040d8760 --- /dev/null +++ b/src/debbuging/tests/Auto/03Many.cl @@ -0,0 +1,71 @@ +class Main inherits IO { + a : AUTO_TYPE; + b : AUTO_TYPE; + c : AUTO_TYPE; + d : AUTO_TYPE; + main(n : AUTO_TYPE) : AUTO_TYPE { + { + a <- b; + b <- c; + c <- d; + d.d(); + } + }; +}; + +class A +{ + a() : SELF_TYPE + { + self + }; +}; + +class B +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; +}; + +class C +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; + c() : SELF_TYPE + { + self + } ; +}; + +class D +{ + a() : SELF_TYPE + { + self + }; + b() : SELF_TYPE + { + self + }; + c() : SELF_TYPE + { + self + }; + d() : SELF_TYPE + { + self + }; +}; + From cf862da809371031a5d520bfbf50065086967f64 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:24:22 -0400 Subject: [PATCH 057/432] Updated git.ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f3c16e09f..6483fe2bf 100644 --- a/.gitignore +++ b/.gitignore @@ -429,3 +429,4 @@ src/zTests/Misc/10BiG.cl src/type_logger.py src/zTests/Auto/00Simple.cl src/zTests/Auto/01Assign.cl +src/semantics/notes.md From 2adde941d3e7f18c1d45f5bc012676d5bc3b83e4 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:25:05 -0400 Subject: [PATCH 058/432] Fixed SoftInferencer bugs --- src/semantics/soft_inferencer.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/semantics/soft_inferencer.py b/src/semantics/soft_inferencer.py index e84d86312..43ec7fc1f 100644 --- a/src/semantics/soft_inferencer.py +++ b/src/semantics/soft_inferencer.py @@ -336,17 +336,16 @@ def visit(self, node, scope): caller_type = expr_node.inferenced_type else: expr_node = self.visit(node.expr, scope) - bridge_type = expr_node.inferenced_type + expr_type = expr_node.inferenced_type caller_type = self.context.get_type( node.type, selftype=False, autotype=False ) - - bridge_clone = bridge_type.clone() - if not conforms(bridge_type, caller_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, caller_type): self.add_error( node, f"Semantic Error: Cannot effect dispatch because expression" - f"type({bridge_clone.name}) does not conforms to " + f"type({expr_clone.name}) does not conforms to " f"caller type({caller_type.name}).", ) caller_type = ErrorType() @@ -354,10 +353,12 @@ def visit(self, node, scope): methods = None if len(caller_type.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] + types = [typex for typex, _ in methods_by_name] conforms(caller_type, TypeBag(set(types), types)) if len(caller_type.type_set): - methods = [(typex, typex.get_method) for typex in caller_type.heads] + methods = [ + (typex, typex.get_method(node.id)) for typex in caller_type.heads + ] else: self.add_error( node, @@ -369,7 +370,7 @@ def visit(self, node, scope): elif len(caller_type.type_set) == 1: caller_type = caller_type.heads[0] try: - methods = [(caller_type, caller_type.get_method(node.id))] + methods = [(caller_type.get_method(node.id), caller_type)] except SemanticError: self.add_error( node, @@ -441,7 +442,6 @@ def visit(self, node, scope): right_type = right_node.inferenced_type right_clone = right_type.clone() - bool_type = self.context.get_type("Bool") if not conforms(left_type, right_type): self.add_error( node, @@ -458,7 +458,7 @@ def visit(self, node, scope): right_node.inferenced_type = ErrorType() comparer_node = inf_ast.ComparerNode(left_node, right_node, node) - comparer_node.inferenced_type = bool_type + comparer_node.inferenced_type = self.context.get_type("Bool") return comparer_node @visitor.when(VariableNode) @@ -467,8 +467,8 @@ def visit(self, node, scope: Scope): var = scope.find_variable(node.value) if var: - node.defined = True - var_type = var.type + var_node.defined = True + var_type = var.get_type() else: var_type = ErrorType() self.add_error( @@ -502,17 +502,17 @@ def visit(self, node, scope): expr_type = expr_node.inferenced_type expr_clone = expr_type.clone() - node_type = self.context.get_type("Int") - if not conforms(expr_type, node_type): + int_type = self.context.get_type("Int") + if not conforms(expr_type, int_type): self.add_error( node, f"Type Error: ~ expresion type({expr_clone.name} does not" " conforms to Int type", ) - node_type = ErrorType() + expr_node.inferenced_type = ErrorType() complement_node = inf_ast.ComplementNode(expr_node, node) - complement_node.inferenced_type = node_type + complement_node.inferenced_type = int_type return complement_node @visitor.when(IsVoidNode) From 6156d6c1e2ce2e479d6cd18118ed33fc8b6b353c Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:25:32 -0400 Subject: [PATCH 059/432] Minor fixes in legacy code --- src/semantics/autotype_collector.py | 229 +++++++++++++++++------- src/semantics/autotype_inferencer.py | 258 +++++++++++++++++---------- 2 files changed, 328 insertions(+), 159 deletions(-) diff --git a/src/semantics/autotype_collector.py b/src/semantics/autotype_collector.py index f7ae41ce6..ab3825bed 100644 --- a/src/semantics/autotype_collector.py +++ b/src/semantics/autotype_collector.py @@ -1,24 +1,50 @@ from semantics.tools import conforms, join, join_list, smart_add import semantics.visitor as visitor -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, Node, NotNode, ProgramNode, StringNode, VarDeclarationNode, VariableNode +from semantics.tools import Context, ErrorType, Scope, SemanticError, TypeBag +from ast.parser_ast import ( + ArithmeticNode, + AssignNode, + AttrDeclarationNode, + BlocksNode, + BooleanNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComparerNode, + ComplementNode, + ConditionalNode, + InstantiateNode, + IntNode, + IsVoidNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + Node, + NotNode, + ProgramNode, + StringNode, + VarDeclarationNode, + VariableNode, +) + class AutotypeCollector: - def __init__(self, context:Context, errors): + def __init__(self, context: Context, errors): self.context = context self.current_type = None self.errors = errors - - @visitor.on('node') + + @visitor.on("node") def visit(self, node, scope): pass @visitor.when(ProgramNode) - def visit(self, node:ProgramNode) -> Scope: + def visit(self, node: ProgramNode) -> Scope: scope = Scope() for declaration in node.declarations: self.visit(declaration, scope.create_child()) - + return scope @visitor.when(ClassDeclarationNode) @@ -27,63 +53,78 @@ def visit(self, node, scope): scope.define_variable("self", TypeBag({self.current_type})) for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) - + for feature in node.features: self.visit(feature, scope) - + @visitor.when(AttrDeclarationNode) def visit(self, node, scope): - node_type = self.current_type.get_attribute(node.id).type.swap_self_type(self.current_type) + node_type = self.current_type.get_attribute(node.id).type.swap_self_type( + self.current_type + ) if not node.expr: node.inferenced_type = node_type return - + self.visit(node.expr, scope) node_expr = node.expr.inferenced_type expr_clone = node_expr.clone() if not conforms(node_expr, node_type): - self.add_error(node, f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({expr_clone.name}) does not conforms to declared type ({node_type.name}).") + self.add_error( + node, + ( + f"Type Error: In class '{self.current_type.name}' attribue" + f"'{node.id}' expression type({expr_clone.name}) does not conforms" + f"to declared type ({node_type.name})." + ), + ) # What is made error type here!!! 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) - + ret_type_decl = current_method.return_type.swap_self_type(self.current_type) self.visit(node.body, scope) ret_type_expr = node.body.inferenced_type ret_expr_clone = ret_type_expr.clone() if not conforms(ret_type_expr, ret_type_decl): - self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})") + self.add_error( + node, + f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})", + ) ret_type_expr = ErrorType() node.inferenced_type = ret_type_expr - ret_type_decl.swap_self_type(self.current_type, back = True) - + ret_type_decl.swap_self_type(self.current_type, back=True) + @visitor.when(BlocksNode) def visit(self, node, scope): for expr in node.expr_list: self.visit(expr, scope) node.inferenced_type = node.expr_list[-1].inferenced_type - + @visitor.when(ConditionalNode) def visit(self, node, scope): self.visit(node.condition, scope) condition_type = node.condition.inferenced_type bool_type = self.context.get_type("Bool") - + condition_clone = condition_type.clone() if not conforms(condition_clone, bool_type): - self.add_error(node, f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.") + self.add_error( + node, + f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.", + ) self.visit(node.then_body, scope) then_type = node.then_body.inferenced_type @@ -92,9 +133,9 @@ def visit(self, node, scope): joined_type = join(then_type, else_type) node.inferenced_type = joined_type - + @visitor.when(CaseNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): self.visit(node.case_expr, scope) type_list = [] @@ -105,11 +146,14 @@ def visit(self, node, scope:Scope): type_list.append(option.inferenced_type) var_type = child.find_variable(option.id).type if var_type in types_visited: - self.add_error(node, f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})") - + self.add_error( + node, + f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})", + ) + joined_type = join_list(type_list) node.inferenced_type = joined_type - + @visitor.when(CaseOptionNode) def visit(self, node, scope): try: @@ -117,7 +161,7 @@ def visit(self, node, scope): except SemanticError as err: self.add_error(node, err) node_type = ErrorType() - + scope.define_variable(node.id, node_type) self.visit(node.expr, scope) node.inferenced_type = node.expr.inferenced_type @@ -127,14 +171,17 @@ def visit(self, node, scope): self.visit(node.condition, scope) condition_type = node.condition.inferenced_type bool_type = self.context.get_type("Bool") - + condition_clone = condition_type.clone() if not conforms(condition_clone, bool_type): - self.add_error(node, f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.") + self.add_error( + node, + f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.", + ) self.visit(node.body, scope) node.inferenced_type = self.context.get_type("Object") - + @visitor.when(LetNode) def visit(self, node, scope): child = scope.create_child() @@ -142,33 +189,41 @@ def visit(self, node, scope): self.visit(var, child) self.visit(node.in_expr, child) 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) + 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: - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' already defined in current scope.") + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' already defined in current scope.", + ) node.defined = False node_type = ErrorType() - + if node.expr: self.visit(node.expr, scope) expr_type = node.expr.inferenced_type expr_clone = expr_type.clone() if not conforms(expr_type, node_type): - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).") - + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).", + ) + node.inferenced_type = node_type @visitor.when(AssignNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): var = scope.find_variable(node.id) if not var: var_type = ErrorType() @@ -176,19 +231,25 @@ def visit(self, node, scope:Scope): 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 node_type = var_type - if var and var.name != 'self': + if var and var.name != "self": node_expr_clone = node.expr.inferenced_type.clone() if not conforms(node_expr, var_type): - self.add_error(node, f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).") + self.add_error( + node, + f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).", + ) node_type = ErrorType() var.type = var_type - elif var.name =='self': - self.add_error(node, "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.") + elif var.name == "self": + self.add_error( + node, + "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.", + ) node_type = ErrorType() node.inferenced_type = node_type @@ -207,10 +268,11 @@ def visit(self, node, scope): bridge_clone = bridge.clone() if not conforms(bridge, caller): - self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") + self.add_error( + node, + f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).", + ) caller = ErrorType() - - methods = None if len(caller.type_set) > 1: @@ -220,14 +282,20 @@ def visit(self, node, scope): if len(caller.type_set): methods = [(t, t.get_method) for t in caller.heads] else: - self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Types {caller.name}.") + self.add_error( + node, + f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Types {caller.name}.", + ) caller = ErrorType() elif len(caller.type_set) == 1: caller_type = caller.heads[0] try: methods = [(caller_type, caller_type.get_method(node.id))] except SemanticError: - self.add_error(node, f"Semantic Error: There is no method \'{node.id}\' that recieves {len(node.params)} arguments in Type \'{caller.name}\'.") + self.add_error( + node, + f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Type '{caller.name}'.", + ) caller = ErrorType() if methods: @@ -247,7 +315,7 @@ def visit(self, node, scope): else: node.inferenced_type = ErrorType() node.inferenced_caller = caller - + @visitor.when(ArithmeticNode) def visit(self, node, scope): self.visit(node.left, scope) @@ -260,10 +328,16 @@ def visit(self, node, scope): int_type = self.context.get_type("Int") if not conforms(left_type, int_type): - self.add_error(node.left, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") + self.add_error( + node.left, + f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.", + ) if not conforms(right_type, int_type): - self.add_error(node.right, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") - + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.", + ) + node.inferenced_type = int_type @visitor.when(ComparerNode) @@ -277,13 +351,18 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") left_clone = left_type.clone() right_clone = right_type.clone() - if not conforms(left_clone, right_type) and not conforms(right_clone, left_type): - self.add_error(node, f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})") + if not conforms(left_clone, right_type) and not conforms( + right_clone, left_type + ): + self.add_error( + node, + f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})", + ) node.inferenced_type = bool_type - + @visitor.when(VariableNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): var = scope.find_variable(node.value) if var: node.defined = True @@ -291,7 +370,9 @@ def visit(self, node, scope:Scope): else: node.defined = False var_type = ErrorType() - self.add_error(node, f"Semantic Error: Variable '{node.value}' is not defined.") + self.add_error( + node, f"Semantic Error: Variable '{node.value}' is not defined." + ) node.inferenced_type = var_type @visitor.when(NotNode) @@ -301,49 +382,59 @@ def visit(self, node, scope): expr_clone = expr_type.clone() bool_type = self.context.get_type("Bool") if not conforms(expr_type, bool_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type") + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to 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 expr_clone = expr_type.clone() node_type = self.context.get_type("Int") - + if not conforms(expr_type, node_type): - self.add_error(node, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type") + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type", + ) node_type = ErrorType() - + node.inferenced_type = node_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.value, selftype=False, autotype=False) + node_type = self.context.get_type( + node.value, selftype=False, autotype=False + ) except SemanticError as err: - self.add_error(f"Semantic Error: Could not instantiate type '{node.value}'.") + self.add_error( + f"Semantic Error: Could not instantiate type '{node.value}'." + ) 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") - def add_error(self, node:Node, text:str): + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/autotype_inferencer.py b/src/semantics/autotype_inferencer.py index 7f04dbdcd..d265d8df8 100644 --- a/src/semantics/autotype_inferencer.py +++ b/src/semantics/autotype_inferencer.py @@ -1,23 +1,56 @@ from parsing.parsing_rules import p_param import semantics.visitor as visitor -from parsing.ast import ArithmeticNode, AssignNode, AttrDeclarationNode, BlocksNode, CaseNode, CaseOptionNode, ClassDeclarationNode, ComparerNode, ComplementNode, ConditionalNode, EqualsNode, IsVoidNode, LetNode, LoopNode, MethodCallNode, MethodDeclarationNode, Node, NotNode, ProgramNode, VarDeclarationNode, VariableNode -from semantics.tools import Context, ErrorType, Scope, TypeBag, conforms, equal, join, join_list, smart_add +from ast.parser_ast import ( + ArithmeticNode, + AssignNode, + AttrDeclarationNode, + BlocksNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComparerNode, + ComplementNode, + ConditionalNode, + EqualsNode, + IsVoidNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + Node, + NotNode, + ProgramNode, + VarDeclarationNode, + VariableNode, +) +from semantics.tools import ( + Context, + ErrorType, + Scope, + TypeBag, + conforms, + equal, + join, + join_list, + smart_add, +) + class AutotypeInferencer: - def __init__(self, context:Context, errors) -> None: + def __init__(self, context: Context, errors) -> None: self.context = context self.current_type = None self.errors = errors - @visitor.on('node') + @visitor.on("node") def visit(self, node, scope): pass @visitor.when(ProgramNode) - def visit(self, node:ProgramNode, scope:Scope): + def visit(self, node: ProgramNode, scope: Scope): for declaration in node.declarations: self.visit(declaration, scope.next_child()) - + scope.reset() @visitor.when(ClassDeclarationNode) @@ -25,54 +58,60 @@ def visit(self, node, scope): self.current_type = self.context.get_type(node.id, unpacked=True) for feature in node.features: self.visit(feature, scope) - + @visitor.when(AttrDeclarationNode) def visit(self, node, scope): if not node.expr: return - + node_infered = node.inferenced_type expr_infered = node.expr.inferenced_type.clone() self.visit(node.expr, scope) new_expr_infered = node.expr.inferenced_type - + if equal(expr_infered, new_expr_infered): return - + new_clone_inferred = new_expr_infered.clone() if not conforms(new_expr_infered, node_infered): - self.add_error(node, f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({new_clone_inferred.name}) does not conforms to declared type ({node_infered.name}).") + self.add_error( + node, + f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({new_clone_inferred.name}) does not conforms to declared type ({node_infered.name}).", + ) # What is made error type here!!! - + @visitor.when(MethodDeclarationNode) - def visit(self, node, scopex:Scope): + def visit(self, node, scopex: Scope): scope = scopex.next_child() - + ret_type_infered = node.body.inferenced_type.clone() self.visit(node.body, scope) new_type_infered = node.body.inferenced_type - + if equal(ret_type_infered, new_type_infered): return - + current_method = self.current_type.get_method(node.id) ret_type_decl = current_method.return_type.swap_self_type(self.current_type) new_clone_infered = new_type_infered.clone() if not conforms(new_type_infered, ret_type_decl): - self.add_error(node, f"Type Error: In Class \'{self.current_type.name}\' method \'{current_method.name}\' return expression type({new_clone_infered.name}) does not conforms to declared return type ({ret_type_decl.name})") + self.add_error( + node, + f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}' return expression type({new_clone_infered.name}) does not conforms to declared return type ({ret_type_decl.name})", + ) ret_type_expr = ErrorType() - + node.inferenced_type = ret_type_expr - ret_type_decl.swap_self_type(self.current_type, back = True) + ret_type_decl.swap_self_type(self.current_type, back=True) @visitor.when(BlocksNode) def visit(self, node, scope): for expr in node.expr_list: self.visit(expr, scope) node.inferenced_type = node.expr_list[-1].inferenced_type - + @visitor.when(ConditionalNode) def visit(self, node, scope): condition_infered = node.condition.inferenced_type.clone() @@ -88,16 +127,21 @@ def visit(self, node, scope): new_else_infered = node.else_body.inferenced_type if not equal(condition_infered, new_condition_infered): - self.add_error(node, f"Type Error: If's condition type({new_condition_infered.name}) does not conforms to Bool type.") - - if equal(then_infered, new_then_infered) and equal(else_infered, new_else_infered): + self.add_error( + node, + f"Type Error: If's condition type({new_condition_infered.name}) does not conforms to Bool type.", + ) + + if equal(then_infered, new_then_infered) and equal( + else_infered, new_else_infered + ): return - + joined_type = join(new_then_infered, new_else_infered) node.inferenced_type = joined_type @visitor.when(CaseNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): self.visit(node.case_expr, scope) type_list = [] @@ -109,13 +153,13 @@ def visit(self, node, scope:Scope): new_option_infered = option.inferenced_type type_list.append(new_option_infered) change = change or not equal(option_infered, new_option_infered) - + if change: joined_type = join_list(type_list) node.inferenced_type = joined_type - + @visitor.when(CaseOptionNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): self.visit(node.expr, scope) @visitor.when(LoopNode) @@ -125,8 +169,11 @@ def visit(self, node, scope): new_cond_infered = node.condition.inferenced_type if not equal(condition_infered, new_cond_infered): - self.add_error(node, f"Type Error: Loop's condition type({new_cond_infered.name}) does not conforms to Bool type.") - + self.add_error( + node, + f"Type Error: Loop's condition type({new_cond_infered.name}) does not conforms to Bool type.", + ) + self.visit(node.body, scope) @visitor.when(LetNode) @@ -136,44 +183,50 @@ def visit(self, node, scope): self.visit(var, child) self.visit(node.in_expr, child) node.inferenced_type = node.in_expr.inferenced_type - + @visitor.when(VarDeclarationNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): if not node.expr: return - + expr_infered = node.expr.inferenced_type.clone() self.visit(node.expr, scope) new_expr_inferred = node.expr.inferenced_type if equal(expr_infered, new_expr_inferred): return - + node_infered = node.inferenced_type new_clone_infered = new_expr_inferred.clone() if not conforms(new_expr_inferred, node_infered): - self.add_error(node, f"Semantic Error: Variable \'{node.id}\' expression type({new_clone_infered.name}) does not conforms to declared type({node_infered.name}).") + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' expression type({new_clone_infered.name}) does not conforms to declared type({node_infered.name}).", + ) @visitor.when(AssignNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): if not node.defined and node.id != "self": return - + expr_infered = node.expr.inferenced_type.clone() self.visit(node.expr, scope) new_expr_infered = node.expr.inferenced_type if equal(expr_infered, new_expr_infered): return - + var_type = scope.find_variable(node.id).type new_clone_infered = new_expr_infered.clone() if not conforms(new_expr_infered, var_type): - self.add_error(node, f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({new_clone_infered.name}) does not conforms to declared type ({var_type.name}).") + self.add_error( + node, + f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({new_clone_infered.name}) does not conforms to declared type ({var_type.name}).", + ) var_type = ErrorType() - + node.inferenced_type = var_type - + @visitor.when(MethodCallNode) def visit(self, node, scope): caller = node.inferenced_caller @@ -184,34 +237,43 @@ def visit(self, node, scope): if not equal(bridge_infered, bridge): bridge_clone = bridge.clone() if not conforms(bridge, caller): - self.add_error(node, f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).") + self.add_error( + node, + f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).", + ) caller = ErrorType() elif node.expr: self.visit(node.expr, scope) caller = node.expr.inferenced_type - + 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), types)) if len(caller.heads) > 1: - error = f"Semantic Error: Method \"{node.id}\" found in {len(caller.heads)} unrelated types:\n" + error = f'Semantic Error: Method "{node.id}" found in {len(caller.heads)} unrelated types:\n' error += " -Found in: " error += ", ".join(typex.name for typex in caller.heads) self.add_error(node, error) caller = ErrorType() elif len(caller.heads) == 0: - self.add_error(node, f"There is no method called {node.id} which takes {len(node.args)} paramters.") + self.add_error( + node, + f"There is no method called {node.id} which takes {len(node.args)} paramters.", + ) caller = ErrorType() - + if len(caller.heads) == 1: caller_type = caller.heads[0] method = caller_type.get_method(node.id) if len(node.args) != len(method.param_types): - self.add_error(node, f"Semantic Error: Method '{node.id}' from class '{caller_type.name}' takes {len(node.args)} arguments but {method.param_types} were given.'") + self.add_error( + node, + f"Semantic Error: Method '{node.id}' from class '{caller_type.name}' takes {len(node.args)} arguments but {method.param_types} were given.'", + ) node.inferenced_type = ErrorType() - + decl_return_type = method.return_type.clone() decl_return_type.swap_self_type(caller_type) @@ -221,43 +283,51 @@ def visit(self, node, scope): for i in range(len(node.args)): arg = node.args[i] p_type = method.param_types[i] - arg_infered = arg.inferenced_type.clone() self.visit(arg, scope) new_arg_infered = arg.inferenced_type new_clone_infered = new_arg_infered.clone() if not conforms(new_arg_infered, p_type): - self.add_error(node.arg, f"Type Error: Argument expression type ({new_clone_infered.name}) does not conforms parameter declared type({p_type.name})") + self.add_error( + node.arg, + f"Type Error: Argument expression type ({new_clone_infered.name}) does not conforms parameter declared type({p_type.name})", + ) node.inferenced_type = TypeBag(type_set, heads) else: node.inferenced_type = ErrorType() node.inferenced_caller = caller - + @visitor.when(ArithmeticNode) def visit(self, node, scope): - left_infered = node.left.inferenced_type#.clone() - right_infered = node.right.inferenced_type#.clone() + left_infered = node.left.inferenced_type # .clone() + right_infered = node.right.inferenced_type # .clone() self.visit(node.left, scope) self.visit(node.right, scope) new_left = node.left.inferenced_type new_right = node.right.inferenced_type - + int_type = self.context.get_type("Int") if not equal(left_infered, new_left): left_clone = new_left.clone() if not conforms(left_infered, int_type): - self.add_error(node.left, f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.") - + self.add_error( + node.left, + f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.", + ) + if not equal(right_infered, new_right): right_clone = new_left.clone() if not conforms(right_infered, int_type): - self.add_error(node.right, f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.") + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.", + ) @visitor.when(ComparerNode) def visit(self, node, scope): - left_infered = node.left.inferenced_type#.clone() - right_infered = node.right.inferenced_type#.clone() + left_infered = node.left.inferenced_type # .clone() + right_infered = node.right.inferenced_type # .clone() self.visit(node.left, scope) self.visit(node.right, scope) @@ -271,16 +341,19 @@ def visit(self, node, scope): return if not conforms(left_clone, new_right) and not conforms(right_clone, new_left): - self.add_error(node, f"Type Error: Left expression type({new_left.name}) does not conforms to right expression type({new_right.name})") + self.add_error( + node, + f"Type Error: Left expression type({new_left.name}) does not conforms to right expression type({new_right.name})", + ) @visitor.when(VariableNode) - def visit(self, node, scope:Scope): + def visit(self, node, scope: Scope): if node.defined: node.inferenced_type = scope.find_variable(node.value).type @visitor.when(NotNode) def visit(self, node, scope): - expr_infered = node.expr.inferenced_type#.clone() + expr_infered = node.expr.inferenced_type # .clone() self.visit(node.expr, scope) new_expr = node.expr.inferenced_type expr_clone = new_expr.clone() @@ -288,11 +361,14 @@ def visit(self, node, scope): if equal(expr_infered, new_expr): return if not conforms(new_expr, bool_type): - self.add_error(node.value, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type") + self.add_error( + node.value, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type", + ) @visitor.when(ComplementNode) def visit(self, node, scope): - expr_infered = node.expr.inferenced_type#.clone() + expr_infered = node.expr.inferenced_type # .clone() self.visit(node.expr, scope) new_expr = node.expr.inferenced_type expr_clone = new_expr.clone() @@ -300,34 +376,36 @@ def visit(self, node, scope): if equal(expr_infered, new_expr): return if not conforms(new_expr, int_type): - self.add_error(node.value, f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type") + self.add_error( + node.value, + f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type", + ) @visitor.when(IsVoidNode) def visit(self, node, scope): self.visit(node.expr, scope) - - def add_error(self, node:Node, text:str): + + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line,col), f"({line}, {col}) - " + text)) - - #todo: los .clone detras de los old_infered_types puede eliminarse, me parece q no son necesarios - #todo: para no tener los .clone en todas las visitas en todos los casos posibles debe actualizarse el - #todo: .inferenced_type - - - #todo: Para pensar: - #todo: que hacer si expr_type no conforma con decl_type - #todo: Convierto expr en error_type si se me queda vacio, si es error ahora va a ser despues - #todo: ademas le pone ya una condicion al bolsa, en caso de que sea AUTO_TYPE - #todo: si lo mantengo igual que puedo ganar? - - #todo: Es necesario agregar una propiedad Autotype a los TypeBag que indiquen quien es quien? - - #todo: En el caso donde Auto1 se conforma de Auto2, y Auto1, nada mas puede ser Int o Object, y el - #todo: otro puede ser de todo, de que manera y cuando achicar Auto2. - #todo: Una manera puede ser cuando no se hayan hecho mas cambios sobre Auto1 y Auto2 - - #todo: AutoType checking for later: - #todo: Redefined methods with params and return type are autotypes - #todo: Check use of self types inside auto types, how does it affects, etc... - #todo: \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) + + # todo: los .clone detras de los old_infered_types puede eliminarse, me parece q no son necesarios + # todo: para no tener los .clone en todas las visitas en todos los casos posibles debe actualizarse el + # todo: .inferenced_type + + # todo: Para pensar: + # todo: que hacer si expr_type no conforma con decl_type + # todo: Convierto expr en error_type si se me queda vacio, si es error ahora va a ser despues + # todo: ademas le pone ya una condicion al bolsa, en caso de que sea AUTO_TYPE + # todo: si lo mantengo igual que puedo ganar? + + # todo: Es necesario agregar una propiedad Autotype a los TypeBag que indiquen quien es quien? + + # todo: En el caso donde Auto1 se conforma de Auto2, y Auto1, nada mas puede ser Int o Object, y el + # todo: otro puede ser de todo, de que manera y cuando achicar Auto2. + # todo: Una manera puede ser cuando no se hayan hecho mas cambios sobre Auto1 y Auto2 + + # todo: AutoType checking for later: + # todo: Redefined methods with params and return type are autotypes + # todo: Check use of self types inside auto types, how does it affects, etc... + # todo: From fbff4188724c73f49c67c745a7c8f66eebe33918 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:26:05 -0400 Subject: [PATCH 060/432] Updated Inferencer AST --- src/ast/inferencer_ast.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 508479aab..0a10e4a54 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -117,12 +117,13 @@ def __init__(self, expr, node): class MethodCallNode(ExpressionNode): - def __init__(self, caller_type, expression, args, node): + def __init__(self, caller_type, expr, args, node): Node.__init__(self, node) self.caller_type = caller_type - self.expression = expression + self.expr = expr self.args = args self.id = node.id + self.type = node.type class UnaryNode(ExpressionNode): From 55f3d4e932f1dd89363ef18abb7b03297af6f111 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:26:27 -0400 Subject: [PATCH 061/432] Added new HardInferencer for hardened inferencing rule checking Updated debdev.py to work with hard inferencer --- src/debdev.py | 16 +- src/semantics/hard_inferencer.py | 522 +++++++++++++++++++++++++++++++ 2 files changed, 533 insertions(+), 5 deletions(-) create mode 100644 src/semantics/hard_inferencer.py diff --git a/src/debdev.py b/src/debdev.py index 6a2fbe426..53fb0ae34 100644 --- a/src/debdev.py +++ b/src/debdev.py @@ -2,7 +2,7 @@ from debbuging import type_logger from parsing import parser -from semantics import type_collector, type_builder, soft_inferencer +from semantics import type_collector, type_builder, soft_inferencer, hard_inferencer def format_errors(errors, s=""): @@ -30,12 +30,18 @@ def run_pipeline(program): soft = soft_inferencer.SoftInferencer(context) soft_ast = soft.visit(ast) + errors += soft.errors + hard = hard_inferencer.HardInferencer(context) + hard_ast = hard.visit(soft_ast) + + hard_ast = hard.visit(hard_ast) + errors += hard.errors # auto_inferencer = autotype_inferencer.AutotypeInferencer(context, errors) # auto_inferencer.visit(ast, scope) logger = type_logger.TypeLogger(context) - log = logger.visit(soft_ast, soft_ast.scope) + log = logger.visit(hard_ast, hard_ast.scope) print(log) s = "Semantic Errors:\n" s = format_errors(errors, s) @@ -49,12 +55,12 @@ def run_pipeline(program): filenames = os.listdir(folder_path) filenames.sort() except FileNotFoundError: - print("Error Importing Files") + print("Error Locating Files") count = 100 filenames = [ r"/home/rodro/Aarka/Complementos de Compilacion/cool-cows/src/debbuging/tests/Auto/" - r"01Assign.cl" + r"03Many.cl" ] for filename in filenames: @@ -78,4 +84,4 @@ def run_pipeline(program): print("EndOfFiles") -# todo: Manejar los self types dentro de los type bags correctamente (acualizar metodo swap swlf types) \ No newline at end of file +# todo: Manejar los self types dentro de los type bags correctamente diff --git a/src/semantics/hard_inferencer.py b/src/semantics/hard_inferencer.py new file mode 100644 index 000000000..52489cbde --- /dev/null +++ b/src/semantics/hard_inferencer.py @@ -0,0 +1,522 @@ +from ast.inferencer_ast import ( + ArithmeticNode, + AssignNode, + AttrDeclarationNode, + BlocksNode, + BooleanNode, + CaseNode, + CaseOptionNode, + ClassDeclarationNode, + ComparerNode, + ComplementNode, + ConditionalNode, + InstantiateNode, + IntNode, + IsVoidNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, + Node, + NotNode, + ProgramNode, + StringNode, + VarDeclarationNode, + VariableNode, +) + +import semantics.visitor as visitor +from semantics.tools import ( + Context, + ErrorType, + Scope, + TypeBag, + conforms, + equal, + join, + join_list, + smart_add, +) + + +class HardInferencer: + def __init__(self, context: Context) -> None: + self.context = context + self.errors = [] + self.pos = set() + self.current_type = None + + @visitor.on("node") + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode) -> ProgramNode: + scope: Scope = node.scope + new_declaration = [] + for declaration in node.declarations: + new_declaration.append(self.visit(declaration, scope.next_child())) + + scope.reset() + program = ProgramNode(new_declaration, scope, node) + return program + + @visitor.when(ClassDeclarationNode) + def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: + self.current_type = self.context.get_type(node.id, unpacked=True) + + new_features = [] + for feature in node.features: + new_features.append(self.visit(feature, scope)) + + class_node = ClassDeclarationNode(new_features, node) + return class_node + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + attr_node = AttrDeclarationNode(node) + attr_node.inferenced_type = node.inferenced_type + + if not node.expr: + return attr_node + + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + + attr_node.expr = expr_node + if equal(expr_type, node.expr.inferenced_type): + return attr_node + + expr_clone = expr_type.clone() + node_type = attr_node.inferenced_type + if not conforms(expr_type, attr_node.inferenced_type): + self.add_error( + node, + ( + f"Type Error: In class '{self.current_type.name}' attribue" + f"'{node.id}' expression type({expr_clone.name}) does not conforms" + f"to declared type ({node_type.name})." + ), + ) + expr_node.inferenced_type = ErrorType() + + return attr_node + + @visitor.when(MethodDeclarationNode) + def visit(self, node, scopex: Scope): + scope = scopex.next_child() + + body_node = self.visit(node.body, scope) + body_type = body_node.inferenced_type + method_node = MethodDeclarationNode(node.type, body_node, node) + method_node.inferenced_type = node.inferenced_type + + if equal(body_type, node.body.inferenced_type): + return method_node + + node_type = method_node.inferenced_type + body_clone = body_type.clone() + if not conforms(body_type, node_type): + self.add_error( + node, + f"Type Error: In Class '{self.current_type.name}' method " + f"'{method_node.id}' return expression type({body_clone.name})" + f" does not conforms to declared return type ({node_type.name})", + ) + body_node.inferenced_type = ErrorType() + + return method_node + + @visitor.when(BlocksNode) + def visit(self, node, scope): + new_expr_list = [] + for expr in node.expr_list: + new_expr_list.append(self.visit(expr, scope)) + + block_node = BlocksNode(new_expr_list, node) + block_node.inferenced_type = block_node.expr_list[-1].inferenced_type + return block_node + + @visitor.when(ConditionalNode) + def visit(self, node, scope): + condition_node = self.visit(node.condition, scope) + then_node = self.visit(node.then_body, scope) + else_node = self.visit(node.else_body, scope) + + condition_type = condition_node.inferenced_type + if not equal(condition_type, node.condition.inferenced_type): + condition_clone = condition_type.clone() + bool_type = self.context.get_type("Bool") + if not conforms(condition_type, bool_type): + self.add_error( + node, + f"Type Error: If's condition type({condition_clone.name})" + " does not conforms to Bool type.", + ) + condition_node.inferenced_type = ErrorType() + + if_node = ConditionalNode(condition_node, then_node, else_node) + + if not equal( + then_node.inferenced_type, node.then_body.inferenced_type + ) or not equal(else_node.inferenced_type, node.else_body.inferenced_type): + then_type = then_node.inferenced_type + else_type = else_node.inferenced_type + joined_type = join(then_type, else_type) + else: + joined_type = node.inferenced_type + + if_node.inferenced_type = joined_type + return if_node + + @visitor.when(CaseNode) + def visit(self, node, scope: Scope): + expr_node = self.visit(node.case_expr, scope) + + type_list = [] + new_options = [] + for option in node.options: + child = scope.next_child() + new_options.append(self.visit(option, child)) + type_list.append(new_options[-1].inferenced_type) + + join_type = join_list(type_list) + case_node = CaseNode(expr_node, new_options, node) + case_node.inferenced_type = join_type + return case_node + + @visitor.when(CaseOptionNode) + def visit(self, node, scope: Scope): + expr_node = self.visit(node.expr, scope) + opt_node = CaseOptionNode(expr_node, node) + return opt_node + + @visitor.when(LoopNode) + def visit(self, node, scope): + condition_node = self.visit(node.condition, scope) + condition_type = condition_node.inferenced_type + + if not equal(condition_type, node.condition.inferenced_type): + bool_type = self.context.get_type("Bool") + condition_clone = condition_type.clone() + if not conforms(condition_type, bool_type): + self.add_error( + node, + f"Type Error: Loop condition type({condition_clone.name})" + " does not conforms to Bool type.", + ) + condition_node.inferenced_type = ErrorType() + + body_node = self.visit(node.body, scope) + loop_node = LoopNode(condition_node, body_node, node) + loop_node.inferenced_type = node.inferenced_type + return loop_node + + @visitor.when(LetNode) + def visit(self, node, scope: Scope): + child = scope.next_child() + + new_decl_list = [] + for var in node.var_decl_list: + new_decl_list.append(self.visit(var, child)) + + in_expr_node = self.visit(node.in_expr, child) + + let_node = LetNode(new_decl_list, in_expr_node, node) + let_node.inferenced_type = in_expr_node.inferenced_type + return let_node + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope: Scope): + var_decl_node = VarDeclarationNode(node) + if node.expr is None: + var_decl_node.inferenced_type = node.inferenced_type + return var_decl_node + + expr_node = self.visit(node.expr, scope) + var_decl_node.expr = expr_node + + if not node.defined: + var_decl_node.inferenced_type = ErrorType() + return var_decl_node + + var_decl_node.defined = True + node_type = scope.find_variable(node.id).get_type() + + expr_type = expr_node.inferenced_type + if equal(expr_type, node.expr.inferenced_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, node_type): + self.add_error( + node, + f"Semantic Error: Variable '{node.id}' expressiontype" + f"({expr_clone.name}) does not conforms to declared" + f"type({node_type.name}).", + ) + expr_node.inferenced_type = ErrorType() + + var_decl_node.inferenced_type = node_type + return var_decl_node + + @visitor.when(AssignNode) + def visit(self, node, scope: Scope): + expr_node = self.visit(node.expr, scope) + assign_node = AssignNode(expr_node, node) + + if not node.defined or node.id == "self": + assign_node.inferenced_type = ErrorType() + return assign_node + + assign_node.defined = True + + decl_type = scope.find_variable(node.id).get_type() + expr_type = expr_node.inferenced_type + if not equal(expr_type, node.expr.inferenced_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, decl_type): + self.add_error( + node, + f"Type Error: Cannot assign new value to variable '{node.id}'." + f" Expression type({expr_clone.name}) does not conforms to" + f" declared type ({decl_type.name}).", + ) + expr_node.inferenced_type = ErrorType() + + assign_node.inferenced_type = decl_type + return assign_node + + @visitor.when(MethodCallNode) + def visit(self, node, scope): + caller_type = node.caller_type + if node.type is not None and node.expr is not None: + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + if not equal(expr_type, node.expression.inferenced_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, caller_type): + self.add_error( + node, + f"Semantic Error: Cannot effect dispatch because expression" + f"type({expr_clone.name}) does not conforms to " + f"caller type({caller_type.name}).", + ) + caller_type = ErrorType() + elif node.expr is not None: + expr_node = self.visit(node.expr, scope) + caller_type = expr_node.inferenced_type + + if len(caller_type.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_type, TypeBag(set(types), types)) + if len(caller_type.heads) > 1: + error = ( + f"Semantic Error: Method '{node.id}' found in" + f" {len(caller_type.heads)} unrelated types:\n" + ) + error += " -Found in: " + error += ", ".join(typex.name for typex in caller_type.heads) + self.add_error(node, error) + caller_type = ErrorType() + elif len(caller_type.heads) == 0: + self.add_error( + node, + f"There is no method called {node.id} which takes" + f" {len(node.args)} paramters.", + ) + caller_type = ErrorType() + + if len(caller_type.heads) == 1: + caller = caller_type.heads[0] + method = caller.get_method(node.id) + + if len(node.args) != len(method.param_types): + self.add_error( + node, + f"Semantic Error: Method '{node.id}' from class " + f"'{caller_type.name}' takes {len(node.args)} arguments but" + f" {method.param_types} were given.'", + ) + node.inferenced_type = ErrorType() + + decl_return_type = method.return_type.clone() + decl_return_type.swap_self_type(caller) + type_set = set() + heads = [] + type_set = smart_add(type_set, heads, decl_return_type) + + new_args = [] + for i in range(len(node.args)): + new_args.append(self.visit(node.args[i], scope)) + + arg_type = new_args[-1].inferenced_type + arg_clone = arg_type.clone() + param_type = method.param_types[i] + if not conforms(arg_type, param_type): + self.add_error( + new_args[-1], + f"Type Error: Argument expression type({arg_clone.name}) does" + f" not conforms parameter declared type({param_type.name})", + ) + infered_type = TypeBag(type_set, heads) + else: + new_args = [] + infered_type = ErrorType() + + call_node = MethodCallNode(caller_type, expr_node, new_args, node) + call_node.inferenced_type = infered_type + return call_node + + @visitor.when(ArithmeticNode) + def visit(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + + int_type = self.context.get_type("Int") + if not equal(left_type, node.left.inferenced_type): + if not conforms(left_type, int_type): + left_clone = left_type.clone() + self.add_error( + node.left, + f"Type Error: Arithmetic Error: Left member type({left_clone.name})" + "does not conforms to Int type.", + ) + left_node.inferenced_type = ErrorType() + if not equal(right_type, node.right.inferenced_type): + right_clone = right_type.clone() + if not conforms(right_type, int_type): + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member " + f"type({right_clone.name})does not conforms to Int type.", + ) + right_node.inferenced_type = ErrorType() + + arith_node = ArithmeticNode(left_node, right_node, node) + arith_node.inferenced_type = int_type + return arith_node + + @visitor.when(ComparerNode) + def visit(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + + if not equal(left_type, node.left.inferenced_type): + if not conforms(left_type, right_type): + left_clone = left_type.clone() + self.add_error( + node.left, + f"Type Error: Comparer Error: Left expression" + f" type({left_clone.name}) " + f" does not conforms to right expression type ({right_type.name}).", + ) + left_node.inferenced_type = ErrorType() + + if not equal(right_type, node.right.inferenced_type): + right_clone = right_type.clone() + if not conforms(right_type, left_type): + self.add_error( + node.right, + f"Type Error: Comparer Error: Right expression" + f" type({right_clone.name})" + f" does not conforms to left expression type ({left_type.name}).", + ) + right_node.inferenced_type = ErrorType() + + comparer = ComparerNode(left_node, right_node) + comparer.inferenced_type = node.inferenced_type # Bool Type :) + return comparer + + @visitor.when(VariableNode) + def visit(self, node, scope: Scope): + var_node = VariableNode(node) + if not node.defined: + var_node.inferenced_type = ErrorType() + return var_node + + var_node.defined = True + var = scope.find_variable(node.value) + var_node.inferenced_type = var.get_type() + return var_node + + @visitor.when(NotNode) + def visit(self, node, scope): + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + bool_type = self.context.get_type("Bool") + if not equal(expr_type, node.expr.inferenced_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, bool_type): + self.add_error( + node, + f"Type Error: Not's expresion type({expr_clone.name} does not" + " conforms to Bool type", + ) + expr_node.inferenced_type = ErrorType() + + not_node = NotNode(expr_node, node) + not_node.inferenced_type = bool_type + return not_node + + @visitor.when(ComplementNode) + def visit(self, node, scope): + expr_node = self.visit(node.expr, scope) + expr_type = expr_node.inferenced_type + int_type = self.context.get_type("Int") + if not equal(expr_type, node.expr.inferenced_type): + expr_clone = expr_type.clone() + if not conforms(expr_type, int_type): + self.add_error( + node, + f"Type Error: ~ expresion type({expr_clone.name} does not" + " conforms to Bool type", + ) + expr_node.inferenced_type = ErrorType() + + complement_node = ComplementNode(expr_node, node) + complement_node.inferenced_type = int_type + return complement_node + + @visitor.when(IsVoidNode) + def visit(self, node, scope): + node_expr = self.visit(node.expr, scope) + is_void_node = IsVoidNode(node_expr, node) + is_void_node.inferenced_type = self.context.get_type("Bool") + return is_void_node + + @visitor.when(InstantiateNode) + def visit(self, node, scope): + instantiate_node = InstantiateNode(node) + instantiate_node.inferenced_type = node.inferenced_type + return instantiate_node + + @visitor.when(IntNode) + def visit(self, node, scope): + int_node = IntNode(node) + int_node.inferenced_type = self.context.get_type("Int") + return int_node + + @visitor.when(StringNode) + def visit(self, node, scope): + str_node = StringNode(node) + str_node.inferenced_type = self.context.get_type("String") + return str_node + + @visitor.when(BooleanNode) + def visit(self, node, scope): + bool_node = BooleanNode(node) + bool_node.inferenced_type = self.context.get_type("Bool") + return bool_node + + def add_error(self, node: Node, text: str): + line, col = node.get_position() if node else (0, 0) + if (line, col) in self.pos: + return + self.pos.add((line, col)) + self.errors.append(((line, col), f"({line}, {col}) - " + text)) From 1894ec9d5ba0ffe2e7bf03982d5b695fc49e4750 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 10:58:35 -0400 Subject: [PATCH 062/432] Moved Hard Inferencer to inference module --- src/semantics/{ => inference}/hard_inferencer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename src/semantics/{ => inference}/hard_inferencer.py (99%) diff --git a/src/semantics/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py similarity index 99% rename from src/semantics/hard_inferencer.py rename to src/semantics/inference/hard_inferencer.py index 52489cbde..3d8ac4993 100644 --- a/src/semantics/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -24,8 +24,7 @@ VarDeclarationNode, VariableNode, ) - -import semantics.visitor as visitor +from utils import visitor from semantics.tools import ( Context, ErrorType, From c0b87c5838a1508428b03bbcca1643674ce51974 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 11:03:30 -0400 Subject: [PATCH 063/432] Added HardInferencer to run_pipeline in __main__.py --- src/__main__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index b10852899..424ab8f09 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,3 +1,4 @@ +from semantics.inference.hard_inferencer import HardInferencer import sys from ply.lex import lex @@ -8,8 +9,6 @@ from parsing import Parser from semantics import TypeBuilder, TypeCollector, TypeChecker from semantics.inference import ( - AutotypeCollector, - AutotypeInferencer, BackInferencer, SoftInferencer, ) @@ -28,8 +27,8 @@ def run_pipeline(program_ast): soft = SoftInferencer(context) soft_ast = soft.visit(program_ast) - # auto_inferencer = autotype_inferencer.AutotypeInferencer(context, errors) - # auto_inferencer.visit(ast, scope) + hard = HardInferencer(context) + hard_ast = hard.visit(program_ast) # logger = type_logger.TypeLogger(context) # log = logger.visit(soft_ast, soft_ast.scope) From 0f7f6167e7eb5f0e327b24d625f42ead4eb944cf Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 23 Apr 2021 12:57:03 -0400 Subject: [PATCH 064/432] Fix error in LexicographicError class --- src/lexing/errors.py | 6 +++--- src/semantics/errors.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lexing/errors.py b/src/lexing/errors.py index 04630810e..7fb9dc98c 100644 --- a/src/lexing/errors.py +++ b/src/lexing/errors.py @@ -1,11 +1,11 @@ class LexicographicError: - def __init__(self, line: int, col: int, char: str) -> None: + def __init__(self, line: int, col: int, message: str) -> None: self.line = line self.col = col - self.char = char + self.message = message def __str__(self) -> str: - return f'({self.line},{self.col}) - LexicographicError: ERROR "{self.char}"' + return f'({self.line},{self.col}) - LexicographicError: ERROR "{self.message}"' def __repr__(self) -> str: return str(self) diff --git a/src/semantics/errors.py b/src/semantics/errors.py index 08fc80eeb..a32a01a68 100644 --- a/src/semantics/errors.py +++ b/src/semantics/errors.py @@ -1,22 +1,22 @@ class InternalError(Exception): @property def text(self): - return "Internal Error: " + self.args[0] + return "InternalError: " + self.args[0] class SemanticError(Exception): @property def text(self): - return "Semantic Error: " + self.args[0] + return "SemanticError: " + self.args[0] class TypeError(SemanticError): @property def text(self): - return "Type Error: " + self.args[0] + return "TypeError: " + self.args[0] class AttributeError(SemanticError): @property def text(self): - return "Attribute Error: " + self.args[0] \ No newline at end of file + return "AttributeError: " + self.args[0] \ No newline at end of file From ad7017a6ae6bf33392a7a9f1001375e6d186ada5 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 12:58:57 -0400 Subject: [PATCH 065/432] Fix minor bugs --- .../inference/autotype_inferencer.py | 3 +- src/semantics/inference/hard_inferencer.py | 31 +++++----- src/semantics/inference/soft_inferencer.py | 56 +++++++++---------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/semantics/inference/autotype_inferencer.py b/src/semantics/inference/autotype_inferencer.py index d265d8df8..8cd729787 100644 --- a/src/semantics/inference/autotype_inferencer.py +++ b/src/semantics/inference/autotype_inferencer.py @@ -1,5 +1,4 @@ -from parsing.parsing_rules import p_param -import semantics.visitor as visitor +from utils.visitor import visitor from ast.parser_ast import ( ArithmeticNode, AssignNode, diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 3d8ac4993..a1b872bc6 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -92,7 +92,7 @@ def visit(self, node, scope): self.add_error( node, ( - f"Type Error: In class '{self.current_type.name}' attribue" + f"TypeError: In class '{self.current_type.name}' attribue" f"'{node.id}' expression type({expr_clone.name}) does not conforms" f"to declared type ({node_type.name})." ), @@ -118,7 +118,7 @@ def visit(self, node, scopex: Scope): if not conforms(body_type, node_type): self.add_error( node, - f"Type Error: In Class '{self.current_type.name}' method " + f"TypeError: In Class '{self.current_type.name}' method " f"'{method_node.id}' return expression type({body_clone.name})" f" does not conforms to declared return type ({node_type.name})", ) @@ -149,7 +149,7 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - f"Type Error: If's condition type({condition_clone.name})" + f"TypeError: If's condition type({condition_clone.name})" " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -201,7 +201,7 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - f"Type Error: Loop condition type({condition_clone.name})" + f"TypeError: Loop condition type({condition_clone.name})" " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -275,7 +275,7 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, decl_type): self.add_error( node, - f"Type Error: Cannot assign new value to variable '{node.id}'." + f"TypeError: Cannot assign new value to variable '{node.id}'." f" Expression type({expr_clone.name}) does not conforms to" f" declared type ({decl_type.name}).", ) @@ -287,6 +287,7 @@ def visit(self, node, scope: Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): caller_type = node.caller_type + expr_node = None if node.type is not None and node.expr is not None: expr_node = self.visit(node.expr, scope) expr_type = expr_node.inferenced_type @@ -295,7 +296,7 @@ def visit(self, node, scope): if not conforms(expr_type, caller_type): self.add_error( node, - f"Semantic Error: Cannot effect dispatch because expression" + f"SemanticError: Cannot effect dispatch because expression" f"type({expr_clone.name}) does not conforms to " f"caller type({caller_type.name}).", ) @@ -310,7 +311,7 @@ def visit(self, node, scope): conforms(caller_type, TypeBag(set(types), types)) if len(caller_type.heads) > 1: error = ( - f"Semantic Error: Method '{node.id}' found in" + f"SemanticError: Method '{node.id}' found in" f" {len(caller_type.heads)} unrelated types:\n" ) error += " -Found in: " @@ -320,7 +321,7 @@ def visit(self, node, scope): elif len(caller_type.heads) == 0: self.add_error( node, - f"There is no method called {node.id} which takes" + f" SemanticError: There is no method called {node.id} which takes" f" {len(node.args)} paramters.", ) caller_type = ErrorType() @@ -332,7 +333,7 @@ def visit(self, node, scope): if len(node.args) != len(method.param_types): self.add_error( node, - f"Semantic Error: Method '{node.id}' from class " + f"SemanticError: Method '{node.id}' from class " f"'{caller_type.name}' takes {len(node.args)} arguments but" f" {method.param_types} were given.'", ) @@ -354,7 +355,7 @@ def visit(self, node, scope): if not conforms(arg_type, param_type): self.add_error( new_args[-1], - f"Type Error: Argument expression type({arg_clone.name}) does" + f"TypeError: Argument expression type({arg_clone.name}) does" f" not conforms parameter declared type({param_type.name})", ) infered_type = TypeBag(type_set, heads) @@ -380,7 +381,7 @@ def visit(self, node, scope): left_clone = left_type.clone() self.add_error( node.left, - f"Type Error: Arithmetic Error: Left member type({left_clone.name})" + f"TypeError: Arithmetic Error: Left member type({left_clone.name})" "does not conforms to Int type.", ) left_node.inferenced_type = ErrorType() @@ -411,7 +412,7 @@ def visit(self, node, scope): left_clone = left_type.clone() self.add_error( node.left, - f"Type Error: Comparer Error: Left expression" + f"TypeError: Comparer Error: Left expression" f" type({left_clone.name}) " f" does not conforms to right expression type ({right_type.name}).", ) @@ -422,7 +423,7 @@ def visit(self, node, scope): if not conforms(right_type, left_type): self.add_error( node.right, - f"Type Error: Comparer Error: Right expression" + f"TypeError: Comparer Error: Right expression" f" type({right_clone.name})" f" does not conforms to left expression type ({left_type.name}).", ) @@ -454,7 +455,7 @@ def visit(self, node, scope): if not conforms(expr_type, bool_type): self.add_error( node, - f"Type Error: Not's expresion type({expr_clone.name} does not" + f"TypeError: Not's expresion type({expr_clone.name} does not" " conforms to Bool type", ) expr_node.inferenced_type = ErrorType() @@ -473,7 +474,7 @@ def visit(self, node, scope): if not conforms(expr_type, int_type): self.add_error( node, - f"Type Error: ~ expresion type({expr_clone.name} does not" + f"TypeError: ~ expresion type({expr_clone.name} does not" " conforms to Bool type", ) expr_node.inferenced_type = ErrorType() diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index b50db621a..91c9d344c 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -95,7 +95,7 @@ def visit(self, node, scope): self.add_error( node, ( - f"Type Error: In class '{self.current_type.name}' attribue" + f"TypeError: In class '{self.current_type.name}' attribue" f"'{node.id}' expression type({expr_clone.name}) does not conforms" f"to declared type ({node_type.name})." ), @@ -121,9 +121,9 @@ def visit(self, node, scopex: Scope): if not conforms(ret_type_expr, ret_type_decl): self.add_error( node, - f"Type Error: In Class '{self.current_type.name}' method " - f"'{current_method.name}' return expression type({ret_expr_clone.name})" - f" does not conforms todeclared return type ({ret_type_decl.name})", + f"TypeError: In Class '{self.current_type.name}' method" + f" '{current_method.name}' return expression type({ret_expr_clone.name})" + f" does not conforms to declared return type ({ret_type_decl.name})", ) body_node.inferenced_type = ErrorType() @@ -154,7 +154,7 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - f"Type Error: If's condition type({condition_clone.name})" + f"TypeError: If's condition type({condition_clone.name})" " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -186,7 +186,7 @@ def visit(self, node, scope: Scope): if var_type in types_visited: self.add_error( node, - "Semantic Error: Case Expression can't have branches" + "SemanticError: Case Expression can't have branches" f"with same case type({var_type.name})", ) @@ -221,7 +221,7 @@ def visit(self, node, scope): if not conforms(condition_type, bool_type): self.add_error( node, - f"Type Error: Loop condition type({condition_clone.name})" + f"TypeError: Loop condition type({condition_clone.name})" " does not conforms to Bool type.", ) condition_node.inferenced_type = ErrorType() @@ -263,7 +263,7 @@ def visit(self, node, scope: Scope): else: self.add_error( node, - f"Semantic Error: Variable '{node.id}' already defined" + f"SemanticError: Variable '{node.id}' already defined" " in current scope.", ) node_type = ErrorType() @@ -277,7 +277,7 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, node_type): self.add_error( node, - f"Semantic Error: Variable '{node.id}' expressiontype" + f"TypeError: Variable '{node.id}' expressiontype" f"({expr_clone.name}) does not conforms to declared" f"type({node_type.name}).", ) @@ -295,7 +295,7 @@ def visit(self, node, scope: Scope): if not var: self.add_error( node, - f"Scope Error: Cannot assign new value to" + f"ScopeError: Cannot assign new value to" f"{node.id} beacuse it is not defined in the current scope", ) decl_type = ErrorType() @@ -307,7 +307,7 @@ def visit(self, node, scope: Scope): if var.name == "self": self.add_error( node, - "Semantic Error: Cannot assign new value. " + "SemanticError: Cannot assign new value. " "Variable 'self' is Read-Only.", ) decl_type = ErrorType() @@ -317,7 +317,7 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, decl_type): self.add_error( node, - f"Type Error: Cannot assign new value to variable '{node.id}'." + f"TypeError: Cannot assign new value to variable '{node.id}'." f" Expression type({expr_clone.name}) does not conforms to" f" declared type ({decl_type.name}).", ) @@ -344,7 +344,7 @@ def visit(self, node, scope): if not conforms(expr_type, caller_type): self.add_error( node, - f"Semantic Error: Cannot effect dispatch because expression" + f"TypeError: Cannot effect dispatch because expression" f"type({expr_clone.name}) does not conforms to " f"caller type({caller_type.name}).", ) @@ -362,21 +362,21 @@ def visit(self, node, scope): else: self.add_error( node, - f"Semantic Error: There is no method '{node.id}'" + f"SemanticError: There is no method '{node.id}'" f"that recieves {len(node.params)} arguments in" f"types {caller_type.name}.", ) caller_type = ErrorType() elif len(caller_type.type_set) == 1: - caller_type = caller_type.heads[0] + caller = caller_type.heads[0] try: - methods = [(caller_type.get_method(node.id), caller_type)] + methods = [(caller, caller.get_method(node.id))] except SemanticError: self.add_error( node, - f"Semantic Error: There is no method '{node.id}'" + f"SemanticError: There is no method '{node.id}'" f"that recieves {len(node.params)} arguments in" - f"Type '{caller_type.name}'.", + f"Type '{caller.name}'.", ) caller_type = ErrorType() @@ -416,15 +416,15 @@ def visit(self, node, scope): if not conforms(left_type, int_type): self.add_error( node.left, - f"Type Error: Arithmetic Error: Left member type({left_clone.name})" - "does not conforms to Int type.", + f"TypeError: ArithmeticError: Left member type({left_clone.name})" + " does not conforms to Int type.", ) left_node.inferenced_type = ErrorType() if not conforms(right_type, int_type): self.add_error( node.right, - f"Type Error: Arithmetic Error: Right member type({right_clone.name})" - "does not conforms to Int type.", + f"TypeError: ArithmeticError: Right member type({right_clone.name})" + " does not conforms to Int type.", ) right_node.inferenced_type = ErrorType() @@ -445,14 +445,14 @@ def visit(self, node, scope): if not conforms(left_type, right_type): self.add_error( node, - f"Type Error: Left expression type({left_clone.name})" + f"TypeError: Left expression type({left_clone.name})" f"does not conforms to right expression type({right_type.name})", ) left_node.inferenced_type = ErrorType() elif not conforms(right_type, left_type): self.add_error( node, - f"Type Error: Right expression type({right_clone.name})" + f"TypeError: Right expression type({right_clone.name})" f"does not conforms to left expression type({left_type.name})", ) right_node.inferenced_type = ErrorType() @@ -472,7 +472,7 @@ def visit(self, node, scope: Scope): else: var_type = ErrorType() self.add_error( - node, f"Semantic Error: Variable '{node.value}' is not defined." + node, f"SemanticError: Variable '{node.value}' is not defined." ) var_node.inferenced_type = var_type return var_node @@ -487,7 +487,7 @@ def visit(self, node, scope): if not conforms(expr_type, bool_type): self.add_error( node, - f"Type Error: Not's expresion type({expr_clone.name} does not" + f"TypeError: Not's expresion type({expr_clone.name} does not" " conforms to Bool type", ) expr_node.inferenced_type = ErrorType() @@ -506,7 +506,7 @@ def visit(self, node, scope): if not conforms(expr_type, int_type): self.add_error( node, - f"Type Error: ~ expresion type({expr_clone.name} does not" + f"TypeError: ~ expresion type({expr_clone.name} does not" " conforms to Int type", ) expr_node.inferenced_type = ErrorType() @@ -532,7 +532,7 @@ def visit(self, node, scope): except SemanticError as err: self.add_error( node, - err + f"\nSemantic Error: Could not instantiate type '{node.value}'.", + err.text + f" Could not instantiate type '{node.value}'.", ) node_type = ErrorType() instantiate_node.inferenced_type = node_type From 45fe7c63f231477e5ebc596580c35f727e633b08 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 13:00:13 -0400 Subject: [PATCH 066/432] Minor changes to __init_.py --- src/semantics/inference/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/semantics/inference/__init__.py b/src/semantics/inference/__init__.py index 273ae535a..38702902e 100644 --- a/src/semantics/inference/__init__.py +++ b/src/semantics/inference/__init__.py @@ -1,4 +1,2 @@ -from .autotype_collector import AutotypeCollector -from .autotype_inferencer import AutotypeInferencer from .soft_inferencer import SoftInferencer from .back_inferencer import BackInferencer From 89d2c17112b4da51d5887c775a387ef36baa9bb2 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 23 Apr 2021 13:01:52 -0400 Subject: [PATCH 067/432] Resolve some conflicts with master --- src/semantics/inference/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/semantics/inference/__init__.py b/src/semantics/inference/__init__.py index 273ae535a..dab81e357 100644 --- a/src/semantics/inference/__init__.py +++ b/src/semantics/inference/__init__.py @@ -1,4 +1,4 @@ -from .autotype_collector import AutotypeCollector -from .autotype_inferencer import AutotypeInferencer +# from .autotype_collector import AutotypeCollector +# from .autotype_inferencer import AutotypeInferencer from .soft_inferencer import SoftInferencer from .back_inferencer import BackInferencer From 573fcad78f8308ab7445755aedc3cca44a1fda49 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 23 Apr 2021 17:40:03 -0400 Subject: [PATCH 068/432] new branch dev --- src/__main__.py | 36 ++++--- src/parsing/parsetab.py | 110 ++++++++++----------- src/semantics/inference/hard_inferencer.py | 2 +- src/semantics/inference/soft_inferencer.py | 2 +- tests/lexer_test.py | 20 ++-- tests/parser_test.py | 13 ++- tests/semantic_test.py | 29 +++--- 7 files changed, 116 insertions(+), 96 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 424ab8f09..19750282c 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,3 +1,4 @@ +from os import error from semantics.inference.hard_inferencer import HardInferencer import sys @@ -7,13 +8,20 @@ # from parsing import Parser from parsing import Parser -from semantics import TypeBuilder, TypeCollector, TypeChecker +from semantics import TypeBuilder, TypeCollector from semantics.inference import ( BackInferencer, SoftInferencer, ) +def format_errors(errors, s=""): + errors.sort(key=lambda x: x[0]) + for error in errors: + s += error[1] + "\n" + return s[:-1] + + def run_pipeline(program_ast): collector = TypeCollector() @@ -26,27 +34,30 @@ def run_pipeline(program_ast): soft = SoftInferencer(context) soft_ast = soft.visit(program_ast) + errors += soft.errors hard = HardInferencer(context) - hard_ast = hard.visit(program_ast) + hard_ast = hard.visit(soft_ast) + errors += hard.errors # logger = type_logger.TypeLogger(context) # log = logger.visit(soft_ast, soft_ast.scope) # print(log) - # s = "Semantic Errors:\n" - # s = format_errors(errors, s) + if len(errors) > 0: + s = format_errors(errors) + print(s) + exit(1) # print(s) -input_file = "src/test.cl" +input_file = "methods2.cl" # "src/test.cl" def main(): - - if len(sys.argv) > 1: - input_file = sys.argv[1] - else: - raise Exception("Incorrect number of arguments") + # if len(sys.argv) > 1: + # input_file = sys.argv[1] + # else: + # raise Exception("Incorrect number of arguments") program = open(input_file).read() @@ -69,9 +80,10 @@ def main(): print(error) exit(1) - # ast = parser.parse(program) + parser = Parser(lexer) + ast = parser.parse(program) - # run_pipeline(ast) + run_pipeline(ast) main() diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 4ca3752b3..20813ed7e 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,7 +6,7 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " _lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} @@ -27,58 +27,58 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parsing_rules.py',39), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',44), - ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',45), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',53), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',54), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',64), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',65), - ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',66), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',74), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',75), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',85), - ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',91), - ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',92), - ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',100), - ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',105), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',111), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',112), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',120), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',126), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',132), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',138), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',144), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',150), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',151), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',159), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',160), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',169), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',175), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',176), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',184), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',190), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',191), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',192), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',207), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',208), - ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',216), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',221), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',227), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',233), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',239), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',245), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',251), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',257), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',263), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',269), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',275), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',281), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',287), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',293), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',299), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',305), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',311), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',317), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',323), + ('program -> class_list','program',1,'p_program','parser.py',39), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',44), + ('class_list -> class ;','class_list',2,'p_class_list','parser.py',45), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',53), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',54), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',64), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',65), + ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',66), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',74), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',75), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',85), + ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',91), + ('params_list -> param','params_list',1,'p_params_list','parser.py',92), + ('params_list -> empty','params_list',1,'p_params_list_empty','parser.py',100), + ('param -> ID : TYPE','param',3,'p_param','parser.py',105), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',111), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',112), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',120), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',126), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',132), + ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',138), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',144), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',150), + ('let_list -> let_single','let_list',1,'p_let_list','parser.py',151), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',159), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',160), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',169), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',175), + ('case_list -> case_single','case_list',1,'p_case_list','parser.py',176), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',184), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',190), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',191), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',192), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',207), + ('args_list -> expression','args_list',1,'p_args_list','parser.py',208), + ('args_list -> empty','args_list',1,'p_args_list_empty','parser.py',216), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',221), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',227), + ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',233), + ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',239), + ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',245), + ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',251), + ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',257), + ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',263), + ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',269), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',275), + ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',281), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',287), + ('expression -> STRING','expression',1,'p_expression_string','parser.py',293), + ('expression -> ID','expression',1,'p_expression_variable','parser.py',299), + ('expression -> TRUE','expression',1,'p_expression_true','parser.py',305), + ('expression -> FALSE','expression',1,'p_expression_false','parser.py',311), + ('expression -> INT','expression',1,'p_expression_int','parser.py',317), + ('empty -> ','empty',0,'p_empty','parser.py',323), ] diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index a1b872bc6..37d88203e 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -117,7 +117,7 @@ def visit(self, node, scopex: Scope): body_clone = body_type.clone() if not conforms(body_type, node_type): self.add_error( - node, + body_node, f"TypeError: In Class '{self.current_type.name}' method " f"'{method_node.id}' return expression type({body_clone.name})" f" does not conforms to declared return type ({node_type.name})", diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 91c9d344c..829f5d38c 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -120,7 +120,7 @@ def visit(self, node, scopex: Scope): ret_expr_clone = ret_type_expr.clone() if not conforms(ret_type_expr, ret_type_decl): self.add_error( - node, + body_node, f"TypeError: In Class '{self.current_type.name}' method" f" '{current_method.name}' return expression type({ret_expr_clone.name})" f" does not conforms to declared return type ({ret_type_decl.name})", diff --git a/tests/lexer_test.py b/tests/lexer_test.py index e105f16db..9a3b7f6a6 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -6,13 +6,13 @@ tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -@pytest.mark.lexer -@pytest.mark.error -@pytest.mark.run(order=1) -@pytest.mark.parametrize("cool_file", tests) -def test_lexer_errors(compiler_path, cool_file): - print(compiler_path) - print(cool_file) - compare_errors( - compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" - ) +# @pytest.mark.lexer +# @pytest.mark.error +# @pytest.mark.run(order=1) +# @pytest.mark.parametrize("cool_file", tests) +# def test_lexer_errors(compiler_path, cool_file): +# print(compiler_path) +# print(cool_file) +# compare_errors( +# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" +# ) diff --git a/tests/parser_test.py b/tests/parser_test.py index 67b74ed54..106c93331 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -1,13 +1,16 @@ # import pytest # import os # from utils import compare_errors - -# tests_dir = __file__.rpartition('/')[0] + '/parser/' -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] - +# +# tests_dir = __file__.rpartition("/")[0] + "/parser/" +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +# +# # @pytest.mark.parser # @pytest.mark.error # @pytest.mark.run(order=2) # @pytest.mark.parametrize("cool_file", tests) # def test_parser_errors(compiler_path, cool_file): -# compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file +# compare_errors( +# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" +# ) diff --git a/tests/semantic_test.py b/tests/semantic_test.py index b4bf38b1f..c80b3552d 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -1,14 +1,19 @@ -# import pytest -# import os -# from utils import compare_errors, first_error_only_line +import pytest +import os +from utils import compare_errors, first_error_only_line -# tests_dir = __file__.rpartition('/')[0] + '/semantic/' -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests_dir = __file__.rpartition("/")[0] + "/semantic/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -# @pytest.mark.semantic -# @pytest.mark.error -# @pytest.mark.run(order=3) -# @pytest.mark.parametrize("cool_file", tests) -# def test_semantic_errors(compiler_path, cool_file): -# compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ -# cmp=first_error_only_line) \ No newline at end of file + +@pytest.mark.semantic +@pytest.mark.error +@pytest.mark.run(order=3) +@pytest.mark.parametrize("cool_file", tests) +def test_semantic_errors(compiler_path, cool_file): + compare_errors( + compiler_path, + tests_dir + cool_file, + tests_dir + cool_file[:-3] + "_error.txt", + cmp=first_error_only_line, + ) From a71191b2deea28c8d03d5648c868f92e22c2dc3b Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 23 Apr 2021 17:55:46 -0400 Subject: [PATCH 069/432] Pass parser unit test --- src/__main__.py | 22 ++--- src/lexing/lexer.py | 30 +++--- src/parsing/parser.py | 201 ++++++++++++++++++++-------------------- src/parsing/parsetab.py | 116 +++++++++++------------ src/test.cl | Bin 233 -> 35 bytes tests/parser_test.py | 22 ++--- 6 files changed, 193 insertions(+), 198 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 424ab8f09..ccf8617e4 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -51,27 +51,21 @@ def main(): program = open(input_file).read() lexer = Lexer() - - # parser = Parser(lexer) - # ast = parser.parse(program) - # print(ast) - tokens = list(lexer.tokenize(program)) - # print(tokens) - # print(lexer.errors) + # for token in tokens: + # print(token, token.line, token.col) - # lexer.input(program) - # tokens = [] - # for token in lexer: - # # tokens.append(token) if lexer.errors: for error in lexer.errors: print(error) exit(1) - # ast = parser.parse(program) - - # run_pipeline(ast) + parser = Parser(Lexer()) + ast = parser.parse(program) + if parser.errors: + for error in parser.errors: + print(error) + exit(1) main() diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index f77f21b67..dca17f790 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -81,9 +81,9 @@ def tokenize(self, data): line, col = self._get_current_pos(data) self.errors.append(LexicographicError(line, col, "INVALID COMMENT")) break - if not self._end_string and self._lexer.lexpos -1 <= len(data) : + if not self._end_string and self._lexer.lexpos - 1 <= len(data): line = self._lexer.lineno - col = self._lexer.col + 1 + col = self._lexer.col + 1 self.errors.append(LexicographicError(line, col, "UNTERMINATED STRING")) if not tok: break @@ -131,7 +131,6 @@ def t_ID(self, t): t.type = self.reserved.get(t.value.lower(), "ID") return t - def t_INT(self, t): r"\d+" self._set_pos(t) @@ -156,7 +155,6 @@ def t_string(self, t): self._end_string = False t.lexer.begin("string") - def t_string_end(self, t): r'(? None: self.errors = [] self.lexer = lexer self.tokens = lexer.tokens - + self.precedence = ( ("right", "ASSIGN"), ("right", "NOT"), @@ -31,16 +53,15 @@ def __init__(self, lexer) -> None: def _build(self): self._parser = yacc(module=self) - - def parse(self,program): + + def parse(self, program): return self._parser.parse(program) - def p_program(self,p): + def p_program(self, p): """program : class_list""" p[0] = ProgramNode(p[1]) - - def p_class_list(self,p): + def p_class_list(self, p): """class_list : class ';' class_list | class ';'""" if len(p) == 4: @@ -48,8 +69,7 @@ def p_class_list(self,p): elif len(p) == 3: p[0] = [p[1]] - - def p_class(self,p): + def p_class(self, p): """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' | CLASS TYPE '{' feature_list '}'""" if len(p) == 8: @@ -59,8 +79,7 @@ def p_class(self,p): p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_feature_list(self,p): + def p_feature_list(self, p): """feature_list : attribute ';' feature_list | method ';' feature_list | empty""" @@ -69,8 +88,7 @@ def p_feature_list(self,p): elif len(p) == 2: p[0] = [] - - def p_attribute(self,p): + def p_attribute(self, p): """attribute : ID ':' TYPE ASSIGN expression | ID ':' TYPE""" if len(p) == 6: @@ -80,14 +98,13 @@ def p_attribute(self,p): p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_method(self,p): - """method : ID '(' params_list ')' ':' TYPE '{' expression '}'""" + def p_method(self, p): + """method : ID '(' params_list ')' ':' TYPE '{' expression '}' + | ID '(' empty ')' ':' TYPE '{' expression '}'""" p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_params_list(self,p): + def p_params_list(self, p): """params_list : param ',' params_list | param""" if len(p) == 4: @@ -95,19 +112,16 @@ def p_params_list(self,p): else: p[0] = [p[1]] + # def p_params_list_empty(self,p): + # """params_list : empty""" + # p[0] = [] - def p_params_list_empty(self,p): - """params_list : empty""" - p[0] = [] - - - def p_param(self,p): + def p_param(self, p): """param : ID ':' TYPE""" p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_list(self,p): + def p_expression_list(self, p): """expression_list : expression ';' expression_list | expression ';'""" if len(p) == 4: @@ -115,38 +129,32 @@ def p_expression_list(self,p): elif len(p) == 3: p[0] = [p[1]] - - def p_expression_assigment(self,p): + def p_expression_assigment(self, p): """expression : ID ASSIGN expression""" p[0] = AssignNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_if_then_else(self,p): + def p_expression_if_then_else(self, p): """expression : IF expression THEN expression ELSE expression FI""" p[0] = ConditionalNode(p[2], p[4], p[6]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_while(self,p): + def p_expression_while(self, p): """expression : WHILE expression LOOP expression POOL""" p[0] = LoopNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_block(self,p): + def p_expression_block(self, p): """expression : '{' expression_list '}'""" p[0] = BlocksNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_let_in(self,p): + def p_expression_let_in(self, p): """expression : LET let_list IN expression""" p[0] = LetNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_let_list(self,p): + def p_let_list(self, p): """let_list : let_single ',' let_list | let_single""" if len(p) == 4: @@ -154,8 +162,7 @@ def p_let_list(self,p): else: p[0] = [p[1]] - - def p_let_single(self,p): + def p_let_single(self, p): """let_single : ID ':' TYPE ASSIGN expression | ID ':' TYPE""" if len(p) == 6: @@ -164,14 +171,12 @@ def p_let_single(self,p): p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_case(self,p): + def p_expression_case(self, p): """expression : CASE expression OF case_list ESAC""" p[0] = CaseNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_case_list(self,p): + def p_case_list(self, p): """case_list : case_single case_list | case_single""" if len(p) == 3: @@ -179,14 +184,12 @@ def p_case_list(self,p): else: p[0] = [p[1]] - - def p_case_single(self,p): + def p_case_single(self, p): """case_single : ID ':' TYPE RET expression ';'""" p[0] = CaseOptionNode(p[1], p[3], p[5]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_dispatch(self,p): + def p_expression_dispatch(self, p): """expression : expression '@' TYPE '.' ID '(' args_list ')' | expression '.' ID '(' args_list ')' | ID '(' args_list ')'""" @@ -202,8 +205,23 @@ def p_expression_dispatch(self,p): p[0] = MethodCallNode(None, None, p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_dispatch_empty(self, p): + """expression : expression '@' TYPE '.' ID '(' empty ')' + | expression '.' ID '(' empty ')' + | ID '(' empty ')'""" + if len(p) == 9: + p[0] = MethodCallNode(p[1], p[3], p[5], p[7]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + elif len(p) == 7: + p[0] = MethodCallNode(p[1], None, p[3], p[5]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + else: + p[0] = MethodCallNode(None, None, p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_args_list(self,p): + def p_args_list(self, p): """args_list : expression ',' args_list | expression""" if len(p) == 4: @@ -211,118 +229,101 @@ def p_args_list(self,p): else: p[0] = [p[1]] + # def p_args_list_empty(self,p): + # """args_list : empty""" + # p[0] = [] - def p_args_list_empty(self,p): - """args_list : empty""" - p[0] = [] - - - def p_expression_instatiate(self,p): + def p_expression_instatiate(self, p): """expression : NEW TYPE""" p[0] = InstantiateNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_isvoid(self,p): + def p_expression_isvoid(self, p): """expression : ISVOID expression""" p[0] = IsVoidNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_not(self,p): + def p_expression_not(self, p): """expression : NOT expression""" p[0] = NotNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_complement(self,p): + def p_expression_complement(self, p): """expression : '~' expression""" p[0] = ComplementNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_plus(self,p): + def p_expression_plus(self, p): """expression : expression '+' expression""" p[0] = PlusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_minus(self,p): + def p_expression_minus(self, p): """expression : expression '-' expression""" p[0] = MinusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_div(self,p): + def p_expression_div(self, p): """expression : expression '/' expression""" p[0] = DivNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_star(self,p): + def p_expression_star(self, p): """expression : expression '*' expression""" p[0] = StarNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_less(self,p): + def p_expression_less(self, p): """expression : expression '<' expression""" p[0] = LessNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_lesseq(self,p): + def p_expression_lesseq(self, p): """expression : expression LESSEQ expression""" p[0] = LessOrEqualNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_equals(self,p): + def p_expression_equals(self, p): """expression : expression '=' expression""" p[0] = EqualsNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_parentheses(self,p): + def p_expression_parentheses(self, p): """expression : '(' expression ')'""" p[0] = p[2] p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_string(self,p): + def p_expression_string(self, p): """expression : STRING""" p[0] = StringNode(p[1]) p[0].set_position(p.slice[1].lineno, p.slice[1].col) - - def p_expression_variable(self,p): + def p_expression_variable(self, p): """expression : ID""" p[0] = VariableNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_true(self,p): + def p_expression_true(self, p): """expression : TRUE""" p[0] = BooleanNode(True) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_false(self,p): + def p_expression_false(self, p): """expression : FALSE""" p[0] = BooleanNode(False) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_int(self,p): + def p_expression_int(self, p): """expression : INT""" p[0] = IntNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_empty(self,p): + def p_empty(self, p): """empty : """ p[0] = [] - - def p_error(self,t): - print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") + def p_error(self, t): + if t is None: + self.errors.append(SyntacticError("EOF", 0, 0)) + else: + self.errors.append(SyntacticError(t.value, t.line, t.col)) diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 4ca3752b3..30b6d6d16 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,9 +6,9 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS COMMENT ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'\n | ID '(' empty ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'expression : expression '@' TYPE '.' ID '(' empty ')'\n | expression '.' ID '(' empty ')'\n | ID '(' empty ')'args_list : expression ',' args_list\n | expressionexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " -_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,36,37,48,49,50,51,70,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,132,133,135,136,142,144,145,146,],[5,18,19,-5,-10,-4,-52,-9,-51,-53,-54,-55,98,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-11,-12,-32,-35,-19,-31,-34,147,]),'TYPE':([4,8,20,32,44,53,54,58,101,131,],[6,10,25,52,76,80,81,86,116,139,]),'INHERITS':([6,],[8,]),'{':([6,10,31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,80,81,95,96,98,99,104,105,108,110,126,128,134,143,],[9,16,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,104,105,40,40,40,40,40,40,40,40,40,40,40,40,]),'ID':([9,16,18,19,21,31,35,38,39,40,41,42,43,45,46,47,56,57,59,60,61,62,63,64,65,66,95,96,98,99,100,102,104,105,108,109,110,118,126,128,134,143,147,],[15,15,15,15,26,36,26,36,36,36,73,36,36,36,36,36,36,36,87,36,36,36,36,36,36,36,36,36,36,36,73,119,36,36,36,123,36,119,36,36,36,36,-30,]),'}':([9,11,14,16,18,19,22,23,24,36,48,49,50,51,69,76,77,78,79,82,88,89,90,91,92,93,94,97,98,103,106,107,113,114,120,121,127,129,135,136,142,144,145,],[-56,17,-8,-56,-56,-56,30,-6,-7,-52,-51,-53,-54,-55,97,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-17,-50,-33,-36,-16,-22,132,133,-20,-27,-32,-35,-19,-31,-34,]),':':([15,26,33,34,73,119,],[20,32,53,54,101,131,]),'(':([15,31,36,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,87,95,96,98,99,104,105,108,110,123,126,128,134,143,],[21,43,57,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,110,43,43,43,43,43,43,43,43,134,43,43,43,43,]),')':([21,27,28,29,36,48,49,50,51,52,55,57,75,76,77,78,79,82,83,84,85,88,89,90,91,92,93,94,97,103,106,107,110,114,122,124,125,127,129,134,135,136,140,141,142,144,145,],[-56,33,34,-14,-52,-51,-53,-54,-55,-15,-13,-56,103,-39,-40,-41,-42,-18,106,107,-38,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-56,-22,-37,135,136,-20,-27,-56,-32,-35,144,145,-19,-31,-34,]),'ASSIGN':([25,36,116,],[31,56,128,]),',':([29,36,48,49,50,51,52,72,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,114,116,127,129,135,136,138,142,144,145,],[35,-52,-51,-53,-54,-55,-15,100,-39,-40,-41,-42,-18,108,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'IF':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'WHILE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,]),'LET':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'CASE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,]),'NEW':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'ISVOID':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'NOT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'~':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'STRING':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'TRUE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'FALSE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'INT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,]),'@':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,58,-51,-53,-54,-55,58,58,58,58,58,-39,58,58,58,58,58,58,58,58,58,58,58,58,-21,-50,-33,-36,58,58,58,58,58,-20,-27,-32,-35,58,58,-19,-31,-34,58,]),'.':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,86,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,59,-51,-53,-54,-55,59,59,59,59,59,-39,59,59,59,59,59,109,59,59,59,59,59,59,59,-21,-50,-33,-36,59,59,59,59,59,-20,-27,-32,-35,59,59,-19,-31,-34,59,]),'+':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,60,-51,-53,-54,-55,60,60,60,60,60,-39,-40,60,-42,60,60,-43,-44,-45,-46,60,60,60,-21,-50,-33,-36,60,60,60,60,60,-20,-27,-32,-35,60,60,-19,-31,-34,60,]),'-':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,61,-51,-53,-54,-55,61,61,61,61,61,-39,-40,61,-42,61,61,-43,-44,-45,-46,61,61,61,-21,-50,-33,-36,61,61,61,61,61,-20,-27,-32,-35,61,61,-19,-31,-34,61,]),'/':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,62,-51,-53,-54,-55,62,62,62,62,62,-39,-40,62,-42,62,62,62,62,-45,-46,62,62,62,-21,-50,-33,-36,62,62,62,62,62,-20,-27,-32,-35,62,62,-19,-31,-34,62,]),'*':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,63,-51,-53,-54,-55,63,63,63,63,63,-39,-40,63,-42,63,63,63,63,-45,-46,63,63,63,-21,-50,-33,-36,63,63,63,63,63,-20,-27,-32,-35,63,63,-19,-31,-34,63,]),'<':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,64,-51,-53,-54,-55,64,64,64,64,64,-39,-40,64,-42,64,64,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,64,64,64,64,64,-20,-27,-32,-35,64,64,-19,-31,-34,64,]),'LESSEQ':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,65,-51,-53,-54,-55,65,65,65,65,65,-39,-40,65,-42,65,65,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,65,65,65,65,65,-20,-27,-32,-35,65,65,-19,-31,-34,65,]),'=':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,66,-51,-53,-54,-55,66,66,66,66,66,-39,-40,66,-42,66,66,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,66,66,66,66,66,-20,-27,-32,-35,66,66,-19,-31,-34,66,]),'THEN':([36,48,49,50,51,67,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,95,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'LOOP':([36,48,49,50,51,68,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,96,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'OF':([36,48,49,50,51,74,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,102,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'ELSE':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,111,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,126,-22,-20,-27,-32,-35,-19,-31,-34,]),'POOL':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,112,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,127,-22,-20,-27,-32,-35,-19,-31,-34,]),'FI':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,137,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,142,-19,-31,-34,]),'IN':([36,48,49,50,51,71,72,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,115,116,127,129,135,136,138,142,144,145,],[-52,-51,-53,-54,-55,99,-24,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-23,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'ESAC':([117,118,130,147,],[129,-29,-28,-30,]),'RET':([139,],[143,]),} _lr_action = {} for _k, _v in _lr_action_items.items(): @@ -17,7 +17,7 @@ _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,18,19,],[11,22,23,24,]),'attribute':([9,16,18,19,],[12,12,12,12,]),'method':([9,16,18,19,],[13,13,13,13,]),'empty':([9,16,18,19,21,34,55,103,105,126,],[14,14,14,14,29,29,82,82,82,82,]),'params_list':([21,34,],[27,53,]),'param':([21,34,],[28,28,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,68,109,115,81,81,128,129,81,135,]),'expression_list':([39,95,],[67,108,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,18,19,],[11,22,23,24,]),'attribute':([9,16,18,19,],[12,12,12,12,]),'method':([9,16,18,19,],[13,13,13,13,]),'empty':([9,16,18,19,21,57,110,134,],[14,14,14,14,28,84,125,141,]),'params_list':([21,35,],[27,55,]),'param':([21,35,],[29,29,]),'expression':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[37,67,68,70,74,75,77,78,79,82,85,88,89,90,91,92,93,94,111,112,70,114,120,121,85,85,137,138,85,146,]),'expression_list':([40,98,],[69,113,]),'let_list':([41,100,],[71,115,]),'let_single':([41,100,],[72,72,]),'args_list':([57,108,110,134,],[83,122,124,140,]),'case_list':([102,118,],[117,130,]),'case_single':([102,118,],[118,118,]),} _lr_goto = {} for _k, _v in _lr_goto_items.items(): @@ -27,58 +27,60 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parsing_rules.py',39), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parsing_rules.py',44), - ('class_list -> class ;','class_list',2,'p_class_list','parsing_rules.py',45), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parsing_rules.py',53), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parsing_rules.py',54), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',64), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parsing_rules.py',65), - ('feature_list -> empty','feature_list',1,'p_feature_list','parsing_rules.py',66), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parsing_rules.py',74), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parsing_rules.py',75), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parsing_rules.py',85), - ('params_list -> param , params_list','params_list',3,'p_params_list','parsing_rules.py',91), - ('params_list -> param','params_list',1,'p_params_list','parsing_rules.py',92), - ('params_list -> empty','params_list',1,'p_params_list_empty','parsing_rules.py',100), - ('param -> ID : TYPE','param',3,'p_param','parsing_rules.py',105), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parsing_rules.py',111), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parsing_rules.py',112), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parsing_rules.py',120), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parsing_rules.py',126), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parsing_rules.py',132), - ('expression -> { expression_list }','expression',3,'p_expression_block','parsing_rules.py',138), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parsing_rules.py',144), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parsing_rules.py',150), - ('let_list -> let_single','let_list',1,'p_let_list','parsing_rules.py',151), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parsing_rules.py',159), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parsing_rules.py',160), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parsing_rules.py',169), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parsing_rules.py',175), - ('case_list -> case_single','case_list',1,'p_case_list','parsing_rules.py',176), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parsing_rules.py',184), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parsing_rules.py',190), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parsing_rules.py',191), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parsing_rules.py',192), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parsing_rules.py',207), - ('args_list -> expression','args_list',1,'p_args_list','parsing_rules.py',208), - ('args_list -> empty','args_list',1,'p_args_list_empty','parsing_rules.py',216), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parsing_rules.py',221), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parsing_rules.py',227), - ('expression -> NOT expression','expression',2,'p_expression_not','parsing_rules.py',233), - ('expression -> ~ expression','expression',2,'p_expression_complement','parsing_rules.py',239), - ('expression -> expression + expression','expression',3,'p_expression_plus','parsing_rules.py',245), - ('expression -> expression - expression','expression',3,'p_expression_minus','parsing_rules.py',251), - ('expression -> expression / expression','expression',3,'p_expression_div','parsing_rules.py',257), - ('expression -> expression * expression','expression',3,'p_expression_star','parsing_rules.py',263), - ('expression -> expression < expression','expression',3,'p_expression_less','parsing_rules.py',269), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parsing_rules.py',275), - ('expression -> expression = expression','expression',3,'p_expression_equals','parsing_rules.py',281), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parsing_rules.py',287), - ('expression -> STRING','expression',1,'p_expression_string','parsing_rules.py',293), - ('expression -> ID','expression',1,'p_expression_variable','parsing_rules.py',299), - ('expression -> TRUE','expression',1,'p_expression_true','parsing_rules.py',305), - ('expression -> FALSE','expression',1,'p_expression_false','parsing_rules.py',311), - ('expression -> INT','expression',1,'p_expression_int','parsing_rules.py',317), - ('empty -> ','empty',0,'p_empty','parsing_rules.py',323), + ('program -> class_list','program',1,'p_program','parser.py',61), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',65), + ('class_list -> class ;','class_list',2,'p_class_list','parser.py',66), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',73), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',74), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',83), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',84), + ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',85), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',92), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',93), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',102), + ('method -> ID ( empty ) : TYPE { expression }','method',9,'p_method','parser.py',103), + ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',108), + ('params_list -> param','params_list',1,'p_params_list','parser.py',109), + ('param -> ID : TYPE','param',3,'p_param','parser.py',120), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',125), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',126), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',133), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',138), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',143), + ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',148), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',153), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',158), + ('let_list -> let_single','let_list',1,'p_let_list','parser.py',159), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',166), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',167), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',175), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',180), + ('case_list -> case_single','case_list',1,'p_case_list','parser.py',181), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',188), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',193), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',194), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',195), + ('expression -> expression @ TYPE . ID ( empty )','expression',8,'p_expression_dispatch_empty','parser.py',209), + ('expression -> expression . ID ( empty )','expression',6,'p_expression_dispatch_empty','parser.py',210), + ('expression -> ID ( empty )','expression',4,'p_expression_dispatch_empty','parser.py',211), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',225), + ('args_list -> expression','args_list',1,'p_args_list','parser.py',226), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',237), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',242), + ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',247), + ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',252), + ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',257), + ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',262), + ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',267), + ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',272), + ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',277), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',282), + ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',287), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',292), + ('expression -> STRING','expression',1,'p_expression_string','parser.py',297), + ('expression -> ID','expression',1,'p_expression_variable','parser.py',302), + ('expression -> TRUE','expression',1,'p_expression_true','parser.py',307), + ('expression -> FALSE','expression',1,'p_expression_false','parser.py',312), + ('expression -> INT','expression',1,'p_expression_int','parser.py',317), + ('empty -> ','empty',0,'p_empty','parser.py',322), ] diff --git a/src/test.cl b/src/test.cl index 6935ada980145507f4a13b06595d890735a1f2d3..8e5cf617f8a42d18bbdf817bbaabf1400a149627 100644 GIT binary patch literal 35 qcmdPUQgBpo&d<+LC@9KLFG|c+NKVXCFHuNJRY=V(D5+G?(gXm(=L-)2 literal 233 zcmX|4yAH!34D8HToS2dhRoZ?*=Jpd<90*B>0}_xSe_!a!lI8Q=+1H%WBjvdG2^$^o zAwvhBY4OPO2){F<(KAKTd5ln9dqM9HgrY|L1yPTO5sTNno6!^i`aM3kLP%bnNn}^9 zgRN70SE^FAzndeQK1R06CqvFEiNaJ Date: Sat, 24 Apr 2021 09:49:50 -0400 Subject: [PATCH 070/432] Delete unused scripts --- src/ast/checker_ast.py | 0 src/semantics/type_checker.py | 13 ------------- 2 files changed, 13 deletions(-) delete mode 100644 src/ast/checker_ast.py delete mode 100644 src/semantics/type_checker.py diff --git a/src/ast/checker_ast.py b/src/ast/checker_ast.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/semantics/type_checker.py b/src/semantics/type_checker.py deleted file mode 100644 index 553176aa3..000000000 --- a/src/semantics/type_checker.py +++ /dev/null @@ -1,13 +0,0 @@ -from utils import visitor - - -class TypeChecker: - def __init__(self) -> None: - pass - - @visitor.on("node") - def visit(self, node): - pass - - - \ No newline at end of file From c2c1cd3ef9767c1b3a38c70aad2b414e654976f7 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 09:50:09 -0400 Subject: [PATCH 071/432] Small change to VarDeclaration node in inferencer_ast.py All VarDeclaration nodes no longer have propertie defined, now is index indicating position in current scope local variables. --- src/ast/inferencer_ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 0a10e4a54..ab0ef6b64 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -103,7 +103,7 @@ def __init__(self, node): Node.__init__(self, node) self.id = node.id self.expr = None # Expression is set later if it exists - self.defined = False + self.index = None # For debbugin purposes self.type = node.type From f1a3b1e7e77a76856bb0c25d02731393c6cd78d8 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 09:55:14 -0400 Subject: [PATCH 072/432] Several changes in SoftInferencer Added error detection when using self illegally. Added error detection while defining parameters. Fixed error detection un CaseNode and CaseOptionNode. Fixed error detection in LetNode. Also modified internal logic so it fits Cool rules better. Fixed error detection in MethodCallNode. Fixed error detection in VariableNode. Bug fix in IsVoidNode. Removed ComparerNode and added LessOrEqualNode, LessNode and EqualNode each own with its own logic. Modified to fit Cool rules. --- src/semantics/inference/soft_inferencer.py | 163 +++++++++++++-------- 1 file changed, 104 insertions(+), 59 deletions(-) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 829f5d38c..30a579262 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -11,9 +11,12 @@ ComparerNode, ComplementNode, ConditionalNode, + EqualsNode, InstantiateNode, IntNode, IsVoidNode, + LessNode, + LessOrEqualNode, LetNode, LoopNode, MethodCallNode, @@ -27,7 +30,7 @@ ) from utils import visitor -from semantics.errors import SemanticError +from semantics.errors import SemanticError, AttributeError from semantics.tools import ( Context, ErrorType, @@ -37,6 +40,7 @@ join, join_list, smart_add, + try_conform, ) @@ -66,7 +70,8 @@ def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNod scope.define_variable("self", TypeBag({self.current_type})) for attr in self.current_type.attributes: - scope.define_variable(attr.name, attr.type) + if attr.name != "self": + scope.define_variable(attr.name, attr.type) new_features = [] for feature in node.features: @@ -77,6 +82,9 @@ def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNod @visitor.when(AttrDeclarationNode) def visit(self, node, scope): + if node.id == "self": + self.add_error(node, "SemanticError: An attribute cannot be named 'self'") + node_type = self.current_type.get_attribute(node.id).type.swap_self_type( self.current_type ) @@ -90,14 +98,14 @@ def visit(self, node, scope): node_expr = expr_node.inferenced_type - expr_clone = node_expr.clone() + expr_name = node_expr.generate_name() if not conforms(node_expr, node_type): self.add_error( node, ( f"TypeError: In class '{self.current_type.name}' attribue" - f"'{node.id}' expression type({expr_clone.name}) does not conforms" - f"to declared type ({node_type.name})." + f" '{node.id}' expression type({expr_name}) does not conforms" + f" to declared type ({node_type.name})." ), ) expr_node.inferenced_type = ErrorType() @@ -111,6 +119,16 @@ def visit(self, node, scopex: Scope): current_method = self.current_type.get_method(node.id) for idx, typex in zip(current_method.param_names, current_method.param_types): + if idx == "self": + self.add_error( + node, + "SemanticError: Cannot use 'self' as formal parameter identifier", + ) + if scope.is_local(idx): + self.add_error( + node, + f"SemanticError: Formal parameter '{idx}' has been defined multiple times.", + ) scope.define_variable(idx, typex) ret_type_decl = current_method.return_type.swap_self_type(self.current_type) @@ -182,13 +200,17 @@ def visit(self, node, scope: Scope): child = scope.create_child() new_options.append(self.visit(option, child)) type_list.append(new_options[-1].inferenced_type) - var_type = child.find_variable(option.id).type + var_type = child.find_variable(option.id).get_type() + var_type = ( + var_type.heads[0] if not isinstance(var_type, ErrorType) else var_type + ) if var_type in types_visited: self.add_error( - node, - "SemanticError: Case Expression can't have branches" + option, + "SemanticError: Case Expression have 2 or more branches" f"with same case type({var_type.name})", ) + types_visited.add(var_type) joined_type = join_list(type_list) @@ -201,7 +223,7 @@ def visit(self, node, scope: Scope): try: node_type = self.context.get_type(node.type, selftype=False, autotype=False) except SemanticError as err: - self.add_error(node, err) + self.add_error(node, err.text) node_type = ErrorType() scope.define_variable(node.id, node_type) @@ -255,18 +277,17 @@ def visit(self, node, scope: Scope): ) except SemanticError as err: node_type = ErrorType() - self.add_error(node, err) + self.add_error(node, err.text) - if not scope.is_local(node.id): - scope.define_variable(node.id, node_type) - var_decl_node.defined = True - else: + if node.id == "self": self.add_error( node, - f"SemanticError: Variable '{node.id}' already defined" - " in current scope.", + "SemanticError: Cannot bound self in a let expression.", ) - node_type = ErrorType() + var_decl_node.id = "" + + var = scope.define_variable(var_decl_node.id, node_type) + var_decl_node.index = len(scope.locals) - 1 var_decl_node.inferenced_type = node_type @@ -277,12 +298,14 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, node_type): self.add_error( node, - f"TypeError: Variable '{node.id}' expressiontype" - f"({expr_clone.name}) does not conforms to declared" - f"type({node_type.name}).", + f"TypeError: Variable '{node.id}' expression type" + f" ({expr_clone.name}) does not conforms to declared" + f" type({node_type.name}).", ) expr_node.inferenced_type = ErrorType() var_decl_node.expr = expr_node + var_decl_node.inferenced_type = expr_node.inferenced_type + # var.type = var_decl_node.inferenced_type return var_decl_node @@ -295,7 +318,7 @@ def visit(self, node, scope: Scope): if not var: self.add_error( node, - f"ScopeError: Cannot assign new value to" + f"SemanticError: Cannot assign new value to" f"{node.id} beacuse it is not defined in the current scope", ) decl_type = ErrorType() @@ -318,12 +341,12 @@ def visit(self, node, scope: Scope): self.add_error( node, f"TypeError: Cannot assign new value to variable '{node.id}'." - f" Expression type({expr_clone.name}) does not conforms to" + f" expression type({expr_clone.name}) does not conforms to" f" declared type ({decl_type.name}).", ) expr_node.inferenced_type = ErrorType() - assign_node.inferenced_type = decl_type + assign_node.inferenced_type = expr_node.inferenced_type return assign_node @visitor.when(MethodCallNode) @@ -362,21 +385,19 @@ def visit(self, node, scope): else: self.add_error( node, - f"SemanticError: There is no method '{node.id}'" - f"that recieves {len(node.params)} arguments in" - f"types {caller_type.name}.", + f"AtributeError: There is no method '{node.id}'" + f" that recieves {len(node.params)} arguments in" + f" types {caller_type.name}.", ) caller_type = ErrorType() elif len(caller_type.type_set) == 1: caller = caller_type.heads[0] try: methods = [(caller, caller.get_method(node.id))] - except SemanticError: + except AttributeError as err: self.add_error( node, - f"SemanticError: There is no method '{node.id}'" - f"that recieves {len(node.params)} arguments in" - f"Type '{caller.name}'.", + err.text, ) caller_type = ErrorType() @@ -404,33 +425,33 @@ def visit(self, node, scope): @visitor.when(ArithmeticNode) def visit(self, node, scope): - left_node = self.visit(node.left, scope) - left_type = left_node.inferenced_type - left_clone = left_type.clone() + left_node, right_node = self.__arithmetic_operation(node, scope) + arith_node = inf_ast.ArithmeticNode(left_node, right_node, node) + arith_node.inferenced_type = self.context.get_type("Int") + return arith_node - right_node = self.visit(node.right, scope) - right_type = right_node.inferenced_type - right_clone = right_type.clone() + @visitor.when(LessNode) + def visit(self, node, scope: Scope): + left_node, right_node = self.__arithmetic_operation(node, scope) + less_node = inf_ast.LessNode(left_node, right_node, node) + less_node.inferenced_type = self.context.get_type("Bool") + return less_node - int_type = self.context.get_type("Int") - if not conforms(left_type, int_type): - self.add_error( - node.left, - f"TypeError: ArithmeticError: Left member type({left_clone.name})" - " does not conforms to Int type.", - ) - left_node.inferenced_type = ErrorType() - if not conforms(right_type, int_type): - self.add_error( - node.right, - f"TypeError: ArithmeticError: Right member type({right_clone.name})" - " does not conforms to Int type.", - ) - right_node.inferenced_type = ErrorType() + @visitor.when(LessOrEqualNode) + def visit(self, node, scope: Scope): + left_node, right_node = self.__arithmetic_operation(node, scope) + lesseq_node = inf_ast.LessOrEqualNode(left_node, right_node, node) + lesseq_node.inferenced_type = self.context.get_type("Bool") + return lesseq_node - arith_node = inf_ast.ArithmeticNode(left_node, right_node, node) - arith_node.inferenced_type = int_type - return arith_node + @visitor.when(EqualsNode) + def visit(self, node, scope: Scope): + left_node = self.visit(node.left, scope) + right_node = self.visit(node.right, scope) + + equal_node = inf_ast.EqualsNode(left_node, right_node, node) + equal_node.inferenced_type = self.context.get_type("Bool") + return equal_node @visitor.when(ComparerNode) def visit(self, node, scope): @@ -471,9 +492,7 @@ def visit(self, node, scope: Scope): var_type = var.get_type() else: var_type = ErrorType() - self.add_error( - node, f"SemanticError: Variable '{node.value}' is not defined." - ) + self.add_error(node, f"NameError: Variable '{node.value}' is not defined.") var_node.inferenced_type = var_type return var_node @@ -506,7 +525,7 @@ def visit(self, node, scope): if not conforms(expr_type, int_type): self.add_error( node, - f"TypeError: ~ expresion type({expr_clone.name} does not" + f"TypeError: ~ expresion type({expr_clone.name}) does not" " conforms to Int type", ) expr_node.inferenced_type = ErrorType() @@ -518,7 +537,7 @@ def visit(self, node, scope): @visitor.when(IsVoidNode) def visit(self, node, scope): node_expr = self.visit(node.expr, scope) - is_void_node = IsVoidNode(node_expr, node) + is_void_node = inf_ast.IsVoidNode(node_expr, node) is_void_node.inferenced_type = self.context.get_type("Bool") return is_void_node @@ -556,6 +575,32 @@ def visit(self, node, scope): bool_node.inferenced_type = self.context.get_type("Bool") return bool_node + def __arithmetic_operation(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + left_clone = left_type.clone() + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + right_clone = right_type.clone() + + int_type = self.context.get_type("Int") + if not conforms(left_type, int_type): + self.add_error( + node.left, + f"TypeError: ArithmeticError: Left member type({left_clone.name})" + " does not conforms to Int type.", + ) + left_node.inferenced_type = ErrorType() + if not conforms(right_type, int_type): + self.add_error( + node.right, + f"TypeError: ArithmeticError: Right member type({right_clone.name})" + " does not conforms to Int type.", + ) + right_node.inferenced_type = ErrorType() + return left_node, right_node + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) self.errors.append(((line, col), f"({line}, {col}) - " + text)) From ee8cde9a9536b8652420a9cf93eaf04d6f717c62 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:05:57 -0400 Subject: [PATCH 073/432] Erase unused code from SoftInferencer --- src/semantics/inference/soft_inferencer.py | 29 ---------------------- 1 file changed, 29 deletions(-) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 30a579262..f1de41f58 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -453,35 +453,6 @@ def visit(self, node, scope: Scope): equal_node.inferenced_type = self.context.get_type("Bool") return equal_node - @visitor.when(ComparerNode) - def visit(self, node, scope): - left_node = self.visit(node.left, scope) - left_type = left_node.inferenced_type - left_clone = left_type.clone() - - right_node = self.visit(node.right, scope) - right_type = right_node.inferenced_type - right_clone = right_type.clone() - - if not conforms(left_type, right_type): - self.add_error( - node, - f"TypeError: Left expression type({left_clone.name})" - f"does not conforms to right expression type({right_type.name})", - ) - left_node.inferenced_type = ErrorType() - elif not conforms(right_type, left_type): - self.add_error( - node, - f"TypeError: Right expression type({right_clone.name})" - f"does not conforms to left expression type({left_type.name})", - ) - right_node.inferenced_type = ErrorType() - - comparer_node = inf_ast.ComparerNode(left_node, right_node, node) - comparer_node.inferenced_type = self.context.get_type("Bool") - return comparer_node - @visitor.when(VariableNode) def visit(self, node, scope: Scope): var_node = inf_ast.VariableNode(node) From 8ac1d776f955e2d50d5f1a74907fdd26eda3e203 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:06:39 -0400 Subject: [PATCH 074/432] Changes to __main__.py Added semantic checking pipelining. --- src/__main__.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index a7c61f179..5751d7aca 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,4 +1,4 @@ -from os import error +from os import close, error from semantics.inference.hard_inferencer import HardInferencer import sys @@ -16,7 +16,7 @@ def format_errors(errors, s=""): - errors.sort(key=lambda x: x[0]) + # errors.sort(key=lambda x: x[0]) for error in errors: s += error[1] + "\n" return s[:-1] @@ -29,8 +29,9 @@ def run_pipeline(program_ast): context = collector.context errors = collector.errors - builder = TypeBuilder(context, errors) + builder = TypeBuilder(context) builder.visit(program_ast) + errors += builder.errors soft = SoftInferencer(context) soft_ast = soft.visit(program_ast) @@ -50,16 +51,16 @@ def run_pipeline(program_ast): # print(s) -input_file = "methods2.cl" # "src/test.cl" - - def main(): - # if len(sys.argv) > 1: - # input_file = sys.argv[1] - # else: - # raise Exception("Incorrect number of arguments") + if len(sys.argv) > 1: + input_file = sys.argv[1] + " " + sys.argv[2] + " " + sys.argv[3] + else: + input_file = "self3.cl" + # raise Exception("Incorrect number of arguments") - program = open(input_file).read() + program_file = open(input_file) + program = program_file.read() + program_file.close() lexer = Lexer() tokens = list(lexer.tokenize(program)) @@ -78,5 +79,7 @@ def main(): print(error) exit(1) + run_pipeline(ast) + main() From 1e4efe15b99e694a5fac9a779c584a1964e47dbc Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:08:18 -0400 Subject: [PATCH 075/432] Fixed many bugs in tools.py Minor changes to TypeBag and ErrorType. Minor changes to Sccope --- src/semantics/tools.py | 45 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/semantics/tools.py b/src/semantics/tools.py index d9b08eaea..3ff8a42be 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools.py @@ -93,19 +93,21 @@ def get_method(self, name: str, local: bool = False, first=None): if not first: first = self.name elif first == self.name: - raise SemanticError(f'Method "{name}" is not defined in class {self.name}.') + raise AttributeError( + f'Method "{name}" is not defined in class {self.name}.' + ) try: return next(method for method in self.methods if method.name == name) except StopIteration: if self.parent is None: - raise SemanticError( + raise AttributeError( f'Method "{name}" is not defined in class {self.name}.' ) try: return self.parent.get_method(name, first=first) - except SemanticError: - raise SemanticError( + except AttributeError: + raise AttributeError( f'Method "{name}" is not defined in class {self.name}.' ) @@ -252,15 +254,16 @@ def __init__(self, type_set, heads=[]) -> None: if len(self.type_set) == 1: self.heads = list(self.type_set) - self.name = self.generate_name() + self.name = "undefined" self.condition_list = [] self.conform_list = [] + self.generate_name() def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list self.update_type_set_from_conforms() - self.name = self.generate_name() + self.generate_name() def update_type_set_from_conforms(self): intersect_set = set() @@ -311,18 +314,20 @@ def swap_self_type(self, swap_type, back=False): self.heads[i] = add_type break - self.name = self.generate_name() + self.generate_name() return self def generate_name(self): if len(self.type_set) == 1: - return self.heads[0].name + self.name = self.heads[0].name + return self.name s = "{" s += ", ".join( typex.name for typex in sorted(self.type_set, key=lambda t: t.index) ) s += "}" + self.name = s return s def clone(self): @@ -378,9 +383,9 @@ def conforms_to(self, other): ) -class ErrorType(Type): +class ErrorType(TypeBag): def __init__(self): - self.name = "" + self.name = "" self.index = 2 ** 32 self.type_set = frozenset() self.heads = frozenset() @@ -391,12 +396,15 @@ def conforms_to(self, other): def bypass(self): return True - def swap_self_type(self, swap_type): + def swap_self_type(self, swap_type, back=False): return self def set_conditions(self, *params): return + def generate_name(self): + return "" + def clone(self): return self @@ -462,7 +470,7 @@ def __init__(self, name, vtype) -> None: self.type: TypeBag = vtype def get_type(self) -> TypeBag or ErrorType: - if isinstance(self.type, ErrorType): + if len(self.type.type_set) == 0: self.type = ErrorType() return self.type @@ -505,6 +513,9 @@ def find_variable(self, vname, index=None): except AttributeError: return None + def get_local_by_index(self, index): + return self.locals[index] + def is_defined(self, vname): return self.find_variable(vname) is not None @@ -535,6 +546,9 @@ def get_all_names(self, s: str = "", level: int = 0): def conforms(bag1: TypeBag, bag2: TypeBag) -> bool: + if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + return True + ordered_set = order_set_by_index(bag2.type_set) condition_list = [] @@ -564,6 +578,11 @@ def try_conform(bag1: TypeBag, bag2: TypeBag) -> TypeBag: def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: + if isinstance(bag1, ErrorType): + return bag2 + if isinstance(bag2, ErrorType): + return bag1 + ancestor_set = set() head_list = [] ordered_set1: Set[Type] = order_set_by_index(bag1.type_set) @@ -607,6 +626,8 @@ def join_list(type_list): def equal(bag1: TypeBag, bag2: TypeBag): + if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + return True set1 = bag1.type_set set2 = bag2.type_set return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) From 50cbad92c84a830df7ec41576fa94aab3f62fe7b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:10:44 -0400 Subject: [PATCH 076/432] Minor changes in __init.py in semantics and inference modules --- src/semantics/__init__.py | 3 +-- src/semantics/inference/__init__.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/semantics/__init__.py b/src/semantics/__init__.py index f01080613..62abedc2d 100644 --- a/src/semantics/__init__.py +++ b/src/semantics/__init__.py @@ -1,3 +1,2 @@ -from .type_checker import TypeChecker from .type_builder import TypeBuilder -from .type_collector import TypeCollector \ No newline at end of file +from .type_collector import TypeCollector diff --git a/src/semantics/inference/__init__.py b/src/semantics/inference/__init__.py index 38702902e..d9a4d8525 100644 --- a/src/semantics/inference/__init__.py +++ b/src/semantics/inference/__init__.py @@ -1,2 +1,3 @@ from .soft_inferencer import SoftInferencer from .back_inferencer import BackInferencer +from .hard_inferencer import HardInferencer From cb5b261ec61e7f6c44ddff9d116fc62bcc901559 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:11:06 -0400 Subject: [PATCH 077/432] Several changes to HardInferencer Various bug fixing all around the code. Major bug fixes when visiting MethodCallNode. Updated logic when visiting VarDeclaration. Now it follow Cool rules to the letter. Removed Comparer node and added LessNode, LessOrEqualNode and EqualNode, each one with it's own logic. Added new set of rules for AUTO_TYPEs when doing an Equal comparison. --- src/semantics/inference/hard_inferencer.py | 284 +++++++++++++-------- 1 file changed, 178 insertions(+), 106 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 37d88203e..bdb0b6cec 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -1,3 +1,4 @@ +from semantics.errors import InternalError, AttributeError from ast.inferencer_ast import ( ArithmeticNode, AssignNode, @@ -10,9 +11,12 @@ ComparerNode, ComplementNode, ConditionalNode, + EqualsNode, InstantiateNode, IntNode, IsVoidNode, + LessNode, + LessOrEqualNode, LetNode, LoopNode, MethodCallNode, @@ -114,12 +118,12 @@ def visit(self, node, scopex: Scope): return method_node node_type = method_node.inferenced_type - body_clone = body_type.clone() + body_name = body_type.generate_name() if not conforms(body_type, node_type): self.add_error( body_node, f"TypeError: In Class '{self.current_type.name}' method " - f"'{method_node.id}' return expression type({body_clone.name})" + f"'{method_node.id}' return expression type({body_name})" f" does not conforms to declared return type ({node_type.name})", ) body_node.inferenced_type = ErrorType() @@ -154,7 +158,7 @@ def visit(self, node, scope): ) condition_node.inferenced_type = ErrorType() - if_node = ConditionalNode(condition_node, then_node, else_node) + if_node = ConditionalNode(condition_node, then_node, else_node, node) if not equal( then_node.inferenced_type, node.then_body.inferenced_type @@ -188,6 +192,7 @@ def visit(self, node, scope: Scope): def visit(self, node, scope: Scope): expr_node = self.visit(node.expr, scope) opt_node = CaseOptionNode(expr_node, node) + opt_node.inferenced_type = expr_node.inferenced_type return opt_node @visitor.when(LoopNode) @@ -228,6 +233,7 @@ def visit(self, node, scope: Scope): @visitor.when(VarDeclarationNode) def visit(self, node, scope: Scope): var_decl_node = VarDeclarationNode(node) + var_decl_node.index = node.index if node.expr is None: var_decl_node.inferenced_type = node.inferenced_type return var_decl_node @@ -235,12 +241,7 @@ def visit(self, node, scope: Scope): expr_node = self.visit(node.expr, scope) var_decl_node.expr = expr_node - if not node.defined: - var_decl_node.inferenced_type = ErrorType() - return var_decl_node - - var_decl_node.defined = True - node_type = scope.find_variable(node.id).get_type() + node_type = scope.get_local_by_index(node.index).get_type() expr_type = expr_node.inferenced_type if equal(expr_type, node.expr.inferenced_type): @@ -248,13 +249,13 @@ def visit(self, node, scope: Scope): if not conforms(expr_type, node_type): self.add_error( node, - f"Semantic Error: Variable '{node.id}' expressiontype" - f"({expr_clone.name}) does not conforms to declared" - f"type({node_type.name}).", + f"Semantic Error: Variable '{node.id}' expression type" + f" ({expr_clone.name}) does not conforms to declared" + f" type({node_type.name}).", ) expr_node.inferenced_type = ErrorType() - var_decl_node.inferenced_type = node_type + # var_decl_node.inferenced_type = expr_node.inferenced_type return var_decl_node @visitor.when(AssignNode) @@ -281,7 +282,7 @@ def visit(self, node, scope: Scope): ) expr_node.inferenced_type = ErrorType() - assign_node.inferenced_type = decl_type + assign_node.inferenced_type = expr_node.inferenced_type return assign_node @visitor.when(MethodCallNode) @@ -291,14 +292,14 @@ def visit(self, node, scope): if node.type is not None and node.expr is not None: expr_node = self.visit(node.expr, scope) expr_type = expr_node.inferenced_type - if not equal(expr_type, node.expression.inferenced_type): + if not equal(expr_type, node.expr.inferenced_type): expr_clone = expr_type.clone() if not conforms(expr_type, caller_type): self.add_error( node, f"SemanticError: Cannot effect dispatch because expression" - f"type({expr_clone.name}) does not conforms to " - f"caller type({caller_type.name}).", + f" type({expr_clone.name}) does not conforms to " + f" caller type({caller_type.name}).", ) caller_type = ErrorType() elif node.expr is not None: @@ -326,42 +327,47 @@ def visit(self, node, scope): ) caller_type = ErrorType() - if len(caller_type.heads) == 1: - caller = caller_type.heads[0] - method = caller.get_method(node.id) - - if len(node.args) != len(method.param_types): - self.add_error( - node, - f"SemanticError: Method '{node.id}' from class " - f"'{caller_type.name}' takes {len(node.args)} arguments but" - f" {method.param_types} were given.'", - ) - node.inferenced_type = ErrorType() - - decl_return_type = method.return_type.clone() - decl_return_type.swap_self_type(caller) - type_set = set() - heads = [] - type_set = smart_add(type_set, heads, decl_return_type) - + if len(caller_type.heads) != 1: new_args = [] - for i in range(len(node.args)): - new_args.append(self.visit(node.args[i], scope)) - - arg_type = new_args[-1].inferenced_type - arg_clone = arg_type.clone() - param_type = method.param_types[i] - if not conforms(arg_type, param_type): + infered_type = ErrorType() + else: + caller = caller_type.heads[0] + try: + method = caller.get_method(node.id) + except AttributeError as err: + # self.add_error(node, err.text) Error notified in soft inferencer + new_args = [] + infered_type = ErrorType() + else: + if len(node.args) != len(method.param_types): self.add_error( - new_args[-1], - f"TypeError: Argument expression type({arg_clone.name}) does" - f" not conforms parameter declared type({param_type.name})", + node, + f"SemanticError: Method '{node.id}' from class " + f"'{caller_type.name}' takes {len(method.param_types)}" + f" positional arguments but {len(node.args)} were given.'", ) - infered_type = TypeBag(type_set, heads) - else: - new_args = [] - infered_type = ErrorType() + node.inferenced_type = ErrorType() + + decl_return_type = method.return_type.clone() + decl_return_type.swap_self_type(caller) + type_set = set() + heads = [] + type_set = smart_add(type_set, heads, decl_return_type) + + new_args = [] + for i in range(len(node.args)): + new_args.append(self.visit(node.args[i], scope)) + if i < len(method.param_types): + arg_type = new_args[-1].inferenced_type + arg_name = arg_type.generate_name() + param_type = method.param_types[i] + if not conforms(arg_type, param_type): + self.add_error( + new_args[-1], + f"TypeError: Argument expression type({arg_name}) does" + f" not conforms parameter declared type({param_type.name})", + ) + infered_type = TypeBag(type_set, heads) call_node = MethodCallNode(caller_type, expr_node, new_args, node) call_node.inferenced_type = infered_type @@ -369,69 +375,35 @@ def visit(self, node, scope): @visitor.when(ArithmeticNode) def visit(self, node, scope): - left_node = self.visit(node.left, scope) - left_type = left_node.inferenced_type - - right_node = self.visit(node.right, scope) - right_type = right_node.inferenced_type - - int_type = self.context.get_type("Int") - if not equal(left_type, node.left.inferenced_type): - if not conforms(left_type, int_type): - left_clone = left_type.clone() - self.add_error( - node.left, - f"TypeError: Arithmetic Error: Left member type({left_clone.name})" - "does not conforms to Int type.", - ) - left_node.inferenced_type = ErrorType() - if not equal(right_type, node.right.inferenced_type): - right_clone = right_type.clone() - if not conforms(right_type, int_type): - self.add_error( - node.right, - f"Type Error: Arithmetic Error: Right member " - f"type({right_clone.name})does not conforms to Int type.", - ) - right_node.inferenced_type = ErrorType() - + left_node, right_node = self.__arithmetic_operation(node, scope) arith_node = ArithmeticNode(left_node, right_node, node) - arith_node.inferenced_type = int_type + arith_node.inferenced_type = self.context.get_type("Int") return arith_node - @visitor.when(ComparerNode) + @visitor.when(LessNode) + def visit(self, node, scope: Scope): + left_node, right_node = self.__arithmetic_operation(node, scope) + less_node = LessNode(left_node, right_node, node) + less_node.inferenced_type = self.context.get_type("Bool") + return less_node + + @visitor.when(LessOrEqualNode) + def visit(self, node, scope: Scope): + left_node, right_node = self.__arithmetic_operation(node, scope) + lesseq_node = LessOrEqualNode(left_node, right_node, node) + lesseq_node.inferenced_type = self.context.get_type("Bool") + return lesseq_node + + @visitor.when(EqualsNode) def visit(self, node, scope): left_node = self.visit(node.left, scope) - left_type = left_node.inferenced_type - right_node = self.visit(node.right, scope) - right_type = right_node.inferenced_type - - if not equal(left_type, node.left.inferenced_type): - if not conforms(left_type, right_type): - left_clone = left_type.clone() - self.add_error( - node.left, - f"TypeError: Comparer Error: Left expression" - f" type({left_clone.name}) " - f" does not conforms to right expression type ({right_type.name}).", - ) - left_node.inferenced_type = ErrorType() - if not equal(right_type, node.right.inferenced_type): - right_clone = right_type.clone() - if not conforms(right_type, left_type): - self.add_error( - node.right, - f"TypeError: Comparer Error: Right expression" - f" type({right_clone.name})" - f" does not conforms to left expression type ({left_type.name}).", - ) - right_node.inferenced_type = ErrorType() + self.__check_member_types(left_node, right_node) - comparer = ComparerNode(left_node, right_node) - comparer.inferenced_type = node.inferenced_type # Bool Type :) - return comparer + eq_node = ComparerNode(left_node, right_node, node) + eq_node.inferenced_type = node.inferenced_type # Bool Type :) + return eq_node @visitor.when(VariableNode) def visit(self, node, scope: Scope): @@ -475,7 +447,7 @@ def visit(self, node, scope): self.add_error( node, f"TypeError: ~ expresion type({expr_clone.name} does not" - " conforms to Bool type", + " conforms to Int type", ) expr_node.inferenced_type = ErrorType() @@ -520,3 +492,103 @@ def add_error(self, node: Node, text: str): return self.pos.add((line, col)) self.errors.append(((line, col), f"({line}, {col}) - " + text)) + + def __check_member_types(self, left_node, right_node): + if self.__unrelated_types(left_node) or self.__unrelated_types(right_node): + return + + bag1: TypeBag = left_node.inferenced_type + bag2: TypeBag = right_node.inferenced_type + + u_obj = self.context.get_type("Object", unpacked=True) + u_int = self.context.get_type("Int", unpacked=True) + u_bool = self.context.get_type("Bool", unpacked=True) + u_string = self.context.get_type("String", unpacked=True) + + contains_obj = u_obj in bag1.type_set and u_obj in bag2.type_set + contains_int = u_int in bag1.type_set and u_int in bag2.type_set + contains_bool = u_bool in bag1.type_set and u_bool in bag2.type_set + contains_string = u_string in bag1.type_set and u_string in bag2.type_set + + if contains_obj or ( + (contains_int and not (contains_bool or contains_string)) + and (contains_bool and not (contains_int or contains_string)) + and (contains_string and not (contains_int or contains_bool)) + ): + if contains_obj: + self.__conform_to_type(left_node, TypeBag({u_obj})) + self.__conform_to_type(right_node, TypeBag({u_obj})) + elif contains_int: + self.__conform_to_type(left_node, TypeBag({u_int})) + self.__conform_to_type(right_node, TypeBag({u_int})) + elif contains_bool: + self.__conform_to_type(left_node, TypeBag({u_bool})) + self.__conform_to_type(right_node, TypeBag({u_bool})) + elif contains_string: + self.__conform_to_type(left_node, TypeBag({u_string})) + self.__conform_to_type(right_node, TypeBag({u_string})) + else: + raise InternalError( + "Compiler is not working correctly(HardInferencer.__check_member_types)" + ) + else: + basic_set = {u_int, u_bool, u_string} + if len(bag1.type_set.intersection(basic_set)) == 1: + self.__conform_to_type(right_node, bag1) + elif len(bag2.type_set.intersection(basic_set)) == 1: + self.__conform_to_type(left_node, bag2) + + def __conform_to_type(self, node: Node, bag: TypeBag): + node_type = node.inferenced_type + node_name = node_type.generate_name() + if not conforms(node_type, bag): + self.add_error( + node, + f"TypeError: Equal Node: Expression type({node_name})" + f"does not conforms to expression({bag.name})", + ) + node.inferenced_type = ErrorType() + + def __arithmetic_operation(self, node, scope): + left_node = self.visit(node.left, scope) + left_type = left_node.inferenced_type + + right_node = self.visit(node.right, scope) + right_type = right_node.inferenced_type + + int_type = self.context.get_type("Int") + if not equal(left_type, node.left.inferenced_type): + if not conforms(left_type, int_type): + left_clone = left_type.clone() + self.add_error( + node.left, + f"TypeError: Arithmetic Error: Left member type({left_clone.name})" + "does not conforms to Int type.", + ) + left_node.inferenced_type = ErrorType() + if not equal(right_type, node.right.inferenced_type): + right_clone = right_type.clone() + if not conforms(right_type, int_type): + self.add_error( + node.right, + f"Type Error: Arithmetic Error: Right member " + f"type({right_clone.name})does not conforms to Int type.", + ) + right_node.inferenced_type = ErrorType() + + return left_node, right_node + + def __unrelated_types(self, node): + typex = node.inferenced_type + if isinstance(typex, ErrorType): + return True + if len(typex.heads) > 1: + self.add_error( + node, + "AutotypeError: AUTO_TYPE is ambigous {" + + ", ".join(typez.name for typez in typex.heads), + +"}", + ) + node.inferenced_type = ErrorType() + return True + return False \ No newline at end of file From b7728c7ebdc195547a81972da23f66247eaef300 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:16:44 -0400 Subject: [PATCH 078/432] Minor fixes Bug correction when obtaining type hierarchy. Modified error text when detecting circular heritage. --- src/semantics/type_collector.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 6653bf579..2d0de96a6 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -46,7 +46,7 @@ def visit(self, node): if node.parent: if node.parent in {"String", "Int, Bool"}: raise SemanticError( - f"Type '{node.id}' cannot inherit from '{node.parent}' beacuse is forbidden." + f"Type '{node.id}' cannot inherit from '{node.parent}' beacuse it is forbidden." ) try: self.type_graph[node.parent].append(node.id) @@ -68,16 +68,21 @@ def get_type_hierarchy(self): if not node in visited: visited.add(node) path = [node] - circular_heritage_errors.append( - self.check_circular_heritage(node, self.type_graph, path, visited) - ) - new_order = new_order + [self.node_dict[node] for node in path] + err = self.check_circular_heritage(node, self.type_graph, path, visited) + if len(err) > 0: # Nodes with invalid parents will be checked to ;) + circular_heritage_errors.append( + (path[1 if len(path) - 1 else 0], err) + ) + # path[1] to detect circular heritage same place tests do :( + try: + new_order = new_order + [self.node_dict[node] for node in path] + except KeyError: + pass - if circular_heritage_errors: - print(circular_heritage_errors) - error = "Semantic Error: Circular Heritage:\n" - error += "\n".join(err for err in circular_heritage_errors) - self.add_error(None, error) + for node_id, err in circular_heritage_errors: + self.add_error( + self.node_dict[node_id], "SemanticError: Circular Heritage: " + err + ) return new_order @@ -102,6 +107,7 @@ def check_circular_heritage(self, root, graph, path, visited): visited.add(node) path.append(node) return self.check_circular_heritage(node, graph, path, visited) + return "" def init_default_classes(self): self.context.create_type("Object").index = 0 From 0713515f5f3a39bf584c546dc152d4f913b277e4 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:18:58 -0400 Subject: [PATCH 079/432] Minor fixes --- src/semantics/type_builder.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index fd9c02a27..5386257a5 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -6,16 +6,16 @@ MethodDeclarationNode, AttrDeclarationNode, ) -from semantics.errors import SemanticError -from semantics.tools import SelfType,TypeBag,ErrorType +from semantics.errors import SemanticError +from semantics.tools import SelfType, TypeBag, ErrorType from semantics.tools import Context class TypeBuilder: - def __init__(self, context: Context, errors): + def __init__(self, context: Context): self.context = context self.current_type = None - self.errors: list = errors + self.errors: list = [] @visitor.on("node") def visit(self, node): @@ -29,7 +29,13 @@ def visit(self, node): self.visit(class_def) try: - self.context.get_type("Main", unpacked=True).get_method("main", local=True) + main = self.context.get_type("Main", unpacked=True).get_method( + "main", local=True + ) + if len(main.param_names) > 0: + raise SemanticError( + "Method 'main' in class 'Main' must not have formal parameters" + ) except SemanticError as err: self.add_error(node, err.text) @@ -60,14 +66,14 @@ def visit(self, node): try: self.current_type.define_attribute(node.id, attr_type) except SemanticError as err: - self.add_error(err.text) + self.add_error(node, err.text) @visitor.when(MethodDeclarationNode) def visit(self, node): try: ret_type = self.context.get_type(node.type) except SemanticError as err: - self.add_error(err.text) + self.add_error(node, err.text) ret_type = ErrorType() params_type = [] From 12aa22c270125f6b1c6824b62c90046fab791563 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:20:30 -0400 Subject: [PATCH 080/432] Parser and Lexer minor changes --- src/lexing/lexer.py | 30 +++---- src/parsing/parser.py | 201 +++++++++++++++++++++--------------------- 2 files changed, 115 insertions(+), 116 deletions(-) diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index f77f21b67..dca17f790 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -81,9 +81,9 @@ def tokenize(self, data): line, col = self._get_current_pos(data) self.errors.append(LexicographicError(line, col, "INVALID COMMENT")) break - if not self._end_string and self._lexer.lexpos -1 <= len(data) : + if not self._end_string and self._lexer.lexpos - 1 <= len(data): line = self._lexer.lineno - col = self._lexer.col + 1 + col = self._lexer.col + 1 self.errors.append(LexicographicError(line, col, "UNTERMINATED STRING")) if not tok: break @@ -131,7 +131,6 @@ def t_ID(self, t): t.type = self.reserved.get(t.value.lower(), "ID") return t - def t_INT(self, t): r"\d+" self._set_pos(t) @@ -156,7 +155,6 @@ def t_string(self, t): self._end_string = False t.lexer.begin("string") - def t_string_end(self, t): r'(? None: self.errors = [] self.lexer = lexer self.tokens = lexer.tokens - + self.precedence = ( ("right", "ASSIGN"), ("right", "NOT"), @@ -31,16 +53,15 @@ def __init__(self, lexer) -> None: def _build(self): self._parser = yacc(module=self) - - def parse(self,program): + + def parse(self, program): return self._parser.parse(program) - def p_program(self,p): + def p_program(self, p): """program : class_list""" p[0] = ProgramNode(p[1]) - - def p_class_list(self,p): + def p_class_list(self, p): """class_list : class ';' class_list | class ';'""" if len(p) == 4: @@ -48,8 +69,7 @@ def p_class_list(self,p): elif len(p) == 3: p[0] = [p[1]] - - def p_class(self,p): + def p_class(self, p): """class : CLASS TYPE INHERITS TYPE '{' feature_list '}' | CLASS TYPE '{' feature_list '}'""" if len(p) == 8: @@ -59,8 +79,7 @@ def p_class(self,p): p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_feature_list(self,p): + def p_feature_list(self, p): """feature_list : attribute ';' feature_list | method ';' feature_list | empty""" @@ -69,8 +88,7 @@ def p_feature_list(self,p): elif len(p) == 2: p[0] = [] - - def p_attribute(self,p): + def p_attribute(self, p): """attribute : ID ':' TYPE ASSIGN expression | ID ':' TYPE""" if len(p) == 6: @@ -80,14 +98,13 @@ def p_attribute(self,p): p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_method(self,p): - """method : ID '(' params_list ')' ':' TYPE '{' expression '}'""" + def p_method(self, p): + """method : ID '(' params_list ')' ':' TYPE '{' expression '}' + | ID '(' empty ')' ':' TYPE '{' expression '}'""" p[0] = MethodDeclarationNode(p[1], p[3], p[6], p[8]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_params_list(self,p): + def p_params_list(self, p): """params_list : param ',' params_list | param""" if len(p) == 4: @@ -95,19 +112,16 @@ def p_params_list(self,p): else: p[0] = [p[1]] + # def p_params_list_empty(self,p): + # """params_list : empty""" + # p[0] = [] - def p_params_list_empty(self,p): - """params_list : empty""" - p[0] = [] - - - def p_param(self,p): + def p_param(self, p): """param : ID ':' TYPE""" p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_list(self,p): + def p_expression_list(self, p): """expression_list : expression ';' expression_list | expression ';'""" if len(p) == 4: @@ -115,38 +129,32 @@ def p_expression_list(self,p): elif len(p) == 3: p[0] = [p[1]] - - def p_expression_assigment(self,p): + def p_expression_assigment(self, p): """expression : ID ASSIGN expression""" p[0] = AssignNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_if_then_else(self,p): + def p_expression_if_then_else(self, p): """expression : IF expression THEN expression ELSE expression FI""" p[0] = ConditionalNode(p[2], p[4], p[6]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_while(self,p): + def p_expression_while(self, p): """expression : WHILE expression LOOP expression POOL""" p[0] = LoopNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_block(self,p): + def p_expression_block(self, p): """expression : '{' expression_list '}'""" p[0] = BlocksNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_let_in(self,p): + def p_expression_let_in(self, p): """expression : LET let_list IN expression""" p[0] = LetNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_let_list(self,p): + def p_let_list(self, p): """let_list : let_single ',' let_list | let_single""" if len(p) == 4: @@ -154,8 +162,7 @@ def p_let_list(self,p): else: p[0] = [p[1]] - - def p_let_single(self,p): + def p_let_single(self, p): """let_single : ID ':' TYPE ASSIGN expression | ID ':' TYPE""" if len(p) == 6: @@ -164,14 +171,12 @@ def p_let_single(self,p): p[0] = VarDeclarationNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_case(self,p): + def p_expression_case(self, p): """expression : CASE expression OF case_list ESAC""" p[0] = CaseNode(p[2], p[4]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_case_list(self,p): + def p_case_list(self, p): """case_list : case_single case_list | case_single""" if len(p) == 3: @@ -179,14 +184,12 @@ def p_case_list(self,p): else: p[0] = [p[1]] - - def p_case_single(self,p): + def p_case_single(self, p): """case_single : ID ':' TYPE RET expression ';'""" p[0] = CaseOptionNode(p[1], p[3], p[5]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_dispatch(self,p): + def p_expression_dispatch(self, p): """expression : expression '@' TYPE '.' ID '(' args_list ')' | expression '.' ID '(' args_list ')' | ID '(' args_list ')'""" @@ -202,8 +205,23 @@ def p_expression_dispatch(self,p): p[0] = MethodCallNode(None, None, p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) + def p_expression_dispatch_empty(self, p): + """expression : expression '@' TYPE '.' ID '(' empty ')' + | expression '.' ID '(' empty ')' + | ID '(' empty ')'""" + if len(p) == 9: + p[0] = MethodCallNode(p[1], p[3], p[5], p[7]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + elif len(p) == 7: + p[0] = MethodCallNode(p[1], None, p[3], p[5]) + p[0].set_position(p.slice[2].line, p.slice[2].col) + + else: + p[0] = MethodCallNode(None, None, p[1], p[3]) + p[0].set_position(p.slice[1].line, p.slice[1].col) - def p_args_list(self,p): + def p_args_list(self, p): """args_list : expression ',' args_list | expression""" if len(p) == 4: @@ -211,118 +229,101 @@ def p_args_list(self,p): else: p[0] = [p[1]] + # def p_args_list_empty(self,p): + # """args_list : empty""" + # p[0] = [] - def p_args_list_empty(self,p): - """args_list : empty""" - p[0] = [] - - - def p_expression_instatiate(self,p): + def p_expression_instatiate(self, p): """expression : NEW TYPE""" p[0] = InstantiateNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_isvoid(self,p): + def p_expression_isvoid(self, p): """expression : ISVOID expression""" p[0] = IsVoidNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_not(self,p): + def p_expression_not(self, p): """expression : NOT expression""" p[0] = NotNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_complement(self,p): + def p_expression_complement(self, p): """expression : '~' expression""" p[0] = ComplementNode(p[2]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_plus(self,p): + def p_expression_plus(self, p): """expression : expression '+' expression""" p[0] = PlusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_minus(self,p): + def p_expression_minus(self, p): """expression : expression '-' expression""" p[0] = MinusNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_div(self,p): + def p_expression_div(self, p): """expression : expression '/' expression""" p[0] = DivNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_star(self,p): + def p_expression_star(self, p): """expression : expression '*' expression""" p[0] = StarNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_less(self,p): + def p_expression_less(self, p): """expression : expression '<' expression""" p[0] = LessNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_lesseq(self,p): + def p_expression_lesseq(self, p): """expression : expression LESSEQ expression""" p[0] = LessOrEqualNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_equals(self,p): + def p_expression_equals(self, p): """expression : expression '=' expression""" p[0] = EqualsNode(p[1], p[3]) p[0].set_position(p.slice[2].line, p.slice[2].col) - - def p_expression_parentheses(self,p): + def p_expression_parentheses(self, p): """expression : '(' expression ')'""" p[0] = p[2] p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_string(self,p): + def p_expression_string(self, p): """expression : STRING""" p[0] = StringNode(p[1]) p[0].set_position(p.slice[1].lineno, p.slice[1].col) - - def p_expression_variable(self,p): + def p_expression_variable(self, p): """expression : ID""" p[0] = VariableNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_true(self,p): + def p_expression_true(self, p): """expression : TRUE""" p[0] = BooleanNode(True) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_false(self,p): + def p_expression_false(self, p): """expression : FALSE""" p[0] = BooleanNode(False) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_expression_int(self,p): + def p_expression_int(self, p): """expression : INT""" p[0] = IntNode(p[1]) p[0].set_position(p.slice[1].line, p.slice[1].col) - - def p_empty(self,p): + def p_empty(self, p): """empty : """ p[0] = [] - - def p_error(self,t): - print(f"Syntax error in input! {t} line:{t.lineno} col:{t.col}") + def p_error(self, t): + if t is None: + self.errors.append(SyntacticError("EOF", 0, 0)) + else: + self.errors.append(SyntacticError(t.value, t.line, t.col)) From 0a5c49ca023c32e430b10ff306dcbb5154016560 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sat, 24 Apr 2021 10:22:40 -0400 Subject: [PATCH 081/432] switching to Master --- .gitignore | 5 ++ src/parsing/parsetab.py | 114 ++++++++++++++++++++-------------------- src/test.cl | Bin 233 -> 35 bytes src/utils/visitor.py | 95 +++++++++++++++++---------------- 4 files changed, 113 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index 6483fe2bf..2699a1b18 100644 --- a/.gitignore +++ b/.gitignore @@ -430,3 +430,8 @@ src/type_logger.py src/zTests/Auto/00Simple.cl src/zTests/Auto/01Assign.cl src/semantics/notes.md +src/test.cl +src/test.cl +src/class1_error.txt +src/class1.cl +src/test.cl diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 20813ed7e..30b6d6d16 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,9 +6,9 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparams_list : emptyparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'args_list : expression ',' args_list\n | expressionargs_list : emptyexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'\n | ID '(' empty ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'expression : expression '@' TYPE '.' ID '(' empty ')'\n | expression '.' ID '(' empty ')'\n | ID '(' empty ')'args_list : expression ',' args_list\n | expressionexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " -_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,35,36,47,48,49,50,68,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,125,127,132,134,135,],[5,18,19,-5,-10,-4,-50,-9,-49,-51,-52,-53,95,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-11,-32,-19,-31,136,]),'TYPE':([4,8,20,32,43,52,56,98,124,],[6,10,25,51,74,78,83,111,130,]),'INHERITS':([6,],[8,]),'{':([6,10,31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,78,92,93,95,96,101,103,105,119,121,126,133,],[9,16,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,101,39,39,39,39,39,39,39,39,39,39,39,]),'ID':([9,16,18,19,21,31,34,37,38,39,40,41,42,44,45,46,54,55,57,58,59,60,61,62,63,64,92,93,95,96,97,99,101,103,104,105,113,119,121,126,133,136,],[15,15,15,15,26,35,26,35,35,35,71,35,35,35,35,35,35,35,84,35,35,35,35,35,35,35,35,35,35,35,71,114,35,35,117,35,114,35,35,35,35,-30,]),'}':([9,11,14,16,18,19,22,23,24,35,47,48,49,50,67,74,75,76,77,79,85,86,87,88,89,90,91,94,95,100,102,108,109,115,120,122,127,132,134,],[-54,17,-8,-54,-54,-54,30,-6,-7,-50,-49,-51,-52,-53,94,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-17,-48,-33,-16,-22,125,-20,-27,-32,-19,-31,]),':':([15,26,33,71,114,],[20,32,52,98,124,]),'(':([15,31,35,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,84,92,93,95,96,101,103,105,117,119,121,126,133,],[21,42,55,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,105,42,42,42,42,42,42,42,126,42,42,42,42,]),')':([21,27,28,29,34,35,47,48,49,50,51,53,55,73,74,75,76,77,79,80,81,82,85,86,87,88,89,90,91,94,100,102,103,105,109,116,118,120,122,126,127,131,132,134,],[-54,33,-13,-14,-54,-50,-49,-51,-52,-53,-15,-12,-54,100,-37,-38,-39,-40,-18,102,-35,-36,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-54,-54,-22,-34,127,-20,-27,-54,-32,134,-19,-31,]),'ASSIGN':([25,35,111,],[31,54,121,]),',':([28,35,47,48,49,50,51,70,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,109,111,120,122,127,129,132,134,],[34,-50,-49,-51,-52,-53,-15,97,-37,-38,-39,-40,-18,103,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-26,-20,-27,-32,-25,-19,-31,]),'IF':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'WHILE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'LET':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,]),'CASE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'NEW':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,]),'ISVOID':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'NOT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'~':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'STRING':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'TRUE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'FALSE':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'INT':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'@':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,56,-49,-51,-52,-53,56,56,56,56,56,-37,56,56,56,56,56,56,56,56,56,56,56,56,-21,-48,-33,56,56,56,56,-20,-27,-32,56,56,-19,-31,56,]),'.':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,83,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,57,-49,-51,-52,-53,57,57,57,57,57,-37,57,57,57,57,57,104,57,57,57,57,57,57,57,-21,-48,-33,57,57,57,57,-20,-27,-32,57,57,-19,-31,57,]),'+':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,58,-49,-51,-52,-53,58,58,58,58,58,-37,-38,58,-40,58,58,-41,-42,-43,-44,58,58,58,-21,-48,-33,58,58,58,58,-20,-27,-32,58,58,-19,-31,58,]),'-':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,59,-49,-51,-52,-53,59,59,59,59,59,-37,-38,59,-40,59,59,-41,-42,-43,-44,59,59,59,-21,-48,-33,59,59,59,59,-20,-27,-32,59,59,-19,-31,59,]),'/':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,60,-49,-51,-52,-53,60,60,60,60,60,-37,-38,60,-40,60,60,60,60,-43,-44,60,60,60,-21,-48,-33,60,60,60,60,-20,-27,-32,60,60,-19,-31,60,]),'*':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,61,-49,-51,-52,-53,61,61,61,61,61,-37,-38,61,-40,61,61,61,61,-43,-44,61,61,61,-21,-48,-33,61,61,61,61,-20,-27,-32,61,61,-19,-31,61,]),'<':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,62,-49,-51,-52,-53,62,62,62,62,62,-37,-38,62,-40,62,62,-41,-42,-43,-44,None,None,None,-21,-48,-33,62,62,62,62,-20,-27,-32,62,62,-19,-31,62,]),'LESSEQ':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,63,-49,-51,-52,-53,63,63,63,63,63,-37,-38,63,-40,63,63,-41,-42,-43,-44,None,None,None,-21,-48,-33,63,63,63,63,-20,-27,-32,63,63,-19,-31,63,]),'=':([35,36,47,48,49,50,65,66,68,72,73,74,75,76,77,79,81,85,86,87,88,89,90,91,94,100,102,106,107,109,115,120,122,127,128,129,132,134,135,],[-50,64,-49,-51,-52,-53,64,64,64,64,64,-37,-38,64,-40,64,64,-41,-42,-43,-44,None,None,None,-21,-48,-33,64,64,64,64,-20,-27,-32,64,64,-19,-31,64,]),'THEN':([35,47,48,49,50,65,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,92,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'LOOP':([35,47,48,49,50,66,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,93,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'OF':([35,47,48,49,50,72,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,99,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,-19,-31,]),'ELSE':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,106,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,119,-22,-20,-27,-32,-19,-31,]),'POOL':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,107,109,120,122,127,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,120,-22,-20,-27,-32,-19,-31,]),'FI':([35,47,48,49,50,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,120,122,127,128,132,134,],[-50,-49,-51,-52,-53,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-20,-27,-32,132,-19,-31,]),'IN':([35,47,48,49,50,69,70,74,75,76,77,79,85,86,87,88,89,90,91,94,100,102,109,110,111,120,122,127,129,132,134,],[-50,-49,-51,-52,-53,96,-24,-37,-38,-39,-40,-18,-41,-42,-43,-44,-45,-46,-47,-21,-48,-33,-22,-23,-26,-20,-27,-32,-25,-19,-31,]),'ESAC':([112,113,123,136,],[122,-29,-28,-30,]),'RET':([130,],[133,]),} +_lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,36,37,48,49,50,51,70,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,132,133,135,136,142,144,145,146,],[5,18,19,-5,-10,-4,-52,-9,-51,-53,-54,-55,98,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-11,-12,-32,-35,-19,-31,-34,147,]),'TYPE':([4,8,20,32,44,53,54,58,101,131,],[6,10,25,52,76,80,81,86,116,139,]),'INHERITS':([6,],[8,]),'{':([6,10,31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,80,81,95,96,98,99,104,105,108,110,126,128,134,143,],[9,16,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,104,105,40,40,40,40,40,40,40,40,40,40,40,40,]),'ID':([9,16,18,19,21,31,35,38,39,40,41,42,43,45,46,47,56,57,59,60,61,62,63,64,65,66,95,96,98,99,100,102,104,105,108,109,110,118,126,128,134,143,147,],[15,15,15,15,26,36,26,36,36,36,73,36,36,36,36,36,36,36,87,36,36,36,36,36,36,36,36,36,36,36,73,119,36,36,36,123,36,119,36,36,36,36,-30,]),'}':([9,11,14,16,18,19,22,23,24,36,48,49,50,51,69,76,77,78,79,82,88,89,90,91,92,93,94,97,98,103,106,107,113,114,120,121,127,129,135,136,142,144,145,],[-56,17,-8,-56,-56,-56,30,-6,-7,-52,-51,-53,-54,-55,97,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-17,-50,-33,-36,-16,-22,132,133,-20,-27,-32,-35,-19,-31,-34,]),':':([15,26,33,34,73,119,],[20,32,53,54,101,131,]),'(':([15,31,36,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,87,95,96,98,99,104,105,108,110,123,126,128,134,143,],[21,43,57,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,110,43,43,43,43,43,43,43,43,134,43,43,43,43,]),')':([21,27,28,29,36,48,49,50,51,52,55,57,75,76,77,78,79,82,83,84,85,88,89,90,91,92,93,94,97,103,106,107,110,114,122,124,125,127,129,134,135,136,140,141,142,144,145,],[-56,33,34,-14,-52,-51,-53,-54,-55,-15,-13,-56,103,-39,-40,-41,-42,-18,106,107,-38,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-56,-22,-37,135,136,-20,-27,-56,-32,-35,144,145,-19,-31,-34,]),'ASSIGN':([25,36,116,],[31,56,128,]),',':([29,36,48,49,50,51,52,72,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,114,116,127,129,135,136,138,142,144,145,],[35,-52,-51,-53,-54,-55,-15,100,-39,-40,-41,-42,-18,108,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'IF':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'WHILE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,]),'LET':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'CASE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,]),'NEW':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'ISVOID':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'NOT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'~':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'STRING':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'TRUE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'FALSE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'INT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,]),'@':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,58,-51,-53,-54,-55,58,58,58,58,58,-39,58,58,58,58,58,58,58,58,58,58,58,58,-21,-50,-33,-36,58,58,58,58,58,-20,-27,-32,-35,58,58,-19,-31,-34,58,]),'.':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,86,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,59,-51,-53,-54,-55,59,59,59,59,59,-39,59,59,59,59,59,109,59,59,59,59,59,59,59,-21,-50,-33,-36,59,59,59,59,59,-20,-27,-32,-35,59,59,-19,-31,-34,59,]),'+':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,60,-51,-53,-54,-55,60,60,60,60,60,-39,-40,60,-42,60,60,-43,-44,-45,-46,60,60,60,-21,-50,-33,-36,60,60,60,60,60,-20,-27,-32,-35,60,60,-19,-31,-34,60,]),'-':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,61,-51,-53,-54,-55,61,61,61,61,61,-39,-40,61,-42,61,61,-43,-44,-45,-46,61,61,61,-21,-50,-33,-36,61,61,61,61,61,-20,-27,-32,-35,61,61,-19,-31,-34,61,]),'/':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,62,-51,-53,-54,-55,62,62,62,62,62,-39,-40,62,-42,62,62,62,62,-45,-46,62,62,62,-21,-50,-33,-36,62,62,62,62,62,-20,-27,-32,-35,62,62,-19,-31,-34,62,]),'*':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,63,-51,-53,-54,-55,63,63,63,63,63,-39,-40,63,-42,63,63,63,63,-45,-46,63,63,63,-21,-50,-33,-36,63,63,63,63,63,-20,-27,-32,-35,63,63,-19,-31,-34,63,]),'<':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,64,-51,-53,-54,-55,64,64,64,64,64,-39,-40,64,-42,64,64,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,64,64,64,64,64,-20,-27,-32,-35,64,64,-19,-31,-34,64,]),'LESSEQ':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,65,-51,-53,-54,-55,65,65,65,65,65,-39,-40,65,-42,65,65,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,65,65,65,65,65,-20,-27,-32,-35,65,65,-19,-31,-34,65,]),'=':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,66,-51,-53,-54,-55,66,66,66,66,66,-39,-40,66,-42,66,66,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,66,66,66,66,66,-20,-27,-32,-35,66,66,-19,-31,-34,66,]),'THEN':([36,48,49,50,51,67,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,95,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'LOOP':([36,48,49,50,51,68,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,96,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'OF':([36,48,49,50,51,74,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,102,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'ELSE':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,111,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,126,-22,-20,-27,-32,-35,-19,-31,-34,]),'POOL':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,112,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,127,-22,-20,-27,-32,-35,-19,-31,-34,]),'FI':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,137,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,142,-19,-31,-34,]),'IN':([36,48,49,50,51,71,72,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,115,116,127,129,135,136,138,142,144,145,],[-52,-51,-53,-54,-55,99,-24,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-23,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'ESAC':([117,118,130,147,],[129,-29,-28,-30,]),'RET':([139,],[143,]),} _lr_action = {} for _k, _v in _lr_action_items.items(): @@ -17,7 +17,7 @@ _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,18,19,],[11,22,23,24,]),'attribute':([9,16,18,19,],[12,12,12,12,]),'method':([9,16,18,19,],[13,13,13,13,]),'empty':([9,16,18,19,21,34,55,103,105,126,],[14,14,14,14,29,29,82,82,82,82,]),'params_list':([21,34,],[27,53,]),'param':([21,34,],[28,28,]),'expression':([31,37,38,39,41,42,44,45,46,54,55,58,59,60,61,62,63,64,92,93,95,96,101,103,105,119,121,126,133,],[36,65,66,68,72,73,75,76,77,79,81,85,86,87,88,89,90,91,106,107,68,109,115,81,81,128,129,81,135,]),'expression_list':([39,95,],[67,108,]),'let_list':([40,97,],[69,110,]),'let_single':([40,97,],[70,70,]),'args_list':([55,103,105,126,],[80,116,118,131,]),'case_list':([99,113,],[112,123,]),'case_single':([99,113,],[113,113,]),} +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,5,],[2,7,]),'class':([0,5,],[3,3,]),'feature_list':([9,16,18,19,],[11,22,23,24,]),'attribute':([9,16,18,19,],[12,12,12,12,]),'method':([9,16,18,19,],[13,13,13,13,]),'empty':([9,16,18,19,21,57,110,134,],[14,14,14,14,28,84,125,141,]),'params_list':([21,35,],[27,55,]),'param':([21,35,],[29,29,]),'expression':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[37,67,68,70,74,75,77,78,79,82,85,88,89,90,91,92,93,94,111,112,70,114,120,121,85,85,137,138,85,146,]),'expression_list':([40,98,],[69,113,]),'let_list':([41,100,],[71,115,]),'let_single':([41,100,],[72,72,]),'args_list':([57,108,110,134,],[83,122,124,140,]),'case_list':([102,118,],[117,130,]),'case_single':([102,118,],[118,118,]),} _lr_goto = {} for _k, _v in _lr_goto_items.items(): @@ -27,58 +27,60 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parser.py',39), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',44), - ('class_list -> class ;','class_list',2,'p_class_list','parser.py',45), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',53), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',54), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',64), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',65), - ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',66), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',74), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',75), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',85), - ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',91), - ('params_list -> param','params_list',1,'p_params_list','parser.py',92), - ('params_list -> empty','params_list',1,'p_params_list_empty','parser.py',100), - ('param -> ID : TYPE','param',3,'p_param','parser.py',105), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',111), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',112), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',120), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',126), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',132), - ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',138), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',144), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',150), - ('let_list -> let_single','let_list',1,'p_let_list','parser.py',151), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',159), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',160), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',169), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',175), - ('case_list -> case_single','case_list',1,'p_case_list','parser.py',176), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',184), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',190), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',191), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',192), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',207), - ('args_list -> expression','args_list',1,'p_args_list','parser.py',208), - ('args_list -> empty','args_list',1,'p_args_list_empty','parser.py',216), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',221), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',227), - ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',233), - ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',239), - ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',245), - ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',251), - ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',257), - ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',263), - ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',269), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',275), - ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',281), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',287), - ('expression -> STRING','expression',1,'p_expression_string','parser.py',293), - ('expression -> ID','expression',1,'p_expression_variable','parser.py',299), - ('expression -> TRUE','expression',1,'p_expression_true','parser.py',305), - ('expression -> FALSE','expression',1,'p_expression_false','parser.py',311), + ('program -> class_list','program',1,'p_program','parser.py',61), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',65), + ('class_list -> class ;','class_list',2,'p_class_list','parser.py',66), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',73), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',74), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',83), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',84), + ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',85), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',92), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',93), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',102), + ('method -> ID ( empty ) : TYPE { expression }','method',9,'p_method','parser.py',103), + ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',108), + ('params_list -> param','params_list',1,'p_params_list','parser.py',109), + ('param -> ID : TYPE','param',3,'p_param','parser.py',120), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',125), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',126), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',133), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',138), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',143), + ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',148), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',153), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',158), + ('let_list -> let_single','let_list',1,'p_let_list','parser.py',159), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',166), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',167), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',175), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',180), + ('case_list -> case_single','case_list',1,'p_case_list','parser.py',181), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',188), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',193), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',194), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',195), + ('expression -> expression @ TYPE . ID ( empty )','expression',8,'p_expression_dispatch_empty','parser.py',209), + ('expression -> expression . ID ( empty )','expression',6,'p_expression_dispatch_empty','parser.py',210), + ('expression -> ID ( empty )','expression',4,'p_expression_dispatch_empty','parser.py',211), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',225), + ('args_list -> expression','args_list',1,'p_args_list','parser.py',226), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',237), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',242), + ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',247), + ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',252), + ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',257), + ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',262), + ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',267), + ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',272), + ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',277), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',282), + ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',287), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',292), + ('expression -> STRING','expression',1,'p_expression_string','parser.py',297), + ('expression -> ID','expression',1,'p_expression_variable','parser.py',302), + ('expression -> TRUE','expression',1,'p_expression_true','parser.py',307), + ('expression -> FALSE','expression',1,'p_expression_false','parser.py',312), ('expression -> INT','expression',1,'p_expression_int','parser.py',317), - ('empty -> ','empty',0,'p_empty','parser.py',323), + ('empty -> ','empty',0,'p_empty','parser.py',322), ] diff --git a/src/test.cl b/src/test.cl index 6935ada980145507f4a13b06595d890735a1f2d3..8e5cf617f8a42d18bbdf817bbaabf1400a149627 100644 GIT binary patch literal 35 qcmdPUQgBpo&d<+LC@9KLFG|c+NKVXCFHuNJRY=V(D5+G?(gXm(=L-)2 literal 233 zcmX|4yAH!34D8HToS2dhRoZ?*=Jpd<90*B>0}_xSe_!a!lI8Q=+1H%WBjvdG2^$^o zAwvhBY4OPO2){F<(KAKTd5ln9dqM9HgrY|L1yPTO5sTNno6!^i`aM3kLP%bnNn}^9 zgRN70SE^FAzndeQK1R06CqvFEiNaJ Date: Sat, 24 Apr 2021 16:43:48 -0400 Subject: [PATCH 082/432] Commit before merge with origin master --- src/__main__.py | 12 ++++++------ src/test.cl | 24 +++++++++++++++++++++++- tests/semantic/case1.cl | 3 ++- tests/semantic_test.py | 24 ++++++++++++------------ tests/utils/utils.py | 2 -- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index ccf8617e4..63355b1ab 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -43,17 +43,17 @@ def run_pipeline(program_ast): def main(): - if len(sys.argv) > 1: - input_file = sys.argv[1] - else: - raise Exception("Incorrect number of arguments") + # if len(sys.argv) > 1: + # input_file = sys.argv[1] + # else: + # raise Exception("Incorrect number of arguments") program = open(input_file).read() lexer = Lexer() tokens = list(lexer.tokenize(program)) - # for token in tokens: - # print(token, token.line, token.col) + for token in tokens: + print(token, token.line, token.col) if lexer.errors: for error in lexer.errors: diff --git a/src/test.cl b/src/test.cl index 8e5cf617f..82c6a4d61 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1 +1,23 @@ -(* A Cool program can't be empty *) \ No newline at end of file +--For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: B <- case 0 of + b: Bool => new F; + i: Int => new E; + esac; +}; diff --git a/tests/semantic/case1.cl b/tests/semantic/case1.cl index 82c6a4d61..e228e7703 100644 --- a/tests/semantic/case1.cl +++ b/tests/semantic/case1.cl @@ -17,7 +17,8 @@ class Main inherits IO { esac; test: B <- case 0 of - b: Bool => new F; + b + : Bool => new F; i: Int => new E; esac; }; diff --git a/tests/semantic_test.py b/tests/semantic_test.py index b4bf38b1f..cac9cd78b 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -1,14 +1,14 @@ -# import pytest -# import os -# from utils import compare_errors, first_error_only_line +import pytest +import os +from utils import compare_errors, first_error_only_line -# tests_dir = __file__.rpartition('/')[0] + '/semantic/' -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests_dir = __file__.rpartition('/')[0] + '/semantic/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -# @pytest.mark.semantic -# @pytest.mark.error -# @pytest.mark.run(order=3) -# @pytest.mark.parametrize("cool_file", tests) -# def test_semantic_errors(compiler_path, cool_file): -# compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ -# cmp=first_error_only_line) \ No newline at end of file +@pytest.mark.semantic +@pytest.mark.error +@pytest.mark.run(order=3) +@pytest.mark.parametrize("cool_file", tests) +def test_semantic_errors(compiler_path, cool_file): + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ + cmp=first_error_only_line) \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index dd1b370b6..957ad9e0a 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -14,8 +14,6 @@ ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' def parse_error(error: str): - print("ESTE ES EL ERROR") - print(error) merror = re.fullmatch(ERROR_FORMAT, error) assert merror, BAD_ERROR_FORMAT % error From 12ae3e390b15b192731e7ed3a58ccf386ceea91c Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:21:06 -0400 Subject: [PATCH 083/432] Deleted unused old scripts --- src/semantics/inference/autotype_collector.py | 451 ------------------ .../inference/autotype_inferencer.py | 410 ---------------- 2 files changed, 861 deletions(-) delete mode 100644 src/semantics/inference/autotype_collector.py delete mode 100644 src/semantics/inference/autotype_inferencer.py diff --git a/src/semantics/inference/autotype_collector.py b/src/semantics/inference/autotype_collector.py deleted file mode 100644 index 3ad99e858..000000000 --- a/src/semantics/inference/autotype_collector.py +++ /dev/null @@ -1,451 +0,0 @@ -from ast.parser_ast import ( - ArithmeticNode, - AssignNode, - AttrDeclarationNode, - BlocksNode, - BooleanNode, - CaseNode, - CaseOptionNode, - ClassDeclarationNode, - ComparerNode, - ComplementNode, - ConditionalNode, - InstantiateNode, - IntNode, - IsVoidNode, - LetNode, - LoopNode, - MethodCallNode, - MethodDeclarationNode, - Node, - NotNode, - ProgramNode, - StringNode, - VarDeclarationNode, - VariableNode, -) - -from utils import visitor -from semantics.tools import ( - Context, - ErrorType, - Scope, - SelfType, - SemanticError, - TypeBag, - conforms, - join, - join_list, - smart_add, -) - - -class AutotypeCollector: - def __init__(self, context: Context, errors): - self.context = context - self.current_type = None - self.errors = errors - - @visitor.on("node") - def visit(self, node, scope): - pass - - @visitor.when(ProgramNode) - def visit(self, node: ProgramNode) -> Scope: - scope = Scope() - for declaration in node.declarations: - self.visit(declaration, scope.create_child()) - - return scope - - @visitor.when(ClassDeclarationNode) - def visit(self, node, scope): - self.current_type = self.context.get_type(node.id, unpacked=True) - scope.define_variable("self", TypeBag({self.current_type})) - for attr in self.current_type.attributes: - scope.define_variable(attr.name, attr.type) - - for feature in node.features: - self.visit(feature, scope) - - @visitor.when(AttrDeclarationNode) - def visit(self, node, scope): - node_type = self.current_type.get_attribute(node.id).type.swap_self_type( - self.current_type - ) - if not node.expr: - node.inferenced_type = node_type - return - - self.visit(node.expr, scope) - node_expr = node.expr.inferenced_type - expr_clone = node_expr.clone() - if not conforms(node_expr, node_type): - self.add_error( - node, - ( - f"Type Error: In class '{self.current_type.name}' attribue" - f"'{node.id}' expression type({expr_clone.name}) does not conforms" - f"to declared type ({node_type.name})." - ), - ) - # What is made error type here!!! - - 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) - - ret_type_decl = current_method.return_type.swap_self_type(self.current_type) - self.visit(node.body, scope) - ret_type_expr = node.body.inferenced_type - - ret_expr_clone = ret_type_expr.clone() - if not conforms(ret_type_expr, ret_type_decl): - self.add_error( - node, - f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}' return expression type({ret_expr_clone.name}) does not conforms to declared return type ({ret_type_decl.name})", - ) - ret_type_expr = ErrorType() - - node.inferenced_type = ret_type_expr - ret_type_decl.swap_self_type(self.current_type, back=True) - - @visitor.when(BlocksNode) - def visit(self, node, scope): - for expr in node.expr_list: - self.visit(expr, scope) - node.inferenced_type = node.expr_list[-1].inferenced_type - - @visitor.when(ConditionalNode) - def visit(self, node, scope): - self.visit(node.condition, scope) - condition_type = node.condition.inferenced_type - bool_type = self.context.get_type("Bool") - - condition_clone = condition_type.clone() - if not conforms(condition_clone, bool_type): - self.add_error( - node, - f"Type Error: If's condition type({condition_type.name}) does not conforms to Bool type.", - ) - - self.visit(node.then_body, scope) - then_type = node.then_body.inferenced_type - self.visit(node.else_body, scope) - 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.case_expr, scope) - - type_list = [] - types_visited = set() - for option in node.options: - child = scope.create_child() - self.visit(option, child) - type_list.append(option.inferenced_type) - var_type = child.find_variable(option.id).type - if var_type in types_visited: - self.add_error( - node, - f"Semantic Error: Case Expression can't have branches with same case type({var_type.name})", - ) - - 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: - self.add_error(node, 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") - - condition_clone = condition_type.clone() - if not conforms(condition_clone, bool_type): - self.add_error( - node, - f"Type Error: Loop condition type({condition_type.name}) does not conforms to Bool type.", - ) - - self.visit(node.body, 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_list: - self.visit(var, child) - self.visit(node.in_expr, child) - 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: - self.add_error( - node, - f"Semantic Error: Variable '{node.id}' already defined in current scope.", - ) - node.defined = False - node_type = ErrorType() - - if node.expr: - self.visit(node.expr, scope) - expr_type = node.expr.inferenced_type - expr_clone = expr_type.clone() - if not conforms(expr_type, node_type): - self.add_error( - node, - f"Semantic Error: Variable '{node.id}' expression type({expr_clone.name}) does not conforms to declared type({node_type.name}).", - ) - - 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 - node_type = var_type - - if var and var.name != "self": - node_expr_clone = node.expr.inferenced_type.clone() - if not conforms(node_expr, var_type): - self.add_error( - node, - f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({node_expr_clone.name}) does not conforms to declared type ({var_type.name}).", - ) - node_type = ErrorType() - var.type = var_type - elif var.name == "self": - self.add_error( - node, - "Semantic Error: Cannot assign new value. Variable 'self' is Read-Only.", - ) - node_type = ErrorType() - - node.inferenced_type = node_type - - @visitor.when(MethodCallNode) - def visit(self, node, scope): - if node.expr == None: - caller = TypeBag({self.current_type}) - elif node.type == None: - self.visit(node.expr, scope) - caller = node.expr.inferenced_type - else: - self.visit(node.expr, scope) - bridge = node.expr.inferenced_type - caller = self.context.get_type(node.type, selftype=False, autotype=False) - - bridge_clone = bridge.clone() - if not conforms(bridge, caller): - self.add_error( - node, - f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).", - ) - caller = ErrorType() - - 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), types)) - if len(caller.type_set): - methods = [(t, t.get_method) for t in caller.heads] - else: - self.add_error( - node, - f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Types {caller.name}.", - ) - caller = ErrorType() - elif len(caller.type_set) == 1: - caller_type = caller.heads[0] - try: - methods = [(caller_type, caller_type.get_method(node.id))] - except SemanticError: - self.add_error( - node, - f"Semantic Error: There is no method '{node.id}' that recieves {len(node.params)} arguments in Type '{caller.name}'.", - ) - caller = ErrorType() - - if methods: - type_set = set() - heads = [] - for typex, method in methods: - ret_type = method.return_type.clone() - ret_type.swap_self_type(typex) - type_set = smart_add(type_set, heads, ret_type) - for i in range(len(node.args)): - arg = node.args[i] - self.visit(arg, scope) - # arg_type = arg.inferenced_type - # arg_clone = arg_type.clone() - # conforms(arg_clone, param_type) - node.inferenced_type = TypeBag(type_set, heads) - else: - node.inferenced_type = ErrorType() - node.inferenced_caller = caller - - @visitor.when(ArithmeticNode) - def visit(self, node, scope): - self.visit(node.left, scope) - left_type = node.left.inferenced_type - left_clone = left_type.clone() - - self.visit(node.right, scope) - right_type = node.right.inferenced_type - right_clone = right_type.clone() - - int_type = self.context.get_type("Int") - if not conforms(left_type, int_type): - self.add_error( - node.left, - f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.", - ) - if not conforms(right_type, int_type): - self.add_error( - node.right, - f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to 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 - - bool_type = self.context.get_type("Bool") - left_clone = left_type.clone() - right_clone = right_type.clone() - if not conforms(left_clone, right_type) and not conforms( - right_clone, left_type - ): - self.add_error( - node, - f"Type Error: Left expression type({left_type.name}) does not conforms to right expression type({right_type.name})", - ) - - node.inferenced_type = bool_type - - @visitor.when(VariableNode) - def visit(self, node, scope: Scope): - var = scope.find_variable(node.value) - if var: - node.defined = True - var_type = var.type - else: - node.defined = False - var_type = ErrorType() - self.add_error( - node, f"Semantic Error: Variable '{node.value}' is not defined." - ) - node.inferenced_type = var_type - - @visitor.when(NotNode) - def visit(self, node, scope): - self.visit(node.expr, scope) - expr_type = node.expr.inferenced_type - expr_clone = expr_type.clone() - bool_type = self.context.get_type("Bool") - if not conforms(expr_type, bool_type): - self.add_error( - node, - f"Type Error: Not's expresion type({expr_clone.name} does not conforms to 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 - expr_clone = expr_type.clone() - node_type = self.context.get_type("Int") - - if not conforms(expr_type, node_type): - self.add_error( - node, - f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type", - ) - node_type = ErrorType() - - node.inferenced_type = node_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.value, selftype=False, autotype=False - ) - except SemanticError as err: - self.add_error( - f"Semantic Error: Could not instantiate type '{node.value}'." - ) - 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") - - def add_error(self, node: Node, text: str): - line, col = node.get_position() if node else (0, 0) - self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/inference/autotype_inferencer.py b/src/semantics/inference/autotype_inferencer.py deleted file mode 100644 index 8cd729787..000000000 --- a/src/semantics/inference/autotype_inferencer.py +++ /dev/null @@ -1,410 +0,0 @@ -from utils.visitor import visitor -from ast.parser_ast import ( - ArithmeticNode, - AssignNode, - AttrDeclarationNode, - BlocksNode, - CaseNode, - CaseOptionNode, - ClassDeclarationNode, - ComparerNode, - ComplementNode, - ConditionalNode, - EqualsNode, - IsVoidNode, - LetNode, - LoopNode, - MethodCallNode, - MethodDeclarationNode, - Node, - NotNode, - ProgramNode, - VarDeclarationNode, - VariableNode, -) -from semantics.tools import ( - Context, - ErrorType, - Scope, - TypeBag, - conforms, - equal, - join, - join_list, - smart_add, -) - - -class AutotypeInferencer: - def __init__(self, context: Context, errors) -> None: - self.context = context - self.current_type = None - self.errors = errors - - @visitor.on("node") - def visit(self, node, scope): - pass - - @visitor.when(ProgramNode) - def visit(self, node: ProgramNode, scope: Scope): - for declaration in node.declarations: - self.visit(declaration, scope.next_child()) - - scope.reset() - - @visitor.when(ClassDeclarationNode) - def visit(self, node, scope): - self.current_type = self.context.get_type(node.id, unpacked=True) - for feature in node.features: - self.visit(feature, scope) - - @visitor.when(AttrDeclarationNode) - def visit(self, node, scope): - if not node.expr: - return - - node_infered = node.inferenced_type - expr_infered = node.expr.inferenced_type.clone() - - self.visit(node.expr, scope) - new_expr_infered = node.expr.inferenced_type - - if equal(expr_infered, new_expr_infered): - return - - new_clone_inferred = new_expr_infered.clone() - if not conforms(new_expr_infered, node_infered): - self.add_error( - node, - f"Type Error: In class '{self.current_type.name}' attribue '{node.id}' expression type({new_clone_inferred.name}) does not conforms to declared type ({node_infered.name}).", - ) - # What is made error type here!!! - - @visitor.when(MethodDeclarationNode) - def visit(self, node, scopex: Scope): - scope = scopex.next_child() - - ret_type_infered = node.body.inferenced_type.clone() - self.visit(node.body, scope) - new_type_infered = node.body.inferenced_type - - if equal(ret_type_infered, new_type_infered): - return - - current_method = self.current_type.get_method(node.id) - ret_type_decl = current_method.return_type.swap_self_type(self.current_type) - new_clone_infered = new_type_infered.clone() - - if not conforms(new_type_infered, ret_type_decl): - self.add_error( - node, - f"Type Error: In Class '{self.current_type.name}' method '{current_method.name}' return expression type({new_clone_infered.name}) does not conforms to declared return type ({ret_type_decl.name})", - ) - ret_type_expr = ErrorType() - - node.inferenced_type = ret_type_expr - ret_type_decl.swap_self_type(self.current_type, back=True) - - @visitor.when(BlocksNode) - def visit(self, node, scope): - for expr in node.expr_list: - self.visit(expr, scope) - node.inferenced_type = node.expr_list[-1].inferenced_type - - @visitor.when(ConditionalNode) - def visit(self, node, scope): - condition_infered = node.condition.inferenced_type.clone() - then_infered = node.then_body.inferenced_type.clone() - else_infered = node.else_body.inferenced_type.clone() - - self.visit(node.condition, scope) - self.visit(node.then_body, scope) - self.visit(node.else_body, scope) - - new_condition_infered = node.condition.inferenced_type - new_then_infered = node.then_body.inferenced_type - new_else_infered = node.else_body.inferenced_type - - if not equal(condition_infered, new_condition_infered): - self.add_error( - node, - f"Type Error: If's condition type({new_condition_infered.name}) does not conforms to Bool type.", - ) - - if equal(then_infered, new_then_infered) and equal( - else_infered, new_else_infered - ): - return - - joined_type = join(new_then_infered, new_else_infered) - node.inferenced_type = joined_type - - @visitor.when(CaseNode) - def visit(self, node, scope: Scope): - self.visit(node.case_expr, scope) - - type_list = [] - change = False - for option in node.options: - child = scope.next_child() - option_infered = option.inferenced_type.clone() - self.visit(option, child) - new_option_infered = option.inferenced_type - type_list.append(new_option_infered) - change = change or not equal(option_infered, new_option_infered) - - if change: - joined_type = join_list(type_list) - node.inferenced_type = joined_type - - @visitor.when(CaseOptionNode) - def visit(self, node, scope: Scope): - self.visit(node.expr, scope) - - @visitor.when(LoopNode) - def visit(self, node, scope): - condition_infered = node.condition.inferenced_type.clone() - self.visit(node.condition, scope) - new_cond_infered = node.condition.inferenced_type - - if not equal(condition_infered, new_cond_infered): - self.add_error( - node, - f"Type Error: Loop's condition type({new_cond_infered.name}) does not conforms to Bool type.", - ) - - self.visit(node.body, scope) - - @visitor.when(LetNode) - def visit(self, node, scope): - child = scope.next_child() - for var in node.var_decl_list: - self.visit(var, child) - self.visit(node.in_expr, child) - node.inferenced_type = node.in_expr.inferenced_type - - @visitor.when(VarDeclarationNode) - def visit(self, node, scope: Scope): - if not node.expr: - return - - expr_infered = node.expr.inferenced_type.clone() - self.visit(node.expr, scope) - new_expr_inferred = node.expr.inferenced_type - - if equal(expr_infered, new_expr_inferred): - return - - node_infered = node.inferenced_type - new_clone_infered = new_expr_inferred.clone() - if not conforms(new_expr_inferred, node_infered): - self.add_error( - node, - f"Semantic Error: Variable '{node.id}' expression type({new_clone_infered.name}) does not conforms to declared type({node_infered.name}).", - ) - - @visitor.when(AssignNode) - def visit(self, node, scope: Scope): - if not node.defined and node.id != "self": - return - - expr_infered = node.expr.inferenced_type.clone() - self.visit(node.expr, scope) - new_expr_infered = node.expr.inferenced_type - - if equal(expr_infered, new_expr_infered): - return - - var_type = scope.find_variable(node.id).type - new_clone_infered = new_expr_infered.clone() - if not conforms(new_expr_infered, var_type): - self.add_error( - node, - f"Type Error: Cannot assign new value to variable '{node.id}'. Expression type({new_clone_infered.name}) does not conforms to declared type ({var_type.name}).", - ) - var_type = ErrorType() - - node.inferenced_type = var_type - - @visitor.when(MethodCallNode) - def visit(self, node, scope): - caller = node.inferenced_caller - if node.type and node.expr: - bridge_infered = node.expr.inferenced_type.clone() - self.visit(node.expr, scope) - bridge = node.expr.inferenced_type - if not equal(bridge_infered, bridge): - bridge_clone = bridge.clone() - if not conforms(bridge, caller): - self.add_error( - node, - f"Semantic Error: Cannot effect dispatch because expression type({bridge_clone.name}) does not conforms to caller type({caller.name}).", - ) - caller = ErrorType() - elif node.expr: - self.visit(node.expr, scope) - caller = node.expr.inferenced_type - - 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), types)) - if len(caller.heads) > 1: - error = f'Semantic Error: Method "{node.id}" found in {len(caller.heads)} unrelated types:\n' - error += " -Found in: " - error += ", ".join(typex.name for typex in caller.heads) - self.add_error(node, error) - caller = ErrorType() - elif len(caller.heads) == 0: - self.add_error( - node, - f"There is no method called {node.id} which takes {len(node.args)} paramters.", - ) - caller = ErrorType() - - if len(caller.heads) == 1: - caller_type = caller.heads[0] - method = caller_type.get_method(node.id) - - if len(node.args) != len(method.param_types): - self.add_error( - node, - f"Semantic Error: Method '{node.id}' from class '{caller_type.name}' takes {len(node.args)} arguments but {method.param_types} were given.'", - ) - node.inferenced_type = ErrorType() - - decl_return_type = method.return_type.clone() - decl_return_type.swap_self_type(caller_type) - - type_set = set() - heads = [] - type_set = smart_add(type_set, heads, decl_return_type) - for i in range(len(node.args)): - arg = node.args[i] - p_type = method.param_types[i] - self.visit(arg, scope) - new_arg_infered = arg.inferenced_type - new_clone_infered = new_arg_infered.clone() - if not conforms(new_arg_infered, p_type): - self.add_error( - node.arg, - f"Type Error: Argument expression type ({new_clone_infered.name}) does not conforms parameter declared type({p_type.name})", - ) - node.inferenced_type = TypeBag(type_set, heads) - else: - node.inferenced_type = ErrorType() - node.inferenced_caller = caller - - @visitor.when(ArithmeticNode) - def visit(self, node, scope): - left_infered = node.left.inferenced_type # .clone() - right_infered = node.right.inferenced_type # .clone() - - self.visit(node.left, scope) - self.visit(node.right, scope) - - new_left = node.left.inferenced_type - new_right = node.right.inferenced_type - - int_type = self.context.get_type("Int") - if not equal(left_infered, new_left): - left_clone = new_left.clone() - if not conforms(left_infered, int_type): - self.add_error( - node.left, - f"Type Error: Arithmetic Error: Left member type({left_clone.name}) does not conforms to Int type.", - ) - - if not equal(right_infered, new_right): - right_clone = new_left.clone() - if not conforms(right_infered, int_type): - self.add_error( - node.right, - f"Type Error: Arithmetic Error: Right member type({right_clone.name}) does not conforms to Int type.", - ) - - @visitor.when(ComparerNode) - def visit(self, node, scope): - left_infered = node.left.inferenced_type # .clone() - right_infered = node.right.inferenced_type # .clone() - - self.visit(node.left, scope) - self.visit(node.right, scope) - - new_left = node.left.inferenced_type - new_right = node.right.inferenced_type - left_clone = new_left.clone() - right_clone = new_right.clone() - - if equal(left_infered, new_left) and equal(right_infered, new_right): - return - - if not conforms(left_clone, new_right) and not conforms(right_clone, new_left): - self.add_error( - node, - f"Type Error: Left expression type({new_left.name}) does not conforms to right expression type({new_right.name})", - ) - - @visitor.when(VariableNode) - def visit(self, node, scope: Scope): - if node.defined: - node.inferenced_type = scope.find_variable(node.value).type - - @visitor.when(NotNode) - def visit(self, node, scope): - expr_infered = node.expr.inferenced_type # .clone() - self.visit(node.expr, scope) - new_expr = node.expr.inferenced_type - expr_clone = new_expr.clone() - bool_type = self.context.get_type("Bool") - if equal(expr_infered, new_expr): - return - if not conforms(new_expr, bool_type): - self.add_error( - node.value, - f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Bool type", - ) - - @visitor.when(ComplementNode) - def visit(self, node, scope): - expr_infered = node.expr.inferenced_type # .clone() - self.visit(node.expr, scope) - new_expr = node.expr.inferenced_type - expr_clone = new_expr.clone() - int_type = self.context.get_type("Int") - if equal(expr_infered, new_expr): - return - if not conforms(new_expr, int_type): - self.add_error( - node.value, - f"Type Error: Not's expresion type({expr_clone.name} does not conforms to Int type", - ) - - @visitor.when(IsVoidNode) - def visit(self, node, scope): - self.visit(node.expr, scope) - - def add_error(self, node: Node, text: str): - line, col = node.get_position() if node else (0, 0) - self.errors.append(((line, col), f"({line}, {col}) - " + text)) - - # todo: los .clone detras de los old_infered_types puede eliminarse, me parece q no son necesarios - # todo: para no tener los .clone en todas las visitas en todos los casos posibles debe actualizarse el - # todo: .inferenced_type - - # todo: Para pensar: - # todo: que hacer si expr_type no conforma con decl_type - # todo: Convierto expr en error_type si se me queda vacio, si es error ahora va a ser despues - # todo: ademas le pone ya una condicion al bolsa, en caso de que sea AUTO_TYPE - # todo: si lo mantengo igual que puedo ganar? - - # todo: Es necesario agregar una propiedad Autotype a los TypeBag que indiquen quien es quien? - - # todo: En el caso donde Auto1 se conforma de Auto2, y Auto1, nada mas puede ser Int o Object, y el - # todo: otro puede ser de todo, de que manera y cuando achicar Auto2. - # todo: Una manera puede ser cuando no se hayan hecho mas cambios sobre Auto1 y Auto2 - - # todo: AutoType checking for later: - # todo: Redefined methods with params and return type are autotypes - # todo: Check use of self types inside auto types, how does it affects, etc... - # todo: From 1339fe26d48a8d8883fabe5e06e3f33e84ac7733 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:21:49 -0400 Subject: [PATCH 084/432] Added new tests probing SELF_TYPE --- src/debbuging/tests/Auto/selftype1.cl | 20 ++++++++++++++++++++ src/debbuging/tests/Auto/selftype2.cl | 19 +++++++++++++++++++ src/debbuging/tests/Auto/selftype3.cl | 20 ++++++++++++++++++++ src/debbuging/tests/Auto/selftype4.cl | 15 +++++++++++++++ src/debbuging/tests/Auto/selftype5.cl | 18 ++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 src/debbuging/tests/Auto/selftype1.cl create mode 100644 src/debbuging/tests/Auto/selftype2.cl create mode 100644 src/debbuging/tests/Auto/selftype3.cl create mode 100644 src/debbuging/tests/Auto/selftype4.cl create mode 100644 src/debbuging/tests/Auto/selftype5.cl diff --git a/src/debbuging/tests/Auto/selftype1.cl b/src/debbuging/tests/Auto/selftype1.cl new file mode 100644 index 000000000..fdfd00bdb --- /dev/null +++ b/src/debbuging/tests/Auto/selftype1.cl @@ -0,0 +1,20 @@ +--Error en B en el metodo test, se debe terminar con un self o new Self. + +class Main inherits IO { + main() : AUTO_TYPE { + self + }; +}; + +class A { + test(): SELF_TYPE { + new A + }; + + test2(): SELF_TYPE { + new SELF_TYPE + }; + }; + + class B inherits A { }; + diff --git a/src/debbuging/tests/Auto/selftype2.cl b/src/debbuging/tests/Auto/selftype2.cl new file mode 100644 index 000000000..c5935252f --- /dev/null +++ b/src/debbuging/tests/Auto/selftype2.cl @@ -0,0 +1,19 @@ +--SELF TYPE no se puede usar como parametro + +class Main inherits IO { + main() : AUTO_TYPE { + self + }; +}; + +class A { + test(b:SELF_TYPE): SELF_TYPE { + b + }; + test2(): SELF_TYPE { + let b:SELF_TYPE in b + }; + }; + + class B inherits A { }; + diff --git a/src/debbuging/tests/Auto/selftype3.cl b/src/debbuging/tests/Auto/selftype3.cl new file mode 100644 index 000000000..0825a946e --- /dev/null +++ b/src/debbuging/tests/Auto/selftype3.cl @@ -0,0 +1,20 @@ +--SELF TYPE no se puede usar en los case + +class Main inherits IO { + main() : AUTO_TYPE { + self + }; +}; + +class A { + test(a:A): Int { + case a of + n:Int => 1; + n:Bool => 2; + n:SELF_TYPE => 4; + esac + }; + }; + + class B inherits A { }; + diff --git a/src/debbuging/tests/Auto/selftype4.cl b/src/debbuging/tests/Auto/selftype4.cl new file mode 100644 index 000000000..8cbf7e828 --- /dev/null +++ b/src/debbuging/tests/Auto/selftype4.cl @@ -0,0 +1,15 @@ +--test2 es de tipo A asi que debe dar error xq A no confoma con SELF_TYPE de A + +class Main inherits IO { + main() : AUTO_TYPE { + self + }; +}; + +class A { + test:A <- self; + test2:SELF_TYPE <- test; + }; + + class B inherits A { }; + diff --git a/src/debbuging/tests/Auto/selftype5.cl b/src/debbuging/tests/Auto/selftype5.cl new file mode 100644 index 000000000..660df1362 --- /dev/null +++ b/src/debbuging/tests/Auto/selftype5.cl @@ -0,0 +1,18 @@ +--Que pasa en test. Su expresion es del tipo A, o del tipo SELF_TYPE + +class Main inherits IO { + main() : AUTO_TYPE { + self + }; +}; + +class A inherits IO { + v:String; + test(): SELF_TYPE + { + new SELF_TYPE.out_string(v) + }; + }; + + class B inherits A { }; + From 3d52b2d0dbe12e2839b4f1729d16699c880d495c Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:22:38 -0400 Subject: [PATCH 085/432] Split tool script into a module Module tool has now all clasess and methods previously defined in tool.py, divided between context, scope, errors and types --- .../{tools.py => tools(deprecated).py} | 57 +- src/semantics/tools/__init__.py | 13 + src/semantics/tools/context.py | 53 ++ src/semantics/{ => tools}/errors.py | 0 src/semantics/tools/scope.py | 83 +++ src/semantics/tools/type.py | 559 ++++++++++++++++++ 6 files changed, 745 insertions(+), 20 deletions(-) rename src/semantics/{tools.py => tools(deprecated).py} (94%) create mode 100644 src/semantics/tools/__init__.py create mode 100644 src/semantics/tools/context.py rename src/semantics/{ => tools}/errors.py (100%) create mode 100644 src/semantics/tools/scope.py create mode 100644 src/semantics/tools/type.py diff --git a/src/semantics/tools.py b/src/semantics/tools(deprecated).py similarity index 94% rename from src/semantics/tools.py rename to src/semantics/tools(deprecated).py index 3ff8a42be..33fbeec7f 100644 --- a/src/semantics/tools.py +++ b/src/semantics/tools(deprecated).py @@ -263,7 +263,6 @@ def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list self.update_type_set_from_conforms() - self.generate_name() def update_type_set_from_conforms(self): intersect_set = set() @@ -284,15 +283,16 @@ def update_heads(self): for typex in self.type_set: if typex in visited: continue - if typex.conforms_to(head): - visited.add(typex) - if typex.index < lower_index: - pos_new_head = [typex] - lower_index = typex.index - elif typex.index == lower_index: - pos_new_head.append(typex) + # if typex.conforms_to(head): + visited.add(typex) + if typex.index < lower_index: + pos_new_head = [typex] + lower_index = typex.index + elif typex.index == lower_index: + pos_new_head.append(typex) new_heads += pos_new_head self.heads = new_heads + self.generate_name() def swap_self_type(self, swap_type, back=False): if not back: @@ -308,15 +308,30 @@ def swap_self_type(self, swap_type, back=False): except KeyError: return self - for i in range(len(self.heads)): - typex = self.heads[i] - if typex.name == remove_type.name: - self.heads[i] = add_type - break - - self.generate_name() + # for i in range(len(self.heads)): + # typex = self.heads[i] + # if typex.name == remove_type.name: + # self.heads[i] = add_type + # break + # + # self.generate_name() + self.update_heads() return self + def add_self_type(self, add_type) -> bool: + if SelfType() in self.type_set and not add_type in self.type_set: + self.type_set.add(add_type) + return True + return False + + def remove_self_type(self, remove_type): + try: + self.type_set.remove(remove_type) + except KeyError: + pass + self.type_set.add(SelfType()) + self.update_heads() + def generate_name(self): if len(self.type_set) == 1: self.name = self.heads[0].name @@ -349,9 +364,13 @@ def __init__(self): self.index = 2 ** 31 def conforms_to(self, other): + if isinstance(other, SelfType): + return True + return False raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") def bypass(self): + return False raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") def __hash__(self) -> int: @@ -422,13 +441,11 @@ def create_type(self, name: str) -> Type: return typex def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> Type: - if selftype and name == "SELF_TYPE": - return TypeBag({SelfType()}) # SelfType() + if not selftype and name == "SELF_TYPE": + raise TypeError(f"Cannot use SELF_TYPE.") # return TypeBag({SelfType()}) if autotype and name == "AUTO_TYPE": self.num_autotypes += 1 - return TypeBag( - self.types, [self.types["Object"]] - ) # AutoType(f"T{self.num_autotypes}", [self.types["Object"]], self.types) + return TypeBag(self.types, [self.types["Object"]]) try: if unpacked: return self.types[name] diff --git a/src/semantics/tools/__init__.py b/src/semantics/tools/__init__.py new file mode 100644 index 000000000..b1a7ab0d2 --- /dev/null +++ b/src/semantics/tools/__init__.py @@ -0,0 +1,13 @@ +from semantics.tools.context import Context +from semantics.tools.scope import Scope +from semantics.tools.type import ( + ErrorType, + SelfType, + TypeBag, + conforms, + equal, + join, + join_list, + smart_add, + try_conform, +) diff --git a/src/semantics/tools/context.py b/src/semantics/tools/context.py new file mode 100644 index 000000000..99d5f1590 --- /dev/null +++ b/src/semantics/tools/context.py @@ -0,0 +1,53 @@ +from semantics.tools.errors import * +from semantics.tools.type import TypeBag, Type, SelfType + + +class Context: + def __init__(self) -> None: + self.types = {} + self.type_graph = None + + def create_type(self, name: str) -> Type: + if name in self.types: + raise SemanticError(f"Type with the same name ({name}) already exists.") + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> Type: + if selftype and name == "SELF_TYPE": + return TypeBag({SelfType()}) # raise TypeError(f"Cannot use SELF_TYPE.") + if autotype and name == "AUTO_TYPE": + return TypeBag(self.types, [self.types["Object"]]) + try: + if unpacked: + return self.types[name] + return TypeBag({self.types[name]}) + except KeyError: + raise TypeError(f'Type "{name}" is not defined.') + + def get_method_by_name(self, name: str, args: int) -> list: + def dfs(root: str, results: list): + try: + for typex in self.type_graph[root]: + for method in self.types[typex].methods: + if name == method.name and args == len(method.param_names): + results.append((self.types[typex], method)) + break + else: + dfs(typex, results) + except KeyError: + pass + + results = [] + dfs("Object", results) + return results + + def __str__(self): + return ( + "{\n\t" + + "\n\t".join(y for x in self.types.values() for y in str(x).split("\n")) + + "\n}" + ) + + def __repr__(self): + return str(self) \ No newline at end of file diff --git a/src/semantics/errors.py b/src/semantics/tools/errors.py similarity index 100% rename from src/semantics/errors.py rename to src/semantics/tools/errors.py diff --git a/src/semantics/tools/scope.py b/src/semantics/tools/scope.py new file mode 100644 index 000000000..6bf85c39b --- /dev/null +++ b/src/semantics/tools/scope.py @@ -0,0 +1,83 @@ +from semantics.tools.type import TypeBag, ErrorType +import itertools as itt + + +class VariableInfo: + def __init__(self, name, vtype) -> None: + self.name: str = name + self.type: TypeBag = vtype + + def get_type(self) -> TypeBag or ErrorType: + if len(self.type.type_set) == 0: + self.type = ErrorType() + return self.type + + def __str__(self): + return self.name + ":" + self.type + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + self.current_child = -1 + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + try: + return ( + self.parent.find_variable(vname, self.index) + if self.parent is not None + else None + ) + except AttributeError: + return None + + def get_local_by_index(self, index): + return self.locals[index] + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) + + def next_child(self): + self.current_child += 1 + return self.children[self.current_child] + + def reset(self): + self.current_child = -1 + for child in self.children: + child.reset() + + def get_all_names(self, s: str = "", level: int = 0): + if self.locals: + s += "\n ".join( + [ + x.name + ":" + str([typex.name for typex in x.type.type_set]) + for x in self.locals + ] + ) + s += "\n\n" + for child in self.children: + s = child.get_all_names(s, level + 1) + return s \ No newline at end of file diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py new file mode 100644 index 000000000..b2cf49ccb --- /dev/null +++ b/src/semantics/tools/type.py @@ -0,0 +1,559 @@ +from semantics.tools.errors import * +from typing import Set +from collections import OrderedDict + + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f"[attrib] {self.name} : {self.type.name};" + + def __repr__(self): + return str(self) + + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ", ".join( + f"{n}:{t.name}" for n, t in zip(self.param_names, self.param_types) + ) + return f"[method] {self.name}({params}): {self.return_type.name};" + + def __eq__(self, other): + return ( + other.name == self.name + and other.return_type == self.return_type + and other.param_types == self.param_types + ) + + +class Type: + def __init__(self, name: str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + self.index = -1 + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError( + f"Type '{self.name}' already has parent type '{self.parent.name}'. Type '{parent.name}' cannot be set as parent." + ) + if parent.name in {"String", "Int", "Bool"}: + raise SemanticError( + f"Cannot set '{self.name}' parent, '{parent.name}' type cannot be inherited." + ) + self.parent = parent + + def define_attribute(self, name: str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError( + f'Attribute "{name}" is already defined in "{self.name}".' + ) + + def get_attribute(self, name: str, first=None): + if not first: + first = self.name + elif first == self.name: + raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') + + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise AttributeError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + try: + return self.parent.get_attribute(name, first=first) + except SemanticError: + raise AttributeError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + + def get_method(self, name: str, local: bool = False, first=None): + if not first: + first = self.name + elif first == self.name: + raise AttributeError( + f'Method "{name}" is not defined in class {self.name}.' + ) + + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise AttributeError( + f'Method "{name}" is not defined in class {self.name}.' + ) + try: + return self.parent.get_method(name, first=first) + except AttributeError: + raise AttributeError( + f'Method "{name}" is not defined in class {self.name}.' + ) + + def define_method( + self, name: str, param_names: list, param_types: list, return_type + ): + if name in (method.name for method in self.methods): + raise SemanticError(f"Method '{name}' already defined in '{self.name}'") + + try: + parent_method = self.get_method(name) + except SemanticError: + parent_method = None + if parent_method: + error_list = [] + return_type.swap_self_type(self) + return_clone = return_type.clone() + parent_method.return_type.swap_self_type(self) + if not conforms(return_type, parent_method.return_type): + error_list.append( + f" -> Same return type: Redefined method has '{return_clone.name}' as return type instead of '{parent_method.return_type.name}'." + ) + if len(param_types) != len(parent_method.param_types): + error_list.append( + f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}." + ) + else: + count = 0 + err = [] + for param_type, parent_param_type in zip( + param_types, parent_method.param_types + ): + param_clone = param_type.clone() + if not conforms(param_type, parent_param_type): + err.append( + f" -Param number {count} has {param_clone.name} as type instead of {parent_param_type.name}" + ) + count += 1 + if err: + s = f" -> Same param types:\n" + "\n".join( + child for child in err + ) + error_list.append(s) + return_type.swap_self_type(self, back=True) + parent_method.return_type.swap_self_type(self, back=True) + if error_list: + err = ( + f"Redifined method '{name}' in class '{self.name}' does not have:\n" + + "\n".join(child for child in error_list) + ) + raise SemanticError(err) + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + + return method + + def all_attributes(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = ( + OrderedDict() + if self.parent is None + else self.parent.all_attributes(clean=False, first=first) + ) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True, first=None): + if not first: + first = self.name + elif first == self.name: + return OrderedDict.values() if clean else OrderedDict() + + plain = ( + OrderedDict() + if self.parent is None + else self.parent.all_methods(clean=False, first=first) + ) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other, first=None): + if not first: + first = self.name + elif self.name == first: + return False + return ( + other.bypass() + or self == other + or self.parent + and self.parent.conforms_to(other, first) + ) + + def bypass(self): + return False + + def least_common_ancestor(self, other): + this = self + if isinstance(this, ErrorType) or isinstance(other, ErrorType): + return ErrorType() + + while this.index < other.index: + other = other.parent + while other.index < this.index: + this = this.parent + if not (this and other): + return None + while this.name != other.name: + this = this.parent + other = other.parent + if this == None: + return None + return this + + def __str__(self): + output = f"type {self.name}" + parent = "" if self.parent is None else f" : {self.parent.name}" + output += parent + output += " {" + output += "\n\t" if self.attributes or self.methods else "" + output += "\n\t".join(str(x) for x in self.attributes) + output += "\n\t" if self.attributes else "" + output += "\n\t".join(str(x) for x in self.methods) + output += "\n" if self.methods else "" + output += "}\n" + return output + + def __repr__(self): + return str(self) + + +class TypeBag: + def __init__(self, type_set, heads=[]) -> None: + self.type_set: set = ( + type_set if isinstance(type_set, set) else from_dict_to_set(type_set) + ) + self.heads: list = heads + if len(self.type_set) == 1: + self.heads = list(self.type_set) + + self.name = "undefined" + self.condition_list = [] + self.conform_list = [] + self.generate_name() + + def set_conditions(self, condition_list, conform_list): + self.condition_list = condition_list + self.conform_list = conform_list + self.update_type_set_from_conforms() + + def update_type_set_from_conforms(self): + intersect_set = set() + for conform_set in self.conform_list: + intersect_set = intersect_set.union(conform_set) + self.type_set = self.type_set.intersection(intersect_set) + self.update_heads() + + def update_heads(self): + new_heads = [] + visited = set() + for head in self.heads: + if head in self.type_set: + new_heads.append(head) + continue + pos_new_head = [] + lower_index = 2 ** 32 + for typex in self.type_set: + if typex in visited: + continue + # if typex.conforms_to(head): + visited.add(typex) + if typex.index < lower_index: + pos_new_head = [typex] + lower_index = typex.index + elif typex.index == lower_index: + pos_new_head.append(typex) + new_heads += pos_new_head + self.heads = new_heads + self.generate_name() + + def swap_self_type(self, swap_type, back=False): + if not back: + remove_type = SelfType() + add_type = swap_type + else: + remove_type = swap_type + add_type = SelfType() + + try: + self.type_set.remove(remove_type) + self.type_set.add(add_type) + except KeyError: + return self + + # for i in range(len(self.heads)): + # typex = self.heads[i] + # if typex.name == remove_type.name: + # self.heads[i] = add_type + # break + # + # self.generate_name() + self.update_heads() + return self + + def add_self_type(self, add_type) -> bool: + if SelfType() in self.type_set and not add_type in self.type_set: + self.type_set.add(add_type) + return True + return False + + def remove_self_type(self, remove_type): + try: + self.type_set.remove(remove_type) + except KeyError: + pass + self.type_set.add(SelfType()) + self.update_heads() + + def generate_name(self): + if len(self.type_set) == 1: + self.name = self.heads[0].name + return self.name + + s = "{" + s += ", ".join( + typex.name for typex in sorted(self.type_set, key=lambda t: t.index) + ) + s += "}" + self.name = s + return s + + def clone(self): + clone = TypeBag(self.type_set.copy(), self.heads.copy()) + clone.condition_list = self.condition_list.copy() + clone.conform_list = self.conform_list.copy() + return clone + + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + + +class SelfType(Type): + def __init__(self): + self.name = "SELF_TYPE" + self.index = 2 ** 31 + + def conforms_to(self, other): + if isinstance(other, SelfType): + return True + return False + raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") + + def bypass(self): + return False + raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") + + def __hash__(self) -> int: + return hash(self.name) + + def __eq__(self, o: object) -> bool: + return isinstance(o, SelfType) + + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + + +class ErrorType(TypeBag): + def __init__(self): + self.name = "" + self.index = 2 ** 32 + self.type_set = frozenset() + self.heads = frozenset() + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def swap_self_type(self, swap_type, back=False): + return self + + def set_conditions(self, *params): + return + + def generate_name(self): + return "" + + def clone(self): + return self + + +def conforms(bag1: TypeBag, bag2: TypeBag) -> bool: + if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + return True + + ordered_set = order_set_by_index(bag2.type_set) + + condition_list = [] + conform_list = [] + for condition in ordered_set: + conform = conform_to_condition(bag1.type_set, condition) + for i in range(len(condition_list)): + conform_i = conform_list[i] + if len(conform_i) == len(conform) and len( + conform.intersection(conform_i) + ) == len(conform): + condition_list[i].add(condition) + break + else: + condition_list.append({condition}) + conform_list.append(conform) + + bag1.set_conditions(condition_list, conform_list) + return len(bag1.type_set) >= 1 + + +def try_conform(bag1: TypeBag, bag2: TypeBag) -> TypeBag: + clone1 = bag1.clone() + if not conforms(bag1, bag2): + return clone1 + return bag2 + + +def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: + if isinstance(bag1, ErrorType): + return bag2 + if isinstance(bag2, ErrorType): + return bag1 + + ancestor_set = set() + head_list = [] + ordered_set1: Set[Type] = order_set_by_index(bag1.type_set) + ordered_set2: Set[Type] = order_set_by_index(bag2.type_set) + ordered_set1, ordered_set2 = ( + (ordered_set1, ordered_set2) + if len(ordered_set1) < len(ordered_set2) + else (ordered_set2, ordered_set1) + ) + for type1 in ordered_set1: + same_branch = False + previous_ancestor = None + previous_type = None + for type2 in ordered_set2: + if same_branch and type2.conforms_to(previous_type): + previous_type = type2 + continue + common_ancestor = type1.least_common_ancestor(type2) + previous_type = type2 + if not previous_ancestor: + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + else: + if previous_ancestor == common_ancestor: + same_branch = True + else: + same_branch = False + smart_add(ancestor_set, head_list, common_ancestor) + previous_ancestor = common_ancestor + + join_result = TypeBag(ancestor_set, head_list) + return join_result + + +def join_list(type_list): + join_result = type_list[0] + for i in range(1, len(type_list)): + type_i = type_list[i] + join_result = join(join_result, type_i) + return join_result + + +def equal(bag1: TypeBag, bag2: TypeBag): + if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + return True + set1 = bag1.type_set + set2 = bag2.type_set + return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) + + +def smart_add(type_set: set, head_list: list, typex: Type): + if isinstance(typex, TypeBag): + return auto_add(type_set, head_list, typex) + + type_set.add(typex) + there_is = False + for i in range(len(head_list)): + head = head_list[i] + ancestor = typex.least_common_ancestor(head) + if ancestor in type_set: + there_is = True + if ancestor == typex: + head_list[i] = typex + break + if not there_is: + head_list.append(typex) + return type_set + + +def auto_add(type_set: set, head_list: list, bag: TypeBag): + type_set = type_set.union(bag.type_set) + aux = set(bag.heads) + for i in range(len(head_list)): + head_i = head_list[i] + for head_j in bag.heads: + ancestor = head_i.least_common_ancestor(head_j) + if ancestor in type_set: + head_list[i] = ancestor + aux.remove(head_j) + break + head_list += [typex for typex in aux] + return type_set + + +def conform_to_condition(type_set, parent) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result + + +def order_set_by_index(type_set): + return sorted(list(type_set), key=lambda x: x.index) + + +def set_intersection(parent, type_set) -> set: + set_result = set() + for typex in type_set: + if typex.conforms_to(parent): + set_result.add(typex) + return set_result + + +def from_dict_to_set(types: dict): + type_set = set() + for typex in types: + type_set.add(types[typex]) + return type_set \ No newline at end of file From a6b5c5dbfb5b6e693a1d95ef01c9784610c0c0d8 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:24:09 -0400 Subject: [PATCH 086/432] Minor change to main --- src/__main__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 5751d7aca..8ce2ec92d 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,5 +1,6 @@ from os import close, error from semantics.inference.hard_inferencer import HardInferencer +from debbuging.type_logger import TypeLogger import sys from ply.lex import lex @@ -41,9 +42,9 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - # logger = type_logger.TypeLogger(context) - # log = logger.visit(soft_ast, soft_ast.scope) - # print(log) + logger = TypeLogger(context) + log = logger.visit(hard_ast, hard_ast.scope) + print(log) if len(errors) > 0: s = format_errors(errors) print(s) @@ -55,7 +56,9 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "self3.cl" + path = "/home/rodro/Aarka/Complementos de Compilacion/cool-cows/src/debbuging/tests/Auto/" + input_file = path + "selftype4.cl" + # input_file = "dispatch6.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) From a474ae4ff2babcb45ff5edc6519572f8fe82662e Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:28:43 -0400 Subject: [PATCH 087/432] Type Builder now checks method's parameters validity --- src/semantics/type_builder.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 5386257a5..ebd1091c2 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -6,9 +6,8 @@ MethodDeclarationNode, AttrDeclarationNode, ) -from semantics.errors import SemanticError -from semantics.tools import SelfType, TypeBag, ErrorType -from semantics.tools import Context +from semantics.tools.errors import SemanticError +from semantics.tools import SelfType, TypeBag, ErrorType, Context class TypeBuilder: @@ -82,10 +81,26 @@ def visit(self, node): p_name = var.id p_type = var.type try: - params_type.append(self.context.get_type(p_type)) + params_type.append(self.context.get_type(p_type, selftype=False)) except SemanticError as err: params_type.append(ErrorType()) - self.add_error(node, err.text) + self.add_error( + node, + err.text + + f" While defining parameter {var.id} in method {node.id}.", + ) + if p_name in params_name: + self.add_error( + node, + f"SemanticError: Formal parameter '{p_name}' has been defined multiple times.", + ) + p_name = f"error({p_name})" + if p_name == "self": + self.add_error( + node, + "SemanticError: Cannot use 'self' as formal parameter identifier.", + ) + p_name = f"error({p_name})" params_name.append(p_name) try: From 475021b646184394e1c35ac348f406f87234e588 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:29:12 -0400 Subject: [PATCH 088/432] Minor changes --- .gitignore | 4 ++++ src/semantics/type_collector.py | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2699a1b18..baba1dc00 100644 --- a/.gitignore +++ b/.gitignore @@ -435,3 +435,7 @@ src/test.cl src/class1_error.txt src/class1.cl src/test.cl +src/dispatch6.cl +src/arithmetic8_error.txt +src/arithmetic8.cl +src/dispatch6_error.txt diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 2d0de96a6..6ae5a2759 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,7 +1,7 @@ from ast.parser_ast import ClassDeclarationNode, Node, ProgramNode -from semantics.errors import SemanticError -from semantics.tools import Context +from semantics.tools.errors import SemanticError +from semantics.tools import Context, SelfType from utils import visitor @@ -116,6 +116,9 @@ def init_default_classes(self): self.context.create_type("IO") self.context.create_type("Bool") + def init_self_type(self): + self.context.types["SELF_TYPE"] = SelfType() + def add_error(self, node: Node, text: str): line, col = node.get_position() if node else (0, 0) self.errors.append(((line, col), f"({line}, {col}) - " + text)) From 1df7047288ef37535814d8cf277b0f6e6db916c8 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:29:35 -0400 Subject: [PATCH 089/432] Changed SoftInferencer logic so it treated SELF_TYPES more accurately according to Cool's Manual --- src/semantics/inference/soft_inferencer.py | 96 ++++++++++++---------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index f1de41f58..57790b54b 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -1,3 +1,4 @@ +from inspect import currentframe import ast.inferencer_ast as inf_ast from ast.parser_ast import ( ArithmeticNode, @@ -30,17 +31,17 @@ ) from utils import visitor -from semantics.errors import SemanticError, AttributeError +from semantics.tools.errors import SemanticError, AttributeError from semantics.tools import ( Context, ErrorType, Scope, + SelfType, TypeBag, conforms, join, join_list, smart_add, - try_conform, ) @@ -67,7 +68,7 @@ def visit(self, node: ProgramNode) -> inf_ast.ProgramNode: @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: self.current_type = self.context.get_type(node.id, unpacked=True) - scope.define_variable("self", TypeBag({self.current_type})) + scope.define_variable("self", TypeBag({SelfType()})) for attr in self.current_type.attributes: if attr.name != "self": @@ -85,9 +86,7 @@ def visit(self, node, scope): if node.id == "self": self.add_error(node, "SemanticError: An attribute cannot be named 'self'") - node_type = self.current_type.get_attribute(node.id).type.swap_self_type( - self.current_type - ) + node_type = self.current_type.get_attribute(node.id).type attr_node = inf_ast.AttrDeclarationNode(node) if not node.expr: @@ -95,11 +94,11 @@ def visit(self, node, scope): return attr_node expr_node = self.visit(node.expr, scope) + expr_type: TypeBag = expr_node.inferenced_type + added_type = expr_type.add_self_type(self.current_type) - node_expr = expr_node.inferenced_type - - expr_name = node_expr.generate_name() - if not conforms(node_expr, node_type): + expr_name = expr_type.generate_name() + if not conforms(expr_type, node_type): self.add_error( node, ( @@ -109,8 +108,11 @@ def visit(self, node, scope): ), ) expr_node.inferenced_type = ErrorType() + if added_type: + expr_type.remove_self_type(self.current_type) + attr_node.expr = expr_node - attr_node.inferenced_type = node_type + attr_node.inferenced_type = expr_type return attr_node @visitor.when(MethodDeclarationNode) @@ -119,33 +121,26 @@ def visit(self, node, scopex: Scope): current_method = self.current_type.get_method(node.id) for idx, typex in zip(current_method.param_names, current_method.param_types): - if idx == "self": - self.add_error( - node, - "SemanticError: Cannot use 'self' as formal parameter identifier", - ) - if scope.is_local(idx): - self.add_error( - node, - f"SemanticError: Formal parameter '{idx}' has been defined multiple times.", - ) scope.define_variable(idx, typex) - ret_type_decl = current_method.return_type.swap_self_type(self.current_type) - body_node = self.visit(node.body, scope) + ret_type_decl: TypeBag = current_method.return_type + body_node = self.visit(node.body, scope) ret_type_expr = body_node.inferenced_type - ret_expr_clone = ret_type_expr.clone() + added_self = ret_type_expr.add_self_type(self.current_type) + + ret_expr_name = ret_type_expr.generate_name() if not conforms(ret_type_expr, ret_type_decl): self.add_error( body_node, f"TypeError: In Class '{self.current_type.name}' method" - f" '{current_method.name}' return expression type({ret_expr_clone.name})" + f" '{current_method.name}' return expression type({ret_expr_name})" f" does not conforms to declared return type ({ret_type_decl.name})", ) body_node.inferenced_type = ErrorType() - ret_type_decl.swap_self_type(self.current_type, back=True) + if added_self: + ret_type_expr.remove_self_type(self.current_type) method_node = inf_ast.MethodDeclarationNode(node.type, body_node, node) method_node.inferenced_type = ret_type_decl @@ -223,7 +218,9 @@ def visit(self, node, scope: Scope): try: node_type = self.context.get_type(node.type, selftype=False, autotype=False) except SemanticError as err: - self.add_error(node, err.text) + self.add_error( + node, err.text + f" While defining Case Option variable {node.id}." + ) node_type = ErrorType() scope.define_variable(node.id, node_type) @@ -272,9 +269,7 @@ def visit(self, node, scope: Scope): var_decl_node = inf_ast.VarDeclarationNode(node) try: - node_type = self.context.get_type(node.type).swap_self_type( - self.current_type - ) + node_type = self.context.get_type(node.type) except SemanticError as err: node_type = ErrorType() self.add_error(node, err.text) @@ -293,7 +288,8 @@ def visit(self, node, scope: Scope): if node.expr: expr_node = self.visit(node.expr, scope) - expr_type = expr_node.inferenced_type + expr_type: TypeBag = expr_node.inferenced_type + added_type = expr_type.add_self_type(self.current_type) expr_clone = expr_type.clone() if not conforms(expr_type, node_type): self.add_error( @@ -303,6 +299,8 @@ def visit(self, node, scope: Scope): f" type({node_type.name}).", ) expr_node.inferenced_type = ErrorType() + if added_type: + expr_type.remove_self_type(self.current_type) var_decl_node.expr = expr_node var_decl_node.inferenced_type = expr_node.inferenced_type # var.type = var_decl_node.inferenced_type @@ -323,7 +321,7 @@ def visit(self, node, scope: Scope): ) decl_type = ErrorType() else: - decl_type = var.type.swap_self_type(self.current_type) + decl_type = var.get_type() assign_node.defined = True if var is not None: @@ -335,7 +333,8 @@ def visit(self, node, scope: Scope): ) decl_type = ErrorType() - expr_type = expr_node.inferenced_type + expr_type: TypeBag = expr_node.inferenced_type + added_type = expr_type.add_self_type(self.current_type) expr_clone = expr_type.clone() if not conforms(expr_type, decl_type): self.add_error( @@ -345,6 +344,8 @@ def visit(self, node, scope: Scope): f" declared type ({decl_type.name}).", ) expr_node.inferenced_type = ErrorType() + if added_type: + expr_type.remove_self_type(self.current_type) assign_node.inferenced_type = expr_node.inferenced_type return assign_node @@ -356,22 +357,30 @@ def visit(self, node, scope): caller_type = TypeBag({self.current_type}) elif node.type is None: expr_node = self.visit(node.expr, scope) - caller_type = expr_node.inferenced_type + caller_type = expr_node.inferenced_type.clone() else: + try: + caller_type = self.context.get_type( + node.type, selftype=False, autotype=False + ) + except SemanticError as err: + self.add_error(node, err + " While setting dispatch caller.") + caller_type = ErrorType() + expr_node = self.visit(node.expr, scope) expr_type = expr_node.inferenced_type - caller_type = self.context.get_type( - node.type, selftype=False, autotype=False - ) - expr_clone = expr_type.clone() + added_type = expr_type.add_self_type(self.current_type) + expr_name = expr_type.generate_name() if not conforms(expr_type, caller_type): self.add_error( node, f"TypeError: Cannot effect dispatch because expression" - f"type({expr_clone.name}) does not conforms to " - f"caller type({caller_type.name}).", + f" type({expr_name}) does not conforms to" + f" caller type({caller_type.name}).", ) caller_type = ErrorType() + if added_type: + expr_type.remove_self_type(self.current_type) methods = None if len(caller_type.type_set) > 1: @@ -392,6 +401,7 @@ def visit(self, node, scope): caller_type = ErrorType() elif len(caller_type.type_set) == 1: caller = caller_type.heads[0] + caller = self.current_type if isinstance(caller, SelfType) else caller try: methods = [(caller, caller.get_method(node.id))] except AttributeError as err: @@ -477,7 +487,7 @@ def visit(self, node, scope): if not conforms(expr_type, bool_type): self.add_error( node, - f"TypeError: Not's expresion type({expr_clone.name} does not" + f"TypeError: Not's expresion type ({expr_clone.name} does not" " conforms to Bool type", ) expr_node.inferenced_type = ErrorType() @@ -516,9 +526,7 @@ def visit(self, node, scope): def visit(self, node, scope): instantiate_node = inf_ast.InstantiateNode(node) try: - node_type = self.context.get_type( - node.value, selftype=False, autotype=False - ) + node_type = self.context.get_type(node.value, autotype=False) except SemanticError as err: self.add_error( node, From 55759b8cb59c5d6caf6a83058531f096817f19e0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 25 Apr 2021 16:31:38 -0400 Subject: [PATCH 090/432] HardInferencer has differnt approach to SELF_TYPES --- src/semantics/inference/hard_inferencer.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index bdb0b6cec..88e0b1e22 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -1,4 +1,4 @@ -from semantics.errors import InternalError, AttributeError +from semantics.tools.errors import InternalError, AttributeError from ast.inferencer_ast import ( ArithmeticNode, AssignNode, @@ -33,6 +33,7 @@ Context, ErrorType, Scope, + SelfType, TypeBag, conforms, equal, @@ -255,7 +256,7 @@ def visit(self, node, scope: Scope): ) expr_node.inferenced_type = ErrorType() - # var_decl_node.inferenced_type = expr_node.inferenced_type + var_decl_node.inferenced_type = expr_node.inferenced_type return var_decl_node @visitor.when(AssignNode) @@ -332,6 +333,7 @@ def visit(self, node, scope): infered_type = ErrorType() else: caller = caller_type.heads[0] + caller = self.current_type if isinstance(caller, SelfType) else caller try: method = caller.get_method(node.id) except AttributeError as err: @@ -358,7 +360,8 @@ def visit(self, node, scope): for i in range(len(node.args)): new_args.append(self.visit(node.args[i], scope)) if i < len(method.param_types): - arg_type = new_args[-1].inferenced_type + arg_type: TypeBag = new_args[-1].inferenced_type + added_type = arg_type.add_self_type(self.current_type) arg_name = arg_type.generate_name() param_type = method.param_types[i] if not conforms(arg_type, param_type): @@ -367,6 +370,8 @@ def visit(self, node, scope): f"TypeError: Argument expression type({arg_name}) does" f" not conforms parameter declared type({param_type.name})", ) + if added_type: + arg_type.remove_self_type(self.current_type) infered_type = TypeBag(type_set, heads) call_node = MethodCallNode(caller_type, expr_node, new_args, node) From 4d58e729dde5d1e438f75e84421c6235d29f4788 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sun, 25 Apr 2021 17:57:35 -0400 Subject: [PATCH 091/432] Implement BackInferencer methods --- src/__main__.py | 28 ++- src/semantics/inference/back_inferencer.py | 191 ++++++++++++++++++++- src/test.cl | 39 ++--- tests/lexer_test.py | 20 +-- tests/parser_test.py | 32 ++-- 5 files changed, 241 insertions(+), 69 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 10cdaa394..82e8108c1 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,17 +1,12 @@ -from os import close, error -from semantics.inference.hard_inferencer import HardInferencer import sys -from ply.lex import lex - from lexing import Lexer - -# from parsing import Parser from parsing import Parser from semantics import TypeBuilder, TypeCollector from semantics.inference import ( - BackInferencer, SoftInferencer, + HardInferencer, + BackInferencer, ) @@ -19,7 +14,7 @@ def format_errors(errors, s=""): # errors.sort(key=lambda x: x[0]) for error in errors: s += error[1] + "\n" - return s[:-1] + return s[:] def run_pipeline(program_ast): @@ -41,21 +36,27 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors + # back = BackInferencer(context) + # back_ast = back.visit(hard_ast) + # errors += back.errors + # logger = type_logger.TypeLogger(context) # log = logger.visit(soft_ast, soft_ast.scope) # print(log) if len(errors) > 0: - s = format_errors(errors) - print(s) + for error in errors: + print(error[1]) + # s = format_errors(errors) + # print(s) exit(1) # print(s) def main(): if len(sys.argv) > 1: - input_file = sys.argv[1] + " " + sys.argv[2] + " " + sys.argv[3] + input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "self3.cl" + input_file = "src/test.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) @@ -64,9 +65,6 @@ def main(): lexer = Lexer() tokens = list(lexer.tokenize(program)) - for token in tokens: - print(token, token.line, token.col) - if lexer.errors: for error in lexer.errors: print(error) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 4dc86c4f5..cabe536ca 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,11 +1,36 @@ +from copy import deepcopy + from ast.inferencer_ast import ( + BinaryNode, + BooleanNode, ClassDeclarationNode, + InstantiateNode, + IntNode, ProgramNode, AttrDeclarationNode, Node, + StringNode, + UnaryNode, + VariableNode, ) -from semantics.tools import Context, Scope, try_conform +from semantics.tools import Context, Scope, TypeBag, join, join_list, try_conform from utils import visitor +from ast.inferencer_ast import ( + ProgramNode, + ClassDeclarationNode, + MethodDeclarationNode, + AttrDeclarationNode, + BlocksNode, + ConditionalNode, + CaseNode, + CaseOptionNode, + LoopNode, + LetNode, + VarDeclarationNode, + AssignNode, + MethodCallNode, + ArithmeticNode, +) # Reducir los AUTO_TYPE declarados a base de el tipo de sus expresiones: @@ -59,19 +84,169 @@ def visit(self, node, scope): expr_type = expr_node.inferenced_type decl_type = node.inferenced_type - # try conforms trata de disminuir la bolsa de tipos de decl_type a base de los - # que tiene expr_type, en caso de que se quede vacio, se mantiene sin cambios - # en la bolsa decl_type decl_type = try_conform(decl_type, expr_type) attr_node.expr = expr_node attr_node.inferenced_type = decl_type return attr_node - # Ten ojo con los selftype dentro de los typebags ... Antes de trabajar con los - # selftypes tienes que cambiarlo por el tipo determinado segun el contexo, utiliza - # el metodo swap_self_type de los objetos TypeBag para realizar esto. Si se te - # escapa un selftype cuando se intente realizar una operacion con el se lanza error + @visitor.when(MethodDeclarationNode) + def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: + # decl_type = node.inferenced_type + scope = scope.create_child() + new_body_node = self.visit(node.body, scope) + body_type = new_body_node.inferenced_type + new_node = MethodDeclarationNode(node.type, new_body_node, node) + + + @visitor.when(BlocksNode) + def visit(self, node: BlocksNode, scope) -> BlocksNode: + new_expr_list = [] + for expr in node.expr_list: + new_expr_list.append(self.visit(expr, scope)) + + new_node = BlocksNode(new_expr_list, node) + decl_type = new_node.inferenced_type + expr_type = new_expr_list[-1].inferenced_type + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(ConditionalNode) + def visit(self, node: ConditionalNode, scope) -> ConditionalNode: + new_condition_node = self.visit(node.condition, scope) + new_then_node = self.visit(node.then_body, scope) + new_else_node = self.visit(node.else_body, scope) + + join_type = join( + new_condition_node.inferenced_type, new_else_node.inferenced_type + ) + decl_type = node.inferenced_type + expr_type = join_type + new_node = ConditionalNode(new_then_node, new_then_node, new_else_node, node) + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(CaseNode) + def visit(self, node: CaseNode, scope) -> CaseNode: + new_case_node = self.visit(node.case_expr, scope) + new_options_nodes = [] + for option in node.options: + child_scope = scope.create_child() + new_options_nodes.append(self.visit(option, child_scope)) + + join_type = join_list([option.inferenced_type for option in new_options_nodes]) + + new_node = CaseNode(new_case_node, new_options_nodes, node) + decl_type = node.inferenced_type + expr_type = join_type + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(CaseOptionNode) + def visit(self, node: CaseOptionNode, scope) -> CaseOptionNode: + new_node_expr = self.visit(node.expr, scope) + new_node = CaseOptionNode(new_node_expr, node) + decl_type = node.inferenced_type + expr_type = new_node_expr.inferenced_type + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(LoopNode) + def visit(self, node: LoopNode, scope) -> LoopNode: + new_condition_node = self.visit(node.condition, scope) + new_body_node = self.visit(node.body, scope) + + new_node = LoopNode(new_condition_node, new_body_node, node) + decl_type = node.inferenced_type + expr_type = self.context.get_type("Object") + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(LetNode) + def visit(self, node: LetNode, scope) -> LetNode: + child_scope = scope.create_child() + + new_var_decl_nodes = [] + for var_decl in node.var_decl_list: + new_var_decl_nodes.append(self.visit(var_decl, child_scope)) + + new_in_node = self.visit(node.in_expr, child_scope) + + new_node = LetNode(new_var_decl_nodes, new_in_node, node) + decl_type = node.inferenced_type + expr_type = new_in_node.inferenced_type + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(VarDeclarationNode) + def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: + scope.define_variable(node.id, node.inferenced_type) + new_expr_node = self.visit(node.expr, scope) + decl_type = node.inferenced_type + expr_type = new_expr_node.inferenced_type + new_node = VarDeclarationNode(node) + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(AssignNode) + def visit(self, node: AssignNode, scope) -> AssignNode: + new_expr_node = self.visit(node.expr, scope) + if node.defined: + decl_type = scope.find_variable(node.id).get_type() + decl_type = node.inferenced_type + expr_type = new_expr_node.inferenced_type + new_node = AssignNode(new_expr_node, node) + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + + @visitor.when(MethodCallNode) + def visit(self, node: MethodCallNode, scope) -> MethodCallNode: + pass + + @visitor.when(BinaryNode) + def visit(self, node: BinaryNode, scope) -> BinaryNode: + new_node = deepcopy(node) + new_left_node = self.visit(node.left, scope) + new_right_node = self.visit(node.right, scope) + + new_node.left = new_left_node + new_node.right = new_right_node + + return new_node + + @visitor.when(UnaryNode) + def visit(self, node: UnaryNode, scope) -> UnaryNode: + new_node = deepcopy(node) + new_expr_node = self.visit(node.expr, scope) + + new_node.expr = new_expr_node + return new_node + + @visitor.when(VariableNode) + def visit(self, node: VariableNode, scope: Scope) -> VariableNode: + new_node = deepcopy(node) + if node.defined: + decl_type = node.inferenced_type + expr_type = scope.find_variable(node.value).get_type() + new_node.inferenced_type = try_conform(decl_type, expr_type) + return new_node + return new_node + + @visitor.when(InstantiateNode) + def visit(self, node: InstantiateNode, scope) -> InstantiateNode: + return deepcopy(node) + + @visitor.when(IntNode) + def visit(self, node, scope) -> IntNode: + return deepcopy(node) + + @visitor.when(StringNode) + def visit(self, node, scope) -> StringNode: + return deepcopy(node) + + @visitor.when(BooleanNode) + def visit(self, node, scope) -> BooleanNode: + return deepcopy(node) # Este metodo deber ser innecesario pues todos los errores son recogidos previamente def add_error(self, node: Node, text: str): diff --git a/src/test.cl b/src/test.cl index 82c6a4d61..6f5f5a35f 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,23 +1,22 @@ ---For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. +--The static types of the two sub-expressions must be Int. -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; +class Main { + a : B <- new B; + b : B; + main(): B { + { + b <- a.method(); + b; + } + }; +}; -class Main inherits IO { - main(): IO { out_string("Hello World!")}; +class A { + method(): SELF_TYPE { + new A + }; +}; - b: B <- case "true" of - i: Int => New C; - b: Bool => New D; - s: String => New E; - esac; - - test: B <- case 0 of - b: Bool => new F; - i: Int => new E; - esac; -}; +class B inherits A { + +}; \ No newline at end of file diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 9a3b7f6a6..e105f16db 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -6,13 +6,13 @@ tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -# @pytest.mark.lexer -# @pytest.mark.error -# @pytest.mark.run(order=1) -# @pytest.mark.parametrize("cool_file", tests) -# def test_lexer_errors(compiler_path, cool_file): -# print(compiler_path) -# print(cool_file) -# compare_errors( -# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" -# ) +@pytest.mark.lexer +@pytest.mark.error +@pytest.mark.run(order=1) +@pytest.mark.parametrize("cool_file", tests) +def test_lexer_errors(compiler_path, cool_file): + print(compiler_path) + print(cool_file) + compare_errors( + compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" + ) diff --git a/tests/parser_test.py b/tests/parser_test.py index 106c93331..b2c5ff048 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -1,16 +1,16 @@ -# import pytest -# import os -# from utils import compare_errors -# -# tests_dir = __file__.rpartition("/")[0] + "/parser/" -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -# -# -# @pytest.mark.parser -# @pytest.mark.error -# @pytest.mark.run(order=2) -# @pytest.mark.parametrize("cool_file", tests) -# def test_parser_errors(compiler_path, cool_file): -# compare_errors( -# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" -# ) +import pytest +import os +from utils import compare_errors + +tests_dir = __file__.rpartition("/")[0] + "/parser/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] + + +@pytest.mark.parser +@pytest.mark.error +@pytest.mark.run(order=2) +@pytest.mark.parametrize("cool_file", tests) +def test_parser_errors(compiler_path, cool_file): + compare_errors( + compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" + ) From c1c57b200d52a9d4ab82bf9aeb4cf44b66f33aaa Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sun, 25 Apr 2021 21:11:20 -0400 Subject: [PATCH 092/432] Changes in BackInferencer --- src/__main__.py | 14 +- src/semantics/inference/back_inferencer.py | 39 +- src/semantics/tools(deprecated).py | 711 --------------------- src/semantics/tools/__init__.py | 1 + src/test.cl | 19 +- 5 files changed, 37 insertions(+), 747 deletions(-) delete mode 100644 src/semantics/tools(deprecated).py diff --git a/src/__main__.py b/src/__main__.py index 8df41f279..b2211fbb9 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,9 +1,6 @@ -<<<<<<< HEAD -======= from os import close, error from semantics.inference.hard_inferencer import HardInferencer from debbuging.type_logger import TypeLogger ->>>>>>> 55759b8cb59c5d6caf6a83058531f096817f19e0 import sys from lexing import Lexer @@ -42,16 +39,19 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - logger = TypeLogger(context) - log = logger.visit(hard_ast, hard_ast.scope) - print(log) + back = BackInferencer(context) + back_ast = back.visit(hard_ast) + + # logger = TypeLogger(context) + # log = logger.visit(hard_ast, back_ast.scope) + # print(log) if len(errors) > 0: for error in errors: print(error[1]) # s = format_errors(errors) # print(s) exit(1) - # print(s) + print(s) def main(): diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index cabe536ca..dc2856641 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,5 +1,7 @@ from copy import deepcopy +from semantics.tools.type import Method, Type + from ast.inferencer_ast import ( BinaryNode, BooleanNode, @@ -29,18 +31,8 @@ VarDeclarationNode, AssignNode, MethodCallNode, - ArithmeticNode, ) -# Reducir los AUTO_TYPE declarados a base de el tipo de sus expresiones: - -# No te debe hacer falta tirar ningun metodo nuevo, es solo ensamblar. - -# Si te hace falta algo en tools.py al final hay varios metodos para trabajar con -# tipos, si no entiendes me escribes o me llamas. Si crees que te hace falta realizar -# una operacion que esos metodos no satisfacen la annades al repertorio, pero avisame -# tambien xq puede estar tirado por una esquina algo que haga algo parecido - class BackInferencer: def __init__(self, context: Context) -> None: @@ -92,12 +84,19 @@ def visit(self, node, scope): @visitor.when(MethodDeclarationNode) def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: - # decl_type = node.inferenced_type scope = scope.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) + new_body_node = self.visit(node.body, scope) body_type = new_body_node.inferenced_type new_node = MethodDeclarationNode(node.type, new_body_node, node) - + decl_type = node.inferenced_type + body_type = new_body_node.inferenced_type + new_node.inferenced_type = try_conform(decl_type, body_type) + return new_node @visitor.when(BlocksNode) def visit(self, node: BlocksNode, scope) -> BlocksNode: @@ -106,7 +105,7 @@ def visit(self, node: BlocksNode, scope) -> BlocksNode: new_expr_list.append(self.visit(expr, scope)) new_node = BlocksNode(new_expr_list, node) - decl_type = new_node.inferenced_type + decl_type = node.inferenced_type expr_type = new_expr_list[-1].inferenced_type new_node.inferenced_type = try_conform(decl_type, expr_type) return new_node @@ -201,7 +200,19 @@ def visit(self, node: AssignNode, scope) -> AssignNode: @visitor.when(MethodCallNode) def visit(self, node: MethodCallNode, scope) -> MethodCallNode: - pass + caller_type: Type = node.caller_type.heads[0] + method: Method = caller_type.get_method(node.id) + + new_args = [] + for arg_expr, param_type in zip(node.args, method.param_types): + arg_node = self.visit(arg_expr, scope) + arg_node.inferenced_type = try_conform(arg_node.inferenced_type, param_type) + new_args.append(arg_node) + + new_expr = self.visit(node.expr,scope) if node.expr else None + new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) + new_node.inferenced_type = try_conform(node.inferenced_type, method.return_type) + return new_node @visitor.when(BinaryNode) def visit(self, node: BinaryNode, scope) -> BinaryNode: diff --git a/src/semantics/tools(deprecated).py b/src/semantics/tools(deprecated).py deleted file mode 100644 index 33fbeec7f..000000000 --- a/src/semantics/tools(deprecated).py +++ /dev/null @@ -1,711 +0,0 @@ -import itertools as itt -from collections import OrderedDict -from typing import FrozenSet, List, Set, Tuple - -from semantics.errors import * - - -class Attribute: - def __init__(self, name, typex): - self.name = name - self.type = typex - - def __str__(self): - return f"[attrib] {self.name} : {self.type.name};" - - def __repr__(self): - return str(self) - - -class Method: - def __init__(self, name, param_names, params_types, return_type): - self.name = name - self.param_names = param_names - self.param_types = params_types - self.return_type = return_type - - def __str__(self): - params = ", ".join( - f"{n}:{t.name}" for n, t in zip(self.param_names, self.param_types) - ) - return f"[method] {self.name}({params}): {self.return_type.name};" - - def __eq__(self, other): - return ( - other.name == self.name - and other.return_type == self.return_type - and other.param_types == self.param_types - ) - - -class Type: - def __init__(self, name: str): - self.name = name - self.attributes = [] - self.methods = [] - self.parent = None - self.index = -1 - - def set_parent(self, parent): - if self.parent is not None: - raise SemanticError( - f"Type '{self.name}' already has parent type '{self.parent.name}'. Type '{parent.name}' cannot be set as parent." - ) - if parent.name in {"String", "Int", "Bool"}: - raise SemanticError( - f"Cannot set '{self.name}' parent, '{parent.name}' type cannot be inherited." - ) - self.parent = parent - - def define_attribute(self, name: str, typex): - try: - self.get_attribute(name) - except SemanticError: - attribute = Attribute(name, typex) - self.attributes.append(attribute) - return attribute - else: - raise SemanticError( - f'Attribute "{name}" is already defined in "{self.name}".' - ) - - def get_attribute(self, name: str, first=None): - if not first: - first = self.name - elif first == self.name: - raise AttributeError(f'Attribute "{name}" is not defined in {self.name}.') - - try: - return next(attr for attr in self.attributes if attr.name == name) - except StopIteration: - if self.parent is None: - raise AttributeError( - f'Attribute "{name}" is not defined in {self.name}.' - ) - try: - return self.parent.get_attribute(name, first=first) - except SemanticError: - raise AttributeError( - f'Attribute "{name}" is not defined in {self.name}.' - ) - - def get_method(self, name: str, local: bool = False, first=None): - if not first: - first = self.name - elif first == self.name: - raise AttributeError( - f'Method "{name}" is not defined in class {self.name}.' - ) - - try: - return next(method for method in self.methods if method.name == name) - except StopIteration: - if self.parent is None: - raise AttributeError( - f'Method "{name}" is not defined in class {self.name}.' - ) - try: - return self.parent.get_method(name, first=first) - except AttributeError: - raise AttributeError( - f'Method "{name}" is not defined in class {self.name}.' - ) - - def define_method( - self, name: str, param_names: list, param_types: list, return_type - ): - if name in (method.name for method in self.methods): - raise SemanticError(f"Method '{name}' already defined in '{self.name}'") - - try: - parent_method = self.get_method(name) - except SemanticError: - parent_method = None - if parent_method: - error_list = [] - return_type.swap_self_type(self) - return_clone = return_type.clone() - parent_method.return_type.swap_self_type(self) - if not conforms(return_type, parent_method.return_type): - error_list.append( - f" -> Same return type: Redefined method has '{return_clone.name}' as return type instead of '{parent_method.return_type.name}'." - ) - if len(param_types) != len(parent_method.param_types): - error_list.append( - f" -> Same amount of params: Redefined method has {len(param_types)} params instead of {len(parent_method.param_types)}." - ) - else: - count = 0 - err = [] - for param_type, parent_param_type in zip( - param_types, parent_method.param_types - ): - param_clone = param_type.clone() - if not conforms(param_type, parent_param_type): - err.append( - f" -Param number {count} has {param_clone.name} as type instead of {parent_param_type.name}" - ) - count += 1 - if err: - s = f" -> Same param types:\n" + "\n".join( - child for child in err - ) - error_list.append(s) - return_type.swap_self_type(self, back=True) - parent_method.return_type.swap_self_type(self, back=True) - if error_list: - err = ( - f"Redifined method '{name}' in class '{self.name}' does not have:\n" - + "\n".join(child for child in error_list) - ) - raise SemanticError(err) - - method = Method(name, param_names, param_types, return_type) - self.methods.append(method) - - return method - - def all_attributes(self, clean=True, first=None): - if not first: - first = self.name - elif first == self.name: - return OrderedDict.values() if clean else OrderedDict() - - plain = ( - OrderedDict() - if self.parent is None - else self.parent.all_attributes(clean=False, first=first) - ) - for attr in self.attributes: - plain[attr.name] = (attr, self) - return plain.values() if clean else plain - - def all_methods(self, clean=True, first=None): - if not first: - first = self.name - elif first == self.name: - return OrderedDict.values() if clean else OrderedDict() - - plain = ( - OrderedDict() - if self.parent is None - else self.parent.all_methods(clean=False, first=first) - ) - for method in self.methods: - plain[method.name] = (method, self) - return plain.values() if clean else plain - - def conforms_to(self, other, first=None): - if not first: - first = self.name - elif self.name == first: - return False - return ( - other.bypass() - or self == other - or self.parent - and self.parent.conforms_to(other, first) - ) - - def bypass(self): - return False - - def least_common_ancestor(self, other): - this = self - if isinstance(this, ErrorType) or isinstance(other, ErrorType): - return ErrorType() - - while this.index < other.index: - other = other.parent - while other.index < this.index: - this = this.parent - if not (this and other): - return None - while this.name != other.name: - this = this.parent - other = other.parent - if this == None: - return None - return this - - def __str__(self): - output = f"type {self.name}" - parent = "" if self.parent is None else f" : {self.parent.name}" - output += parent - output += " {" - output += "\n\t" if self.attributes or self.methods else "" - output += "\n\t".join(str(x) for x in self.attributes) - output += "\n\t" if self.attributes else "" - output += "\n\t".join(str(x) for x in self.methods) - output += "\n" if self.methods else "" - output += "}\n" - return output - - def __repr__(self): - return str(self) - - -class TypeBag: - def __init__(self, type_set, heads=[]) -> None: - self.type_set: set = ( - type_set if isinstance(type_set, set) else from_dict_to_set(type_set) - ) - self.heads: list = heads - if len(self.type_set) == 1: - self.heads = list(self.type_set) - - self.name = "undefined" - self.condition_list = [] - self.conform_list = [] - self.generate_name() - - def set_conditions(self, condition_list, conform_list): - self.condition_list = condition_list - self.conform_list = conform_list - self.update_type_set_from_conforms() - - def update_type_set_from_conforms(self): - intersect_set = set() - for conform_set in self.conform_list: - intersect_set = intersect_set.union(conform_set) - self.type_set = self.type_set.intersection(intersect_set) - self.update_heads() - - def update_heads(self): - new_heads = [] - visited = set() - for head in self.heads: - if head in self.type_set: - new_heads.append(head) - continue - pos_new_head = [] - lower_index = 2 ** 32 - for typex in self.type_set: - if typex in visited: - continue - # if typex.conforms_to(head): - visited.add(typex) - if typex.index < lower_index: - pos_new_head = [typex] - lower_index = typex.index - elif typex.index == lower_index: - pos_new_head.append(typex) - new_heads += pos_new_head - self.heads = new_heads - self.generate_name() - - def swap_self_type(self, swap_type, back=False): - if not back: - remove_type = SelfType() - add_type = swap_type - else: - remove_type = swap_type - add_type = SelfType() - - try: - self.type_set.remove(remove_type) - self.type_set.add(add_type) - except KeyError: - return self - - # for i in range(len(self.heads)): - # typex = self.heads[i] - # if typex.name == remove_type.name: - # self.heads[i] = add_type - # break - # - # self.generate_name() - self.update_heads() - return self - - def add_self_type(self, add_type) -> bool: - if SelfType() in self.type_set and not add_type in self.type_set: - self.type_set.add(add_type) - return True - return False - - def remove_self_type(self, remove_type): - try: - self.type_set.remove(remove_type) - except KeyError: - pass - self.type_set.add(SelfType()) - self.update_heads() - - def generate_name(self): - if len(self.type_set) == 1: - self.name = self.heads[0].name - return self.name - - s = "{" - s += ", ".join( - typex.name for typex in sorted(self.type_set, key=lambda t: t.index) - ) - s += "}" - self.name = s - return s - - def clone(self): - clone = TypeBag(self.type_set.copy(), self.heads.copy()) - clone.condition_list = self.condition_list.copy() - clone.conform_list = self.conform_list.copy() - return clone - - def __str__(self): - return self.name - - def __repr__(self): - return str(self) - - -class SelfType(Type): - def __init__(self): - self.name = "SELF_TYPE" - self.index = 2 ** 31 - - def conforms_to(self, other): - if isinstance(other, SelfType): - return True - return False - raise InternalError("SELF_TYPE is yet to be assigned, cannot conform.") - - def bypass(self): - return False - raise InternalError("SELF_TYPE is yet to be assigned, cannot bypass.") - - def __hash__(self) -> int: - return hash(self.name) - - def __eq__(self, o: object) -> bool: - return isinstance(o, SelfType) - - def __str__(self): - return self.name - - def __repr__(self): - return str(self) - - -class FuncType(Type): - def __init__(self, name: str, params: Tuple[Type, ...], ret_type: Type) -> None: - self.name = name - self.params = params - self.ret_type = ret_type - - def conforms_to(self, other): - if not isinstance(other, FuncType): - raise InternalError( - ( - "A FunctionType can only conform to other Function" - f"Type, not to {other.__class__.__name__}" - ) - ) - - -class ErrorType(TypeBag): - def __init__(self): - self.name = "" - self.index = 2 ** 32 - self.type_set = frozenset() - self.heads = frozenset() - - def conforms_to(self, other): - return True - - def bypass(self): - return True - - def swap_self_type(self, swap_type, back=False): - return self - - def set_conditions(self, *params): - return - - def generate_name(self): - return "" - - def clone(self): - return self - - -class Context: - def __init__(self) -> None: - self.types = {} - self.num_autotypes = 0 - self.type_graph = None - - def create_type(self, name: str) -> Type: - if name in self.types: - raise SemanticError(f"Type with the same name ({name}) already exists.") - typex = self.types[name] = Type(name) - return typex - - def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> Type: - if not selftype and name == "SELF_TYPE": - raise TypeError(f"Cannot use SELF_TYPE.") # return TypeBag({SelfType()}) - if autotype and name == "AUTO_TYPE": - self.num_autotypes += 1 - return TypeBag(self.types, [self.types["Object"]]) - try: - if unpacked: - return self.types[name] - return TypeBag({self.types[name]}) - except KeyError: - raise TypeError(f'Type "{name}" is not defined.') - - def get_method_by_name(self, name: str, args: int) -> list: - def dfs(root: str, results: list): - try: - for typex in self.type_graph[root]: - for method in self.types[typex].methods: - if name == method.name and args == len(method.param_names): - results.append((self.types[typex], method)) - break - else: - dfs(typex, results) - except KeyError: - pass - - results = [] - dfs("Object", results) - return results - - def __str__(self): - return ( - "{\n\t" - + "\n\t".join(y for x in self.types.values() for y in str(x).split("\n")) - + "\n}" - ) - - def __repr__(self): - return str(self) - - -class VariableInfo: - def __init__(self, name, vtype) -> None: - self.name: str = name - self.type: TypeBag = vtype - - def get_type(self) -> TypeBag or ErrorType: - if len(self.type.type_set) == 0: - self.type = ErrorType() - return self.type - - def __str__(self): - return self.name + ":" + self.type - - -class Scope: - def __init__(self, parent=None): - self.locals = [] - self.parent = parent - self.children = [] - self.index = 0 if parent is None else len(parent) - self.current_child = -1 - - def __len__(self): - return len(self.locals) - - def create_child(self): - child = Scope(self) - self.children.append(child) - return child - - def define_variable(self, vname, vtype): - info = VariableInfo(vname, vtype) - self.locals.append(info) - return info - - def find_variable(self, vname, index=None): - locals = self.locals if index is None else itt.islice(self.locals, index) - try: - return next(x for x in locals if x.name == vname) - except StopIteration: - try: - return ( - self.parent.find_variable(vname, self.index) - if self.parent is not None - else None - ) - except AttributeError: - return None - - def get_local_by_index(self, index): - return self.locals[index] - - def is_defined(self, vname): - return self.find_variable(vname) is not None - - def is_local(self, vname): - return any(True for x in self.locals if x.name == vname) - - def next_child(self): - self.current_child += 1 - return self.children[self.current_child] - - def reset(self): - self.current_child = -1 - for child in self.children: - child.reset() - - def get_all_names(self, s: str = "", level: int = 0): - if self.locals: - s += "\n ".join( - [ - x.name + ":" + str([typex.name for typex in x.type.type_set]) - for x in self.locals - ] - ) - s += "\n\n" - for child in self.children: - s = child.get_all_names(s, level + 1) - return s - - -def conforms(bag1: TypeBag, bag2: TypeBag) -> bool: - if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): - return True - - ordered_set = order_set_by_index(bag2.type_set) - - condition_list = [] - conform_list = [] - for condition in ordered_set: - conform = conform_to_condition(bag1.type_set, condition) - for i in range(len(condition_list)): - conform_i = conform_list[i] - if len(conform_i) == len(conform) and len( - conform.intersection(conform_i) - ) == len(conform): - condition_list[i].add(condition) - break - else: - condition_list.append({condition}) - conform_list.append(conform) - - bag1.set_conditions(condition_list, conform_list) - return len(bag1.type_set) >= 1 - - -def try_conform(bag1: TypeBag, bag2: TypeBag) -> TypeBag: - clone1 = bag1.clone() - if not conforms(bag1, bag2): - return clone1 - return bag2 - - -def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: - if isinstance(bag1, ErrorType): - return bag2 - if isinstance(bag2, ErrorType): - return bag1 - - ancestor_set = set() - head_list = [] - ordered_set1: Set[Type] = order_set_by_index(bag1.type_set) - ordered_set2: Set[Type] = order_set_by_index(bag2.type_set) - ordered_set1, ordered_set2 = ( - (ordered_set1, ordered_set2) - if len(ordered_set1) < len(ordered_set2) - else (ordered_set2, ordered_set1) - ) - for type1 in ordered_set1: - same_branch = False - previous_ancestor = None - previous_type = None - for type2 in ordered_set2: - if same_branch and type2.conforms_to(previous_type): - previous_type = type2 - continue - common_ancestor = type1.least_common_ancestor(type2) - previous_type = type2 - if not previous_ancestor: - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - else: - if previous_ancestor == common_ancestor: - same_branch = True - else: - same_branch = False - smart_add(ancestor_set, head_list, common_ancestor) - previous_ancestor = common_ancestor - - join_result = TypeBag(ancestor_set, head_list) - return join_result - - -def join_list(type_list): - join_result = type_list[0] - for i in range(1, len(type_list)): - type_i = type_list[i] - join_result = join(join_result, type_i) - return join_result - - -def equal(bag1: TypeBag, bag2: TypeBag): - if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): - return True - set1 = bag1.type_set - set2 = bag2.type_set - return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) - - -def smart_add(type_set: set, head_list: list, typex: Type): - if isinstance(typex, TypeBag): - return auto_add(type_set, head_list, typex) - - type_set.add(typex) - there_is = False - for i in range(len(head_list)): - head = head_list[i] - ancestor = typex.least_common_ancestor(head) - if ancestor in type_set: - there_is = True - if ancestor == typex: - head_list[i] = typex - break - if not there_is: - head_list.append(typex) - return type_set - - -def auto_add(type_set: set, head_list: list, bag: TypeBag): - type_set = type_set.union(bag.type_set) - aux = set(bag.heads) - for i in range(len(head_list)): - head_i = head_list[i] - for head_j in bag.heads: - ancestor = head_i.least_common_ancestor(head_j) - if ancestor in type_set: - head_list[i] = ancestor - aux.remove(head_j) - break - head_list += [typex for typex in aux] - return type_set - - -def conform_to_condition(type_set, parent) -> set: - set_result = set() - for typex in type_set: - if typex.conforms_to(parent): - set_result.add(typex) - return set_result - - -def order_set_by_index(type_set): - return sorted(list(type_set), key=lambda x: x.index) - - -def set_intersection(parent, type_set) -> set: - set_result = set() - for typex in type_set: - if typex.conforms_to(parent): - set_result.add(typex) - return set_result - - -def from_dict_to_set(types: dict): - type_set = set() - for typex in types: - type_set.add(types[typex]) - return type_set diff --git a/src/semantics/tools/__init__.py b/src/semantics/tools/__init__.py index b1a7ab0d2..e3057e7a8 100644 --- a/src/semantics/tools/__init__.py +++ b/src/semantics/tools/__init__.py @@ -10,4 +10,5 @@ join_list, smart_add, try_conform, + Type, ) diff --git a/src/test.cl b/src/test.cl index 6f5f5a35f..a7e902679 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,22 +1,11 @@ --The static types of the two sub-expressions must be Int. class Main { - a : B <- new B; - b : B; - main(): B { + a : AUTO_TYPE <- 12; + hola(b: AUTO_TYPE): AUTO_TYPE {b}; + main(): Int { { - b <- a.method(); - b; + hola(a) + 12; } }; }; - -class A { - method(): SELF_TYPE { - new A - }; -}; - -class B inherits A { - -}; \ No newline at end of file From 7136f20bd2beb47dcbc606f24e0cafcaaf16454e Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sun, 25 Apr 2021 21:13:12 -0400 Subject: [PATCH 093/432] Minor changes in __main__.py --- src/__main__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index b2211fbb9..a6f9615d6 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -42,16 +42,16 @@ def run_pipeline(program_ast): back = BackInferencer(context) back_ast = back.visit(hard_ast) + print(back_ast) # logger = TypeLogger(context) # log = logger.visit(hard_ast, back_ast.scope) # print(log) if len(errors) > 0: - for error in errors: - print(error[1]) - # s = format_errors(errors) - # print(s) + # for error in errors: + # print(error[1]) + s = format_errors(errors) + print(s) exit(1) - print(s) def main(): From 85760a5befaecab9044218e1d50dbc5935ebf5cb Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Mon, 26 Apr 2021 01:53:23 -0400 Subject: [PATCH 094/432] Added unify function in tools and make some changes in back_inferencer --- src/ast/inferencer_ast.py | 6 +- src/semantics/inference/back_inferencer.py | 84 ++++++++++++---------- src/semantics/inference/hard_inferencer.py | 6 +- src/semantics/inference/soft_inferencer.py | 11 ++- src/semantics/tools/__init__.py | 1 + src/semantics/tools/type.py | 17 ++++- src/test.cl | 2 +- 7 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index ab0ef6b64..e9a9d3914 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -41,13 +41,15 @@ def __init__(self, node): class MethodDeclarationNode(DeclarationNode): - def __init__(self, return_type, body, node): + def __init__(self, params, return_type, body, node): Node.__init__(self, node) self.id = node.id + # this is a patch, the ideal is to recv a copy of the params + self.params: List[VarDeclarationNode] = params self.type = return_type self.body = body # for debbugin purposes - self.params = node.params + # self.params = node.params class ExpressionNode(Node): diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index dc2856641..a82398535 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,21 +1,7 @@ from copy import deepcopy from semantics.tools.type import Method, Type - -from ast.inferencer_ast import ( - BinaryNode, - BooleanNode, - ClassDeclarationNode, - InstantiateNode, - IntNode, - ProgramNode, - AttrDeclarationNode, - Node, - StringNode, - UnaryNode, - VariableNode, -) -from semantics.tools import Context, Scope, TypeBag, join, join_list, try_conform +from semantics.tools import Context, Scope, TypeBag, join, join_list, unify from utils import visitor from ast.inferencer_ast import ( ProgramNode, @@ -31,6 +17,17 @@ VarDeclarationNode, AssignNode, MethodCallNode, + BinaryNode, + BooleanNode, + ClassDeclarationNode, + InstantiateNode, + IntNode, + ProgramNode, + AttrDeclarationNode, + Node, + StringNode, + UnaryNode, + VariableNode, ) @@ -76,7 +73,7 @@ def visit(self, node, scope): expr_type = expr_node.inferenced_type decl_type = node.inferenced_type - decl_type = try_conform(decl_type, expr_type) + decl_type = unify(decl_type, expr_type) attr_node.expr = expr_node attr_node.inferenced_type = decl_type @@ -85,17 +82,23 @@ def visit(self, node, scope): @visitor.when(MethodDeclarationNode) def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: scope = scope.create_child() - current_method = self.current_type.get_method(node.id) + current_method: 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) + # for idx, typex in zip(current_method.param_names, current_method.param_types): + # scope.define_variable(idx, typex) + + new_params = [] + for param in node.params: + new_params.append(self.visit(param, scope)) + + current_method.param_types = [param.inferenced_type for param in new_params] new_body_node = self.visit(node.body, scope) body_type = new_body_node.inferenced_type - new_node = MethodDeclarationNode(node.type, new_body_node, node) + new_node = MethodDeclarationNode(new_params, node.type, new_body_node, node) decl_type = node.inferenced_type body_type = new_body_node.inferenced_type - new_node.inferenced_type = try_conform(decl_type, body_type) + new_node.inferenced_type = unify(decl_type, body_type) return new_node @visitor.when(BlocksNode) @@ -107,7 +110,7 @@ def visit(self, node: BlocksNode, scope) -> BlocksNode: new_node = BlocksNode(new_expr_list, node) decl_type = node.inferenced_type expr_type = new_expr_list[-1].inferenced_type - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(ConditionalNode) @@ -122,7 +125,7 @@ def visit(self, node: ConditionalNode, scope) -> ConditionalNode: decl_type = node.inferenced_type expr_type = join_type new_node = ConditionalNode(new_then_node, new_then_node, new_else_node, node) - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(CaseNode) @@ -138,7 +141,7 @@ def visit(self, node: CaseNode, scope) -> CaseNode: new_node = CaseNode(new_case_node, new_options_nodes, node) decl_type = node.inferenced_type expr_type = join_type - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(CaseOptionNode) @@ -147,7 +150,7 @@ def visit(self, node: CaseOptionNode, scope) -> CaseOptionNode: new_node = CaseOptionNode(new_node_expr, node) decl_type = node.inferenced_type expr_type = new_node_expr.inferenced_type - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(LoopNode) @@ -156,9 +159,7 @@ def visit(self, node: LoopNode, scope) -> LoopNode: new_body_node = self.visit(node.body, scope) new_node = LoopNode(new_condition_node, new_body_node, node) - decl_type = node.inferenced_type - expr_type = self.context.get_type("Object") - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = node.inferenced_type return new_node @visitor.when(LetNode) @@ -174,17 +175,23 @@ def visit(self, node: LetNode, scope) -> LetNode: new_node = LetNode(new_var_decl_nodes, new_in_node, node) decl_type = node.inferenced_type expr_type = new_in_node.inferenced_type - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(VarDeclarationNode) def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: + scope.define_variable(node.id, node.inferenced_type) - new_expr_node = self.visit(node.expr, scope) - decl_type = node.inferenced_type - expr_type = new_expr_node.inferenced_type new_node = VarDeclarationNode(node) - new_node.inferenced_type = try_conform(decl_type, expr_type) + + if node.expr: + new_expr_node = self.visit(node.expr, scope) + decl_type = node.inferenced_type + expr_type = new_expr_node.inferenced_type + new_node.inferenced_type = unify(decl_type, expr_type) + else: + new_node.inferenced_type = node.inferenced_type + return new_node @visitor.when(AssignNode) @@ -195,7 +202,7 @@ def visit(self, node: AssignNode, scope) -> AssignNode: decl_type = node.inferenced_type expr_type = new_expr_node.inferenced_type new_node = AssignNode(new_expr_node, node) - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node @visitor.when(MethodCallNode) @@ -206,12 +213,13 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: new_args = [] for arg_expr, param_type in zip(node.args, method.param_types): arg_node = self.visit(arg_expr, scope) - arg_node.inferenced_type = try_conform(arg_node.inferenced_type, param_type) + arg_node.inferenced_type = unify(arg_node.inferenced_type, param_type) new_args.append(arg_node) - new_expr = self.visit(node.expr,scope) if node.expr else None + + new_expr = self.visit(node.expr, scope) if node.expr else None new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) - new_node.inferenced_type = try_conform(node.inferenced_type, method.return_type) + new_node.inferenced_type = unify(node.inferenced_type, method.return_type) return new_node @visitor.when(BinaryNode) @@ -239,7 +247,7 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: if node.defined: decl_type = node.inferenced_type expr_type = scope.find_variable(node.value).get_type() - new_node.inferenced_type = try_conform(decl_type, expr_type) + new_node.inferenced_type = unify(decl_type, expr_type) return new_node return new_node diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 88e0b1e22..a2577117a 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -110,9 +110,13 @@ def visit(self, node, scope): def visit(self, node, scopex: Scope): scope = scopex.next_child() + new_params = [] + for param in node.params: + new_params.append(self.visit(param,scope)) + body_node = self.visit(node.body, scope) body_type = body_node.inferenced_type - method_node = MethodDeclarationNode(node.type, body_node, node) + method_node = MethodDeclarationNode(new_params, node.type, body_node, node) method_node.inferenced_type = node.inferenced_type if equal(body_type, node.body.inferenced_type): diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 57790b54b..30c9d7777 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -120,8 +120,11 @@ def visit(self, node, scopex: Scope): 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) + # for idx, typex in zip(current_method.param_names, current_method.param_types): + # scope.define_variable(idx, typex) + new_params = [] + for param in node.params: + new_params.append(self.visit(param, scope)) ret_type_decl: TypeBag = current_method.return_type @@ -142,7 +145,9 @@ def visit(self, node, scopex: Scope): if added_self: ret_type_expr.remove_self_type(self.current_type) - method_node = inf_ast.MethodDeclarationNode(node.type, body_node, node) + method_node = inf_ast.MethodDeclarationNode( + new_params, node.type, body_node, node + ) method_node.inferenced_type = ret_type_decl return method_node diff --git a/src/semantics/tools/__init__.py b/src/semantics/tools/__init__.py index e3057e7a8..afe3b3074 100644 --- a/src/semantics/tools/__init__.py +++ b/src/semantics/tools/__init__.py @@ -11,4 +11,5 @@ smart_add, try_conform, Type, + unify ) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index b2cf49ccb..db302b620 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -556,4 +556,19 @@ def from_dict_to_set(types: dict): type_set = set() for typex in types: type_set.add(types[typex]) - return type_set \ No newline at end of file + return type_set + + +def unify(a: TypeBag, b: TypeBag) -> None: + + intersection = set() + for type1 in a.type_set: + for type2 in b.type_set: + if type1.name == type2.name: + intersection.add(type1) + + a.type_set = intersection + a.update_heads() + b.type_set = intersection + b.update_heads() + return a \ No newline at end of file diff --git a/src/test.cl b/src/test.cl index a7e902679..f7457a5b0 100644 --- a/src/test.cl +++ b/src/test.cl @@ -5,7 +5,7 @@ class Main { hola(b: AUTO_TYPE): AUTO_TYPE {b}; main(): Int { { - hola(a) + 12; + hola(a); } }; }; From 627d69ab78d52c7613a0e7534171e68afab356a8 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 00:35:19 -0400 Subject: [PATCH 095/432] Add attribute to decl_type to inferencer_ast.CaseOptionNode --- src/ast/inferencer_ast.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index e9a9d3914..95aca1301 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -82,6 +82,7 @@ def __init__(self, ret_expr, node): Node.__init__(self, node) self.id = node.id self.expr = ret_expr + self.decl_type = node.type # For debbuging purposes self.type = node.type From 11da54952a9dbce49465781bade8af5180663943 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 00:35:57 -0400 Subject: [PATCH 096/432] Add types_ast.py --- src/ast/types_ast.py | 205 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/ast/types_ast.py diff --git a/src/ast/types_ast.py b/src/ast/types_ast.py new file mode 100644 index 000000000..eacc02be1 --- /dev/null +++ b/src/ast/types_ast.py @@ -0,0 +1,205 @@ +from typing import List, Tuple + + +class Node: + def __init__(self, node) -> None: + self.line = node.line + self.col = node.col + self.type = None + + def get_position(self) -> Tuple[int, int]: + return self.line, self.col + + +class ProgramNode(Node): + def __init__(self, declarations, node: Node): + Node.__init__(self, node) + self.declarations = declarations + + +class DeclarationNode(Node): + pass + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, features, node): + Node.__init__(self, node) + self.features = features + self.id = node.id + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, node): + Node.__init__(self, node) + self.id = node.id + self.expr = None + + +class MethodDeclarationNode(DeclarationNode): + def __init__(self, params, return_type, body, node): + Node.__init__(self, node) + self.id = node.id + self.params: List[VarDeclarationNode] = params + self.type = return_type + self.body = body + + +class ExpressionNode(Node): + pass + + +class BlocksNode(ExpressionNode): + def __init__(self, expr_list, node): + Node.__init__(self, node) + self.expr_list = expr_list + + +class ConditionalNode(ExpressionNode): + def __init__(self, condition, then_node, else_node, node): + Node.__init__(self, node) + self.condition = condition + self.then_body = then_node + self.else_body = else_node + + +class CaseNode(ExpressionNode): + def __init__(self, case_expr, options, node): + Node.__init__(self, node) + self.case_expr = case_expr + self.options: List[CaseOptionNode] = options + + +class CaseOptionNode(ExpressionNode): + def __init__(self, ret_expr, node): + Node.__init__(self, node) + self.id = node.id + self.decl_type = node.type + self.expr = ret_expr + + +class LoopNode(ExpressionNode): + def __init__(self, condition, body, node): + Node.__init__(self, node) + self.condition = condition + self.body = body + + +class LetNode(ExpressionNode): + def __init__(self, var_decl_list, in_expr, node): + Node.__init__(self, node) + self.var_decl_list = var_decl_list + self.in_expr = in_expr + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, node): + Node.__init__(self, node) + self.id = node.id + self.expr = None # Expression is set later if it exists + self.index = None + + +class AssignNode(ExpressionNode): + def __init__(self, expr, node): + Node.__init__(self, node) + self.id = node.id + self.expr = expr + self.defined = False + + +class MethodCallNode(ExpressionNode): + def __init__(self, caller_type, expr, args, node): + Node.__init__(self, node) + self.caller_type = caller_type + self.expr = expr + self.args = args + self.id = node.id + + +class UnaryNode(ExpressionNode): + def __init__(self, expr, node): + Node.__init__(self, node) + self.expr = expr + + +class IsVoidNode(UnaryNode): + pass + + +class NotNode(UnaryNode): + pass + + +class ComplementNode(UnaryNode): + pass + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right, node): + Node.__init__(self, node) + self.left = left + self.right = right + + +class ComparerNode(BinaryNode): + pass + + +class LessNode(ComparerNode): + pass + + +class LessOrEqualNode(ComparerNode): + pass + + +class EqualsNode(ComparerNode): + pass + + +class ArithmeticNode(BinaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class AtomicNode(ExpressionNode): + def __init__(self, node): + Node.__init__(self, node) + self.value = node.value + + +class BooleanNode(AtomicNode): + pass + + +class IntNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + def __init__(self, node): + super().__init__(node) + self.defined = False + + +class InstantiateNode(AtomicNode): + pass From 1dbd0c8ecf63c0edad54f481292b776a75507fb2 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 00:36:27 -0400 Subject: [PATCH 097/432] Add types_inferencer.py --- src/semantics/inference/types_inferencer.py | 114 ++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/semantics/inference/types_inferencer.py diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py new file mode 100644 index 000000000..2331f6319 --- /dev/null +++ b/src/semantics/inference/types_inferencer.py @@ -0,0 +1,114 @@ +from semantics.tools.type import ErrorType +from utils import visitor + +from semantics.tools import TypeBag +import ast.types_ast as types_ast +from ast.inferencer_ast import ( + ProgramNode, + ClassDeclarationNode, + MethodDeclarationNode, + AttrDeclarationNode, + BlocksNode, + ConditionalNode, + CaseNode, + CaseOptionNode, + LoopNode, + LetNode, + VarDeclarationNode, + AssignNode, + MethodCallNode, + BinaryNode, + BooleanNode, + ClassDeclarationNode, + InstantiateNode, + IntNode, + ProgramNode, + AttrDeclarationNode, + Node, + StringNode, + UnaryNode, + VariableNode, +) + + +class TypesInferencer: + def __init__(self) -> None: + pass + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode) -> types_ast.ProgramNode: + class_decl = [] + for decl in node.declarations: + class_decl.append(self.visit(decl)) + + return types_ast.ProgramNode(class_decl, node) + + @visitor.when(ClassDeclarationNode) + def visit(self, node: ClassDeclarationNode) -> types_ast.ClassDeclarationNode: + features = [] + for feature in node.features: + features.append(self.visit(feature)) + + return types_ast.ClassDeclarationNode(features, node) + + @visitor.when(AttrDeclarationNode) + def visit(self, node: AttrDeclarationNode) -> types_ast.AttrDeclarationNode: + new_node = types_ast.AttrDeclarationNode(node) + if node.expr: + new_node.expr = self.visit(node.expr) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(MethodDeclarationNode) + def visit(self, node: MethodDeclarationNode) -> types_ast.MethodDeclarationNode: + body = self.visit(node.body) + params = [self.visit(param) for param in node.params] + ret_type = self._reduce_to_type(node.inferenced_type) + return types_ast.MethodDeclarationNode(params, ret_type, node) + + @visitor.when(BlocksNode) + def visit(self, node: BlocksNode) -> types_ast.BlocksNode: + expr_list = [self.visit(expr) for expr in node.expr_list] + + new_node = types_ast.BlocksNode(expr_list, node) + new_node.type = expr_list[-1].type + return new_node + + @visitor.when(ConditionalNode) + def visit(self, node: ConditionalNode) -> types_ast.ConditionalNode: + condition = self.visit(node.condition) + then_body = self.visit(node.then_body) + else_body = self.visit(node.else_body) + + new_node = types_ast.ConditionalNode(condition, then_body, else_body, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(CaseNode) + def visit(self, node: CaseNode) -> types_ast.CaseNode: + expr = self.visit(node.case_expr) + case_options = [self.visit(option) for option in node.options] + new_node = types_ast.CaseNode(expr, case_options, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(CaseOptionNode) + def visit(self, node: CaseOptionNode) -> types_ast.CaseOptionNode: + return types_ast.CaseOptionNode(self.visit(node.expr),node) + + @visitor.when() + + + def _reduce_to_type(self, bag: TypeBag, node: Node): + if bag.heads > 1: + self.add_error(node, "ErrorType: Ambiguous type declaration") + return ErrorType() + return bag.heads[0] + + def add_error(self, node, text: str): + line, col = node.get_position() if node else (0, 0) + self.errors.append(((line, col), f"({line}, {col}) - " + text)) \ No newline at end of file From 4f6d6c00bcdbcda1605fa1c574086fdd7b5527dd Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 01:00:15 -0400 Subject: [PATCH 098/432] Add at_type attribute to inferencer_ast.MethodCallNode --- src/ast/inferencer_ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 95aca1301..069b81f1c 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -126,7 +126,7 @@ def __init__(self, caller_type, expr, args, node): self.expr = expr self.args = args self.id = node.id - self.type = node.type + self.at_type = node.type class UnaryNode(ExpressionNode): From 38ec7f3d6ebf1541ed3dfed43e802dbe1d90ea5c Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 01:01:51 -0400 Subject: [PATCH 099/432] Add at_type attribute to types_ast.MethodCallNode --- src/ast/types_ast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/types_ast.py b/src/ast/types_ast.py index eacc02be1..af8be5b2b 100644 --- a/src/ast/types_ast.py +++ b/src/ast/types_ast.py @@ -73,7 +73,7 @@ class CaseOptionNode(ExpressionNode): def __init__(self, ret_expr, node): Node.__init__(self, node) self.id = node.id - self.decl_type = node.type + self.decl_type = node.decl_type self.expr = ret_expr @@ -114,6 +114,7 @@ def __init__(self, caller_type, expr, args, node): self.expr = expr self.args = args self.id = node.id + self.at_type = node.at_type class UnaryNode(ExpressionNode): From 8adbb6278bdcf1789c2ed1675100b841e7b0f3c9 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 01:14:19 -0400 Subject: [PATCH 100/432] Remove defined property from types_ast.VariableNode --- src/ast/types_ast.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ast/types_ast.py b/src/ast/types_ast.py index af8be5b2b..b63c28ef7 100644 --- a/src/ast/types_ast.py +++ b/src/ast/types_ast.py @@ -197,9 +197,7 @@ class StringNode(AtomicNode): class VariableNode(AtomicNode): - def __init__(self, node): - super().__init__(node) - self.defined = False + pass class InstantiateNode(AtomicNode): From fa12b6542b077800ee9aaa02d79c423c50423771 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 01:27:50 -0400 Subject: [PATCH 101/432] Implement methods in TypesInferencer --- src/semantics/inference/types_inferencer.py | 139 ++++++++++++++++++-- 1 file changed, 130 insertions(+), 9 deletions(-) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 2331f6319..4111ac52a 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,9 +1,22 @@ +import types from semantics.tools.type import ErrorType from utils import visitor from semantics.tools import TypeBag import ast.types_ast as types_ast from ast.inferencer_ast import ( + BinaryNode, + BooleanNode, + ComplementNode, + DivNode, + EqualsNode, + InstantiateNode, + IntNode, + LessNode, + LessOrEqualNode, + MinusNode, + NotNode, + PlusNode, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, @@ -14,20 +27,17 @@ CaseOptionNode, LoopNode, LetNode, + StarNode, + StringNode, VarDeclarationNode, AssignNode, MethodCallNode, - BinaryNode, - BooleanNode, ClassDeclarationNode, - InstantiateNode, - IntNode, ProgramNode, AttrDeclarationNode, Node, - StringNode, - UnaryNode, VariableNode, + IsVoidNode, ) @@ -98,10 +108,121 @@ def visit(self, node: CaseNode) -> types_ast.CaseNode: @visitor.when(CaseOptionNode) def visit(self, node: CaseOptionNode) -> types_ast.CaseOptionNode: - return types_ast.CaseOptionNode(self.visit(node.expr),node) + return types_ast.CaseOptionNode(self.visit(node.expr), node) + + @visitor.when(LoopNode) + def visit(self, node: LoopNode) -> types_ast.LoopNode: + condition = self.visit(node.condition) + body = self.visit(node.body) + new_node = types_ast.LoopNode(condition, body, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(LetNode) + def visit(self, node: LetNode) -> types_ast.LetNode: + var_decl_list = [self.visit(var_decl) for var_decl in node.var_decl_list] + in_expr = self.visit(node.in_expr) + new_node = types_ast.LetNode(var_decl_list, in_expr, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(VarDeclarationNode) + def visit(self, node: VarDeclarationNode) -> types_ast.VarDeclarationNode: + new_node = types_ast.VarDeclarationNode(node) + if node.expr: + new_node.expr = self.visit(node.expr) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node - @visitor.when() - + @visitor.when(AssignNode) + def visit(self, node: AssignNode) -> types_ast.AssignNode: + expr = self.visit(node.expr) + new_node = types_ast.AssignNode(expr, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(MethodCallNode) + def visit(self, node: MethodCallNode) -> types_ast.MethodCallNode: + args = [self.visit(arg) for arg in node.args] + caller_expr = self.visit(node.expr) + new_node = types_ast.MethodCallNode(node.caller_type, caller_expr, args, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(VariableNode) + def visit(self, node: VariableNode) -> types_ast.VariableNode: + new_node = types_ast.VariableNode(node) + if node.defined: + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(IsVoidNode) + def visit(self, node: IsVoidNode) -> types_ast.IsVoidNode: + expr = self.visit(node.expr) + new_node = types_ast.IsVoidNode(expr, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(NotNode) + def visit(self, node: NotNode) -> types_ast.NotNode: + expr = self.visit(node.expr) + new_node = types_ast.NotNode(expr, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(ComplementNode) + def visit(self, node: ComplementNode) -> types_ast.ComplementNode: + expr = self.visit(node.expr) + new_node = types_ast.ComplementNode(expr, node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(BinaryNode) + def visit(self, node: EqualsNode) -> types_ast.PlusNode: + left = self.visit(node.left) + right = self.visit(node.right) + + if isinstance(PlusNode): + new_node = types_ast.PlusNode(left, right, node) + elif isinstance(MinusNode): + new_node = types_ast.MinusNode(left, right, node) + elif isinstance(DivNode): + new_node = types_ast.DivNode(left, right, node) + elif isinstance(StarNode): + new_node = types_ast.StarNode(left, right, node) + elif isinstance(LessNode): + new_node = types_ast.LessNode(left, right, node) + elif isinstance(LessOrEqualNode): + new_node = types_ast.LessOrEqualNode(left, right, node) + elif isinstance(EqualsNode): + new_node = types_ast.EqualsNode(left, right, node) + + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(BooleanNode) + def visit(self, node: BooleanNode) -> types_ast.BooleanNode: + new_node = types_ast.BooleanNode(node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(StringNode) + def visit(self, node: StringNode) -> types_ast.StringNode: + new_node = types_ast.StringNode(node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(IntNode) + def visit(self, node: IntNode) -> types_ast.IntNode: + new_node = types_ast.IntNode(node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node + + @visitor.when(InstantiateNode) + def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: + new_node = types_ast.InstantiateNode(node) + new_node.type = self._reduce_to_type(node.inferenced_type) + return new_node def _reduce_to_type(self, bag: TypeBag, node: Node): if bag.heads > 1: From 48d80fdbaf03139c21d1f29f21686d8088ca981a Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 01:50:41 -0400 Subject: [PATCH 102/432] Fix some bugs --- src/__main__.py | 6 +++--- src/ast/inferencer_ast.py | 2 +- src/ast/types_ast.py | 2 +- src/semantics/inference/hard_inferencer.py | 9 +++++++-- src/semantics/inference/soft_inferencer.py | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index a6f9615d6..f1105e8c1 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -39,10 +39,10 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - back = BackInferencer(context) - back_ast = back.visit(hard_ast) + # back = BackInferencer(context) + # back_ast = back.visit(hard_ast) - print(back_ast) + # print(back_ast) # logger = TypeLogger(context) # log = logger.visit(hard_ast, back_ast.scope) # print(log) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 069b81f1c..95aca1301 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -126,7 +126,7 @@ def __init__(self, caller_type, expr, args, node): self.expr = expr self.args = args self.id = node.id - self.at_type = node.type + self.type = node.type class UnaryNode(ExpressionNode): diff --git a/src/ast/types_ast.py b/src/ast/types_ast.py index b63c28ef7..76d03e77c 100644 --- a/src/ast/types_ast.py +++ b/src/ast/types_ast.py @@ -114,7 +114,7 @@ def __init__(self, caller_type, expr, args, node): self.expr = expr self.args = args self.id = node.id - self.at_type = node.at_type + self.at_type = node.type class UnaryNode(ExpressionNode): diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index a2577117a..5ef54b739 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -108,11 +108,16 @@ def visit(self, node, scope): @visitor.when(MethodDeclarationNode) def visit(self, node, scopex: Scope): - scope = scopex.next_child() + scope: Scope = scopex.next_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) new_params = [] for param in node.params: - new_params.append(self.visit(param,scope)) + new_params.append(self.visit(param, scope)) + # scope.define_variable(param.name, ) body_node = self.visit(node.body, scope) body_type = body_node.inferenced_type diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 30c9d7777..bdc738d33 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -120,8 +120,8 @@ def visit(self, node, scopex: Scope): 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) + for idx, typex in zip(current_method.param_names, current_method.param_types): + scope.define_variable(idx, typex) new_params = [] for param in node.params: new_params.append(self.visit(param, scope)) From 59b3c401c7ca40fc83cf452e743896238a2e38de Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 03:09:49 -0400 Subject: [PATCH 103/432] Fix minor bugs in TypesInferencer --- src/__main__.py | 9 +++-- src/semantics/inference/types_inferencer.py | 40 ++++++++++----------- src/test.cl | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index f1105e8c1..10f6f7370 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -11,6 +11,7 @@ HardInferencer, BackInferencer, ) +from semantics.inference.types_inferencer import TypesInferencer def format_errors(errors, s=""): @@ -39,10 +40,12 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - # back = BackInferencer(context) - # back_ast = back.visit(hard_ast) + back = BackInferencer(context) + back_ast = back.visit(hard_ast) - # print(back_ast) + type_ast = TypesInferencer().visit(back_ast) + + print("Hi") # logger = TypeLogger(context) # log = logger.visit(hard_ast, back_ast.scope) # print(log) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 4111ac52a..81534b533 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -70,15 +70,15 @@ def visit(self, node: AttrDeclarationNode) -> types_ast.AttrDeclarationNode: new_node = types_ast.AttrDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(MethodDeclarationNode) def visit(self, node: MethodDeclarationNode) -> types_ast.MethodDeclarationNode: body = self.visit(node.body) params = [self.visit(param) for param in node.params] - ret_type = self._reduce_to_type(node.inferenced_type) - return types_ast.MethodDeclarationNode(params, ret_type, node) + ret_type = self._reduce_to_type(node.inferenced_type,node) + return types_ast.MethodDeclarationNode(params, ret_type,body, node) @visitor.when(BlocksNode) def visit(self, node: BlocksNode) -> types_ast.BlocksNode: @@ -95,7 +95,7 @@ def visit(self, node: ConditionalNode) -> types_ast.ConditionalNode: else_body = self.visit(node.else_body) new_node = types_ast.ConditionalNode(condition, then_body, else_body, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(CaseNode) @@ -103,7 +103,7 @@ def visit(self, node: CaseNode) -> types_ast.CaseNode: expr = self.visit(node.case_expr) case_options = [self.visit(option) for option in node.options] new_node = types_ast.CaseNode(expr, case_options, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(CaseOptionNode) @@ -115,7 +115,7 @@ def visit(self, node: LoopNode) -> types_ast.LoopNode: condition = self.visit(node.condition) body = self.visit(node.body) new_node = types_ast.LoopNode(condition, body, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(LetNode) @@ -123,7 +123,7 @@ def visit(self, node: LetNode) -> types_ast.LetNode: var_decl_list = [self.visit(var_decl) for var_decl in node.var_decl_list] in_expr = self.visit(node.in_expr) new_node = types_ast.LetNode(var_decl_list, in_expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(VarDeclarationNode) @@ -131,14 +131,14 @@ def visit(self, node: VarDeclarationNode) -> types_ast.VarDeclarationNode: new_node = types_ast.VarDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(AssignNode) def visit(self, node: AssignNode) -> types_ast.AssignNode: expr = self.visit(node.expr) new_node = types_ast.AssignNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(MethodCallNode) @@ -146,35 +146,35 @@ def visit(self, node: MethodCallNode) -> types_ast.MethodCallNode: args = [self.visit(arg) for arg in node.args] caller_expr = self.visit(node.expr) new_node = types_ast.MethodCallNode(node.caller_type, caller_expr, args, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(VariableNode) def visit(self, node: VariableNode) -> types_ast.VariableNode: new_node = types_ast.VariableNode(node) if node.defined: - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(IsVoidNode) def visit(self, node: IsVoidNode) -> types_ast.IsVoidNode: expr = self.visit(node.expr) new_node = types_ast.IsVoidNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(NotNode) def visit(self, node: NotNode) -> types_ast.NotNode: expr = self.visit(node.expr) new_node = types_ast.NotNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(ComplementNode) def visit(self, node: ComplementNode) -> types_ast.ComplementNode: expr = self.visit(node.expr) new_node = types_ast.ComplementNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(BinaryNode) @@ -197,35 +197,35 @@ def visit(self, node: EqualsNode) -> types_ast.PlusNode: elif isinstance(EqualsNode): new_node = types_ast.EqualsNode(left, right, node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(BooleanNode) def visit(self, node: BooleanNode) -> types_ast.BooleanNode: new_node = types_ast.BooleanNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(StringNode) def visit(self, node: StringNode) -> types_ast.StringNode: new_node = types_ast.StringNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(IntNode) def visit(self, node: IntNode) -> types_ast.IntNode: new_node = types_ast.IntNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node @visitor.when(InstantiateNode) def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: new_node = types_ast.InstantiateNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type) + new_node.type = self._reduce_to_type(node.inferenced_type,node) return new_node def _reduce_to_type(self, bag: TypeBag, node: Node): - if bag.heads > 1: + if len(bag.heads) > 1: self.add_error(node, "ErrorType: Ambiguous type declaration") return ErrorType() return bag.heads[0] diff --git a/src/test.cl b/src/test.cl index f7457a5b0..c99dc6c11 100644 --- a/src/test.cl +++ b/src/test.cl @@ -2,7 +2,7 @@ class Main { a : AUTO_TYPE <- 12; - hola(b: AUTO_TYPE): AUTO_TYPE {b}; + hola(b: Int): AUTO_TYPE {b}; main(): Int { { hola(a); From 31e9dbfcb0b51db243bcd67fe936df0800dd00ef Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 10:48:26 -0400 Subject: [PATCH 104/432] Add errors in TypesInferencer --- src/__main__.py | 4 +++- src/semantics/inference/types_inferencer.py | 6 +++++- src/semantics/tools/type.py | 11 +++++++---- src/test.cl | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 10f6f7370..917fb4445 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -43,7 +43,9 @@ def run_pipeline(program_ast): back = BackInferencer(context) back_ast = back.visit(hard_ast) - type_ast = TypesInferencer().visit(back_ast) + types = TypesInferencer() + types_ast = types.visit(back_ast) + errors += types.errors print("Hi") # logger = TypeLogger(context) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 81534b533..727824fca 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -43,7 +43,8 @@ class TypesInferencer: def __init__(self) -> None: - pass + self.errors = [] + @visitor.on("node") def visit(self, node): @@ -228,6 +229,9 @@ def _reduce_to_type(self, bag: TypeBag, node: Node): if len(bag.heads) > 1: self.add_error(node, "ErrorType: Ambiguous type declaration") return ErrorType() + if len(bag.heads) == 0: + self.add_error(node, "ErrorType: Cannot infer type") + return ErrorType() return bag.heads[0] def add_error(self, node, text: str): diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index db302b620..bcb055e62 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -331,9 +331,10 @@ def remove_self_type(self, remove_type): self.update_heads() def generate_name(self): - if len(self.type_set) == 1: - self.name = self.heads[0].name - return self.name + # TODO: Cuando se tiene en el type_set un SelfType() y no hay nada en head explota + # if len(self.type_set) == 1: + # self.name = self.heads[0].name + # return self.name s = "{" s += ", ".join( @@ -564,9 +565,11 @@ def unify(a: TypeBag, b: TypeBag) -> None: intersection = set() for type1 in a.type_set: for type2 in b.type_set: - if type1.name == type2.name: + if type1.name == type2.name: + # if type1.conforms_to(type2) or type2.conforms_to(type1): intersection.add(type1) + a.type_set = intersection a.update_heads() b.type_set = intersection diff --git a/src/test.cl b/src/test.cl index c99dc6c11..70a55aecb 100644 --- a/src/test.cl +++ b/src/test.cl @@ -6,6 +6,7 @@ class Main { main(): Int { { hola(a); + self; } }; }; From 4bce29501a7513ad9b6cd4079aec6721256c4669 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 11:11:46 -0400 Subject: [PATCH 105/432] Add src/utils/deep_equals.py --- src/utils/deep_equals.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/utils/deep_equals.py diff --git a/src/utils/deep_equals.py b/src/utils/deep_equals.py new file mode 100644 index 000000000..f0f40224e --- /dev/null +++ b/src/utils/deep_equals.py @@ -0,0 +1,14 @@ +import json + +_all_ = ['deep_equals'] + +def generate_json_string(a): + json_dump = json.dumps(a) + return str(json_dump) + + +def deep_equals(a, b) -> bool: + return generate_json_string(a) == generate_json_string(b) + +# TODO: Implementar deep_equals para hacer varias pasadas +# del BackInferncer si no hay cambios en el ast que se devuelve \ No newline at end of file From 4e1c6b48468e9281f6e7b6c423e20190b689c46a Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 11:27:44 -0400 Subject: [PATCH 106/432] Fix bug in TypesInferecencer related to SELF_TYPE variables --- src/__main__.py | 26 +++++++++++++--------- src/semantics/inference/__init__.py | 1 + src/semantics/inference/back_inferencer.py | 6 ++--- src/test.cl | 7 +++--- src/utils/__init__.py | 3 ++- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 917fb4445..37d42696e 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,5 +1,3 @@ -from os import close, error -from semantics.inference.hard_inferencer import HardInferencer from debbuging.type_logger import TypeLogger import sys @@ -10,8 +8,8 @@ SoftInferencer, HardInferencer, BackInferencer, + TypesInferencer, ) -from semantics.inference.types_inferencer import TypesInferencer def format_errors(errors, s=""): @@ -40,24 +38,27 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - back = BackInferencer(context) + if len(errors) > 0: + s = format_errors(errors) + print(s) + exit(1) + + back = BackInferencer(context) back_ast = back.visit(hard_ast) types = TypesInferencer() - types_ast = types.visit(back_ast) + types_ast = types.visit(back_ast) errors += types.errors - print("Hi") - # logger = TypeLogger(context) - # log = logger.visit(hard_ast, back_ast.scope) - # print(log) if len(errors) > 0: - # for error in errors: - # print(error[1]) s = format_errors(errors) print(s) exit(1) + # logger = TypeLogger(context) + # log = logger.visit(hard_ast, back_ast.scope) + # print(log) + def main(): if len(sys.argv) > 1: @@ -88,3 +89,6 @@ def main(): main() + + +# TODO: la varibel 'self' no tiene inferenced_type \ No newline at end of file diff --git a/src/semantics/inference/__init__.py b/src/semantics/inference/__init__.py index d9a4d8525..f05053dbf 100644 --- a/src/semantics/inference/__init__.py +++ b/src/semantics/inference/__init__.py @@ -1,3 +1,4 @@ from .soft_inferencer import SoftInferencer from .back_inferencer import BackInferencer from .hard_inferencer import HardInferencer +from .types_inferencer import TypesInferencer diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index a82398535..4198d401a 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -94,7 +94,7 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: current_method.param_types = [param.inferenced_type for param in new_params] new_body_node = self.visit(node.body, scope) - body_type = new_body_node.inferenced_type + body_type = new_body_node.inferenced_type.swap_self_type(self.current_type) new_node = MethodDeclarationNode(new_params, node.type, new_body_node, node) decl_type = node.inferenced_type body_type = new_body_node.inferenced_type @@ -181,7 +181,7 @@ def visit(self, node: LetNode, scope) -> LetNode: @visitor.when(VarDeclarationNode) def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: - scope.define_variable(node.id, node.inferenced_type) + scope.define_variable(node.id, node.inferenced_type.swap_self_type(self.current_type)) new_node = VarDeclarationNode(node) if node.expr: @@ -245,7 +245,7 @@ def visit(self, node: UnaryNode, scope) -> UnaryNode: def visit(self, node: VariableNode, scope: Scope) -> VariableNode: new_node = deepcopy(node) if node.defined: - decl_type = node.inferenced_type + decl_type = node.inferenced_type.swap_self_type(self.current_type) expr_type = scope.find_variable(node.value).get_type() new_node.inferenced_type = unify(decl_type, expr_type) return new_node diff --git a/src/test.cl b/src/test.cl index 70a55aecb..ed529815c 100644 --- a/src/test.cl +++ b/src/test.cl @@ -2,10 +2,11 @@ class Main { a : AUTO_TYPE <- 12; - hola(b: Int): AUTO_TYPE {b}; - main(): Int { +-- hola(b: Int): AUTO_TYPE {b}; + main(): AUTO_TYPE { { - hola(a); +-- hola(a); +-- a; self; } }; diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 100cda756..77a87f5f4 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1 +1,2 @@ -from .visitor import * \ No newline at end of file +from .visitor import * +from .deep_equals import * \ No newline at end of file From 3eac327d6920750cb59a5620ddb202014d70d6de Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 11:31:07 -0400 Subject: [PATCH 107/432] Remove unnecessary TODO in __main__.py --- src/__main__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 37d42696e..3bb5f9278 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -90,5 +90,3 @@ def main(): main() - -# TODO: la varibel 'self' no tiene inferenced_type \ No newline at end of file From 9565b6160db1b4795093b7e880e8db52ffd455d0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 27 Apr 2021 12:34:12 -0400 Subject: [PATCH 108/432] Test cases for inferencer --- src/__main__.py | 11 ++- .../tests/Auto/{01Assign.cl => assign1.cl} | 3 +- src/debbuging/tests/Auto/call1.cl | 78 +++++++++++++++++++ src/debbuging/tests/Auto/case1.cl | 17 ++++ src/debbuging/tests/Auto/case2.cl | 69 ++++++++++++++++ src/debbuging/tests/Auto/if1.cl | 7 ++ .../tests/Auto/{02Many.cl => many1.cl} | 0 .../tests/Auto/{03Many.cl => many2.cl} | 0 src/debbuging/tests/Auto/point1.cl | 35 +++++++++ src/debbuging/tests/Auto/point2.cl | 33 ++++++++ .../tests/Auto/{00Simple.cl => simple1.cl} | 3 +- 11 files changed, 248 insertions(+), 8 deletions(-) rename src/debbuging/tests/Auto/{01Assign.cl => assign1.cl} (59%) create mode 100644 src/debbuging/tests/Auto/call1.cl create mode 100644 src/debbuging/tests/Auto/case1.cl create mode 100644 src/debbuging/tests/Auto/case2.cl create mode 100644 src/debbuging/tests/Auto/if1.cl rename src/debbuging/tests/Auto/{02Many.cl => many1.cl} (100%) rename src/debbuging/tests/Auto/{03Many.cl => many2.cl} (100%) create mode 100644 src/debbuging/tests/Auto/point1.cl create mode 100644 src/debbuging/tests/Auto/point2.cl rename src/debbuging/tests/Auto/{00Simple.cl => simple1.cl} (51%) diff --git a/src/__main__.py b/src/__main__.py index 3bb5f9278..73e3416c1 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -50,21 +50,21 @@ def run_pipeline(program_ast): types_ast = types.visit(back_ast) errors += types.errors + logger = TypeLogger(context) + log = logger.visit(back_ast, back_ast.scope) + print(log) + if len(errors) > 0: s = format_errors(errors) print(s) exit(1) - # logger = TypeLogger(context) - # log = logger.visit(hard_ast, back_ast.scope) - # print(log) - def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/test.cl" + input_file = "debbuging/tests/Auto/point2.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) @@ -89,4 +89,3 @@ def main(): main() - diff --git a/src/debbuging/tests/Auto/01Assign.cl b/src/debbuging/tests/Auto/assign1.cl similarity index 59% rename from src/debbuging/tests/Auto/01Assign.cl rename to src/debbuging/tests/Auto/assign1.cl index 79d75a0bd..625171ff3 100644 --- a/src/debbuging/tests/Auto/01Assign.cl +++ b/src/debbuging/tests/Auto/assign1.cl @@ -1,6 +1,7 @@ class Main inherits IO { a : AUTO_TYPE; - main(n : AUTO_TYPE) : AUTO_TYPE { + n : AUTO_TYPE; + main() : AUTO_TYPE { a <- n + 1 }; }; diff --git a/src/debbuging/tests/Auto/call1.cl b/src/debbuging/tests/Auto/call1.cl new file mode 100644 index 000000000..f4ca0b5a4 --- /dev/null +++ b/src/debbuging/tests/Auto/call1.cl @@ -0,0 +1,78 @@ +class Main inherits IO { + main(): String + { + "Kabuki" + } + test(x : AUTO_TYPE, y : AUTO_TYPE) : AUTO_TYPE { + { + if true then x.me() else y.myself() fi; + x.he(); + if false then x else y fi; + } + }; +}; + +class A { + me():SELF_TYPE + { + self + }; + you():SELF_TYPE + { + self + }; + he():SELF_TYPE + { + self + }; +}; + +class B inherits A { + us():SELF_TYPE + { + self + }; +}; + +class C inherits B { }; + +class D inherits C { + they():SELF_TYPE + { + self + }; +}; + +class E inherits D { }; + + +class F inherits C { }; + +class G inherits F { + myself():SELF_TYPE + { + self + }; + }; + +class H inherits G { }; + + +class I{ + me():String + { + "Confusing" + }; + you():SELF_TYPE + { + self + }; + she():SELF_TYPE + { + self + }; +}; + +class J inherits I { }; + +class K inherits J { }; diff --git a/src/debbuging/tests/Auto/case1.cl b/src/debbuging/tests/Auto/case1.cl new file mode 100644 index 000000000..3b742a5cd --- /dev/null +++ b/src/debbuging/tests/Auto/case1.cl @@ -0,0 +1,17 @@ +class Main inherits IO { + main(): String + { + "Kabuki" + }; + + test(a : AUTO_TYPE, b : AUTO_TYPE) : AUTO_TYPE { + { + if b then not b else a + 1 fi; + case 3 + 5 of + n : Bool => b; + n : Int => not b; + n : String => b; + esac; + } + }; +}; diff --git a/src/debbuging/tests/Auto/case2.cl b/src/debbuging/tests/Auto/case2.cl new file mode 100644 index 000000000..aab5f0a2b --- /dev/null +++ b/src/debbuging/tests/Auto/case2.cl @@ -0,0 +1,69 @@ +(* +En este ejemplo se muestra como en la primera etapa de el inferenciador se maneja las ambiguedades en los Auto Types +*) + +class Main inherits IO { + main(a : AUTO_TYPE, b : AUTO_TYPE) : AUTO_TYPE { + { + if b then not b else a fi; + case 3 + 5 of + n : Bool => a.me(); + n : Int => 0; + n : String => "Yay!"; + esac; + a.you(); + a.she(); + } + }; +}; + +class A { + me():SELF_TYPE + { + self + }; + you():SELF_TYPE + { + self + }; + he():SELF_TYPE + { + self + }; +}; +(* +class B inherits A { }; + +class C inherits B { }; + +class D inherits C { }; + +class E inherits D { }; + + +class F inherits C { }; + +class G inherits F { }; + +class H inherits G { }; +*) + +class I{ + me():SELF_TYPE + { + self + }; + you():SELF_TYPE + { + self + }; + she():SELF_TYPE + { + self + }; +}; +(* +class J inherits I { }; + +class K inherits J { }; +*) diff --git a/src/debbuging/tests/Auto/if1.cl b/src/debbuging/tests/Auto/if1.cl new file mode 100644 index 000000000..d2704c5f5 --- /dev/null +++ b/src/debbuging/tests/Auto/if1.cl @@ -0,0 +1,7 @@ +class Main inherits IO { + a : AUTO_TYPE; + b : AUTO_TYPE; + main() : AUTO_TYPE { + if b then a + 1 else a fi + }; +}; diff --git a/src/debbuging/tests/Auto/02Many.cl b/src/debbuging/tests/Auto/many1.cl similarity index 100% rename from src/debbuging/tests/Auto/02Many.cl rename to src/debbuging/tests/Auto/many1.cl diff --git a/src/debbuging/tests/Auto/03Many.cl b/src/debbuging/tests/Auto/many2.cl similarity index 100% rename from src/debbuging/tests/Auto/03Many.cl rename to src/debbuging/tests/Auto/many2.cl diff --git a/src/debbuging/tests/Auto/point1.cl b/src/debbuging/tests/Auto/point1.cl new file mode 100644 index 000000000..b885cb472 --- /dev/null +++ b/src/debbuging/tests/Auto/point1.cl @@ -0,0 +1,35 @@ +class Main { + step(p : AUTO_TYPE) : AUTO_TYPE + { + p.translate(1,1) + }; + + main() : Int + { + let q : AUTO_TYPE <- new Point.init(0,0) in + { + step(q); + } + }; +}; + +class Point { + x : AUTO_TYPE; + y : AUTO_TYPE; + translate(a:AUTO_TYPE, b:AUTO_TYPE) : AUTO_TYPE + { + { + x <- a * b; + y <- a + b; + } + }; + init(a:AUTO_TYPE, b:AUTO_TYPE) : AUTO_TYPE + { + { + x <- a; + y <- b; + self; + } + }; + +}; diff --git a/src/debbuging/tests/Auto/point2.cl b/src/debbuging/tests/Auto/point2.cl new file mode 100644 index 000000000..6ae345d67 --- /dev/null +++ b/src/debbuging/tests/Auto/point2.cl @@ -0,0 +1,33 @@ +class Main { + step(p : AUTO_TYPE) : AUTO_TYPE + { + p.translate(1,1) + }; + + main() : Object { + let p : AUTO_TYPE <- new Point.init(0,0) in { + step(p); -- Puede lanzar error semantico + } + }; +}; + +class Point { + x : AUTO_TYPE; + y : AUTO_TYPE; + translate(a:AUTO_TYPE, b:AUTO_TYPE) : AUTO_TYPE + { + { + x <- a; + y <- b; + } + }; + init(a:AUTO_TYPE, b:AUTO_TYPE) : AUTO_TYPE + { + { + x <- a; + y <- b; + self; + } + }; + +}; diff --git a/src/debbuging/tests/Auto/00Simple.cl b/src/debbuging/tests/Auto/simple1.cl similarity index 51% rename from src/debbuging/tests/Auto/00Simple.cl rename to src/debbuging/tests/Auto/simple1.cl index ca2ffb704..9d30decbe 100644 --- a/src/debbuging/tests/Auto/00Simple.cl +++ b/src/debbuging/tests/Auto/simple1.cl @@ -1,5 +1,6 @@ class Main inherits IO { - main(n : AUTO_TYPE) : AUTO_TYPE { + n:AUTO_TYPE; + main() : AUTO_TYPE { n + 1 }; }; From 358208c4633f2fe6a4332b59f78af1a156673d7b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 27 Apr 2021 12:35:01 -0400 Subject: [PATCH 109/432] Minor bug fixes in soft inferencer and hard inferencer --- src/semantics/inference/hard_inferencer.py | 13 ++++++++++++- src/semantics/inference/soft_inferencer.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 5ef54b739..ea54226fd 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -11,6 +11,7 @@ ComparerNode, ComplementNode, ConditionalNode, + DivNode, EqualsNode, InstantiateNode, IntNode, @@ -21,9 +22,12 @@ LoopNode, MethodCallNode, MethodDeclarationNode, + MinusNode, Node, NotNode, + PlusNode, ProgramNode, + StarNode, StringNode, VarDeclarationNode, VariableNode, @@ -390,7 +394,14 @@ def visit(self, node, scope): @visitor.when(ArithmeticNode) def visit(self, node, scope): left_node, right_node = self.__arithmetic_operation(node, scope) - arith_node = ArithmeticNode(left_node, right_node, node) + if isinstance(node, PlusNode): + arith_node = PlusNode(left_node, right_node, node) + elif isinstance(node, MinusNode): + arith_node = MinusNode(left_node, right_node, node) + elif isinstance(node, StarNode): + arith_node = StarNode(left_node, right_node, node) + elif isinstance(node, DivNode): + arith_node = DivNode(left_node, right_node, node) arith_node.inferenced_type = self.context.get_type("Int") return arith_node diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index bdc738d33..ac3a211e0 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -12,6 +12,7 @@ ComparerNode, ComplementNode, ConditionalNode, + DivNode, EqualsNode, InstantiateNode, IntNode, @@ -22,9 +23,12 @@ LoopNode, MethodCallNode, MethodDeclarationNode, + MinusNode, Node, NotNode, + PlusNode, ProgramNode, + StarNode, StringNode, VarDeclarationNode, VariableNode, @@ -441,7 +445,14 @@ def visit(self, node, scope): @visitor.when(ArithmeticNode) def visit(self, node, scope): left_node, right_node = self.__arithmetic_operation(node, scope) - arith_node = inf_ast.ArithmeticNode(left_node, right_node, node) + if isinstance(node, PlusNode): + arith_node = inf_ast.PlusNode(left_node, right_node, node) + elif isinstance(node, MinusNode): + arith_node = inf_ast.MinusNode(left_node, right_node, node) + elif isinstance(node, StarNode): + arith_node = inf_ast.StarNode(left_node, right_node, node) + elif isinstance(node, DivNode): + arith_node = inf_ast.DivNode(left_node, right_node, node) arith_node.inferenced_type = self.context.get_type("Int") return arith_node From cd481875303710d349f69021c222299a82b368e8 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 27 Apr 2021 12:36:14 -0400 Subject: [PATCH 110/432] Minor bug fix in BynaryNode in TypesInferencer --- src/semantics/inference/types_inferencer.py | 53 ++++++++++----------- src/semantics/tools/type.py | 6 +-- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 727824fca..567297d62 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -44,7 +44,6 @@ class TypesInferencer: def __init__(self) -> None: self.errors = [] - @visitor.on("node") def visit(self, node): @@ -71,15 +70,15 @@ def visit(self, node: AttrDeclarationNode) -> types_ast.AttrDeclarationNode: new_node = types_ast.AttrDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(MethodDeclarationNode) def visit(self, node: MethodDeclarationNode) -> types_ast.MethodDeclarationNode: body = self.visit(node.body) params = [self.visit(param) for param in node.params] - ret_type = self._reduce_to_type(node.inferenced_type,node) - return types_ast.MethodDeclarationNode(params, ret_type,body, node) + ret_type = self._reduce_to_type(node.inferenced_type, node) + return types_ast.MethodDeclarationNode(params, ret_type, body, node) @visitor.when(BlocksNode) def visit(self, node: BlocksNode) -> types_ast.BlocksNode: @@ -96,7 +95,7 @@ def visit(self, node: ConditionalNode) -> types_ast.ConditionalNode: else_body = self.visit(node.else_body) new_node = types_ast.ConditionalNode(condition, then_body, else_body, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(CaseNode) @@ -104,7 +103,7 @@ def visit(self, node: CaseNode) -> types_ast.CaseNode: expr = self.visit(node.case_expr) case_options = [self.visit(option) for option in node.options] new_node = types_ast.CaseNode(expr, case_options, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(CaseOptionNode) @@ -116,7 +115,7 @@ def visit(self, node: LoopNode) -> types_ast.LoopNode: condition = self.visit(node.condition) body = self.visit(node.body) new_node = types_ast.LoopNode(condition, body, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(LetNode) @@ -124,7 +123,7 @@ def visit(self, node: LetNode) -> types_ast.LetNode: var_decl_list = [self.visit(var_decl) for var_decl in node.var_decl_list] in_expr = self.visit(node.in_expr) new_node = types_ast.LetNode(var_decl_list, in_expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(VarDeclarationNode) @@ -132,14 +131,14 @@ def visit(self, node: VarDeclarationNode) -> types_ast.VarDeclarationNode: new_node = types_ast.VarDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(AssignNode) def visit(self, node: AssignNode) -> types_ast.AssignNode: expr = self.visit(node.expr) new_node = types_ast.AssignNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(MethodCallNode) @@ -147,35 +146,35 @@ def visit(self, node: MethodCallNode) -> types_ast.MethodCallNode: args = [self.visit(arg) for arg in node.args] caller_expr = self.visit(node.expr) new_node = types_ast.MethodCallNode(node.caller_type, caller_expr, args, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(VariableNode) def visit(self, node: VariableNode) -> types_ast.VariableNode: new_node = types_ast.VariableNode(node) if node.defined: - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(IsVoidNode) def visit(self, node: IsVoidNode) -> types_ast.IsVoidNode: expr = self.visit(node.expr) new_node = types_ast.IsVoidNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(NotNode) def visit(self, node: NotNode) -> types_ast.NotNode: expr = self.visit(node.expr) new_node = types_ast.NotNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(ComplementNode) def visit(self, node: ComplementNode) -> types_ast.ComplementNode: expr = self.visit(node.expr) new_node = types_ast.ComplementNode(expr, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(BinaryNode) @@ -183,46 +182,46 @@ def visit(self, node: EqualsNode) -> types_ast.PlusNode: left = self.visit(node.left) right = self.visit(node.right) - if isinstance(PlusNode): + if isinstance(node, PlusNode): new_node = types_ast.PlusNode(left, right, node) - elif isinstance(MinusNode): + elif isinstance(node, MinusNode): new_node = types_ast.MinusNode(left, right, node) - elif isinstance(DivNode): + elif isinstance(node, DivNode): new_node = types_ast.DivNode(left, right, node) - elif isinstance(StarNode): + elif isinstance(node, StarNode): new_node = types_ast.StarNode(left, right, node) - elif isinstance(LessNode): + elif isinstance(node, LessNode): new_node = types_ast.LessNode(left, right, node) - elif isinstance(LessOrEqualNode): + elif isinstance(node, LessOrEqualNode): new_node = types_ast.LessOrEqualNode(left, right, node) - elif isinstance(EqualsNode): + elif isinstance(node, EqualsNode): new_node = types_ast.EqualsNode(left, right, node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(BooleanNode) def visit(self, node: BooleanNode) -> types_ast.BooleanNode: new_node = types_ast.BooleanNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(StringNode) def visit(self, node: StringNode) -> types_ast.StringNode: new_node = types_ast.StringNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(IntNode) def visit(self, node: IntNode) -> types_ast.IntNode: new_node = types_ast.IntNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(InstantiateNode) def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: new_node = types_ast.InstantiateNode(node) - new_node.type = self._reduce_to_type(node.inferenced_type,node) + new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node def _reduce_to_type(self, bag: TypeBag, node: Node): diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index bcb055e62..a35a3e416 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -561,15 +561,13 @@ def from_dict_to_set(types: dict): def unify(a: TypeBag, b: TypeBag) -> None: - intersection = set() for type1 in a.type_set: for type2 in b.type_set: - if type1.name == type2.name: - # if type1.conforms_to(type2) or type2.conforms_to(type1): + if type1.name == type2.name: + # if type1.conforms_to(type2) or type2.conforms_to(type1): intersection.add(type1) - a.type_set = intersection a.update_heads() b.type_set = intersection From 27b984675df86f6803fa91bfdd2c6d089f8b31f0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 27 Apr 2021 12:37:08 -0400 Subject: [PATCH 111/432] Added scope.reset() as a final step while visiting ProgramNode in BackInferencer --- src/semantics/inference/back_inferencer.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 4198d401a..98f0ac3a9 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -48,6 +48,7 @@ def visit(self, node: ProgramNode) -> ProgramNode: for declaration in node.declarations: new_declaration.append(self.visit(declaration, scope.next_child())) + scope.reset() program = ProgramNode(new_declaration, scope, node) return program @@ -90,7 +91,7 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: new_params = [] for param in node.params: new_params.append(self.visit(param, scope)) - + current_method.param_types = [param.inferenced_type for param in new_params] new_body_node = self.visit(node.body, scope) @@ -181,7 +182,9 @@ def visit(self, node: LetNode, scope) -> LetNode: @visitor.when(VarDeclarationNode) def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: - scope.define_variable(node.id, node.inferenced_type.swap_self_type(self.current_type)) + scope.define_variable( + node.id, node.inferenced_type.swap_self_type(self.current_type) + ) new_node = VarDeclarationNode(node) if node.expr: @@ -216,7 +219,6 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: arg_node.inferenced_type = unify(arg_node.inferenced_type, param_type) new_args.append(arg_node) - new_expr = self.visit(node.expr, scope) if node.expr else None new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) new_node.inferenced_type = unify(node.inferenced_type, method.return_type) From bfb7e78f566b7d60fe4c87bdc86b13f9d68fcf25 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 27 Apr 2021 12:48:46 -0400 Subject: [PATCH 112/432] Commit before merge with origin master --- src/__main__.py | 8 ++--- src/semantics/inference/types_inferencer.py | 1 - src/semantics/tools/type.py | 7 ++-- src/test.cl | 36 +++++++++++++-------- tests/semantic/case1.cl | 3 +- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 3bb5f9278..7e50f38ff 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -38,10 +38,10 @@ def run_pipeline(program_ast): hard_ast = hard.visit(soft_ast) errors += hard.errors - if len(errors) > 0: - s = format_errors(errors) - print(s) - exit(1) + # if len(errors) > 0: + # s = format_errors(errors) + # print(s) + # exit(1) back = BackInferencer(context) back_ast = back.visit(hard_ast) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 727824fca..9608d17c1 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,4 +1,3 @@ -import types from semantics.tools.type import ErrorType from utils import visitor diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index bcb055e62..a2ef3eb3b 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -332,9 +332,9 @@ def remove_self_type(self, remove_type): def generate_name(self): # TODO: Cuando se tiene en el type_set un SelfType() y no hay nada en head explota - # if len(self.type_set) == 1: - # self.name = self.heads[0].name - # return self.name + if len(self.type_set) == 1: + self.name = self.heads[0].name + return self.name s = "{" s += ", ".join( @@ -566,6 +566,7 @@ def unify(a: TypeBag, b: TypeBag) -> None: for type1 in a.type_set: for type2 in b.type_set: if type1.name == type2.name: + # TODO: Mejorar la interseccion # if type1.conforms_to(type2) or type2.conforms_to(type1): intersection.add(type1) diff --git a/src/test.cl b/src/test.cl index ed529815c..82c6a4d61 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,13 +1,23 @@ ---The static types of the two sub-expressions must be Int. - -class Main { - a : AUTO_TYPE <- 12; --- hola(b: Int): AUTO_TYPE {b}; - main(): AUTO_TYPE { - { --- hola(a); --- a; - self; - } - }; -}; +--For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: B <- case 0 of + b: Bool => new F; + i: Int => new E; + esac; +}; diff --git a/tests/semantic/case1.cl b/tests/semantic/case1.cl index e228e7703..82c6a4d61 100644 --- a/tests/semantic/case1.cl +++ b/tests/semantic/case1.cl @@ -17,8 +17,7 @@ class Main inherits IO { esac; test: B <- case 0 of - b - : Bool => new F; + b: Bool => new F; i: Int => new E; esac; }; From 684d308c664800d6926391fab226aba20e61f9a2 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 27 Apr 2021 12:48:51 -0400 Subject: [PATCH 113/432] Minor change in SoftInferencer --- src/debbuging/tests/Auto/case2.cl | 4 +++- src/semantics/inference/soft_inferencer.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/debbuging/tests/Auto/case2.cl b/src/debbuging/tests/Auto/case2.cl index aab5f0a2b..5bc1464a3 100644 --- a/src/debbuging/tests/Auto/case2.cl +++ b/src/debbuging/tests/Auto/case2.cl @@ -3,7 +3,9 @@ En este ejemplo se muestra como en la primera etapa de el inferenciador se manej *) class Main inherits IO { - main(a : AUTO_TYPE, b : AUTO_TYPE) : AUTO_TYPE { + a : AUTO_TYPE; b : AUTO_TYPE; + + main() : AUTO_TYPE { { if b then not b else a fi; case 3 + 5 of diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index ac3a211e0..3b2de6b6e 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -366,7 +366,7 @@ def visit(self, node, scope): caller_type = TypeBag({self.current_type}) elif node.type is None: expr_node = self.visit(node.expr, scope) - caller_type = expr_node.inferenced_type.clone() + caller_type = expr_node.inferenced_type else: try: caller_type = self.context.get_type( From 7003aaa767aaa8624f6c740da9c6a8603a2c156d Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Wed, 28 Apr 2021 19:57:04 -0400 Subject: [PATCH 114/432] Commit before push to master --- src/__main__.py | 2 +- src/ast/inferencer_ast.py | 1 - src/semantics/inference/back_inferencer.py | 9 ++++---- src/test.cl | 27 ++++------------------ 4 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 0c76613b3..3d1bf3bdf 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -64,7 +64,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests/Auto/point2.cl" + input_file = "src/test.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/ast/inferencer_ast.py b/src/ast/inferencer_ast.py index 95aca1301..bcaa007e1 100644 --- a/src/ast/inferencer_ast.py +++ b/src/ast/inferencer_ast.py @@ -44,7 +44,6 @@ class MethodDeclarationNode(DeclarationNode): def __init__(self, params, return_type, body, node): Node.__init__(self, node) self.id = node.id - # this is a patch, the ideal is to recv a copy of the params self.params: List[VarDeclarationNode] = params self.type = return_type self.body = body diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 98f0ac3a9..91a30996c 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -68,6 +68,7 @@ def visit(self, node, scope): attr_node = AttrDeclarationNode(node) if not node.expr: + attr_node.inferenced_type = node.inferenced_type return attr_node expr_node = self.visit(node.expr, scope) @@ -120,12 +121,12 @@ def visit(self, node: ConditionalNode, scope) -> ConditionalNode: new_then_node = self.visit(node.then_body, scope) new_else_node = self.visit(node.else_body, scope) - join_type = join( - new_condition_node.inferenced_type, new_else_node.inferenced_type - ) + join_type = join(new_then_node.inferenced_type, new_else_node.inferenced_type) decl_type = node.inferenced_type expr_type = join_type - new_node = ConditionalNode(new_then_node, new_then_node, new_else_node, node) + new_node = ConditionalNode( + new_condition_node, new_then_node, new_else_node, node + ) new_node.inferenced_type = unify(decl_type, expr_type) return new_node diff --git a/src/test.cl b/src/test.cl index 82c6a4d61..9d30decbe 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,23 +1,6 @@ ---For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- case "true" of - i: Int => New C; - b: Bool => New D; - s: String => New E; - esac; - - test: B <- case 0 of - b: Bool => new F; - i: Int => new E; - esac; -}; + n:AUTO_TYPE; + main() : AUTO_TYPE { + n + 1 + }; +}; From b16a4b1bc48d005284bb22b996ff52c8ae75855d Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Wed, 28 Apr 2021 21:44:44 -0400 Subject: [PATCH 115/432] Fix some bugs in BackInferencer --- src/__main__.py | 2 ++ src/debbuging/tests/Auto/many2.cl | 2 +- src/debbuging/tests/Auto/simple2.cl | 13 ++++++++++++ src/semantics/inference/back_inferencer.py | 8 +++++--- src/semantics/inference/types_inferencer.py | 2 +- src/semantics/tools/type.py | 22 +++++++++++++++++---- src/test.cl | 19 ++++++++++++------ 7 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 src/debbuging/tests/Auto/simple2.cl diff --git a/src/__main__.py b/src/__main__.py index 3d1bf3bdf..0707318d6 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -45,6 +45,8 @@ def run_pipeline(program_ast): back = BackInferencer(context) back_ast = back.visit(hard_ast) + back_ast = back.visit(back_ast) + back_ast = back.visit(back_ast) types = TypesInferencer() types_ast = types.visit(back_ast) diff --git a/src/debbuging/tests/Auto/many2.cl b/src/debbuging/tests/Auto/many2.cl index 0040d8760..6005716a8 100644 --- a/src/debbuging/tests/Auto/many2.cl +++ b/src/debbuging/tests/Auto/many2.cl @@ -3,7 +3,7 @@ class Main inherits IO { b : AUTO_TYPE; c : AUTO_TYPE; d : AUTO_TYPE; - main(n : AUTO_TYPE) : AUTO_TYPE { + main() : AUTO_TYPE { { a <- b; b <- c; diff --git a/src/debbuging/tests/Auto/simple2.cl b/src/debbuging/tests/Auto/simple2.cl new file mode 100644 index 000000000..17ec0ca8e --- /dev/null +++ b/src/debbuging/tests/Auto/simple2.cl @@ -0,0 +1,13 @@ +class Main { + main () : Int {0}; + + method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ + a <- e; + b <- a; + c <- b; + d <- c; + e <- f; + f <- 12; + f; + }}; +}; \ No newline at end of file diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 91a30996c..0d14ca8cd 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -184,7 +184,7 @@ def visit(self, node: LetNode, scope) -> LetNode: def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: scope.define_variable( - node.id, node.inferenced_type.swap_self_type(self.current_type) + node.id, node.inferenced_type #.swap_self_type(self.current_type) ) new_node = VarDeclarationNode(node) @@ -203,9 +203,11 @@ def visit(self, node: AssignNode, scope) -> AssignNode: new_expr_node = self.visit(node.expr, scope) if node.defined: decl_type = scope.find_variable(node.id).get_type() - decl_type = node.inferenced_type + else: + decl_type = new_expr_node.inferenced_type expr_type = new_expr_node.inferenced_type new_node = AssignNode(new_expr_node, node) + new_node.defined = node.defined new_node.inferenced_type = unify(decl_type, expr_type) return new_node @@ -255,7 +257,7 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: return new_node @visitor.when(InstantiateNode) - def visit(self, node: InstantiateNode, scope) -> InstantiateNode: + def visit(self, node, scope) -> InstantiateNode: return deepcopy(node) @visitor.when(IntNode) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index bffa3aff4..9e9c97538 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -177,7 +177,7 @@ def visit(self, node: ComplementNode) -> types_ast.ComplementNode: return new_node @visitor.when(BinaryNode) - def visit(self, node: EqualsNode) -> types_ast.PlusNode: + def visit(self, node) -> types_ast.BinaryNode: left = self.visit(node.left) right = self.visit(node.right) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 633e5f32a..40379c924 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -567,10 +567,24 @@ def unify(a: TypeBag, b: TypeBag) -> None: if type1.name == type2.name: # TODO: Mejorar la interseccion # if type1.conforms_to(type2) or type2.conforms_to(type1): - intersection.add(type1) - - a.type_set = intersection + intersection.add(type1.name) + to_remove = [] + for typex in a.type_set: + if typex.name not in intersection: + to_remove.append(typex) + for typex in to_remove: + a.type_set.remove(typex) + + to_remove = [] + for typex in b.type_set: + if typex.name not in intersection: + to_remove.append(typex) + for typex in to_remove: + b.type_set.remove(typex) + + + # a.type_set = intersection a.update_heads() - b.type_set = intersection + # b.type_set = intersection b.update_heads() return a \ No newline at end of file diff --git a/src/test.cl b/src/test.cl index 9d30decbe..17ec0ca8e 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,6 +1,13 @@ -class Main inherits IO { - n:AUTO_TYPE; - main() : AUTO_TYPE { - n + 1 - }; -}; +class Main { + main () : Int {0}; + + method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ + a <- e; + b <- a; + c <- b; + d <- c; + e <- f; + f <- 12; + f; + }}; +}; \ No newline at end of file From 986a751a8a79e247a2fa304539c6f4ef6b17c168 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 29 Apr 2021 02:28:11 -0400 Subject: [PATCH 116/432] Fix minor bugs in BackInferencer --- src/__main__.py | 1 + src/semantics/inference/back_inferencer.py | 15 +++----- src/semantics/tools/type.py | 41 ++++++++++------------ src/test.cl | 6 ++-- 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 0707318d6..921966740 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -47,6 +47,7 @@ def run_pipeline(program_ast): back_ast = back.visit(hard_ast) back_ast = back.visit(back_ast) back_ast = back.visit(back_ast) + back_ast = back.visit(back_ast) types = TypesInferencer() types_ast = types.visit(back_ast) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 0d14ca8cd..4634b512c 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -86,14 +86,14 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: scope = scope.create_child() current_method: 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) - new_params = [] for param in node.params: new_params.append(self.visit(param, scope)) - current_method.param_types = [param.inferenced_type for param in new_params] + current_method.param_types = [ + unify(new_param.inferenced_type, typex) + for new_param, typex in zip(new_params, current_method.param_types) + ] new_body_node = self.visit(node.body, scope) body_type = new_body_node.inferenced_type.swap_self_type(self.current_type) @@ -184,7 +184,7 @@ def visit(self, node: LetNode, scope) -> LetNode: def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: scope.define_variable( - node.id, node.inferenced_type #.swap_self_type(self.current_type) + node.id, node.inferenced_type.swap_self_type(self.current_type) ) new_node = VarDeclarationNode(node) @@ -271,8 +271,3 @@ def visit(self, node, scope) -> StringNode: @visitor.when(BooleanNode) def visit(self, node, scope) -> BooleanNode: return deepcopy(node) - - # Este metodo deber ser innecesario pues todos los errores son recogidos previamente - def add_error(self, node: Node, text: str): - line, col = node.get_position() if node is not None else (0, 0) - self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 40379c924..02f33bf8d 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -350,6 +350,16 @@ def clone(self): clone.conform_list = self.conform_list.copy() return clone + def update(self, other): + self.name = other.name + self.condition_list = other.condition_list + self.conform_list = other.conform_list + self.type_set = other.type_set + self.heads = other.heads + + + + def __str__(self): return self.name @@ -560,31 +570,16 @@ def from_dict_to_set(types: dict): return type_set -def unify(a: TypeBag, b: TypeBag) -> None: +def unify(a: TypeBag, b: TypeBag) -> TypeBag: intersection = set() for type1 in a.type_set: for type2 in b.type_set: - if type1.name == type2.name: - # TODO: Mejorar la interseccion - # if type1.conforms_to(type2) or type2.conforms_to(type1): - intersection.add(type1.name) - to_remove = [] - for typex in a.type_set: - if typex.name not in intersection: - to_remove.append(typex) - for typex in to_remove: - a.type_set.remove(typex) - - to_remove = [] - for typex in b.type_set: - if typex.name not in intersection: - to_remove.append(typex) - for typex in to_remove: - b.type_set.remove(typex) - - - # a.type_set = intersection + if type1.name == type2.name: + intersection.add(type1) + + a.type_set = intersection a.update_heads() - # b.type_set = intersection + b.type_set = intersection b.update_heads() - return a \ No newline at end of file + return a + diff --git a/src/test.cl b/src/test.cl index 17ec0ca8e..784b4afc0 100644 --- a/src/test.cl +++ b/src/test.cl @@ -1,13 +1,13 @@ class Main { - main () : Int {0}; + -- main () : AUTO_TYPE { method(1,2,3,4,5,6) }; + main(): Int {0}; - method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ + method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): Int{{ a <- e; b <- a; c <- b; d <- c; e <- f; - f <- 12; f; }}; }; \ No newline at end of file From 22c2f6fe0a75e88ac43ea491882a59e324de25c5 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 29 Apr 2021 12:04:33 -0400 Subject: [PATCH 117/432] Add new Auto test case --- src/debbuging/tests/Auto/simple3.cl | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/debbuging/tests/Auto/simple3.cl diff --git a/src/debbuging/tests/Auto/simple3.cl b/src/debbuging/tests/Auto/simple3.cl new file mode 100644 index 000000000..bd31a67ea --- /dev/null +++ b/src/debbuging/tests/Auto/simple3.cl @@ -0,0 +1,13 @@ +class Main { + main () : Int {0}; + + method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ + a <- e; + b <- a; + c <- b; + d <- c; + e <- f; + d <- "Test"; + f <- 12; + }}; +}; From 12042582aee269db2c354b0fdf3468db4fce6429 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 29 Apr 2021 12:06:25 -0400 Subject: [PATCH 118/432] Minor changes --- src/__main__.py | 17 +++++++++++++---- src/semantics/inference/hard_inferencer.py | 4 ++-- src/semantics/inference/types_inferencer.py | 4 ++-- src/semantics/tools/scope.py | 4 ++-- src/semantics/tools/type.py | 21 ++++++++++----------- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 0707318d6..b537c9ec1 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -9,6 +9,7 @@ HardInferencer, BackInferencer, TypesInferencer, + types_inferencer, ) @@ -45,28 +46,36 @@ def run_pipeline(program_ast): back = BackInferencer(context) back_ast = back.visit(hard_ast) + # back_ast = hard.visit(back_ast) back_ast = back.visit(back_ast) + # back_ast = hard.visit(back_ast) back_ast = back.visit(back_ast) + # back_ast = hard.visit(back_ast) + # back_ast = back.visit(back_ast) + # back_ast = back.visit(back_ast) + # back_ast = back.visit(back_ast) types = TypesInferencer() types_ast = types.visit(back_ast) errors += types.errors - # logger = TypeLogger(context) - # log = logger.visit(back_ast, back_ast.scope) - # print(log) + logger = TypeLogger(context) + log = logger.visit(back_ast, back_ast.scope) + print(log) if len(errors) > 0: s = format_errors(errors) print(s) exit(1) + return types_ast + def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/test.cl" + input_file = "src/debbuging/tests/Auto/simple3.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index ea54226fd..22146abe0 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -95,14 +95,14 @@ def visit(self, node, scope): if equal(expr_type, node.expr.inferenced_type): return attr_node - expr_clone = expr_type.clone() + expr_name = expr_type.generate_name() node_type = attr_node.inferenced_type if not conforms(expr_type, attr_node.inferenced_type): self.add_error( node, ( f"TypeError: In class '{self.current_type.name}' attribue" - f"'{node.id}' expression type({expr_clone.name}) does not conforms" + f"'{node.id}' expression type({expr_name}) does not conforms" f"to declared type ({node_type.name})." ), ) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 9e9c97538..a4e2106d1 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -225,10 +225,10 @@ def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: def _reduce_to_type(self, bag: TypeBag, node: Node): if len(bag.heads) > 1: - self.add_error(node, "ErrorType: Ambiguous type declaration") + self.add_error(node, f"TypeError: Ambiguous type declaration, multiple values {bag.generate_name()}") return ErrorType() if len(bag.heads) == 0: - self.add_error(node, "ErrorType: Cannot infer type") + self.add_error(node, "TypeError: Cannot infer type") return ErrorType() return bag.heads[0] diff --git a/src/semantics/tools/scope.py b/src/semantics/tools/scope.py index 6bf85c39b..236e7b0bc 100644 --- a/src/semantics/tools/scope.py +++ b/src/semantics/tools/scope.py @@ -8,8 +8,8 @@ def __init__(self, name, vtype) -> None: self.type: TypeBag = vtype def get_type(self) -> TypeBag or ErrorType: - if len(self.type.type_set) == 0: - self.type = ErrorType() + # if len(self.type.type_set) == 0: + # self.type = ErrorType() return self.type def __str__(self): diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 40379c924..15b05825c 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -257,6 +257,10 @@ def __init__(self, type_set, heads=[]) -> None: self.conform_list = [] self.generate_name() + @property + def error_type(self): + return len(self.heads) > 0 + def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list @@ -306,13 +310,6 @@ def swap_self_type(self, swap_type, back=False): except KeyError: return self - # for i in range(len(self.heads)): - # typex = self.heads[i] - # if typex.name == remove_type.name: - # self.heads[i] = add_type - # break - # - # self.generate_name() self.update_heads() return self @@ -331,7 +328,10 @@ def remove_self_type(self, remove_type): self.update_heads() def generate_name(self): - # TODO: Cuando se tiene en el type_set un SelfType() y no hay nada en head explota + if self.error_type: + self.name = "" + return self.name + if len(self.type_set) == 1: self.name = self.heads[0].name return self.name @@ -564,9 +564,9 @@ def unify(a: TypeBag, b: TypeBag) -> None: intersection = set() for type1 in a.type_set: for type2 in b.type_set: - if type1.name == type2.name: + if type1.name == type2.name: # TODO: Mejorar la interseccion - # if type1.conforms_to(type2) or type2.conforms_to(type1): + # if type1.conforms_to(type2) or type2.conforms_to(type1): intersection.add(type1.name) to_remove = [] for typex in a.type_set: @@ -581,7 +581,6 @@ def unify(a: TypeBag, b: TypeBag) -> None: to_remove.append(typex) for typex in to_remove: b.type_set.remove(typex) - # a.type_set = intersection a.update_heads() From 3814b7dc6c16ed9636b5587cc79326c79a01e943 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 29 Apr 2021 12:14:34 -0400 Subject: [PATCH 119/432] Fix bug in BackInferencer related to AST's scope --- src/semantics/inference/back_inferencer.py | 19 +++++++++---------- src/test.cl | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 4634b512c..6eb6abc53 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,4 +1,4 @@ -from copy import deepcopy +from copy import copy, deepcopy from semantics.tools.type import Method, Type from semantics.tools import Context, Scope, TypeBag, join, join_list, unify @@ -43,12 +43,11 @@ def visit(self, node, scope): @visitor.when(ProgramNode) def visit(self, node: ProgramNode) -> ProgramNode: - scope: Scope = node.scope + scope = Scope() new_declaration = [] for declaration in node.declarations: - new_declaration.append(self.visit(declaration, scope.next_child())) + new_declaration.append(self.visit(declaration, scope.create_child())) - scope.reset() program = ProgramNode(new_declaration, scope, node) return program @@ -240,7 +239,7 @@ def visit(self, node: BinaryNode, scope) -> BinaryNode: @visitor.when(UnaryNode) def visit(self, node: UnaryNode, scope) -> UnaryNode: - new_node = deepcopy(node) + new_node = copy(node) new_expr_node = self.visit(node.expr, scope) new_node.expr = new_expr_node @@ -248,7 +247,7 @@ def visit(self, node: UnaryNode, scope) -> UnaryNode: @visitor.when(VariableNode) def visit(self, node: VariableNode, scope: Scope) -> VariableNode: - new_node = deepcopy(node) + new_node = copy(node) if node.defined: decl_type = node.inferenced_type.swap_self_type(self.current_type) expr_type = scope.find_variable(node.value).get_type() @@ -258,16 +257,16 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: @visitor.when(InstantiateNode) def visit(self, node, scope) -> InstantiateNode: - return deepcopy(node) + return copy(node) @visitor.when(IntNode) def visit(self, node, scope) -> IntNode: - return deepcopy(node) + return copy(node) @visitor.when(StringNode) def visit(self, node, scope) -> StringNode: - return deepcopy(node) + return copy(node) @visitor.when(BooleanNode) def visit(self, node, scope) -> BooleanNode: - return deepcopy(node) + return copy(node) diff --git a/src/test.cl b/src/test.cl index 784b4afc0..23b0326d6 100644 --- a/src/test.cl +++ b/src/test.cl @@ -2,12 +2,12 @@ class Main { -- main () : AUTO_TYPE { method(1,2,3,4,5,6) }; main(): Int {0}; - method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): Int{{ + method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ a <- e; b <- a; c <- b; d <- c; e <- f; - f; + f <- 12; }}; }; \ No newline at end of file From 5e15045217384b74e978eb85aed65d5d5c84be00 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 29 Apr 2021 12:17:28 -0400 Subject: [PATCH 120/432] Change deepcopy for copy in BackInferencer --- src/semantics/inference/back_inferencer.py | 2 +- src/test.cl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 6eb6abc53..ec2b56c92 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -228,7 +228,7 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: @visitor.when(BinaryNode) def visit(self, node: BinaryNode, scope) -> BinaryNode: - new_node = deepcopy(node) + new_node = copy(node) new_left_node = self.visit(node.left, scope) new_right_node = self.visit(node.right, scope) diff --git a/src/test.cl b/src/test.cl index 23b0326d6..febe48b82 100644 --- a/src/test.cl +++ b/src/test.cl @@ -8,6 +8,6 @@ class Main { c <- b; d <- c; e <- f; - f <- 12; + f + 12; }}; }; \ No newline at end of file From cd05812cbdea4b35b21b9c547f02fc9f3d641c9a Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 29 Apr 2021 21:14:21 -0400 Subject: [PATCH 121/432] Updated TypeBag to function as ErrorType --- src/semantics/tools/type.py | 66 ++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 15b05825c..432354c1b 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -1,5 +1,5 @@ from semantics.tools.errors import * -from typing import Set +from typing import List, Set from collections import OrderedDict @@ -248,32 +248,40 @@ def __init__(self, type_set, heads=[]) -> None: self.type_set: set = ( type_set if isinstance(type_set, set) else from_dict_to_set(type_set) ) - self.heads: list = heads + self.heads: List[Type] = heads if len(self.type_set) == 1: self.heads = list(self.type_set) - self.name = "undefined" self.condition_list = [] self.conform_list = [] - self.generate_name() @property - def error_type(self): - return len(self.heads) > 0 + def error_type(self) -> bool: + return len(self.heads) == 0 + + @property + def name(self) -> str: + return self.generate_name() + + def set_conditions(self, condition_list, conform_list) -> None: + if self.error_type: + return - def set_conditions(self, condition_list, conform_list): self.condition_list = condition_list self.conform_list = conform_list - self.update_type_set_from_conforms() + self.__update_type_set_from_conforms() - def update_type_set_from_conforms(self): + def __update_type_set_from_conforms(self) -> None: intersect_set = set() for conform_set in self.conform_list: intersect_set = intersect_set.union(conform_set) self.type_set = self.type_set.intersection(intersect_set) self.update_heads() - def update_heads(self): + def update_heads(self) -> None: + if self.error_type: + return + new_heads = [] visited = set() for head in self.heads: @@ -285,6 +293,7 @@ def update_heads(self): for typex in self.type_set: if typex in visited: continue + # if typex.conforms_to(head): visited.add(typex) if typex.index < lower_index: @@ -294,9 +303,11 @@ def update_heads(self): pos_new_head.append(typex) new_heads += pos_new_head self.heads = new_heads - self.generate_name() def swap_self_type(self, swap_type, back=False): + if self.error_type: + return + if not back: remove_type = SelfType() add_type = swap_type @@ -311,15 +322,19 @@ def swap_self_type(self, swap_type, back=False): return self self.update_heads() - return self def add_self_type(self, add_type) -> bool: + if self.error_type: + return False + if SelfType() in self.type_set and not add_type in self.type_set: self.type_set.add(add_type) return True return False - def remove_self_type(self, remove_type): + def remove_self_type(self, remove_type) -> None: + if self.error_type: + return try: self.type_set.remove(remove_type) except KeyError: @@ -327,21 +342,19 @@ def remove_self_type(self, remove_type): self.type_set.add(SelfType()) self.update_heads() - def generate_name(self): + def generate_name(self) -> str: if self.error_type: - self.name = "" - return self.name + return "" if len(self.type_set) == 1: - self.name = self.heads[0].name - return self.name + name = self.heads[0].name + return name s = "{" s += ", ".join( typex.name for typex in sorted(self.type_set, key=lambda t: t.index) ) s += "}" - self.name = s return s def clone(self): @@ -413,6 +426,9 @@ def clone(self): def conforms(bag1: TypeBag, bag2: TypeBag) -> bool: if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + raise InternalError("Use of deprecated ErrorType in conforms") + + if bag1.error_type or bag2.error_type: return True ordered_set = order_set_by_index(bag2.type_set) @@ -444,9 +460,12 @@ def try_conform(bag1: TypeBag, bag2: TypeBag) -> TypeBag: def join(bag1: TypeBag, bag2: TypeBag) -> TypeBag: - if isinstance(bag1, ErrorType): + if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + raise InternalError("Use of deprecated ErrorType in Join") + + if bag1.error_type: return bag2 - if isinstance(bag2, ErrorType): + if bag2.error_type: return bag1 ancestor_set = set() @@ -493,7 +512,10 @@ def join_list(type_list): def equal(bag1: TypeBag, bag2: TypeBag): if isinstance(bag1, ErrorType) or isinstance(bag2, ErrorType): + raise InternalError("Use of deprecated type ErrorType") + if bag1.error_type or bag2.error_type: return True + set1 = bag1.type_set set2 = bag2.type_set return len(set1) == len(set2) and len(set1.intersection(set2)) == len(set2) @@ -518,7 +540,7 @@ def smart_add(type_set: set, head_list: list, typex: Type): return type_set -def auto_add(type_set: set, head_list: list, bag: TypeBag): +def auto_add(type_set: set, head_list: List[TypeBag], bag: TypeBag): type_set = type_set.union(bag.type_set) aux = set(bag.heads) for i in range(len(head_list)): From 966759d5a713dd03a6a2fd0f63997d9604c81b24 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 29 Apr 2021 21:15:06 -0400 Subject: [PATCH 122/432] Update SofInferencer and HardInferecer to not use ErrorTypes --- src/semantics/inference/hard_inferencer.py | 31 +++++----------------- src/semantics/inference/soft_inferencer.py | 31 ++++------------------ 2 files changed, 12 insertions(+), 50 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 22146abe0..a64444251 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -35,7 +35,6 @@ from utils import visitor from semantics.tools import ( Context, - ErrorType, Scope, SelfType, TypeBag, @@ -106,7 +105,6 @@ def visit(self, node, scope): f"to declared type ({node_type.name})." ), ) - expr_node.inferenced_type = ErrorType() return attr_node @@ -140,7 +138,6 @@ def visit(self, node, scopex: Scope): f"'{method_node.id}' return expression type({body_name})" f" does not conforms to declared return type ({node_type.name})", ) - body_node.inferenced_type = ErrorType() return method_node @@ -170,7 +167,6 @@ def visit(self, node, scope): f"TypeError: If's condition type({condition_clone.name})" " does not conforms to Bool type.", ) - condition_node.inferenced_type = ErrorType() if_node = ConditionalNode(condition_node, then_node, else_node, node) @@ -223,7 +219,6 @@ def visit(self, node, scope): f"TypeError: Loop condition type({condition_clone.name})" " does not conforms to Bool type.", ) - condition_node.inferenced_type = ErrorType() body_node = self.visit(node.body, scope) loop_node = LoopNode(condition_node, body_node, node) @@ -267,7 +262,6 @@ def visit(self, node, scope: Scope): f" ({expr_clone.name}) does not conforms to declared" f" type({node_type.name}).", ) - expr_node.inferenced_type = ErrorType() var_decl_node.inferenced_type = expr_node.inferenced_type return var_decl_node @@ -278,7 +272,6 @@ def visit(self, node, scope: Scope): assign_node = AssignNode(expr_node, node) if not node.defined or node.id == "self": - assign_node.inferenced_type = ErrorType() return assign_node assign_node.defined = True @@ -294,7 +287,6 @@ def visit(self, node, scope: Scope): f" Expression type({expr_clone.name}) does not conforms to" f" declared type ({decl_type.name}).", ) - expr_node.inferenced_type = ErrorType() assign_node.inferenced_type = expr_node.inferenced_type return assign_node @@ -315,7 +307,6 @@ def visit(self, node, scope): f" type({expr_clone.name}) does not conforms to " f" caller type({caller_type.name}).", ) - caller_type = ErrorType() elif node.expr is not None: expr_node = self.visit(node.expr, scope) caller_type = expr_node.inferenced_type @@ -332,18 +323,16 @@ def visit(self, node, scope): error += " -Found in: " error += ", ".join(typex.name for typex in caller_type.heads) self.add_error(node, error) - caller_type = ErrorType() elif len(caller_type.heads) == 0: self.add_error( node, f" SemanticError: There is no method called {node.id} which takes" f" {len(node.args)} paramters.", ) - caller_type = ErrorType() if len(caller_type.heads) != 1: new_args = [] - infered_type = ErrorType() + infered_type = TypeBag(set()) else: caller = caller_type.heads[0] caller = self.current_type if isinstance(caller, SelfType) else caller @@ -352,7 +341,7 @@ def visit(self, node, scope): except AttributeError as err: # self.add_error(node, err.text) Error notified in soft inferencer new_args = [] - infered_type = ErrorType() + infered_type = TypeBag(set()) else: if len(node.args) != len(method.param_types): self.add_error( @@ -361,7 +350,6 @@ def visit(self, node, scope): f"'{caller_type.name}' takes {len(method.param_types)}" f" positional arguments but {len(node.args)} were given.'", ) - node.inferenced_type = ErrorType() decl_return_type = method.return_type.clone() decl_return_type.swap_self_type(caller) @@ -434,7 +422,6 @@ def visit(self, node, scope): def visit(self, node, scope: Scope): var_node = VariableNode(node) if not node.defined: - var_node.inferenced_type = ErrorType() return var_node var_node.defined = True @@ -455,7 +442,6 @@ def visit(self, node, scope): f"TypeError: Not's expresion type({expr_clone.name} does not" " conforms to Bool type", ) - expr_node.inferenced_type = ErrorType() not_node = NotNode(expr_node, node) not_node.inferenced_type = bool_type @@ -474,7 +460,6 @@ def visit(self, node, scope): f"TypeError: ~ expresion type({expr_clone.name} does not" " conforms to Int type", ) - expr_node.inferenced_type = ErrorType() complement_node = ComplementNode(expr_node, node) complement_node.inferenced_type = int_type @@ -572,7 +557,6 @@ def __conform_to_type(self, node: Node, bag: TypeBag): f"TypeError: Equal Node: Expression type({node_name})" f"does not conforms to expression({bag.name})", ) - node.inferenced_type = ErrorType() def __arithmetic_operation(self, node, scope): left_node = self.visit(node.left, scope) @@ -590,22 +574,21 @@ def __arithmetic_operation(self, node, scope): f"TypeError: Arithmetic Error: Left member type({left_clone.name})" "does not conforms to Int type.", ) - left_node.inferenced_type = ErrorType() + if not equal(right_type, node.right.inferenced_type): right_clone = right_type.clone() if not conforms(right_type, int_type): self.add_error( node.right, - f"Type Error: Arithmetic Error: Right member " + f"TypeError: Arithmetic Error: Right member " f"type({right_clone.name})does not conforms to Int type.", ) - right_node.inferenced_type = ErrorType() return left_node, right_node def __unrelated_types(self, node): - typex = node.inferenced_type - if isinstance(typex, ErrorType): + typex: TypeBag = node.inferenced_type + if typex.error_type: return True if len(typex.heads) > 1: self.add_error( @@ -614,6 +597,6 @@ def __unrelated_types(self, node): + ", ".join(typez.name for typez in typex.heads), +"}", ) - node.inferenced_type = ErrorType() + node.inferenced_type = TypeBag(set()) return True return False \ No newline at end of file diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 3b2de6b6e..7e0c85b1b 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -1,4 +1,5 @@ from inspect import currentframe +from typing import Type import ast.inferencer_ast as inf_ast from ast.parser_ast import ( ArithmeticNode, @@ -38,7 +39,6 @@ from semantics.tools.errors import SemanticError, AttributeError from semantics.tools import ( Context, - ErrorType, Scope, SelfType, TypeBag, @@ -111,7 +111,6 @@ def visit(self, node, scope): f" to declared type ({node_type.name})." ), ) - expr_node.inferenced_type = ErrorType() if added_type: expr_type.remove_self_type(self.current_type) @@ -144,7 +143,6 @@ def visit(self, node, scopex: Scope): f" '{current_method.name}' return expression type({ret_expr_name})" f" does not conforms to declared return type ({ret_type_decl.name})", ) - body_node.inferenced_type = ErrorType() if added_self: ret_type_expr.remove_self_type(self.current_type) @@ -179,7 +177,6 @@ def visit(self, node, scope): f"TypeError: If's condition type({condition_clone.name})" " does not conforms to Bool type.", ) - condition_node.inferenced_type = ErrorType() then_node = self.visit(node.then_body, scope) else_node = self.visit(node.else_body, scope) @@ -205,9 +202,7 @@ def visit(self, node, scope: Scope): new_options.append(self.visit(option, child)) type_list.append(new_options[-1].inferenced_type) var_type = child.find_variable(option.id).get_type() - var_type = ( - var_type.heads[0] if not isinstance(var_type, ErrorType) else var_type - ) + var_type = var_type.heads[0] if not var_type.error_type else var_type if var_type in types_visited: self.add_error( option, @@ -230,7 +225,6 @@ def visit(self, node, scope: Scope): self.add_error( node, err.text + f" While defining Case Option variable {node.id}." ) - node_type = ErrorType() scope.define_variable(node.id, node_type) expr_node = self.visit(node.expr, scope) @@ -252,7 +246,6 @@ def visit(self, node, scope): f"TypeError: Loop condition type({condition_clone.name})" " does not conforms to Bool type.", ) - condition_node.inferenced_type = ErrorType() body_node = self.visit(node.body, scope) loop_node = inf_ast.LoopNode(condition_node, body_node, node) @@ -280,7 +273,7 @@ def visit(self, node, scope: Scope): try: node_type = self.context.get_type(node.type) except SemanticError as err: - node_type = ErrorType() + node_type = TypeBag(set(), []) self.add_error(node, err.text) if node.id == "self": @@ -307,12 +300,10 @@ def visit(self, node, scope: Scope): f" ({expr_clone.name}) does not conforms to declared" f" type({node_type.name}).", ) - expr_node.inferenced_type = ErrorType() if added_type: expr_type.remove_self_type(self.current_type) var_decl_node.expr = expr_node var_decl_node.inferenced_type = expr_node.inferenced_type - # var.type = var_decl_node.inferenced_type return var_decl_node @@ -328,7 +319,6 @@ def visit(self, node, scope: Scope): f"SemanticError: Cannot assign new value to" f"{node.id} beacuse it is not defined in the current scope", ) - decl_type = ErrorType() else: decl_type = var.get_type() assign_node.defined = True @@ -340,7 +330,6 @@ def visit(self, node, scope: Scope): "SemanticError: Cannot assign new value. " "Variable 'self' is Read-Only.", ) - decl_type = ErrorType() expr_type: TypeBag = expr_node.inferenced_type added_type = expr_type.add_self_type(self.current_type) @@ -352,7 +341,6 @@ def visit(self, node, scope: Scope): f" expression type({expr_clone.name}) does not conforms to" f" declared type ({decl_type.name}).", ) - expr_node.inferenced_type = ErrorType() if added_type: expr_type.remove_self_type(self.current_type) @@ -374,7 +362,6 @@ def visit(self, node, scope): ) except SemanticError as err: self.add_error(node, err + " While setting dispatch caller.") - caller_type = ErrorType() expr_node = self.visit(node.expr, scope) expr_type = expr_node.inferenced_type @@ -387,7 +374,6 @@ def visit(self, node, scope): f" type({expr_name}) does not conforms to" f" caller type({caller_type.name}).", ) - caller_type = ErrorType() if added_type: expr_type.remove_self_type(self.current_type) @@ -407,7 +393,6 @@ def visit(self, node, scope): f" that recieves {len(node.params)} arguments in" f" types {caller_type.name}.", ) - caller_type = ErrorType() elif len(caller_type.type_set) == 1: caller = caller_type.heads[0] caller = self.current_type if isinstance(caller, SelfType) else caller @@ -418,7 +403,6 @@ def visit(self, node, scope): node, err.text, ) - caller_type = ErrorType() new_args = [] for i in range(len(node.args)): @@ -438,7 +422,7 @@ def visit(self, node, scope): method_call_node.inferenced_type = TypeBag(type_set, heads) else: # Errors already notified previuosly - method_call_node.inferenced_type = ErrorType() + method_call_node.inferenced_type = TypeBag(set()) # ErrorType return method_call_node @@ -488,7 +472,6 @@ def visit(self, node, scope: Scope): var_node.defined = True var_type = var.get_type() else: - var_type = ErrorType() self.add_error(node, f"NameError: Variable '{node.value}' is not defined.") var_node.inferenced_type = var_type return var_node @@ -506,7 +489,6 @@ def visit(self, node, scope): f"TypeError: Not's expresion type ({expr_clone.name} does not" " conforms to Bool type", ) - expr_node.inferenced_type = ErrorType() not_node = inf_ast.NotNode(expr_node, node) not_node.inferenced_type = bool_type @@ -525,7 +507,6 @@ def visit(self, node, scope): f"TypeError: ~ expresion type({expr_clone.name}) does not" " conforms to Int type", ) - expr_node.inferenced_type = ErrorType() complement_node = inf_ast.ComplementNode(expr_node, node) complement_node.inferenced_type = int_type @@ -548,7 +529,7 @@ def visit(self, node, scope): node, err.text + f" Could not instantiate type '{node.value}'.", ) - node_type = ErrorType() + instantiate_node.inferenced_type = node_type return instantiate_node @@ -586,14 +567,12 @@ def __arithmetic_operation(self, node, scope): f"TypeError: ArithmeticError: Left member type({left_clone.name})" " does not conforms to Int type.", ) - left_node.inferenced_type = ErrorType() if not conforms(right_type, int_type): self.add_error( node.right, f"TypeError: ArithmeticError: Right member type({right_clone.name})" " does not conforms to Int type.", ) - right_node.inferenced_type = ErrorType() return left_node, right_node def add_error(self, node: Node, text: str): From 4f1db985fcf977757538bc16a7f46e7b9e157407 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Thu, 29 Apr 2021 21:15:20 -0400 Subject: [PATCH 123/432] Minor Fixes --- src/__main__.py | 30 ++++++++++----------- src/semantics/inference/types_inferencer.py | 5 +++- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index b537c9ec1..a10af6adf 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -44,23 +44,23 @@ def run_pipeline(program_ast): print(s) exit(1) - back = BackInferencer(context) - back_ast = back.visit(hard_ast) - # back_ast = hard.visit(back_ast) - back_ast = back.visit(back_ast) - # back_ast = hard.visit(back_ast) - back_ast = back.visit(back_ast) - # back_ast = hard.visit(back_ast) + # back = BackInferencer(context) + # back_ast = back.visit(hard_ast) + ## back_ast = hard.visit(back_ast) # back_ast = back.visit(back_ast) + ## back_ast = hard.visit(back_ast) # back_ast = back.visit(back_ast) - # back_ast = back.visit(back_ast) - - types = TypesInferencer() - types_ast = types.visit(back_ast) - errors += types.errors + ## back_ast = hard.visit(back_ast) + ## back_ast = back.visit(back_ast) + ## back_ast = back.visit(back_ast) + ## back_ast = back.visit(back_ast) + # + # types = TypesInferencer() + # types_ast = types.visit(back_ast) + # errors += types.errors logger = TypeLogger(context) - log = logger.visit(back_ast, back_ast.scope) + log = logger.visit(hard_ast, hard_ast.scope) print(log) if len(errors) > 0: @@ -68,14 +68,14 @@ def run_pipeline(program_ast): print(s) exit(1) - return types_ast + # return types_ast def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/debbuging/tests/Auto/simple3.cl" + input_file = "./debbuging/tests/Auto/simple2.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index a4e2106d1..4ca8507e7 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -225,7 +225,10 @@ def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: def _reduce_to_type(self, bag: TypeBag, node: Node): if len(bag.heads) > 1: - self.add_error(node, f"TypeError: Ambiguous type declaration, multiple values {bag.generate_name()}") + self.add_error( + node, + f"TypeError: Ambiguous type declaration, multiple values {bag.generate_name()}", + ) return ErrorType() if len(bag.heads) == 0: self.add_error(node, "TypeError: Cannot infer type") From 2529a7b4c057d99d6879a1f16c08858dfd31bd50 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sat, 1 May 2021 14:35:41 -0400 Subject: [PATCH 124/432] Small change in __main__.py --- src/__main__.py | 4 ++-- src/debbuging/tests/Auto/simple3.cl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 89024ba39..bf03a454b 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -48,7 +48,7 @@ def run_pipeline(program_ast): back_ast = back.visit(hard_ast) # back_ast = hard.visit(back_ast) back_ast = back.visit(back_ast) - # back_ast = hard.visit(back_ast) + # # back_ast = hard.visit(back_ast) back_ast = back.visit(back_ast) back_ast = back.visit(back_ast) @@ -72,7 +72,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/debbuging/tests/Auto/simple3.cl" + input_file = "src/debbuging/tests/Auto/simple2.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/debbuging/tests/Auto/simple3.cl b/src/debbuging/tests/Auto/simple3.cl index bd31a67ea..1002ddcde 100644 --- a/src/debbuging/tests/Auto/simple3.cl +++ b/src/debbuging/tests/Auto/simple3.cl @@ -7,7 +7,7 @@ class Main { c <- b; d <- c; e <- f; - d <- "Test"; + -- d <- "Test"; f <- 12; }}; }; From 12a9dbbf174a7c2644187687f7b54697389cc162 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sat, 1 May 2021 18:26:16 -0400 Subject: [PATCH 125/432] Fix bug in hard_inferencer.py --- src/semantics/inference/hard_inferencer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index a64444251..c24747c15 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -414,7 +414,7 @@ def visit(self, node, scope): self.__check_member_types(left_node, right_node) - eq_node = ComparerNode(left_node, right_node, node) + eq_node = EqualsNode(left_node, right_node, node) eq_node.inferenced_type = node.inferenced_type # Bool Type :) return eq_node From eb1c790c9f71a53a53efc0ad4c3cbfb2f111c3b4 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Sat, 1 May 2021 18:41:11 -0400 Subject: [PATCH 126/432] Make BackInferencer number of visits based on changes in the ast --- src/__main__.py | 18 +++---- src/debbuging/tests/Auto/call1.cl | 2 +- src/debbuging/tests/Auto/fibonacci.cl | 18 +++++++ src/debbuging/tests/Auto/not_that_simple.cl | 23 +++++++++ src/debbuging/tests/Auto/rec_function.cl | 10 ++++ src/debbuging/tests/Auto/simple3.cl | 4 +- src/debbuging/tests/Auto/simple4.cl | 11 ++++ src/semantics/inference/back_inferencer.py | 56 ++++++++++++++------- src/semantics/inference/types_inferencer.py | 6 +-- src/semantics/tools/type.py | 30 ++++++++--- 10 files changed, 137 insertions(+), 41 deletions(-) create mode 100644 src/debbuging/tests/Auto/fibonacci.cl create mode 100644 src/debbuging/tests/Auto/not_that_simple.cl create mode 100644 src/debbuging/tests/Auto/rec_function.cl create mode 100644 src/debbuging/tests/Auto/simple4.cl diff --git a/src/__main__.py b/src/__main__.py index 464df621e..e893b43b5 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -44,21 +44,19 @@ def run_pipeline(program_ast): print(s) exit(1) + change = True back = BackInferencer(context) - back_ast = back.visit(hard_ast) - # back_ast = hard.visit(back_ast) - back_ast = back.visit(back_ast) - # # back_ast = hard.visit(back_ast) - back_ast = back.visit(back_ast) - back_ast = back.visit(back_ast) + + while change: + back_ast, change = back.visit(hard_ast) types = TypesInferencer() types_ast = types.visit(back_ast) errors += types.errors - logger = TypeLogger(context) - log = logger.visit(hard_ast, hard_ast.scope) - print(log) + # logger = TypeLogger(context) + # log = logger.visit(hard_ast, hard_ast.scope) + # print(log) if len(errors) > 0: s = format_errors(errors) @@ -72,7 +70,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "./debbuging/tests/Auto/simple2.cl" + input_file = "src/debbuging/tests/Auto/not_that_simple.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/debbuging/tests/Auto/call1.cl b/src/debbuging/tests/Auto/call1.cl index f4ca0b5a4..b665399af 100644 --- a/src/debbuging/tests/Auto/call1.cl +++ b/src/debbuging/tests/Auto/call1.cl @@ -2,7 +2,7 @@ class Main inherits IO { main(): String { "Kabuki" - } + }; test(x : AUTO_TYPE, y : AUTO_TYPE) : AUTO_TYPE { { if true then x.me() else y.myself() fi; diff --git a/src/debbuging/tests/Auto/fibonacci.cl b/src/debbuging/tests/Auto/fibonacci.cl new file mode 100644 index 000000000..ce62a5680 --- /dev/null +++ b/src/debbuging/tests/Auto/fibonacci.cl @@ -0,0 +1,18 @@ +class Main { + main (): Int { + 1 + }; + + iterative_fibonacci(n: AUTO_TYPE) : AUTO_TYPE { + let i: AUTO_TYPE <- 2, n1: AUTO_TYPE <- 1, n2: AUTO_TYPE <- 1 in { + while i < n loop + let temp: AUTO_TYPE <- n2 in { + n2 <- n2 + n1; + n1 <- temp; + i <- i + 1; + } + pool; + n2; + } + }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/not_that_simple.cl b/src/debbuging/tests/Auto/not_that_simple.cl new file mode 100644 index 000000000..f5c989a51 --- /dev/null +++ b/src/debbuging/tests/Auto/not_that_simple.cl @@ -0,0 +1,23 @@ +class Main + { + main ( ) : Int + { { + case + { + let i: AUTO_TYPE <- 3 in + { + let i: AUTO_TYPE <- "Hola" in + { + case 5 of z: String => let i : AUTO_TYPE in + { + i<- case self of x: Int => 4; esac; + }; + esac; + }; + }; + } + of + y : AUTO_TYPE => let i: AUTO_TYPE <- y in y ; + esac ; + } } ; + } ; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/rec_function.cl b/src/debbuging/tests/Auto/rec_function.cl new file mode 100644 index 000000000..77d0095e6 --- /dev/null +++ b/src/debbuging/tests/Auto/rec_function.cl @@ -0,0 +1,10 @@ +class Main { main (): Int { 0 }; }; + +class A { + f(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE{ + if (a=1) then b else g(a+1, b/2) fi + }; + g(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE{ + if (b=1) then a else f(a/2, b+1) fi + }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/simple3.cl b/src/debbuging/tests/Auto/simple3.cl index 1002ddcde..18a023ac4 100644 --- a/src/debbuging/tests/Auto/simple3.cl +++ b/src/debbuging/tests/Auto/simple3.cl @@ -5,9 +5,9 @@ class Main { a <- e; b <- a; c <- b; - d <- c; + d <- c; -- debe dar error aqui e <- f; - -- d <- "Test"; + d <- "Test"; f <- 12; }}; }; diff --git a/src/debbuging/tests/Auto/simple4.cl b/src/debbuging/tests/Auto/simple4.cl new file mode 100644 index 000000000..fdb664db4 --- /dev/null +++ b/src/debbuging/tests/Auto/simple4.cl @@ -0,0 +1,11 @@ +class Main { + main (): Int { + 0 + }; + boo (): AUTO_TYPE{ + self@Main.foo(2) + }; + foo (a: AUTO_TYPE): AUTO_TYPE{ + a=1 + }; +}; \ No newline at end of file diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index ec2b56c92..141ff041e 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,6 +1,7 @@ from copy import copy, deepcopy +from typing import Tuple -from semantics.tools.type import Method, Type +from semantics.tools.type import Method, SelfType, Type from semantics.tools import Context, Scope, TypeBag, join, join_list, unify from utils import visitor from ast.inferencer_ast import ( @@ -36,24 +37,27 @@ def __init__(self, context: Context) -> None: self.context = context self.errors = [] self.current_type = None + self.changed = False @visitor.on("node") def visit(self, node, scope): pass @visitor.when(ProgramNode) - def visit(self, node: ProgramNode) -> ProgramNode: + def visit(self, node: ProgramNode) -> Tuple[ProgramNode, bool]: scope = Scope() + self.changed = False new_declaration = [] for declaration in node.declarations: new_declaration.append(self.visit(declaration, scope.create_child())) program = ProgramNode(new_declaration, scope, node) - return program + return program, self.changed @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: self.current_type = self.context.get_type(node.id, unpacked=True) + scope.define_variable("self", TypeBag({SelfType()})) new_features = [] for feature in node.features: @@ -63,18 +67,21 @@ def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNod return class_node @visitor.when(AttrDeclarationNode) - def visit(self, node, scope): + def visit(self, node, scope: Scope): attr_node = AttrDeclarationNode(node) if not node.expr: attr_node.inferenced_type = node.inferenced_type + scope.define_variable(node.id, node.inferenced_type) return attr_node expr_node = self.visit(node.expr, scope) expr_type = expr_node.inferenced_type decl_type = node.inferenced_type - decl_type = unify(decl_type, expr_type) + decl_type, changed = unify(decl_type, expr_type) + scope.define_variable(node.id, decl_type) + self.changed |= changed attr_node.expr = expr_node attr_node.inferenced_type = decl_type @@ -89,17 +96,20 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: for param in node.params: new_params.append(self.visit(param, scope)) - current_method.param_types = [ + param_types = [ unify(new_param.inferenced_type, typex) for new_param, typex in zip(new_params, current_method.param_types) ] + current_method.param_types = [i[0] for i in param_types] + self.changed |= any([i[1] for i in param_types]) new_body_node = self.visit(node.body, scope) body_type = new_body_node.inferenced_type.swap_self_type(self.current_type) new_node = MethodDeclarationNode(new_params, node.type, new_body_node, node) decl_type = node.inferenced_type body_type = new_body_node.inferenced_type - new_node.inferenced_type = unify(decl_type, body_type) + new_node.inferenced_type, changed = unify(decl_type, body_type) + self.changed |= changed return new_node @visitor.when(BlocksNode) @@ -111,7 +121,8 @@ def visit(self, node: BlocksNode, scope) -> BlocksNode: new_node = BlocksNode(new_expr_list, node) decl_type = node.inferenced_type expr_type = new_expr_list[-1].inferenced_type - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(ConditionalNode) @@ -126,7 +137,8 @@ def visit(self, node: ConditionalNode, scope) -> ConditionalNode: new_node = ConditionalNode( new_condition_node, new_then_node, new_else_node, node ) - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(CaseNode) @@ -142,7 +154,8 @@ def visit(self, node: CaseNode, scope) -> CaseNode: new_node = CaseNode(new_case_node, new_options_nodes, node) decl_type = node.inferenced_type expr_type = join_type - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(CaseOptionNode) @@ -151,7 +164,8 @@ def visit(self, node: CaseOptionNode, scope) -> CaseOptionNode: new_node = CaseOptionNode(new_node_expr, node) decl_type = node.inferenced_type expr_type = new_node_expr.inferenced_type - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(LoopNode) @@ -176,7 +190,8 @@ def visit(self, node: LetNode, scope) -> LetNode: new_node = LetNode(new_var_decl_nodes, new_in_node, node) decl_type = node.inferenced_type expr_type = new_in_node.inferenced_type - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(VarDeclarationNode) @@ -191,7 +206,8 @@ def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: new_expr_node = self.visit(node.expr, scope) decl_type = node.inferenced_type expr_type = new_expr_node.inferenced_type - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed else: new_node.inferenced_type = node.inferenced_type @@ -207,7 +223,8 @@ def visit(self, node: AssignNode, scope) -> AssignNode: expr_type = new_expr_node.inferenced_type new_node = AssignNode(new_expr_node, node) new_node.defined = node.defined - new_node.inferenced_type = unify(decl_type, expr_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @visitor.when(MethodCallNode) @@ -218,12 +235,14 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: new_args = [] for arg_expr, param_type in zip(node.args, method.param_types): arg_node = self.visit(arg_expr, scope) - arg_node.inferenced_type = unify(arg_node.inferenced_type, param_type) + arg_node.inferenced_type, changed = unify(arg_node.inferenced_type, param_type) + self.changed |= changed new_args.append(arg_node) new_expr = self.visit(node.expr, scope) if node.expr else None new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) - new_node.inferenced_type = unify(node.inferenced_type, method.return_type) + new_node.inferenced_type, changed = unify(node.inferenced_type, method.return_type) + self.changed |= changed return new_node @visitor.when(BinaryNode) @@ -250,8 +269,9 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: new_node = copy(node) if node.defined: decl_type = node.inferenced_type.swap_self_type(self.current_type) - expr_type = scope.find_variable(node.value).get_type() - new_node.inferenced_type = unify(decl_type, expr_type) + expr_type = scope.find_variable(node.value).get_type().swap_self_type(self.current_type) + new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node return new_node diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 4ca8507e7..ff3a8a9e0 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -229,10 +229,10 @@ def _reduce_to_type(self, bag: TypeBag, node: Node): node, f"TypeError: Ambiguous type declaration, multiple values {bag.generate_name()}", ) - return ErrorType() + return TypeBag(set()) if len(bag.heads) == 0: - self.add_error(node, "TypeError: Cannot infer type") - return ErrorType() + self.add_error(node, "TypeError: Cannot infer expression's type") + return TypeBag(set()) return bag.heads[0] def add_error(self, node, text: str): diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 4e750b8cd..9bf1e7dd3 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -1,5 +1,5 @@ from semantics.tools.errors import * -from typing import List, Set +from typing import List, Set, Tuple from collections import OrderedDict @@ -322,6 +322,7 @@ def swap_self_type(self, swap_type, back=False): return self self.update_heads() + return self def add_self_type(self, add_type) -> bool: if self.error_type: @@ -369,9 +370,6 @@ def update(self, other): self.conform_list = other.conform_list self.type_set = other.type_set self.heads = other.heads - - - def __str__(self): return self.name @@ -592,16 +590,34 @@ def from_dict_to_set(types: dict): return type_set -def unify(a: TypeBag, b: TypeBag) -> TypeBag: +def unify(a: TypeBag, b: TypeBag) -> Tuple[TypeBag, bool]: + if a.error_type: + return b, False + if b.error_type: + return a, False + intersection = set() + if len(a.type_set)==1 and len(b.type_set)==1: + type_a = list(a.type_set)[0] + type_b = list(b.type_set)[0] + if type_b.conforms_to(type_a): + return a, False + return TypeBag(set()), False + for type1 in a.type_set: for type2 in b.type_set: - if type1.name == type2.name: + if type2 == type1: intersection.add(type1) + changed = (not equals_set(a.type_set, intersection)) or ( + not equals_set(b.type_set, intersection) + ) a.type_set = intersection a.update_heads() b.type_set = intersection b.update_heads() - return a + return a, changed + +def equals_set(a: set, b: set) -> bool: + return a.issubset(b) and b.issubset(a) From 2894047b6346c8c975c60289927252af60a93339 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 3 May 2021 20:04:52 -0400 Subject: [PATCH 127/432] Added new tests and renamed 2 --- src/debbuging/tests/Auto/ackerman.cl | 16 ++++++++++++++++ src/debbuging/tests/Auto/attributes1.cl | 8 ++++++++ .../{not_that_simple.cl => not_that_simple1.cl} | 4 ++-- .../Auto/{rec_function.cl => recursive1.cl} | 0 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/debbuging/tests/Auto/ackerman.cl create mode 100644 src/debbuging/tests/Auto/attributes1.cl rename src/debbuging/tests/Auto/{not_that_simple.cl => not_that_simple1.cl} (88%) rename src/debbuging/tests/Auto/{rec_function.cl => recursive1.cl} (100%) diff --git a/src/debbuging/tests/Auto/ackerman.cl b/src/debbuging/tests/Auto/ackerman.cl new file mode 100644 index 000000000..1c70d9901 --- /dev/null +++ b/src/debbuging/tests/Auto/ackerman.cl @@ -0,0 +1,16 @@ +class Main { + main() :Int{ + 3 + }; + test(a:AUTO_TYPE, b:AUTO_TYPE) : AUTO_TYPE { + ackermann(a, b) + }; + + ackermann(m : AUTO_TYPE, n: AUTO_TYPE) : AUTO_TYPE { + if (m=0) then n+1 else + if (n=0) then ackermann(m-1, 1) else + ackermann(m-1, ackermann(m, n-1)) + fi + fi + }; +}; diff --git a/src/debbuging/tests/Auto/attributes1.cl b/src/debbuging/tests/Auto/attributes1.cl new file mode 100644 index 000000000..5f0bee915 --- /dev/null +++ b/src/debbuging/tests/Auto/attributes1.cl @@ -0,0 +1,8 @@ +class Main inherits IO { + p:AUTO_TYPE <- 5; + pp:AUTO_TYPE; + main() : AUTO_TYPE + { + pp<-self + }; +}; diff --git a/src/debbuging/tests/Auto/not_that_simple.cl b/src/debbuging/tests/Auto/not_that_simple1.cl similarity index 88% rename from src/debbuging/tests/Auto/not_that_simple.cl rename to src/debbuging/tests/Auto/not_that_simple1.cl index f5c989a51..0ba6576f7 100644 --- a/src/debbuging/tests/Auto/not_that_simple.cl +++ b/src/debbuging/tests/Auto/not_that_simple1.cl @@ -17,7 +17,7 @@ class Main }; } of - y : AUTO_TYPE => let i: AUTO_TYPE <- y in y ; + y : Int => let i: AUTO_TYPE <- y in y ; esac ; } } ; - } ; \ No newline at end of file + } ; diff --git a/src/debbuging/tests/Auto/rec_function.cl b/src/debbuging/tests/Auto/recursive1.cl similarity index 100% rename from src/debbuging/tests/Auto/rec_function.cl rename to src/debbuging/tests/Auto/recursive1.cl From ea8650559a562fb46db87e95e0852bf24fae01f3 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 3 May 2021 20:05:20 -0400 Subject: [PATCH 128/432] Minor bug fix --- src/__main__.py | 11 +++++---- src/semantics/inference/back_inferencer.py | 27 ++++++++++++++++++---- src/semantics/inference/soft_inferencer.py | 1 + src/semantics/tools/type.py | 4 ++-- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index e893b43b5..d8f384f09 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -47,16 +47,17 @@ def run_pipeline(program_ast): change = True back = BackInferencer(context) + back_ast, change = back.visit(hard_ast) while change: - back_ast, change = back.visit(hard_ast) + back_ast, change = back.visit(back_ast) types = TypesInferencer() types_ast = types.visit(back_ast) errors += types.errors - # logger = TypeLogger(context) - # log = logger.visit(hard_ast, hard_ast.scope) - # print(log) + logger = TypeLogger(context) + log = logger.visit(hard_ast, back_ast.scope) + print(log) if len(errors) > 0: s = format_errors(errors) @@ -70,7 +71,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/debbuging/tests/Auto/not_that_simple.cl" + input_file = "debbuging/tests/Auto/not_that_simple1.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 141ff041e..0293d7fb9 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -1,4 +1,5 @@ from copy import copy, deepcopy +from semantics.tools.errors import SemanticError from typing import Tuple from semantics.tools.type import Method, SelfType, Type @@ -142,7 +143,7 @@ def visit(self, node: ConditionalNode, scope) -> ConditionalNode: return new_node @visitor.when(CaseNode) - def visit(self, node: CaseNode, scope) -> CaseNode: + def visit(self, node: CaseNode, scope: Scope) -> CaseNode: new_case_node = self.visit(node.case_expr, scope) new_options_nodes = [] for option in node.options: @@ -159,12 +160,20 @@ def visit(self, node: CaseNode, scope) -> CaseNode: return new_node @visitor.when(CaseOptionNode) - def visit(self, node: CaseOptionNode, scope) -> CaseOptionNode: + def visit(self, node: CaseOptionNode, scope: Scope) -> CaseOptionNode: + try: + node_type = self.context.get_type(node.type, selftype=False, autotype=False) + except SemanticError as err: + node_type = TypeBag(set()) + + scope.define_variable(node.id, node_type) + new_node_expr = self.visit(node.expr, scope) new_node = CaseOptionNode(new_node_expr, node) decl_type = node.inferenced_type expr_type = new_node_expr.inferenced_type new_node.inferenced_type, changed = unify(decl_type, expr_type) + self.changed |= changed return new_node @@ -235,13 +244,17 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: new_args = [] for arg_expr, param_type in zip(node.args, method.param_types): arg_node = self.visit(arg_expr, scope) - arg_node.inferenced_type, changed = unify(arg_node.inferenced_type, param_type) + arg_node.inferenced_type, changed = unify( + arg_node.inferenced_type, param_type + ) self.changed |= changed new_args.append(arg_node) new_expr = self.visit(node.expr, scope) if node.expr else None new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) - new_node.inferenced_type, changed = unify(node.inferenced_type, method.return_type) + new_node.inferenced_type, changed = unify( + node.inferenced_type, method.return_type + ) self.changed |= changed return new_node @@ -269,7 +282,11 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: new_node = copy(node) if node.defined: decl_type = node.inferenced_type.swap_self_type(self.current_type) - expr_type = scope.find_variable(node.value).get_type().swap_self_type(self.current_type) + expr_type = ( + scope.find_variable(node.value) + .get_type() + .swap_self_type(self.current_type) + ) new_node.inferenced_type, changed = unify(decl_type, expr_type) self.changed |= changed return new_node diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 7e0c85b1b..c67a5aecc 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -225,6 +225,7 @@ def visit(self, node, scope: Scope): self.add_error( node, err.text + f" While defining Case Option variable {node.id}." ) + node_type = TypeBag(set()) scope.define_variable(node.id, node_type) expr_node = self.visit(node.expr, scope) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 9bf1e7dd3..a177cf5c4 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -597,13 +597,13 @@ def unify(a: TypeBag, b: TypeBag) -> Tuple[TypeBag, bool]: return a, False intersection = set() - if len(a.type_set)==1 and len(b.type_set)==1: + if len(a.type_set) == 1 and len(b.type_set) == 1: type_a = list(a.type_set)[0] type_b = list(b.type_set)[0] if type_b.conforms_to(type_a): return a, False return TypeBag(set()), False - + for type1 in a.type_set: for type2 in b.type_set: if type2 == type1: From f00e306ce5fffafa3bb1c1919ccbf1b525be38a2 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 3 May 2021 20:38:56 -0400 Subject: [PATCH 129/432] Removed ErroType declarations --- src/semantics/type_builder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index ebd1091c2..15a0f4fdd 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -7,7 +7,7 @@ AttrDeclarationNode, ) from semantics.tools.errors import SemanticError -from semantics.tools import SelfType, TypeBag, ErrorType, Context +from semantics.tools import SelfType, TypeBag, Context class TypeBuilder: @@ -60,7 +60,7 @@ def visit(self, node): attr_type = self.context.get_type(node.type) except SemanticError as err: self.add_error(node, err.text) - attr_type = ErrorType() + attr_type = TypeBag(set()) try: self.current_type.define_attribute(node.id, attr_type) @@ -73,7 +73,7 @@ def visit(self, node): ret_type = self.context.get_type(node.type) except SemanticError as err: self.add_error(node, err.text) - ret_type = ErrorType() + ret_type = TypeBag(set()) params_type = [] params_name = [] @@ -83,7 +83,7 @@ def visit(self, node): try: params_type.append(self.context.get_type(p_type, selftype=False)) except SemanticError as err: - params_type.append(ErrorType()) + params_type.append(TypeBag(set())) self.add_error( node, err.text From 8f4f3a9bde40bd445e67221056a24b5441f520e2 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 May 2021 19:47:22 -0400 Subject: [PATCH 130/432] Minor bug fix --- src/semantics/inference/hard_inferencer.py | 8 +++++--- src/semantics/inference/soft_inferencer.py | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index c24747c15..aaad29690 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -117,9 +117,9 @@ def visit(self, node, scopex: Scope): scope.define_variable(idx, typex) new_params = [] - for param in node.params: - new_params.append(self.visit(param, scope)) - # scope.define_variable(param.name, ) + # for param in node.params: + # new_params.append(self.visit(param, scope)) + # # scope.define_variable(param.name, ) body_node = self.visit(node.body, scope) body_type = body_node.inferenced_type @@ -272,6 +272,7 @@ def visit(self, node, scope: Scope): assign_node = AssignNode(expr_node, node) if not node.defined or node.id == "self": + assign_node.inferenced_type = TypeBag(set()) return assign_node assign_node.defined = True @@ -422,6 +423,7 @@ def visit(self, node, scope): def visit(self, node, scope: Scope): var_node = VariableNode(node) if not node.defined: + var_node.inferenced_type = TypeBag(set()) return var_node var_node.defined = True diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index c67a5aecc..f29bc4a21 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -126,8 +126,8 @@ def visit(self, node, scopex: Scope): for idx, typex in zip(current_method.param_names, current_method.param_types): scope.define_variable(idx, typex) new_params = [] - for param in node.params: - new_params.append(self.visit(param, scope)) + # for param in node.params: + # new_params.append(self.visit(param, scope)) ret_type_decl: TypeBag = current_method.return_type @@ -334,12 +334,12 @@ def visit(self, node, scope: Scope): expr_type: TypeBag = expr_node.inferenced_type added_type = expr_type.add_self_type(self.current_type) - expr_clone = expr_type.clone() + expr_name = expr_type.name if not conforms(expr_type, decl_type): self.add_error( node, f"TypeError: Cannot assign new value to variable '{node.id}'." - f" expression type({expr_clone.name}) does not conforms to" + f" Expression type({expr_name}) does not conforms to" f" declared type ({decl_type.name}).", ) if added_type: @@ -474,6 +474,8 @@ def visit(self, node, scope: Scope): var_type = var.get_type() else: self.add_error(node, f"NameError: Variable '{node.value}' is not defined.") + var_type = TypeBag(set()) + var_node.inferenced_type = var_type return var_node @@ -530,6 +532,7 @@ def visit(self, node, scope): node, err.text + f" Could not instantiate type '{node.value}'.", ) + node_type = TypeBag(set()) instantiate_node.inferenced_type = node_type return instantiate_node From 630725ccc541241f0b8a91060137ed170a05e6a7 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 17:47:58 -0400 Subject: [PATCH 131/432] Fix bug in BackInferencer --- src/semantics/inference/back_inferencer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 0293d7fb9..b0e13523e 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -282,11 +282,11 @@ def visit(self, node: VariableNode, scope: Scope) -> VariableNode: new_node = copy(node) if node.defined: decl_type = node.inferenced_type.swap_self_type(self.current_type) - expr_type = ( - scope.find_variable(node.value) - .get_type() - .swap_self_type(self.current_type) - ) + expr_type = scope.find_variable(node.value) + if expr_type is not None: + expr_type = expr_type.get_type().swap_self_type(self.current_type) + else: + expr_type = decl_type new_node.inferenced_type, changed = unify(decl_type, expr_type) self.changed |= changed return new_node From ba03cc76665fd783ffe0e6a8f6a8696ee8fccd0d Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 17:50:02 -0400 Subject: [PATCH 132/432] Added support for inferencing the more general type in parameters and the more concrete in the rest of expressions --- src/semantics/inference/types_inferencer.py | 144 +++++++++++++------- 1 file changed, 92 insertions(+), 52 deletions(-) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index ff3a8a9e0..2775f6f1a 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,7 +1,7 @@ -from semantics.tools.type import ErrorType +from semantics.tools.type import join_list from utils import visitor -from semantics.tools import TypeBag +from semantics.tools import TypeBag, Scope import ast.types_ast as types_ast from ast.inferencer_ast import ( BinaryNode, @@ -45,141 +45,168 @@ def __init__(self) -> None: self.errors = [] @visitor.on("node") - def visit(self, node): + def visit(self, node, scope): pass @visitor.when(ProgramNode) def visit(self, node: ProgramNode) -> types_ast.ProgramNode: class_decl = [] + scope = Scope() for decl in node.declarations: - class_decl.append(self.visit(decl)) + class_decl.append(self.visit(decl, scope.create_child())) return types_ast.ProgramNode(class_decl, node) @visitor.when(ClassDeclarationNode) - def visit(self, node: ClassDeclarationNode) -> types_ast.ClassDeclarationNode: + def visit(self, node: ClassDeclarationNode, scope: Scope) -> types_ast.ClassDeclarationNode: features = [] for feature in node.features: - features.append(self.visit(feature)) + features.append(self.visit(feature, scope)) return types_ast.ClassDeclarationNode(features, node) @visitor.when(AttrDeclarationNode) - def visit(self, node: AttrDeclarationNode) -> types_ast.AttrDeclarationNode: + def visit(self, node: AttrDeclarationNode, scope: Scope) -> types_ast.AttrDeclarationNode: new_node = types_ast.AttrDeclarationNode(node) if node.expr: - new_node.expr = self.visit(node.expr) + new_node.expr = self.visit(node.expr, scope) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(MethodDeclarationNode) - def visit(self, node: MethodDeclarationNode) -> types_ast.MethodDeclarationNode: - body = self.visit(node.body) - params = [self.visit(param) for param in node.params] + def visit(self, node: MethodDeclarationNode, scope: Scope) -> types_ast.MethodDeclarationNode: + scope = scope.create_child() + + for param in node.params: + param_type = self._reduce_to_type(param.inferenced_type, general=True) + scope.define_variable(param.id, param_type) + + params = [self.visit(param, scope) for param in node.params] + + body = self.visit(node.body, scope) + ret_type = self._reduce_to_type(node.inferenced_type, node) return types_ast.MethodDeclarationNode(params, ret_type, body, node) @visitor.when(BlocksNode) - def visit(self, node: BlocksNode) -> types_ast.BlocksNode: - expr_list = [self.visit(expr) for expr in node.expr_list] + def visit(self, node: BlocksNode, scope: Scope) -> types_ast.BlocksNode: + expr_list = [self.visit(expr, scope) for expr in node.expr_list] new_node = types_ast.BlocksNode(expr_list, node) new_node.type = expr_list[-1].type return new_node @visitor.when(ConditionalNode) - def visit(self, node: ConditionalNode) -> types_ast.ConditionalNode: - condition = self.visit(node.condition) - then_body = self.visit(node.then_body) - else_body = self.visit(node.else_body) + def visit(self, node: ConditionalNode, scope: Scope) -> types_ast.ConditionalNode: + condition = self.visit(node.condition, scope) + then_body = self.visit(node.then_body, scope) + else_body = self.visit(node.else_body, scope) new_node = types_ast.ConditionalNode(condition, then_body, else_body, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(CaseNode) - def visit(self, node: CaseNode) -> types_ast.CaseNode: - expr = self.visit(node.case_expr) - case_options = [self.visit(option) for option in node.options] + def visit(self, node: CaseNode, scope: Scope) -> types_ast.CaseNode: + expr = self.visit(node.case_expr, scope) + + case_options = [] + for option in node.options: + child_scope = scope.create_child() + case_options.append(self.visit(option, child_scope)) + new_node = types_ast.CaseNode(expr, case_options, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(CaseOptionNode) - def visit(self, node: CaseOptionNode) -> types_ast.CaseOptionNode: - return types_ast.CaseOptionNode(self.visit(node.expr), node) + def visit(self, node: CaseOptionNode, scope: Scope) -> types_ast.CaseOptionNode: + return types_ast.CaseOptionNode(self.visit(node.expr, scope), node) @visitor.when(LoopNode) - def visit(self, node: LoopNode) -> types_ast.LoopNode: - condition = self.visit(node.condition) - body = self.visit(node.body) + def visit(self, node: LoopNode, scope: Scope) -> types_ast.LoopNode: + condition = self.visit(node.condition, scope) + body = self.visit(node.body, scope) new_node = types_ast.LoopNode(condition, body, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(LetNode) - def visit(self, node: LetNode) -> types_ast.LetNode: - var_decl_list = [self.visit(var_decl) for var_decl in node.var_decl_list] - in_expr = self.visit(node.in_expr) + def visit(self, node: LetNode, scope: Scope) -> types_ast.LetNode: + scope = scope.create_child() + var_decl_list = [self.visit(var_decl, scope) for var_decl in node.var_decl_list] + in_expr = self.visit(node.in_expr,scope) new_node = types_ast.LetNode(var_decl_list, in_expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(VarDeclarationNode) - def visit(self, node: VarDeclarationNode) -> types_ast.VarDeclarationNode: + def visit(self, node: VarDeclarationNode, scope: Scope) -> types_ast.VarDeclarationNode: new_node = types_ast.VarDeclarationNode(node) if node.expr: - new_node.expr = self.visit(node.expr) - new_node.type = self._reduce_to_type(node.inferenced_type, node) + new_node.expr = self.visit(node.expr, scope) + + var_info = scope.find_variable(node.id) + if var_info is None: + new_node.type = self._reduce_to_type(node.inferenced_type, node) + else: + new_node.type = var_info.type + return new_node @visitor.when(AssignNode) - def visit(self, node: AssignNode) -> types_ast.AssignNode: - expr = self.visit(node.expr) + def visit(self, node: AssignNode, scope: Scope) -> types_ast.AssignNode: + expr = self.visit(node.expr, scope) new_node = types_ast.AssignNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(MethodCallNode) - def visit(self, node: MethodCallNode) -> types_ast.MethodCallNode: - args = [self.visit(arg) for arg in node.args] - caller_expr = self.visit(node.expr) + def visit(self, node: MethodCallNode, scope: Scope) -> types_ast.MethodCallNode: + args = [self.visit(arg, scope) for arg in node.args] + caller_expr = self.visit(node.expr, scope) new_node = types_ast.MethodCallNode(node.caller_type, caller_expr, args, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(VariableNode) - def visit(self, node: VariableNode) -> types_ast.VariableNode: + def visit(self, node: VariableNode, scope: Scope) -> types_ast.VariableNode: new_node = types_ast.VariableNode(node) + if node.defined: - new_node.type = self._reduce_to_type(node.inferenced_type, node) + var_info = scope.find_variable(node.value) + if var_info is None: + new_node.type = self._reduce_to_type(node.inferenced_type, node) + else: + new_node.type = var_info.type + return new_node @visitor.when(IsVoidNode) - def visit(self, node: IsVoidNode) -> types_ast.IsVoidNode: - expr = self.visit(node.expr) + def visit(self, node: IsVoidNode, scope: Scope) -> types_ast.IsVoidNode: + expr = self.visit(node.expr, scope) new_node = types_ast.IsVoidNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(NotNode) - def visit(self, node: NotNode) -> types_ast.NotNode: - expr = self.visit(node.expr) + def visit(self, node: NotNode, scope: Scope) -> types_ast.NotNode: + expr = self.visit(node.expr, scope) new_node = types_ast.NotNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(ComplementNode) - def visit(self, node: ComplementNode) -> types_ast.ComplementNode: + def visit(self, node: ComplementNode, scope: Scope) -> types_ast.ComplementNode: expr = self.visit(node.expr) new_node = types_ast.ComplementNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(BinaryNode) - def visit(self, node) -> types_ast.BinaryNode: - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, scope: Scope) -> types_ast.BinaryNode: + left = self.visit(node.left, scope) + right = self.visit(node.right, scope) if isinstance(node, PlusNode): new_node = types_ast.PlusNode(left, right, node) @@ -200,30 +227,30 @@ def visit(self, node) -> types_ast.BinaryNode: return new_node @visitor.when(BooleanNode) - def visit(self, node: BooleanNode) -> types_ast.BooleanNode: + def visit(self, node: BooleanNode, scope: Scope) -> types_ast.BooleanNode: new_node = types_ast.BooleanNode(node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(StringNode) - def visit(self, node: StringNode) -> types_ast.StringNode: + def visit(self, node: StringNode, scope: Scope) -> types_ast.StringNode: new_node = types_ast.StringNode(node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(IntNode) - def visit(self, node: IntNode) -> types_ast.IntNode: + def visit(self, node: IntNode, scope: Scope) -> types_ast.IntNode: new_node = types_ast.IntNode(node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(InstantiateNode) - def visit(self, node: InstantiateNode) -> types_ast.InstantiateNode: + def visit(self, node: InstantiateNode, scope: Scope) -> types_ast.InstantiateNode: new_node = types_ast.InstantiateNode(node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node - def _reduce_to_type(self, bag: TypeBag, node: Node): + def _reduce_to_type(self, bag: TypeBag, node: Node, general=False): if len(bag.heads) > 1: self.add_error( node, @@ -233,7 +260,20 @@ def _reduce_to_type(self, bag: TypeBag, node: Node): if len(bag.heads) == 0: self.add_error(node, "TypeError: Cannot infer expression's type") return TypeBag(set()) - return bag.heads[0] + + if general: + return bag.heads[0] + + order_types = list(bag.type_set) + order_types.sort(key=lambda x: -1 * x.index) + + higher_index_types = [order_types[0]] + higher_index = order_types[0].index + for typex in order_types[2:]: + if typex.index == higher_index: + higher_index_types.append(typex) + + return join_list(higher_index_types) def add_error(self, node, text: str): line, col = node.get_position() if node else (0, 0) From a941207a91f91102dfe3f252daa0f862f550f66c Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 17:50:53 -0400 Subject: [PATCH 133/432] Small change in __main__.py for debugging --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index d8f384f09..ac8a96857 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -71,7 +71,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests/Auto/not_that_simple1.cl" + input_file = "src/debbuging/tests/Auto/recursive1.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) From 4be4384054e6db2918144e24ba845fbe81c755cf Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 23:22:31 -0400 Subject: [PATCH 134/432] Fix small bug in swap_self_type --- src/semantics/tools/type.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index a177cf5c4..70e342ebc 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -306,7 +306,7 @@ def update_heads(self) -> None: def swap_self_type(self, swap_type, back=False): if self.error_type: - return + return self if not back: remove_type = SelfType() @@ -619,5 +619,28 @@ def unify(a: TypeBag, b: TypeBag) -> Tuple[TypeBag, bool]: return a, changed +# def unify(a: TypeBag, b: TypeBag) -> Tuple[TypeBag, bool]: +# if a.error_type: +# return b, False +# if b.error_type: +# return a, False + +# if len(a.type_set) == 1 and len(b.type_set) == 1: +# type_a = list(a.type_set)[0] +# type_b = list(b.type_set)[0] +# if type_b.conforms_to(type_a): +# return a, False +# return TypeBag(set()), False + +# a_clone = a.clone() +# change = conforms(a_clone, b) +# if not change: +# return a, change + +# a.type_set = a_clone.type_set +# a.update_heads() +# return a, change + + def equals_set(a: set, b: set) -> bool: return a.issubset(b) and b.issubset(a) From 0203c28fb6e15d4a805640b03eaa81687ad3a13c Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 23:54:00 -0400 Subject: [PATCH 135/432] Fix some minor bugs --- src/__main__.py | 2 +- src/debbuging/tests/Auto/mixed1.cl | 19 ++++++++++++ src/debbuging/tests/Auto/mixed2.cl | 34 +++++++++++++++++++++ src/debbuging/tests/Auto/mixed3.cl | 32 +++++++++++++++++++ src/semantics/inference/back_inferencer.py | 4 +-- src/semantics/inference/hard_inferencer.py | 5 ++- src/semantics/inference/soft_inferencer.py | 5 +-- src/semantics/inference/types_inferencer.py | 27 ++++++++-------- 8 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 src/debbuging/tests/Auto/mixed1.cl create mode 100644 src/debbuging/tests/Auto/mixed2.cl create mode 100644 src/debbuging/tests/Auto/mixed3.cl diff --git a/src/__main__.py b/src/__main__.py index ac8a96857..bc4f57376 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -71,7 +71,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/debbuging/tests/Auto/recursive1.cl" + input_file = "src/debbuging/tests/Auto/mixed3.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/debbuging/tests/Auto/mixed1.cl b/src/debbuging/tests/Auto/mixed1.cl new file mode 100644 index 000000000..fe238a0c3 --- /dev/null +++ b/src/debbuging/tests/Auto/mixed1.cl @@ -0,0 +1,19 @@ +class Main { + main() : Int { 0 }; + + method0( a : AUTO_TYPE) : AUTO_TYPE { + { + a.method(a); + a; + } + }; + +}; + +class A { + method(a : AUTO_TYPE): AUTO_TYPE { a }; +}; + +class B inherits A { + method(b : AUTO_TYPE) : AUTO_TYPE { b }; +}; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/mixed2.cl b/src/debbuging/tests/Auto/mixed2.cl new file mode 100644 index 000000000..7a76f5767 --- /dev/null +++ b/src/debbuging/tests/Auto/mixed2.cl @@ -0,0 +1,34 @@ +class Main { + main() : Int {0}; + + s : AUTO_TYPE <- method1(s); -- esto debe dar error semantico porque 's' + -- todavia no esta definida cuando se pasa como + -- parametro ??? + + method0( a: A) : AUTO_TYPE { + { + a; + } + }; + + d : B; + method1(a: AUTO_TYPE) : AUTO_TYPE { + { + method0(a); + d <- a; + a; + } + }; +}; + +class A { + +}; + +class B inherits A { + +}; + +class C inherits B { + +}; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/mixed3.cl b/src/debbuging/tests/Auto/mixed3.cl new file mode 100644 index 000000000..9a9e382c0 --- /dev/null +++ b/src/debbuging/tests/Auto/mixed3.cl @@ -0,0 +1,32 @@ +class Main { + main() : Int {0}; + + s : AUTO_TYPE <- method1(f); + f : AUTO_TYPE; + method0( a: A) : AUTO_TYPE { + { + a; + } + }; + + d : B; + method1(a: AUTO_TYPE) : AUTO_TYPE { + { + method0(a); + d <- a; + a; + } + }; +}; + +class A { + +}; + +class B inherits A { + +}; + +class C inherits B { + +}; \ No newline at end of file diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index b0e13523e..609784bad 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -98,7 +98,7 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: new_params.append(self.visit(param, scope)) param_types = [ - unify(new_param.inferenced_type, typex) + unify(typex, new_param.inferenced_type ) for new_param, typex in zip(new_params, current_method.param_types) ] current_method.param_types = [i[0] for i in param_types] @@ -245,7 +245,7 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: for arg_expr, param_type in zip(node.args, method.param_types): arg_node = self.visit(arg_expr, scope) arg_node.inferenced_type, changed = unify( - arg_node.inferenced_type, param_type + param_type, arg_node.inferenced_type ) self.changed |= changed new_args.append(arg_node) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index aaad29690..d1fd283e9 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -117,9 +117,8 @@ def visit(self, node, scopex: Scope): scope.define_variable(idx, typex) new_params = [] - # for param in node.params: - # new_params.append(self.visit(param, scope)) - # # scope.define_variable(param.name, ) + for param in node.params: + new_params.append(self.visit(param, scope)) body_node = self.visit(node.body, scope) body_type = body_node.inferenced_type diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index f29bc4a21..b07a202e7 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -125,9 +125,10 @@ def visit(self, node, scopex: Scope): for idx, typex in zip(current_method.param_names, current_method.param_types): scope.define_variable(idx, typex) + new_params = [] - # for param in node.params: - # new_params.append(self.visit(param, scope)) + for param in node.params: + new_params.append(self.visit(param, scope)) ret_type_decl: TypeBag = current_method.return_type diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 2775f6f1a..f6a9e1ae1 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,4 +1,5 @@ -from semantics.tools.type import join_list +from typing import List +from semantics.tools.type import Type, join_list from utils import visitor from semantics.tools import TypeBag, Scope @@ -78,7 +79,7 @@ def visit(self, node: MethodDeclarationNode, scope: Scope) -> types_ast.MethodDe scope = scope.create_child() for param in node.params: - param_type = self._reduce_to_type(param.inferenced_type, general=True) + param_type = self._reduce_to_type(param.inferenced_type,node, general=True) scope.define_variable(param.id, param_type) params = [self.visit(param, scope) for param in node.params] @@ -147,10 +148,8 @@ def visit(self, node: VarDeclarationNode, scope: Scope) -> types_ast.VarDeclarat new_node.expr = self.visit(node.expr, scope) var_info = scope.find_variable(node.id) - if var_info is None: - new_node.type = self._reduce_to_type(node.inferenced_type, node) - else: - new_node.type = var_info.type + general = var_info is not None # it's a param + new_node.type = self._reduce_to_type(node.inferenced_type,node, general) return new_node @@ -175,11 +174,9 @@ def visit(self, node: VariableNode, scope: Scope) -> types_ast.VariableNode: if node.defined: var_info = scope.find_variable(node.value) - if var_info is None: - new_node.type = self._reduce_to_type(node.inferenced_type, node) - else: - new_node.type = var_info.type - + general = var_info is not None + new_node.type = self._reduce_to_type(node.inferenced_type, node, general) + return new_node @visitor.when(IsVoidNode) @@ -273,7 +270,13 @@ def _reduce_to_type(self, bag: TypeBag, node: Node, general=False): if typex.index == higher_index: higher_index_types.append(typex) - return join_list(higher_index_types) + return self._join_types(higher_index_types) + + def _join_types(self, types : List[Type]): + types_bags = [] + for typex in types: + types_bags.append(TypeBag({typex}, heads=[typex])) + return join_list(types_bags).heads[0] def add_error(self, node, text: str): line, col = node.get_position() if node else (0, 0) From d569805c4597ad46fc7f56d8852fa2b0c58b4dd7 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Thu, 6 May 2021 23:58:05 -0400 Subject: [PATCH 136/432] Add some comments to tests cases --- src/debbuging/tests/Auto/mixed3.cl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debbuging/tests/Auto/mixed3.cl b/src/debbuging/tests/Auto/mixed3.cl index 9a9e382c0..1606e5de4 100644 --- a/src/debbuging/tests/Auto/mixed3.cl +++ b/src/debbuging/tests/Auto/mixed3.cl @@ -9,11 +9,11 @@ class Main { } }; - d : B; + d : B; method1(a: AUTO_TYPE) : AUTO_TYPE { { method0(a); - d <- a; + d <- a; -- si se comenta esta linea 'a' deberia ser de tipo 'A' a; } }; From 44e4920a894831eb91681ee26b47e905a93b6b14 Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Fri, 7 May 2021 00:10:07 -0400 Subject: [PATCH 137/432] Add ParamNode to parser_ast.py and change parser rule --- src/ast/parser_ast.py | 6 ++++++ src/parsing/parser.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ast/parser_ast.py b/src/ast/parser_ast.py index a17b358d7..6f452f671 100644 --- a/src/ast/parser_ast.py +++ b/src/ast/parser_ast.py @@ -60,6 +60,12 @@ def __init__(self, idx, typex, expression=None): self.type = typex self.expr = expression +class ParamNode(ExpressionNode): + def __init__(self, idx, typex): + Node.__init__(self) + self.id = idx + self.type = typex + class AssignNode(ExpressionNode): def __init__(self, idx, expr): diff --git a/src/parsing/parser.py b/src/parsing/parser.py index d949f0b8c..bf448a4ba 100644 --- a/src/parsing/parser.py +++ b/src/parsing/parser.py @@ -28,6 +28,7 @@ StringNode, VarDeclarationNode, VariableNode, + ParamNode, ) from parsing.errors import SyntacticError @@ -118,7 +119,7 @@ def p_params_list(self, p): def p_param(self, p): """param : ID ':' TYPE""" - p[0] = VarDeclarationNode(p[1], p[3]) + p[0] = ParamNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) def p_expression_list(self, p): From 8826c0dcab53465235f0de90f978e696e877e622 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 9 May 2021 21:37:51 -0400 Subject: [PATCH 138/432] Added new test cases --- src/debbuging/tests/Auto/attributes2.cl | 7 ++++++ src/debbuging/tests/Auto/equals1.cl | 15 +++++++++++ src/debbuging/tests/Auto/mixed3.cl | 2 +- src/debbuging/tests/Auto/param1.cl | 32 ++++++++++++++++++++++++ src/debbuging/tests/Auto/param2.cl | 33 +++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/debbuging/tests/Auto/attributes2.cl create mode 100644 src/debbuging/tests/Auto/equals1.cl create mode 100644 src/debbuging/tests/Auto/param1.cl create mode 100644 src/debbuging/tests/Auto/param2.cl diff --git a/src/debbuging/tests/Auto/attributes2.cl b/src/debbuging/tests/Auto/attributes2.cl new file mode 100644 index 000000000..57a828c38 --- /dev/null +++ b/src/debbuging/tests/Auto/attributes2.cl @@ -0,0 +1,7 @@ +class Main inherits IO { + n:AUTO_TYPE; + main() : AUTO_TYPE { + n = p + }; + p:AUTO_TYPE; +}; diff --git a/src/debbuging/tests/Auto/equals1.cl b/src/debbuging/tests/Auto/equals1.cl new file mode 100644 index 000000000..55929242e --- /dev/null +++ b/src/debbuging/tests/Auto/equals1.cl @@ -0,0 +1,15 @@ +class Main inherits IO { + n:AUTO_TYPE; + p:AUTO_TYPE; + main() : AUTO_TYPE { + n = p + }; + test1(): AUTO_TYPE { + { + n <- p; + p <- "Whooooshwith4os"; + } + }; + + +}; diff --git a/src/debbuging/tests/Auto/mixed3.cl b/src/debbuging/tests/Auto/mixed3.cl index 1606e5de4..9391c765b 100644 --- a/src/debbuging/tests/Auto/mixed3.cl +++ b/src/debbuging/tests/Auto/mixed3.cl @@ -29,4 +29,4 @@ class B inherits A { class C inherits B { -}; \ No newline at end of file +}; diff --git a/src/debbuging/tests/Auto/param1.cl b/src/debbuging/tests/Auto/param1.cl new file mode 100644 index 000000000..0af4bd246 --- /dev/null +++ b/src/debbuging/tests/Auto/param1.cl @@ -0,0 +1,32 @@ +class Main { + main() : Int {0}; + + s : AUTO_TYPE <- method1(s); --Esto deberia dar error no se puede pasar s xq no debe existir + f : AUTO_TYPE; + method0( a: A) : AUTO_TYPE { + { + a; + } + }; + + d : B; + method1(a: AUTO_TYPE) : AUTO_TYPE { + { + method0(a); + d <- a; -- si se comenta esta linea 'a' deberia ser de tipo "A, B o C" si no, de tipo "B o C" + 1; + } + }; +}; + +class A { + +}; + +class B inherits A { + +}; + +class C inherits B { + +}; diff --git a/src/debbuging/tests/Auto/param2.cl b/src/debbuging/tests/Auto/param2.cl new file mode 100644 index 000000000..214fa63ce --- /dev/null +++ b/src/debbuging/tests/Auto/param2.cl @@ -0,0 +1,33 @@ +class Main { + main() : Int {0}; + + s : AUTO_TYPE <- method1(f); --Esto deberia dar error no se puede pasar s xq no debe existir + f : AUTO_TYPE; + method0( a: A) : AUTO_TYPE { + { + a; + } + }; + + d : B; + method1(a: AUTO_TYPE) : AUTO_TYPE { + { + method0(a); + s <- "Error"; -- s no puede ser string ni int + d <- a; -- si se comenta esta linea 'a' deberia ser de tipo "A, B o C" si no, de tipo "B o C" + 1; + } + }; +}; + +class A { + +}; + +class B inherits A { + +}; + +class C inherits B { + +}; From c2db83a0ab475754d9acece70af5fa929af91816 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Sun, 9 May 2021 21:39:58 -0400 Subject: [PATCH 139/432] Minor updates --- src/__main__.py | 4 ++-- src/semantics/inference/soft_inferencer.py | 3 ++- tests/lexer_test.py | 28 +++++++++++----------- tests/parser_test.py | 24 +++++++++---------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index bc4f57376..7978d111c 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -56,7 +56,7 @@ def run_pipeline(program_ast): errors += types.errors logger = TypeLogger(context) - log = logger.visit(hard_ast, back_ast.scope) + log = logger.visit(back_ast, back_ast.scope) print(log) if len(errors) > 0: @@ -71,7 +71,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "src/debbuging/tests/Auto/mixed3.cl" + input_file = "debbuging/tests/Auto/equals1.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index b07a202e7..34457ae0f 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -125,9 +125,10 @@ def visit(self, node, scopex: Scope): for idx, typex in zip(current_method.param_names, current_method.param_types): scope.define_variable(idx, typex) - + new_params = [] for param in node.params: + continue new_params.append(self.visit(param, scope)) ret_type_decl: TypeBag = current_method.return_type diff --git a/tests/lexer_test.py b/tests/lexer_test.py index e105f16db..36de97d6f 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -2,17 +2,17 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition("/")[0] + "/lexer/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] - - -@pytest.mark.lexer -@pytest.mark.error -@pytest.mark.run(order=1) -@pytest.mark.parametrize("cool_file", tests) -def test_lexer_errors(compiler_path, cool_file): - print(compiler_path) - print(cool_file) - compare_errors( - compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" - ) +# tests_dir = __file__.rpartition("/")[0] + "/lexer/" +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +# +# +# @pytest.mark.lexer +# @pytest.mark.error +# @pytest.mark.run(order=1) +# @pytest.mark.parametrize("cool_file", tests) +# def test_lexer_errors(compiler_path, cool_file): +# print(compiler_path) +# print(cool_file) +# compare_errors( +# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" +# ) diff --git a/tests/parser_test.py b/tests/parser_test.py index b2c5ff048..30dc1c95b 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -2,15 +2,15 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition("/")[0] + "/parser/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] - - -@pytest.mark.parser -@pytest.mark.error -@pytest.mark.run(order=2) -@pytest.mark.parametrize("cool_file", tests) -def test_parser_errors(compiler_path, cool_file): - compare_errors( - compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" - ) +# tests_dir = __file__.rpartition("/")[0] + "/parser/" +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +# +# +# @pytest.mark.parser +# @pytest.mark.error +# @pytest.mark.run(order=2) +# @pytest.mark.parametrize("cool_file", tests) +# def test_parser_errors(compiler_path, cool_file): +# compare_errors( +# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" +# ) From 960edaee1df20fa2510ee9cc86fa452ce73c3c04 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 20 Sep 2021 21:05:08 -0400 Subject: [PATCH 140/432] refactor: minor changes --- src/__main__.py | 5 +- src/debdev.py | 87 ---------------------- src/semantics/inference/soft_inferencer.py | 4 +- 3 files changed, 4 insertions(+), 92 deletions(-) delete mode 100644 src/debdev.py diff --git a/src/__main__.py b/src/__main__.py index 7978d111c..2374bbb3e 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -9,7 +9,6 @@ HardInferencer, BackInferencer, TypesInferencer, - types_inferencer, ) @@ -64,14 +63,14 @@ def run_pipeline(program_ast): print(s) exit(1) - # return types_ast + return types_ast def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests/Auto/equals1.cl" + input_file = "debbuging/tests/Auto/call1.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/debdev.py b/src/debdev.py deleted file mode 100644 index 53fb0ae34..000000000 --- a/src/debdev.py +++ /dev/null @@ -1,87 +0,0 @@ -import os - -from debbuging import type_logger -from parsing import parser -from semantics import type_collector, type_builder, soft_inferencer, hard_inferencer - - -def format_errors(errors, s=""): - count = 1 - errors.sort(key=lambda x: x[0]) - for error in errors: - num = str(count) if count > 9 else "0" + str(count) - s += num + ". " + error[1] + "\n" - count += 1 - return s - - -def run_pipeline(program): - ast = parser.parse(program) - - collector = type_collector.TypeCollector() - collector.visit(ast) - context = collector.context - errors = collector.errors - # print('Context\n', context) - - builder = type_builder.TypeBuilder(context, errors) - builder.visit(ast) - # print('Context\n', context) - - soft = soft_inferencer.SoftInferencer(context) - soft_ast = soft.visit(ast) - errors += soft.errors - - hard = hard_inferencer.HardInferencer(context) - hard_ast = hard.visit(soft_ast) - - hard_ast = hard.visit(hard_ast) - errors += hard.errors - # auto_inferencer = autotype_inferencer.AutotypeInferencer(context, errors) - # auto_inferencer.visit(ast, scope) - - logger = type_logger.TypeLogger(context) - log = logger.visit(hard_ast, hard_ast.scope) - print(log) - s = "Semantic Errors:\n" - s = format_errors(errors, s) - print(s) - - -try: - misc = r"./tests/Misc" - auto = r"./tests/Auto" - folder_path = auto - filenames = os.listdir(folder_path) - filenames.sort() -except FileNotFoundError: - print("Error Locating Files") -count = 100 - -filenames = [ - r"/home/rodro/Aarka/Complementos de Compilacion/cool-cows/src/debbuging/tests/Auto/" - r"03Many.cl" -] - -for filename in filenames: - if count == 0: - print("Reach Count Limit") - break - - path = os.path.join(folder_path, filename) - file = open(path, "r") - program = file.read() - file.close() - - print(f"Running {filename}") - run_pipeline(program) - count -= 1 - print("-------------------------------------------------------------------------\n") - if len(filenames) > 1: - # input() - pass - -print("EndOfFiles") - - -# todo: Manejar los self types dentro de los type bags correctamente diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 34457ae0f..ac3721214 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -384,6 +384,7 @@ def visit(self, node, scope): if len(caller_type.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] + caller_type_name = caller_type.generate_name() conforms(caller_type, TypeBag(set(types), types)) if len(caller_type.type_set): methods = [ @@ -394,7 +395,7 @@ def visit(self, node, scope): node, f"AtributeError: There is no method '{node.id}'" f" that recieves {len(node.params)} arguments in" - f" types {caller_type.name}.", + f" types {caller_type_name}.", ) elif len(caller_type.type_set) == 1: caller = caller_type.heads[0] @@ -426,7 +427,6 @@ def visit(self, node, scope): else: # Errors already notified previuosly method_call_node.inferenced_type = TypeBag(set()) # ErrorType - return method_call_node @visitor.when(ArithmeticNode) From 9ad95e32b6c115e924b0530e8a802564e5ae6655 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 20 Sep 2021 21:05:52 -0400 Subject: [PATCH 141/432] fix: fix an issue while forming new TypeBag heads --- src/semantics/tools/type.py | 40 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index 70e342ebc..eed0442f8 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -282,27 +282,25 @@ def update_heads(self) -> None: if self.error_type: return - new_heads = [] - visited = set() - for head in self.heads: - if head in self.type_set: - new_heads.append(head) - continue - pos_new_head = [] - lower_index = 2 ** 32 - for typex in self.type_set: - if typex in visited: - continue - - # if typex.conforms_to(head): - visited.add(typex) - if typex.index < lower_index: - pos_new_head = [typex] - lower_index = typex.index - elif typex.index == lower_index: - pos_new_head.append(typex) - new_heads += pos_new_head - self.heads = new_heads + # new_heads = [] + # visited = set() + # for head in self.heads: + # if head in self.type_set: + # new_heads.append(head) + # continue + pos_new_head = [] + lower_index = 2 ** 32 + for typex in self.type_set: + #if typex in visited: + # continue + + if typex.index < lower_index: + pos_new_head = [typex] + lower_index = typex.index + elif typex.index == lower_index: + pos_new_head.append(typex) + #new_heads += pos_new_head + self.heads = pos_new_head#new_heads def swap_self_type(self, swap_type, back=False): if self.error_type: From 9b5208fda6e20251e1e486faa2fe2462ffc262cf Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 20 Sep 2021 21:06:41 -0400 Subject: [PATCH 142/432] beibi: uncomment testers --- tests/lexer_test.py | 26 ++++++++++++-------------- tests/parser_test.py | 22 ++++++++++------------ 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 36de97d6f..7cc100b22 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -2,17 +2,15 @@ import os from utils import compare_errors -# tests_dir = __file__.rpartition("/")[0] + "/lexer/" -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -# -# -# @pytest.mark.lexer -# @pytest.mark.error -# @pytest.mark.run(order=1) -# @pytest.mark.parametrize("cool_file", tests) -# def test_lexer_errors(compiler_path, cool_file): -# print(compiler_path) -# print(cool_file) -# compare_errors( -# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" -# ) +tests_dir = __file__.rpartition("/")[0] + "/lexer/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +@pytest.mark.lexer +@pytest.mark.error +@pytest.mark.run(order=1) +@pytest.mark.parametrize("cool_file", tests) +def test_lexer_errors(compiler_path, cool_file): + print(compiler_path) + print(cool_file) + compare_errors( + compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" + ) diff --git a/tests/parser_test.py b/tests/parser_test.py index 30dc1c95b..5c98fd1b2 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -2,15 +2,13 @@ import os from utils import compare_errors -# tests_dir = __file__.rpartition("/")[0] + "/parser/" -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] -# -# -# @pytest.mark.parser -# @pytest.mark.error -# @pytest.mark.run(order=2) -# @pytest.mark.parametrize("cool_file", tests) -# def test_parser_errors(compiler_path, cool_file): -# compare_errors( -# compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" -# ) +tests_dir = __file__.rpartition("/")[0] + "/parser/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +@pytest.mark.parser +@pytest.mark.error +@pytest.mark.run(order=2) +@pytest.mark.parametrize("cool_file", tests) +def test_parser_errors(compiler_path, cool_file): + compare_errors( + compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" + ) From 9b75aff4c6c32955c2c156d6768b0a007459db79 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 5 Oct 2021 13:03:14 -0400 Subject: [PATCH 143/432] codegen: add cil_ast module --- src/ast/cil_ast.py | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/ast/cil_ast.py diff --git a/src/ast/cil_ast.py b/src/ast/cil_ast.py new file mode 100644 index 000000000..76ea49a3f --- /dev/null +++ b/src/ast/cil_ast.py @@ -0,0 +1,93 @@ +from typing import List + +class Node: + def __init__(self) -> None: + pass + + def __str__(self) -> str: + raise NotImplementedError() + +class ExpressionNode: + pass + +class StringNode(Node): + pass + +class LetVarDeclarationNode(ExpressionNode): + def __init__(self, idx:str, typex:str, expression=None): + Node.__init__(self) + self.idx= idx + self.type = typex + self.expression = expression + +class DeclarationNode(Node): + def info(self): + raise NotImplementedError() + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx:str, typex:str, expression:ExpressionNode=None, locals:List[ExpressionNode]=[]) -> None: + super().__init__() + self.id = idx + self.type = typex + self.expression = expression + + def __str__(self) -> str: + return f"attribute {self.id}" + + def info(self): + pass + +class MethodDeclarationNode(DeclarationNode): + def __init__(self, idx:str, params:List[ParamNodes], locals:List[ExpressionNode], body:ExpressionNode, return_type:str,) -> None: + super().__init__() + self.idx = idx + self.paramas = params + self.locals = locals + self.return_type = return_type + self.body = body + + def __str__(self): + # Return func name and address + pass + + def info(self): + # Return all the code of the function + pass + +class ClassDeclarationNode(Node): + def __init__(self, idx:str, parent:str, features:List[DeclarationNode]) -> None: + super().__init__() + self. idx= idx + self.parent = parent + self.features = features + + def __str__(self) -> str: + type_str = ("type " + self. idx+ (f" : {self.parent}" if self.parent != "" else "") + " {\n") + type_str += " ;\n".join(str(feature) for feature in self.features) + type_str += ";\n}\n" + + +class ProgramNode(Node): + def __init__(self, types:List[ClassDeclarationNode], data:List[StringNode], code: List[MethodDeclarationNode]) -> None: + super().__init__() + self.types = types + self.data = data + self.code = code + + def __str__(self) -> str: + types = ".TYPE\n" + types += "\n".join(str(typex) for typex in self.types) + + data = ".DATA\n" + data = "\n".join(str(string_node) for string_node in self.data) + + code = ".CODE\n" + code += "\n".join(func_node.info() for func_node in self.code) + + return f"{types}\n{data}\n{code}" + + + + + + From 79ac86f6f29d0eca4e2ccc76e122357907ae230d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 5 Oct 2021 13:22:00 -0400 Subject: [PATCH 144/432] docs: add docs to document every part of the parser --- src/docs/codegen.md | 49 +++++++++++++++++++++++++++++++++++++++++++ src/docs/inference.md | 2 ++ src/docs/lexing.md | 2 ++ src/docs/parsing.md | 2 ++ src/docs/semantics.md | 2 ++ 5 files changed, 57 insertions(+) create mode 100644 src/docs/codegen.md create mode 100644 src/docs/inference.md create mode 100644 src/docs/lexing.md create mode 100644 src/docs/parsing.md create mode 100644 src/docs/semantics.md diff --git a/src/docs/codegen.md b/src/docs/codegen.md new file mode 100644 index 000000000..eb14584aa --- /dev/null +++ b/src/docs/codegen.md @@ -0,0 +1,49 @@ +# Generacion de Codigo + +Despues de realizado el chequeo semantico se procede a realizar la generacion de codigo con el ast obtenido como resultado. + +Se utiliza un nuevo ast para esta parte del compilador _codegen_ast.py_. + +Cada nodo de este nuevo AST se representa a si mismo en cil. + +### Program Node \ + +``` +.TYPE + + +... + + +.DATA + + +... + + +.CODE + + +... + + + +... + +``` + +### Class Declaration Node \ + +``` + + +... + + + +... + +``` + +### Function Declaration Node \ + diff --git a/src/docs/inference.md b/src/docs/inference.md new file mode 100644 index 000000000..74e0eb852 --- /dev/null +++ b/src/docs/inference.md @@ -0,0 +1,2 @@ +# Inferencia + diff --git a/src/docs/lexing.md b/src/docs/lexing.md new file mode 100644 index 000000000..9c8ac14ce --- /dev/null +++ b/src/docs/lexing.md @@ -0,0 +1,2 @@ +# Lexer + diff --git a/src/docs/parsing.md b/src/docs/parsing.md new file mode 100644 index 000000000..918acad19 --- /dev/null +++ b/src/docs/parsing.md @@ -0,0 +1,2 @@ +# Parser + diff --git a/src/docs/semantics.md b/src/docs/semantics.md new file mode 100644 index 000000000..2b9137abb --- /dev/null +++ b/src/docs/semantics.md @@ -0,0 +1,2 @@ +# Semantica + From 2b64dff0cf8b9a92ef02b0cf6c572fcaf7f9951f Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 5 Oct 2021 13:58:42 -0400 Subject: [PATCH 145/432] docs(codegen): add minor things --- src/docs/codegen.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index eb14584aa..34d6c47fb 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -47,3 +47,25 @@ Cada nodo de este nuevo AST se representa a si mismo en cil. ### Function Declaration Node \ +``` +todo +``` + +### Function Declaration Node info() + +``` +todo +``` + +### Attribute Declaration Node \ + +``` +todo +``` + +### Attribute Declaration Node info() \ + +``` +todo +``` + From eaedcdd1310f094f00d41bb2d0c00a51d437f0fa Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 5 Oct 2021 13:59:28 -0400 Subject: [PATCH 146/432] docs(inference): add base documentation of inferencer internal working --- src/docs/inference.md | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/docs/inference.md b/src/docs/inference.md index 74e0eb852..191039c0a 100644 --- a/src/docs/inference.md +++ b/src/docs/inference.md @@ -1,2 +1,48 @@ # Inferencia +Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger existe alguno que no tiene un ancestro comun mas general con los demas. + +## Funcionamiento + +El inferenciador se ejecuta varias veces, en cada una realizando un chequeo distinto. + +### Soft Inferencer + +Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. + +Aplica las reglas de cool para realizar la infererencia. Este permite que haya ambiguedad y que un tipo por determinar puede tener varios ancestros sin nada en comun. + +En el lenguage cool esto se evidencia cuando se hace un llamado a una funcion del estilo + +``` +a.func(); +``` + +donde el tipo de _a_ no es definido. El inferenciador buscara todas las clases con un metodo de nombre func y cantidad de parametro determinad y los tendra como posibles tipos para _a_. En estos casos _a_ puede ser de varios tipos no relacionados por ejemplo cuando: + +``` +class A { + method func():Int{ + 3 + 3 + } +}; +class B { + method func():String{ + "3 + 3" + } +}; +``` + +$a \in \{A, B\}$ donde A hereda de B y viceversa $a \notin \text{Object}$. pues Object no tiene un metodo func que recibe 0 argumentos. + +Debido a que las variables pueden tener varios tipos no relacionados tampoco se revisa las comparaciones de igual. + +### Hard Inferenecer + +Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. + +En esta parte el inferenicador realiza las misma acciones que en el Soft Inferencer, excepto que ya una variable $a$ no puede tener tipos de datos no relacionados. Se revisa que las comparaciones de igualdad que ambos miembros sean del mismo tipo. + +### Back Inferencer + +Este se encarga de inferir el tipo de una variable a base del valor de la expresion. From 00a3c7aae9dcd53946e343951a623e21b1ee65a9 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 5 Oct 2021 14:08:42 -0400 Subject: [PATCH 147/432] core(codegen): add code gen base module --- src/code_gen/cil_gen.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/code_gen/cil_gen.py diff --git a/src/code_gen/cil_gen.py b/src/code_gen/cil_gen.py new file mode 100644 index 000000000..b8d0d5177 --- /dev/null +++ b/src/code_gen/cil_gen.py @@ -0,0 +1,31 @@ +from utils import visitor +from ast.types_ast import ( + ProgramNode, + ClassDeclarationNode, + AttrDeclarationNode, + MethodDeclarationNode + ) + +class CilGenerator: + def __init__(self) -> None: + pass + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode): + pass + + @visitor.when(ClassDeclarationNode) + def visit(self, node:ClassDeclarationNode): + pass + + @visitor.when(AttrDeclarationNode) + def visit(self, node:AttrDeclarationNode): + pass + + @visitor.when(MethodDeclarationNode) + def visit(self, node:MethodDeclarationNode): + pass From 506f29756dfe485c68684a0f1f31e1a99b1752c6 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Wed, 6 Oct 2021 13:54:22 -0400 Subject: [PATCH 148/432] core(codegen): implement more classes to achive cil --- src/ast/cil_ast.py | 52 ++++++++++++++++++++++++++++++++++++++++- src/code_gen/cil_gen.py | 52 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/ast/cil_ast.py b/src/ast/cil_ast.py index 76ea49a3f..8475867a0 100644 --- a/src/ast/cil_ast.py +++ b/src/ast/cil_ast.py @@ -10,9 +10,59 @@ def __str__(self) -> str: class ExpressionNode: pass -class StringNode(Node): +class AtomicNode(ExpressionNode): pass +class StringNode(AtomicNode): + pass + +class IntNode(AtomicNode): + pass + +class VariableNode(ExpressionNode): + pass + +class VarDeclarationNode(ExpressionNode): + pass + +class LetNode(ExpressionNode): + pass + +class LoopNonde(ExpressionNode): + pass + +class CaseOptionNode(ExpressionNode): + pass + +class CaseNode(ExpressionNode): + def __init__(self, case_expr:ExpressionNode, options:List[CaseOptionNode]) -> None: + super().__init__() + self.case_expr = case_expr + self.options = options + +class ConditionalNode(ExpressionNode): + def __init__(self, condition:ExpressionNode, then_node:ExpressionNode, else_node:ExpressionNode) -> None: + super().__init__() + self.condition = condition + self.then_node = then_node + self.else_node = else_node + + def __str__(self): + # ToDo + pass + +class BlocksNode(ExpressionNode): + def __init__(self, expression_list:List[ExpressionNode]) -> None: + super().__init__() + self.expression_list = expression_list + + def __str__(self): + block_str = "{\n" + block_str += ";\n".join(expression for expression in self.expression_list) + block_str += ";\n}\n" + return block_str + + class LetVarDeclarationNode(ExpressionNode): def __init__(self, idx:str, typex:str, expression=None): Node.__init__(self) diff --git a/src/code_gen/cil_gen.py b/src/code_gen/cil_gen.py index b8d0d5177..74c818318 100644 --- a/src/code_gen/cil_gen.py +++ b/src/code_gen/cil_gen.py @@ -1,9 +1,19 @@ from utils import visitor from ast.types_ast import ( + CaseNode, + CaseOptionNode, + ConditionalNode, + IntNode, + LetNode, + LoopNode, ProgramNode, ClassDeclarationNode, AttrDeclarationNode, - MethodDeclarationNode + MethodDeclarationNode, + BlocksNode, + StringNode, + VarDeclarationNode, + VariableNode ) class CilGenerator: @@ -29,3 +39,43 @@ def visit(self, node:AttrDeclarationNode): @visitor.when(MethodDeclarationNode) def visit(self, node:MethodDeclarationNode): pass + + @visitor.when(BlocksNode) + def visit(self, node:BlocksNode): + pass + + @visitor.when(ConditionalNode) + def visit(self, node:ConditionalNode): + pass + + @visitor.when(CaseNode) + def visit(self, node:CaseNode): + pass + + @visitor.when(CaseOptionNode) + def visit(self, node:CaseOptionNode): + pass + + @visitor.when(LoopNode) + def visit(self, node:LoopNode): + pass + + @visitor.when(LetNode) + def visit(self, node:LetNode): + pass + + @visitor.when(VarDeclarationNode) + def visit(self, node:VarDeclarationNode): + pass + + @visitor.when(VariableNode) + def visit(self, node:VariableNode): + pass + + @visitor.when(StringNode) + def visit(self, node:StringNode): + pass + + @visitor.when(IntNode) + def visit(self, node:IntNode): + pass From 6f6db833531e65808e6478824dc21b813f42f472 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 8 Oct 2021 15:09:18 -0400 Subject: [PATCH 149/432] docs(codegen): expand ccil grammar --- src/code_gen/cil_gen.py | 61 ++++++++++----------- src/docs/codegen.md | 114 +++++++++++++++++----------------------- 2 files changed, 80 insertions(+), 95 deletions(-) diff --git a/src/code_gen/cil_gen.py b/src/code_gen/cil_gen.py index 74c818318..6372f63ca 100644 --- a/src/code_gen/cil_gen.py +++ b/src/code_gen/cil_gen.py @@ -1,20 +1,21 @@ from utils import visitor from ast.types_ast import ( - CaseNode, - CaseOptionNode, - ConditionalNode, - IntNode, - LetNode, - LoopNode, - ProgramNode, - ClassDeclarationNode, - AttrDeclarationNode, - MethodDeclarationNode, - BlocksNode, - StringNode, - VarDeclarationNode, - VariableNode - ) + CaseNode, + CaseOptionNode, + ConditionalNode, + IntNode, + LetNode, + LoopNode, + ProgramNode, + ClassDeclarationNode, + AttrDeclarationNode, + MethodDeclarationNode, + BlocksNode, + StringNode, + VarDeclarationNode, + VariableNode, +) + class CilGenerator: def __init__(self) -> None: @@ -25,57 +26,57 @@ def visit(self, node): pass @visitor.when(ProgramNode) - def visit(self, node:ProgramNode): + def visit(self, node: ProgramNode): pass @visitor.when(ClassDeclarationNode) - def visit(self, node:ClassDeclarationNode): + def visit(self, node: ClassDeclarationNode): pass - + @visitor.when(AttrDeclarationNode) - def visit(self, node:AttrDeclarationNode): + def visit(self, node: AttrDeclarationNode): pass @visitor.when(MethodDeclarationNode) - def visit(self, node:MethodDeclarationNode): + def visit(self, node: MethodDeclarationNode): pass @visitor.when(BlocksNode) - def visit(self, node:BlocksNode): + def visit(self, node: BlocksNode): pass @visitor.when(ConditionalNode) - def visit(self, node:ConditionalNode): + def visit(self, node: ConditionalNode): pass @visitor.when(CaseNode) - def visit(self, node:CaseNode): + def visit(self, node: CaseNode): pass @visitor.when(CaseOptionNode) - def visit(self, node:CaseOptionNode): + def visit(self, node: CaseOptionNode): pass @visitor.when(LoopNode) - def visit(self, node:LoopNode): + def visit(self, node: LoopNode): pass @visitor.when(LetNode) - def visit(self, node:LetNode): + def visit(self, node: LetNode): pass @visitor.when(VarDeclarationNode) - def visit(self, node:VarDeclarationNode): + def visit(self, node: VarDeclarationNode): pass @visitor.when(VariableNode) - def visit(self, node:VariableNode): + def visit(self, node: VariableNode): pass @visitor.when(StringNode) - def visit(self, node:StringNode): + def visit(self, node: StringNode): pass @visitor.when(IntNode) - def visit(self, node:IntNode): + def visit(self, node: IntNode): pass diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 34d6c47fb..53a914f6f 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -1,71 +1,55 @@ -# Generacion de Codigo +# Generacion de Codigo Intermedio Despues de realizado el chequeo semantico se procede a realizar la generacion de codigo con el ast obtenido como resultado. Se utiliza un nuevo ast para esta parte del compilador _codegen_ast.py_. -Cada nodo de este nuevo AST se representa a si mismo en cil. - -### Program Node \ - -``` -.TYPE - - -... - - -.DATA - - -... - - -.CODE - - -... - - - -... - -``` - -### Class Declaration Node \ - -``` - - -... - - - -... - -``` - -### Function Declaration Node \ - -``` -todo -``` - -### Function Declaration Node info() - -``` -todo -``` - -### Attribute Declaration Node \ - -``` -todo -``` - -### Attribute Declaration Node info() \ - -``` -todo -``` +Cada nodo de este nuevo AST se representa a si mismo en ccil (cool cows intermediate language). +$$ +\begin{array}{rcl} +\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ +\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ +\text{Type} &\rarr& \text{FeatureList}\\ +\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ +&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ +\\ +\text{CodeList} &\rarr& \text{AttrCode }|\text{ FuncCode }|\text{ CodeList }| \space\epsilon\\ +&|& \text{ AttrCode; CodeList } | \text{ FuncCode; CodeList}\\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList Expression} \}\\ +\text{FuncCode} &\rarr& \text{id }\{\\ +&&\text{ParamList}\\ +&&\text{LocalList}\\ +&&\text{Expression}\\ +&&\text{\}}\\ +\\ +\text{Expression} &\rarr& \text{id = AtomicOp}\\ +&|& \text{goto id}\\ +&|& \text{label id}\\ +&|& \text{return Atom}\\ +&|& \text{setattr id id Atom}\\ +&|& \text{if Atom goto id}\\ +&|& \text{ArgList id = call id}\\ +&|& \text{ArgList id = vcall id id }\\ +&|& \text{\{ExpressionList\}}\\ +\text{ExpressionList} &\rarr& \text{Expression; ExpressionList } | \text{ Expression} \\ +\text{ArgList} &\rarr& \text{arg id; ArgList } | \space\epsilon \\ + +\text{AtomicOp} &\rarr& \text{Atom + Atom}\\ +&|& \text{Atom + Atom}\\ +&|& \text{Atom - Atom}\\ +&|& \text{Atom * Atom}\\ +&|& \text{Atom / Atom}\\ +&|& \text{not Atom}\\ +&|& \text{neg Atom}\\ +&|& \text{Atom < Atom}\\ +&|& \text{Atom <= Atom}\\ +&|& \text{Atom = Atom}\\ +&|& \text{allocate id}\\ +&|& \text{getattr id id}\\ +&|& \text{Atom}\\ +\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ +\text{Constant} &\rarr& \text{ integer } | \text{ string } | \text{ boolean } +\end{array} +$$ +Remaining = {Let, Case } From dc0d1e0f3578d04460cf5ac1f749443920f88c90 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 8 Oct 2021 15:09:59 -0400 Subject: [PATCH 150/432] fix(codegen): rename cil to ccil (cool cows intermediate language) --- src/code_gen/{cil_gen.py => ccil_gen.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/code_gen/{cil_gen.py => ccil_gen.py} (100%) diff --git a/src/code_gen/cil_gen.py b/src/code_gen/ccil_gen.py similarity index 100% rename from src/code_gen/cil_gen.py rename to src/code_gen/ccil_gen.py From 2d818136dccaad5a872a6c5b391bb8a10145c993 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 8 Oct 2021 16:49:01 -0400 Subject: [PATCH 151/432] docs(codegen): add examples of cool inputs and ccil outputs --- src/docs/codegen.md | 237 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 230 insertions(+), 7 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 53a914f6f..86bc72e00 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -22,20 +22,19 @@ $$ &&\text{Expression}\\ &&\text{\}}\\ \\ -\text{Expression} &\rarr& \text{id = AtomicOp}\\ +\text{Expression} &\rarr& \text{id = ReturnOp}\\ &|& \text{goto id}\\ &|& \text{label id}\\ &|& \text{return Atom}\\ &|& \text{setattr id id Atom}\\ &|& \text{if Atom goto id}\\ -&|& \text{ArgList id = call id}\\ -&|& \text{ArgList id = vcall id id }\\ -&|& \text{\{ExpressionList\}}\\ +&|& \text{ArgList id = call id integer}\\ +&|& \text{ArgList id = vcall id id integer }\\ +&|& \text{ExpressionList}\\ \text{ExpressionList} &\rarr& \text{Expression; ExpressionList } | \text{ Expression} \\ \text{ArgList} &\rarr& \text{arg id; ArgList } | \space\epsilon \\ -\text{AtomicOp} &\rarr& \text{Atom + Atom}\\ -&|& \text{Atom + Atom}\\ +\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ &|& \text{Atom - Atom}\\ &|& \text{Atom * Atom}\\ &|& \text{Atom / Atom}\\ @@ -51,5 +50,229 @@ $$ \text{Constant} &\rarr& \text{ integer } | \text{ string } | \text{ boolean } \end{array} $$ -Remaining = {Let, Case } + +## Transformaciones + +#### While Loop + +**Cool Input** + +``` +while () loop pool +``` + +**CCIL Output** + +```assembly +label while_init +x = +neg_x = neg x +if neg_x goto while_end + + + +goto while_init +label while_end +``` + +#### If Then Else + +**Cool Input** + +``` +if then else fi +``` + +**CCIL Output** + +```assembly +x = +if x goto then_expr +label else_expr + + + +goto endif + +label then_expr + + + +label endif +``` + +#### Let In + +**Cool Input** + +``` +let :, ... : in +``` + +**CCIL Output** + +```assembly + + +... + + +# Si existe alguna variable let inicializada con una expresion, ejecutarla + + +... + + + +``` + +#### Case Of + +**Cool Input** + +``` +case of + : => + : => + ... + : => +esac +``` + +**CCIL Output** + +```assembly + + +... + + +x = +t = typeof x +label init_case +t1 = typeof +b1 = t1 == t +if b1 goto branch1 + +t2 = typeof +b2 = t2 == t +if b2 goto branch2 + +... + +tn = typeof +bn = tn == t +if bn goto branchn + +label branch1 + +goto end_case + +label branch2 + +goto end_case + +... + +label branchn + +goto end_case + +label end_case +``` + +El typeof tambien se conforma con un ancestro. Que evaluaria la operacion de igualdad para escoger la rama adecuada? Lanzar un runtime error si no se escoge ninguna rama(eso puede pasar despues del cheque semantico?) + +#### Function Static Call + +**Cool Input** + +``` +(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +r = call n +``` + +#### Function Dynamic Call + +**Cool Input** + +``` +@(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +t = allocate +r = vcall t n +``` + +#### Method Declaration + +**Cool Input** + +``` +(:, ..., :) : +{ + +} +``` + +**CCIL Output** + +```assembly +function { + param + param + ... + param + local + local + ... + local + + r = + return r +} +``` + +#### Expression Block + +**Cool Input** + +``` +{ + ; + ; + ... + ; +} +``` + +**CCIL Output** + +``` + + +... + + + + +... + +``` From be641cf0e781869b672c25199a5e771e59fdaf6f Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Fri, 8 Oct 2021 16:56:28 -0400 Subject: [PATCH 152/432] docs(codegen): minor fix --- src/docs/codegen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 86bc72e00..596bcc266 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -117,7 +117,7 @@ let :, ... : in ... -# Si existe alguna variable let inicializada con una expresion, ejecutarla +# Si existe alguna variable let inicializada con una expresion, ejecutar dicha expresion ... From e27930b6a419bffc8a4bc69671bc186b2628e76b Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 12 Oct 2021 10:34:13 -0400 Subject: [PATCH 153/432] fix: rename cil_ast.py to ccil_ast.py --- src/ast/{cil_ast.py => ccil_ast.py} | 99 +++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 28 deletions(-) rename src/ast/{cil_ast.py => ccil_ast.py} (63%) diff --git a/src/ast/cil_ast.py b/src/ast/ccil_ast.py similarity index 63% rename from src/ast/cil_ast.py rename to src/ast/ccil_ast.py index 8475867a0..133fef5ed 100644 --- a/src/ast/cil_ast.py +++ b/src/ast/ccil_ast.py @@ -1,5 +1,6 @@ from typing import List + class Node: def __init__(self) -> None: pass @@ -7,42 +8,65 @@ def __init__(self) -> None: def __str__(self) -> str: raise NotImplementedError() -class ExpressionNode: - pass + +class ExpressionNode(Node): + def __init__(self, locals: List = []) -> None: + self.locals = locals + class AtomicNode(ExpressionNode): pass + class StringNode(AtomicNode): pass + class IntNode(AtomicNode): pass + class VariableNode(ExpressionNode): pass + class VarDeclarationNode(ExpressionNode): pass + class LetNode(ExpressionNode): pass -class LoopNonde(ExpressionNode): + +class LoopNode(ExpressionNode): pass + class CaseOptionNode(ExpressionNode): pass + class CaseNode(ExpressionNode): - def __init__(self, case_expr:ExpressionNode, options:List[CaseOptionNode]) -> None: - super().__init__() + def __init__( + self, + case_expr: ExpressionNode, + options: List[CaseOptionNode], + locals: List = [], + ) -> None: + super().__init__(locals=locals) self.case_expr = case_expr self.options = options + class ConditionalNode(ExpressionNode): - def __init__(self, condition:ExpressionNode, then_node:ExpressionNode, else_node:ExpressionNode) -> None: - super().__init__() + def __init__( + self, + condition: ExpressionNode, + then_node: ExpressionNode, + else_node: ExpressionNode, + locals: List = [], + ) -> None: + super().__init__(locals=locals) self.condition = condition self.then_node = then_node self.else_node = else_node @@ -51,8 +75,9 @@ def __str__(self): # ToDo pass + class BlocksNode(ExpressionNode): - def __init__(self, expression_list:List[ExpressionNode]) -> None: + def __init__(self, expression_list: List[ExpressionNode]) -> None: super().__init__() self.expression_list = expression_list @@ -64,18 +89,25 @@ def __str__(self): class LetVarDeclarationNode(ExpressionNode): - def __init__(self, idx:str, typex:str, expression=None): - Node.__init__(self) - self.idx= idx + def __init__(self, idx: str, typex: str, expression=None, locals=[]): + super().__init__(self, locals=locals) + self.idx = idx self.type = typex self.expression = expression + class DeclarationNode(Node): def info(self): raise NotImplementedError() - + + class AttrDeclarationNode(DeclarationNode): - def __init__(self, idx:str, typex:str, expression:ExpressionNode=None, locals:List[ExpressionNode]=[]) -> None: + def __init__( + self, + idx: str, + typex: str, + expression: ExpressionNode = None, + ) -> None: super().__init__() self.id = idx self.type = typex @@ -87,38 +119,55 @@ def __str__(self) -> str: def info(self): pass + class MethodDeclarationNode(DeclarationNode): - def __init__(self, idx:str, params:List[ParamNodes], locals:List[ExpressionNode], body:ExpressionNode, return_type:str,) -> None: + def __init__( + self, + idx: str, + params: List[ParamNodes], + body: ExpressionNode, + return_type: str, + ) -> None: super().__init__() self.idx = idx self.paramas = params - self.locals = locals self.return_type = return_type self.body = body def __str__(self): - # Return func name and address + # Return func name and address pass - + def info(self): # Return all the code of the function pass + class ClassDeclarationNode(Node): - def __init__(self, idx:str, parent:str, features:List[DeclarationNode]) -> None: + def __init__(self, idx: str, parent: str, features: List[DeclarationNode]) -> None: super().__init__() - self. idx= idx + self.idx = idx self.parent = parent self.features = features def __str__(self) -> str: - type_str = ("type " + self. idx+ (f" : {self.parent}" if self.parent != "" else "") + " {\n") + type_str = ( + "type " + + self.idx + + (f" : {self.parent}" if self.parent != "" else "") + + " {\n" + ) type_str += " ;\n".join(str(feature) for feature in self.features) type_str += ";\n}\n" class ProgramNode(Node): - def __init__(self, types:List[ClassDeclarationNode], data:List[StringNode], code: List[MethodDeclarationNode]) -> None: + def __init__( + self, + types: List[ClassDeclarationNode], + data: List[StringNode], + code: List[MethodDeclarationNode], + ) -> None: super().__init__() self.types = types self.data = data @@ -130,14 +179,8 @@ def __str__(self) -> str: data = ".DATA\n" data = "\n".join(str(string_node) for string_node in self.data) - + code = ".CODE\n" code += "\n".join(func_node.info() for func_node in self.code) return f"{types}\n{data}\n{code}" - - - - - - From 1eb60b38faed3d39ead274147ee4a068c59f7bab Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 12 Oct 2021 10:36:46 -0400 Subject: [PATCH 154/432] core(codegen): add more functionality to ccil visitor --- src/code_gen/ccil_gen.py | 77 ++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 6372f63ca..a265de72c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,3 +1,4 @@ +from typing import List from utils import visitor from ast.types_ast import ( CaseNode, @@ -15,68 +16,100 @@ VarDeclarationNode, VariableNode, ) +import ast.ccil_ast as ccil -class CilGenerator: +class CCILGenerator: def __init__(self) -> None: - pass + self.count = 0 @visitor.on("node") def visit(self, node): pass @visitor.when(ProgramNode) - def visit(self, node: ProgramNode): - pass + def visit(self, node: ProgramNode) -> ccil.ProgramNode: + class_decl: List[ccil.ClassDeclarationNode] = [] + for declaration in node.declarations: + class_decl.append(self.visit(declaration)) + + # The other things need should be deleted? + return ccil.ProgramNode(class_decl) @visitor.when(ClassDeclarationNode) - def visit(self, node: ClassDeclarationNode): - pass + def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: + class_features: List[ccil.DeclarationNode] = [] + for feature in node.features: + class_features.append(self.visit(feature)) + + # Parent apparently is not needed? + return ccil.ClassDeclarationNode(node.id, parent="?", features=class_features) @visitor.when(AttrDeclarationNode) - def visit(self, node: AttrDeclarationNode): - pass + def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: + ccil_node: ccil.AttrDeclarationNode = ccil.AttrDeclarationNode( + node.id, node.type, None + ) + if node.expr is not None: + ccil_node.expression = self.visit(node.expr) + return ccil_node @visitor.when(MethodDeclarationNode) - def visit(self, node: MethodDeclarationNode): - pass + def visit(self, node: MethodDeclarationNode) -> ccil.MethodDeclarationNode: + # What to do about parameter ?? Unanswered question from the past... + + body: ccil.ExpressionNode = self.visit(node.body) + # Fill return with something :( + return MethodDeclarationNode() @visitor.when(BlocksNode) - def visit(self, node: BlocksNode): - pass + def visit(self, node: BlocksNode) -> ccil.BlocksNode: + expr_list: List[ccil.ExpressionNode] = [ + self.visit(expr) for expr in node.expr_list + ] + return ccil.BlocksNode(expr_list) @visitor.when(ConditionalNode) - def visit(self, node: ConditionalNode): - pass + def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: + condition: ccil.ExpressionNode = self.visit(node.condition) + then_body: ccil.ExpressionNode = self.visit(node.then_body) + else_body: ccil.ExpressionNode = self.visit(node.else_body) + + return ccil.ConditionalNode(condition, then_body, else_body) @visitor.when(CaseNode) - def visit(self, node: CaseNode): + def visit(self, node: CaseNode) -> ccil.CaseNode: pass @visitor.when(CaseOptionNode) - def visit(self, node: CaseOptionNode): + def visit(self, node: CaseOptionNode) -> ccil.CaseOptionNode: pass @visitor.when(LoopNode) - def visit(self, node: LoopNode): + def visit(self, node: LoopNode) -> ccil.LoopNode: pass @visitor.when(LetNode) - def visit(self, node: LetNode): + def visit(self, node: LetNode) -> ccil.LetNode: pass @visitor.when(VarDeclarationNode) - def visit(self, node: VarDeclarationNode): + def visit(self, node: VarDeclarationNode) -> ccil.VarDeclarationNode: pass @visitor.when(VariableNode) - def visit(self, node: VariableNode): + def visit(self, node: VariableNode) -> ccil.VariableNode: pass @visitor.when(StringNode) - def visit(self, node: StringNode): + def visit(self, node: StringNode) -> ccil.StringNode: pass @visitor.when(IntNode) - def visit(self, node: IntNode): + def visit(self, node: IntNode) -> ccil.IntNode: pass + + def generate_var_name(self) -> str: + """Generate a new local name""" + self.count += 1 + return f"v{self.count}" From 51ac3afa55abf88ef47a50b2222f65ccaddf2200 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 12 Oct 2021 10:37:15 -0400 Subject: [PATCH 155/432] docs(codegen): minor update --- src/docs/codegen.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 596bcc266..4c815ec20 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -28,6 +28,7 @@ $$ &|& \text{return Atom}\\ &|& \text{setattr id id Atom}\\ &|& \text{if Atom goto id}\\ +&|& \text{ifFalse Atom goto id}\\ &|& \text{ArgList id = call id integer}\\ &|& \text{ArgList id = vcall id id integer }\\ &|& \text{ExpressionList}\\ @@ -66,8 +67,7 @@ while () loop pool ```assembly label while_init x = -neg_x = neg x -if neg_x goto while_end +ifFalse x goto while_end @@ -87,16 +87,15 @@ if then else fi ```assembly x = -if x goto then_expr -label else_expr +ifFalse x goto else_expr +label then_expr - + goto endif +label else_expr -label then_expr - - + label endif ``` From 1411566675707d33afdfddfc6b9d6d8a5a4c32bf Mon Sep 17 00:00:00 2001 From: Adrian Portales Date: Tue, 12 Oct 2021 14:59:37 -0400 Subject: [PATCH 156/432] fix: change default list as argument for a sentinel value --- src/ast/ccil_ast.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ast/ccil_ast.py b/src/ast/ccil_ast.py index 133fef5ed..978bd5b26 100644 --- a/src/ast/ccil_ast.py +++ b/src/ast/ccil_ast.py @@ -10,7 +10,9 @@ def __str__(self) -> str: class ExpressionNode(Node): - def __init__(self, locals: List = []) -> None: + def __init__(self, locals: List = None ) -> None: + if locals is None: + self.locals = [] self.locals = locals @@ -51,8 +53,10 @@ def __init__( self, case_expr: ExpressionNode, options: List[CaseOptionNode], - locals: List = [], + locals: List = None, ) -> None: + if locals is None: + locals = [] super().__init__(locals=locals) self.case_expr = case_expr self.options = options @@ -64,8 +68,10 @@ def __init__( condition: ExpressionNode, then_node: ExpressionNode, else_node: ExpressionNode, - locals: List = [], + locals: List = None, ) -> None: + if locals is None: + locals = [] super().__init__(locals=locals) self.condition = condition self.then_node = then_node @@ -89,7 +95,9 @@ def __str__(self): class LetVarDeclarationNode(ExpressionNode): - def __init__(self, idx: str, typex: str, expression=None, locals=[]): + def __init__(self, idx: str, typex: str, expression=None, locals=None): + if locals is None: + locals = [] super().__init__(self, locals=locals) self.idx = idx self.type = typex From cdfb5b01d6ae85af5cae294c3ed8e0d6c57fbe79 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Mon, 3 Jan 2022 15:59:08 -0500 Subject: [PATCH 157/432] Oumuamua --- src/ast/ccil_ast.py | 140 +++++++++++++++------------------------ src/code_gen/ccil_gen.py | 29 +++++--- src/code_gen/tools.py | 1 + 3 files changed, 72 insertions(+), 98 deletions(-) create mode 100644 src/code_gen/tools.py diff --git a/src/ast/ccil_ast.py b/src/ast/ccil_ast.py index 978bd5b26..9dd954f36 100644 --- a/src/ast/ccil_ast.py +++ b/src/ast/ccil_ast.py @@ -1,18 +1,28 @@ -from typing import List +from typing import List, Tuple class Node: - def __init__(self) -> None: - pass + def __init__(self, node) -> None: + self.line: int = node.line + self.col: int = node.col + self.type = None - def __str__(self) -> str: - raise NotImplementedError() + def get_position(self) -> Tuple[int, int]: + return self.line, self.col class ExpressionNode(Node): - def __init__(self, locals: List = None ) -> None: + def __init__(self, node, value: str, locals: List[str] = None) -> None: + """ + Parameters: + node <- Node to set this node positon in the original cool program. + value <- Name of the local variable where the expresion final value is going to be stored. + locals <- list of local variables needed to be initialized to expression to work. + """ + super().__init__(node) if locals is None: self.locals = [] + self.value = value self.locals = locals @@ -33,7 +43,11 @@ class VariableNode(ExpressionNode): class VarDeclarationNode(ExpressionNode): - pass + def __init__( + self, expr: ExpressionNode, node, value: str, locals: List = None + ) -> None: + super().__init__(node, value, locals=locals) + self.expression = expr class LetNode(ExpressionNode): @@ -53,11 +67,11 @@ def __init__( self, case_expr: ExpressionNode, options: List[CaseOptionNode], + node, + value: str, locals: List = None, ) -> None: - if locals is None: - locals = [] - super().__init__(locals=locals) + super().__init__(node, value, locals=locals) self.case_expr = case_expr self.options = options @@ -68,65 +82,47 @@ def __init__( condition: ExpressionNode, then_node: ExpressionNode, else_node: ExpressionNode, + node, + value: str, locals: List = None, ) -> None: - if locals is None: - locals = [] - super().__init__(locals=locals) + super().__init__(node, value, locals=locals) self.condition = condition self.then_node = then_node self.else_node = else_node - def __str__(self): - # ToDo - pass - class BlocksNode(ExpressionNode): - def __init__(self, expression_list: List[ExpressionNode]) -> None: - super().__init__() + def __init__( + self, + expression_list: List[ExpressionNode], + node, + value: str, + locals: List = None, + ) -> None: + super().__init__(node, value, locals=locals) self.expression_list = expression_list - def __str__(self): - block_str = "{\n" - block_str += ";\n".join(expression for expression in self.expression_list) - block_str += ";\n}\n" - return block_str - class LetVarDeclarationNode(ExpressionNode): - def __init__(self, idx: str, typex: str, expression=None, locals=None): - if locals is None: - locals = [] - super().__init__(self, locals=locals) - self.idx = idx - self.type = typex + def __init__(self, expression: ExpressionNode, node, value: str, locals=None): + super().__init__(self, node, value, locals=locals) + self.id = node.id + self.type = node.type self.expression = expression class DeclarationNode(Node): - def info(self): - raise NotImplementedError() + pass class AttrDeclarationNode(DeclarationNode): - def __init__( - self, - idx: str, - typex: str, - expression: ExpressionNode = None, - ) -> None: - super().__init__() - self.id = idx - self.type = typex + def __init__(self, expression: ExpressionNode, node) -> None: + super().__init__(node) + self.id = node.id + self.type = node.type self.expression = expression - def __str__(self) -> str: - return f"attribute {self.id}" - - def info(self): - pass - class MethodDeclarationNode(DeclarationNode): def __init__( @@ -135,60 +131,30 @@ def __init__( params: List[ParamNodes], body: ExpressionNode, return_type: str, + node, ) -> None: - super().__init__() + super().__init__(node) self.idx = idx self.paramas = params self.return_type = return_type self.body = body - def __str__(self): - # Return func name and address - pass - - def info(self): - # Return all the code of the function - pass - class ClassDeclarationNode(Node): - def __init__(self, idx: str, parent: str, features: List[DeclarationNode]) -> None: - super().__init__() - self.idx = idx - self.parent = parent + def __init__(self, features: List[DeclarationNode], node) -> None: + super().__init__(node) + self.idx = node.id + self.parent = "?" self.features = features - def __str__(self) -> str: - type_str = ( - "type " - + self.idx - + (f" : {self.parent}" if self.parent != "" else "") - + " {\n" - ) - type_str += " ;\n".join(str(feature) for feature in self.features) - type_str += ";\n}\n" - class ProgramNode(Node): def __init__( self, types: List[ClassDeclarationNode], - data: List[StringNode], - code: List[MethodDeclarationNode], + data: List[str], + node, ) -> None: - super().__init__() + super().__init__(node) self.types = types self.data = data - self.code = code - - def __str__(self) -> str: - types = ".TYPE\n" - types += "\n".join(str(typex) for typex in self.types) - - data = ".DATA\n" - data = "\n".join(str(string_node) for string_node in self.data) - - code = ".CODE\n" - code += "\n".join(func_node.info() for func_node in self.code) - - return f"{types}\n{data}\n{code}" diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a265de72c..eff433be5 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -21,7 +21,8 @@ class CCILGenerator: def __init__(self) -> None: - self.count = 0 + self.count: int = 0 + self.data: List[str] = [] @visitor.on("node") def visit(self, node): @@ -33,8 +34,7 @@ def visit(self, node: ProgramNode) -> ccil.ProgramNode: for declaration in node.declarations: class_decl.append(self.visit(declaration)) - # The other things need should be deleted? - return ccil.ProgramNode(class_decl) + return ccil.ProgramNode(class_decl, self.data, node) @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: @@ -42,8 +42,7 @@ def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: for feature in node.features: class_features.append(self.visit(feature)) - # Parent apparently is not needed? - return ccil.ClassDeclarationNode(node.id, parent="?", features=class_features) + return ccil.ClassDeclarationNode(class_features, node) @visitor.when(AttrDeclarationNode) def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: @@ -67,7 +66,7 @@ def visit(self, node: BlocksNode) -> ccil.BlocksNode: expr_list: List[ccil.ExpressionNode] = [ self.visit(expr) for expr in node.expr_list ] - return ccil.BlocksNode(expr_list) + return ccil.BlocksNode(expr_list, node) @visitor.when(ConditionalNode) def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: @@ -75,7 +74,8 @@ def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: then_body: ccil.ExpressionNode = self.visit(node.then_body) else_body: ccil.ExpressionNode = self.visit(node.else_body) - return ccil.ConditionalNode(condition, then_body, else_body) + value = self.generate_var_name() + return ccil.ConditionalNode(condition, then_body, else_body, value, [value]) @visitor.when(CaseNode) def visit(self, node: CaseNode) -> ccil.CaseNode: @@ -91,15 +91,22 @@ def visit(self, node: LoopNode) -> ccil.LoopNode: @visitor.when(LetNode) def visit(self, node: LetNode) -> ccil.LetNode: - pass + new_decl_list: List[VarDeclarationNode] = [] + for let_decl_node in node.var_decl_list: + new_decl_list.append(self.visit(let_decl_node)) + node_expr: ccil.ExpressionNode = self.visit(node.in_expr) @visitor.when(VarDeclarationNode) def visit(self, node: VarDeclarationNode) -> ccil.VarDeclarationNode: - pass + value = self.generate_var_name() + if node.expr is not None: + ccil_node_expr: ccil.ExpressionNode = self.visit(node.expr) + return ccil.VarDeclarationNode(ccil_node_expr, node, value, [value]) + return ccil.VarDeclarationNode(None, node, value, [value]) @visitor.when(VariableNode) def visit(self, node: VariableNode) -> ccil.VariableNode: - pass + return ccil.VariableNode(node, value=node.id) @visitor.when(StringNode) def visit(self, node: StringNode) -> ccil.StringNode: @@ -107,7 +114,7 @@ def visit(self, node: StringNode) -> ccil.StringNode: @visitor.when(IntNode) def visit(self, node: IntNode) -> ccil.IntNode: - pass + return ccil.IntNode(node, value="") def generate_var_name(self) -> str: """Generate a new local name""" diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py new file mode 100644 index 000000000..5e08e797f --- /dev/null +++ b/src/code_gen/tools.py @@ -0,0 +1 @@ + From bf8ce3aa971cb6684f46260c3e6463cbe9a75385 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 07:50:36 -0500 Subject: [PATCH 158/432] Update codegen doc --- src/docs/codegen.md | 94 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 4c815ec20..59af56a44 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -54,6 +54,100 @@ $$ ## Transformaciones +#### Program Declaration + +**Cool Input** + +```haskell +class A1 { ... } +class A2 { ... } +... +class AN { ... } +``` + +**CCIL Output** + +```assembly + +... + + +# Pending, should string literals be added here? + + + +... + <- ; + a2: <- ; + ... + am: <- ; + -- Uninitialized attributes + aq: ; + ... + ak: ; + + -- Functions + f1() { } + f2() { } + ... + fn() { } + +} +``` + +**CCIL Output** + +```assembly +type C { + # Initialized and uninitialized attributes together + attribute a1; + ... + attribute am; + attribute aq; + ... + attribute ak; + + method f1 : ; + ... + method fn : ; +} +``` + +#### Class Inheritance + +Se annade sobre la que ya tiene A, como se maneja la memoria, se annaden los atributos de B, despues de las funciones de A, o despues de los atributos de A + +**Cool Input** + +```haskell +class A { + +} + +class B inherits A { + +} +``` + +**CCIL Output** + +``` +``` + + + #### While Loop **Cool Input** From 48eeba1afba2cabd543316b1fca280341b9b4362 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 09:20:13 -0500 Subject: [PATCH 159/432] Add make_id to put new id names and a data class --- src/code_gen/tools.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 5e08e797f..e392e7364 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1 +1,23 @@ - +from dataclasses import dataclass + +from ast.ccil_ast import ExpressionNode + + +@dataclass +class LocalVar: + cool_name: str + ccil_name: str + boundExpression: ExpressionNode | None + + +def make_id(name: str, main_num: int, snd_num: int = -1, thrd_num: int = -1): + main_num_str = str(main_num) + snd_num_str = "" + thrd_num_str = "" + + if snd_num != -1: + snd_num_str = f"_{snd_num}" + if thrd_num != -1: + thrd_num_str = f"_{thrd_num}" + + return f"{name}_{main_num_str}{snd_num_str}{thrd_num_str}" From 6e9dd361256a7b8a4c0c7a1ef4f56422e3a25b0c Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 09:21:35 -0500 Subject: [PATCH 160/432] Minor changes --- src/code_gen/ccil_gen.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index eff433be5..02a4078e5 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,4 +1,4 @@ -from typing import List +from typing import Dict, List from utils import visitor from ast.types_ast import ( CaseNode, @@ -16,16 +16,18 @@ VarDeclarationNode, VariableNode, ) +from code_gen.tools import make_id import ast.ccil_ast as ccil class CCILGenerator: def __init__(self) -> None: - self.count: int = 0 - self.data: List[str] = [] + self.constant_data: List[str] + # This is not needed in this layer of abstraction + self.count: Dict[str, int] = {"while": 0, "if": 0, "case": 0, "function": 0} @visitor.on("node") - def visit(self, node): + def visit(self, _): pass @visitor.when(ProgramNode) @@ -34,7 +36,7 @@ def visit(self, node: ProgramNode) -> ccil.ProgramNode: for declaration in node.declarations: class_decl.append(self.visit(declaration)) - return ccil.ProgramNode(class_decl, self.data, node) + return ccil.ProgramNode(class_decl, self.constant_data, node) @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: @@ -55,10 +57,11 @@ def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: @visitor.when(MethodDeclarationNode) def visit(self, node: MethodDeclarationNode) -> ccil.MethodDeclarationNode: - # What to do about parameter ?? Unanswered question from the past... + + for param in node.params: + pass body: ccil.ExpressionNode = self.visit(node.body) - # Fill return with something :( return MethodDeclarationNode() @visitor.when(BlocksNode) @@ -79,7 +82,8 @@ def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: @visitor.when(CaseNode) def visit(self, node: CaseNode) -> ccil.CaseNode: - pass + locals = [] + expressions = [] @visitor.when(CaseOptionNode) def visit(self, node: CaseOptionNode) -> ccil.CaseOptionNode: @@ -115,8 +119,3 @@ def visit(self, node: StringNode) -> ccil.StringNode: @visitor.when(IntNode) def visit(self, node: IntNode) -> ccil.IntNode: return ccil.IntNode(node, value="") - - def generate_var_name(self) -> str: - """Generate a new local name""" - self.count += 1 - return f"v{self.count}" From ffc00733e429132ab27d04ddc08e750cd419cff0 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 10:57:08 -0500 Subject: [PATCH 161/432] Rename ast to asts and update imports accordingly --- src/{ast => asts}/__init__.py | 0 src/{ast => asts}/ccil_ast.py | 2 +- src/{ast => asts}/inferencer_ast.py | 0 src/{ast => asts}/parser_ast.py | 0 src/{ast => asts}/types_ast.py | 0 src/debbuging/type_logger.py | 2 +- src/semantics/inference/back_inferencer.py | 2 +- src/semantics/inference/hard_inferencer.py | 4 ++-- src/semantics/inference/soft_inferencer.py | 4 ++-- src/semantics/inference/types_inferencer.py | 6 +++--- src/semantics/type_builder.py | 2 +- src/semantics/type_collector.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) rename src/{ast => asts}/__init__.py (100%) rename src/{ast => asts}/ccil_ast.py (97%) rename src/{ast => asts}/inferencer_ast.py (100%) rename src/{ast => asts}/parser_ast.py (100%) rename src/{ast => asts}/types_ast.py (100%) diff --git a/src/ast/__init__.py b/src/asts/__init__.py similarity index 100% rename from src/ast/__init__.py rename to src/asts/__init__.py diff --git a/src/ast/ccil_ast.py b/src/asts/ccil_ast.py similarity index 97% rename from src/ast/ccil_ast.py rename to src/asts/ccil_ast.py index 9dd954f36..5d9b6f5c4 100644 --- a/src/ast/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -17,7 +17,7 @@ def __init__(self, node, value: str, locals: List[str] = None) -> None: Parameters: node <- Node to set this node positon in the original cool program. value <- Name of the local variable where the expresion final value is going to be stored. - locals <- list of local variables needed to be initialized to expression to work. + locals <- List of local variables needed to be initialized to execute expression. """ super().__init__(node) if locals is None: diff --git a/src/ast/inferencer_ast.py b/src/asts/inferencer_ast.py similarity index 100% rename from src/ast/inferencer_ast.py rename to src/asts/inferencer_ast.py diff --git a/src/ast/parser_ast.py b/src/asts/parser_ast.py similarity index 100% rename from src/ast/parser_ast.py rename to src/asts/parser_ast.py diff --git a/src/ast/types_ast.py b/src/asts/types_ast.py similarity index 100% rename from src/ast/types_ast.py rename to src/asts/types_ast.py diff --git a/src/debbuging/type_logger.py b/src/debbuging/type_logger.py index e0424e109..c6fead434 100644 --- a/src/debbuging/type_logger.py +++ b/src/debbuging/type_logger.py @@ -1,5 +1,5 @@ from utils import visitor -from ast.inferencer_ast import ( +from asts.inferencer_ast import ( AssignNode, AtomicNode, AttrDeclarationNode, diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 609784bad..0572b409a 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -5,7 +5,7 @@ from semantics.tools.type import Method, SelfType, Type from semantics.tools import Context, Scope, TypeBag, join, join_list, unify from utils import visitor -from ast.inferencer_ast import ( +from asts.inferencer_ast import ( ProgramNode, ClassDeclarationNode, MethodDeclarationNode, diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index d1fd283e9..43bc7935b 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -1,5 +1,5 @@ from semantics.tools.errors import InternalError, AttributeError -from ast.inferencer_ast import ( +from asts.inferencer_ast import ( ArithmeticNode, AssignNode, AttrDeclarationNode, @@ -600,4 +600,4 @@ def __unrelated_types(self, node): ) node.inferenced_type = TypeBag(set()) return True - return False \ No newline at end of file + return False diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index ac3721214..8b4b69ef5 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -1,7 +1,7 @@ from inspect import currentframe from typing import Type -import ast.inferencer_ast as inf_ast -from ast.parser_ast import ( +import asts.inferencer_ast as inf_ast +from asts.parser_ast import ( ArithmeticNode, AssignNode, AttrDeclarationNode, diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index f6a9e1ae1..137132f58 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -3,8 +3,8 @@ from utils import visitor from semantics.tools import TypeBag, Scope -import ast.types_ast as types_ast -from ast.inferencer_ast import ( +import asts.types_ast as types_ast +from asts.inferencer_ast import ( BinaryNode, BooleanNode, ComplementNode, @@ -280,4 +280,4 @@ def _join_types(self, types : List[Type]): def add_error(self, node, text: str): line, col = node.get_position() if node else (0, 0) - self.errors.append(((line, col), f"({line}, {col}) - " + text)) \ No newline at end of file + self.errors.append(((line, col), f"({line}, {col}) - " + text)) diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 15a0f4fdd..ee63987bb 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,5 +1,5 @@ from utils import visitor -from ast.parser_ast import ( +from asts.parser_ast import ( Node, ProgramNode, ClassDeclarationNode, diff --git a/src/semantics/type_collector.py b/src/semantics/type_collector.py index 6ae5a2759..3fc06d986 100644 --- a/src/semantics/type_collector.py +++ b/src/semantics/type_collector.py @@ -1,4 +1,4 @@ -from ast.parser_ast import ClassDeclarationNode, Node, ProgramNode +from asts.parser_ast import ClassDeclarationNode, Node, ProgramNode from semantics.tools.errors import SemanticError from semantics.tools import Context, SelfType From 72df305286ecdf0ff17495df80d5299e5308c0f4 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 10:58:17 -0500 Subject: [PATCH 162/432] Add poetry as a dependency manager --- poetry.lock | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 17 +++++ 2 files changed, 184 insertions(+) create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 000000000..4531e801c --- /dev/null +++ b/poetry.lock @@ -0,0 +1,167 @@ +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.4.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pyparsing" +version = "3.0.6" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "6.2.5" +description = "pytest: simple powerful testing with Python" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[metadata] +lock-version = "1.1" +python-versions = "^3.10" +content-hash = "f576a82b5e6c2b19c78eb67cb6508703b706de1eca9d33f7bc29c732a6b070ca" + +[metadata.files] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +ply = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] +pyparsing = [ + {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, + {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, +] +pytest = [ + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..1cc2c14dd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "cool-compiler-2021" +version = "0.1.0" +description = "COOL language compiler" +authors = ["rodrigo-pino "] +license = "MIT" + +[tool.poetry.dependencies] +python = "^3.10" +pytest = "^6.2.5" +ply = "^3.11" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" From c71f50b2ffe745dc098a703490d1adfdfc40f6f3 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 11:36:54 -0500 Subject: [PATCH 163/432] Improved LocalVar class --- src/code_gen/tools.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index e392e7364..bdff6032b 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from ast.ccil_ast import ExpressionNode +from asts.ccil_ast import ExpressionNode @dataclass @@ -9,15 +9,34 @@ class LocalVar: ccil_name: str boundExpression: ExpressionNode | None + @property + def get_name(self): + assert self.ccil_name != "" + return self.ccil_name -def make_id(name: str, main_num: int, snd_num: int = -1, thrd_num: int = -1): + @staticmethod + def new_temporal_var(name: str, boundExpression: ExpressionNode): + return LocalVar("", name, boundExpression) + + @staticmethod + def new_user_defined_var( + name: str, ccil_name: str, boundExpression: ExpressionNode | None = None + ): + return LocalVar(name, ccil_name, boundExpression) + + +def make_id( + name: str, main_num: int, aux_name: str = "", snd_num: int = -1, thrd_num: int = -1 +): main_num_str = str(main_num) snd_num_str = "" thrd_num_str = "" + if aux_name != "": + aux_name = f"_{aux_name}" if snd_num != -1: snd_num_str = f"_{snd_num}" if thrd_num != -1: thrd_num_str = f"_{thrd_num}" - return f"{name}_{main_num_str}{snd_num_str}{thrd_num_str}" + return f"{name}{aux_name}_{main_num_str}{snd_num_str}{thrd_num_str}" From 6f616eccfbff302d5e5366206f467cb81b13a9f7 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 11:46:41 -0500 Subject: [PATCH 164/432] Add some type annotations --- src/asts/types_ast.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index 76d03e77c..3589c83d0 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -1,4 +1,5 @@ from typing import List, Tuple +from __future__ import annotations class Node: @@ -12,7 +13,7 @@ def get_position(self) -> Tuple[int, int]: class ProgramNode(Node): - def __init__(self, declarations, node: Node): + def __init__(self, declarations: List[ClassDeclarationNode], node: Node): Node.__init__(self, node) self.declarations = declarations @@ -22,10 +23,13 @@ class DeclarationNode(Node): class ClassDeclarationNode(DeclarationNode): - def __init__(self, features, node): + def __init__( + self, features: List[AttrDeclarationNode | MethodDeclarationNode], node + ): Node.__init__(self, node) - self.features = features - self.id = node.id + self.id: str = node.id + self.features: List[AttrDeclarationNode | MethodDeclarationNode] = features + self.parent = node.parent class AttrDeclarationNode(DeclarationNode): From 7eee970189c7ba6b5ffee9f83efe70907b370eff Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:41:13 -0500 Subject: [PATCH 165/432] Improve nodes --- src/asts/ccil_ast.py | 63 +++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 5d9b6f5c4..c620eb749 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -1,5 +1,7 @@ from typing import List, Tuple +from code_gen.tools import LocalVar + class Node: def __init__(self, node) -> None: @@ -12,19 +14,23 @@ def get_position(self) -> Tuple[int, int]: class ExpressionNode(Node): - def __init__(self, node, value: str, locals: List[str] = None) -> None: + def __init__(self, node, locals: List[LocalVar] = None) -> None: """ Parameters: node <- Node to set this node positon in the original cool program. - value <- Name of the local variable where the expresion final value is going to be stored. locals <- List of local variables needed to be initialized to execute expression. + value <- Name of the local variable where the expresion final value is going to be stored. """ super().__init__(node) if locals is None: - self.locals = [] - self.value = value + locals = [] + self.locals = locals + @property + def value(self): + return self.locals[-1] + class AtomicNode(ExpressionNode): pass @@ -43,10 +49,8 @@ class VariableNode(ExpressionNode): class VarDeclarationNode(ExpressionNode): - def __init__( - self, expr: ExpressionNode, node, value: str, locals: List = None - ) -> None: - super().__init__(node, value, locals=locals) + def __init__(self, expr: ExpressionNode, node, locals: List = None) -> None: + super().__init__(node, locals=locals) self.expression = expr @@ -68,10 +72,9 @@ def __init__( case_expr: ExpressionNode, options: List[CaseOptionNode], node, - value: str, locals: List = None, ) -> None: - super().__init__(node, value, locals=locals) + super().__init__(node, locals=locals) self.case_expr = case_expr self.options = options @@ -83,10 +86,9 @@ def __init__( then_node: ExpressionNode, else_node: ExpressionNode, node, - value: str, locals: List = None, ) -> None: - super().__init__(node, value, locals=locals) + super().__init__(node, locals=locals) self.condition = condition self.then_node = then_node self.else_node = else_node @@ -97,16 +99,15 @@ def __init__( self, expression_list: List[ExpressionNode], node, - value: str, locals: List = None, ) -> None: - super().__init__(node, value, locals=locals) + super().__init__(node, locals=locals) self.expression_list = expression_list class LetVarDeclarationNode(ExpressionNode): - def __init__(self, expression: ExpressionNode, node, value: str, locals=None): - super().__init__(self, node, value, locals=locals) + def __init__(self, expression: ExpressionNode, node, locals=None): + super().__init__(self, node, locals=locals) self.id = node.id self.type = node.type self.expression = expression @@ -117,35 +118,43 @@ class DeclarationNode(Node): class AttrDeclarationNode(DeclarationNode): - def __init__(self, expression: ExpressionNode, node) -> None: + def __init__(self, expression: ExpressionNode | None, node) -> None: super().__init__(node) self.id = node.id self.type = node.type self.expression = expression + self.value = expression.value if expression is not None else None class MethodDeclarationNode(DeclarationNode): def __init__( self, idx: str, - params: List[ParamNodes], + params: List[VarDeclarationNode], body: ExpressionNode, - return_type: str, node, ) -> None: super().__init__(node) - self.idx = idx - self.paramas = params - self.return_type = return_type - self.body = body + self.idx: str = idx + self.params: List[VarDeclarationNode] = params + self.body: ExpressionNode = body + self.value = body.value class ClassDeclarationNode(Node): - def __init__(self, features: List[DeclarationNode], node) -> None: + def __init__( + self, + attributes: List[AttrDeclarationNode], + methods: List[MethodDeclarationNode], + feature_info: List, + node, + ) -> None: super().__init__(node) - self.idx = node.id - self.parent = "?" - self.features = features + self.idx: str = node.id + self.parent: str = node.parent + self.attributes: List[AttrDeclarationNode] = attributes + self.methods: List[MethodDeclarationNode] = methods + self.feature_info: List = feature_info class ProgramNode(Node): From 3f3d963d876304f74884750bcbf534ff8b1b01fe Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:42:14 -0500 Subject: [PATCH 166/432] Add feature class to keep track of function and attributes and cool and ccil names --- src/code_gen/tools.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index bdff6032b..851b3c6fe 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -3,6 +3,17 @@ from asts.ccil_ast import ExpressionNode +@dataclass +class Feature: + cool_name: str + ccil_name: str + attribute: bool + + @property + def is_attribute(self): + return self.attribute + + @dataclass class LocalVar: cool_name: str From 0eeb91726259b5f7708230d6075d1547fa2a15ef Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:42:50 -0500 Subject: [PATCH 167/432] Add constants that will define ccil naming --- src/code_gen/constants.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/code_gen/constants.py diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py new file mode 100644 index 000000000..e34a58de4 --- /dev/null +++ b/src/code_gen/constants.py @@ -0,0 +1,5 @@ +ATTR_NAME = "attr" + +CASE_INIT = "init_case" +CASE_END = "end_case" +CASE_BRANCH = "case_branch" From f962334fc5ba67a544fa73e79cbba44d2a2d14d1 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:43:30 -0500 Subject: [PATCH 168/432] Update docs --- src/docs/codegen.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 59af56a44..b73bada78 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -240,6 +240,7 @@ esac ... + x = t = typeof x label init_case From 57253738cc07d2845ff425a189138cb6b512cb5d Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:44:07 -0500 Subject: [PATCH 169/432] Improve and build base --- src/code_gen/ccil_gen.py | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 02a4078e5..a807e23ff 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,6 +1,7 @@ from typing import Dict, List +from code_gen.constants import ATTR_NAME from utils import visitor -from ast.types_ast import ( +from asts.types_ast import ( CaseNode, CaseOptionNode, ConditionalNode, @@ -16,16 +17,22 @@ VarDeclarationNode, VariableNode, ) -from code_gen.tools import make_id -import ast.ccil_ast as ccil +from code_gen.tools import Feature, make_id +import asts.ccil_ast as ccil class CCILGenerator: def __init__(self) -> None: - self.constant_data: List[str] - # This is not needed in this layer of abstraction + self.warnings: List[str] = [] + self.constant_data: List[str] = [] self.count: Dict[str, int] = {"while": 0, "if": 0, "case": 0, "function": 0} + self.class_name: str + self.attr_count: int + self.func_count: int + self.feature_name: str + self.local_var_count: int + @visitor.on("node") def visit(self, _): pass @@ -34,20 +41,35 @@ def visit(self, _): def visit(self, node: ProgramNode) -> ccil.ProgramNode: class_decl: List[ccil.ClassDeclarationNode] = [] for declaration in node.declarations: + self.set_class_params(declaration.id) class_decl.append(self.visit(declaration)) return ccil.ProgramNode(class_decl, self.constant_data, node) @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: - class_features: List[ccil.DeclarationNode] = [] + class_attr: List[ccil.AttrDeclarationNode] = [] + class_func: List[ccil.MethodDeclarationNode] = [] + class_feat: List[Feature] = [] + + # Sort by putting attributes first, delete if this is the case already + node.features.sort(key=lambda x: isinstance(x, AttrDeclarationNode)) for feature in node.features: - class_features.append(self.visit(feature)) + self.set_feature_params(feature.id) + if isinstance(feature, AttrDeclarationNode): + class_attr.append(self.visit(feature)) + class_feat.append(Feature(feature.id, "ccil_name", True)) + else: + class_func.append(self.visit(feature)) + class_feat.append(Feature(feature.id, "ccil_name", False)) - return ccil.ClassDeclarationNode(class_features, node) + return ccil.ClassDeclarationNode(class_attr, class_func, class_feat, node) @visitor.when(AttrDeclarationNode) def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: + ccil_node_name = make_id( + ATTR_NAME, + ) ccil_node: ccil.AttrDeclarationNode = ccil.AttrDeclarationNode( node.id, node.type, None ) @@ -78,7 +100,7 @@ def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: else_body: ccil.ExpressionNode = self.visit(node.else_body) value = self.generate_var_name() - return ccil.ConditionalNode(condition, then_body, else_body, value, [value]) + return ccil.ConditionalNode(condition, then_body, else_body, [value]) @visitor.when(CaseNode) def visit(self, node: CaseNode) -> ccil.CaseNode: @@ -119,3 +141,12 @@ def visit(self, node: StringNode) -> ccil.StringNode: @visitor.when(IntNode) def visit(self, node: IntNode) -> ccil.IntNode: return ccil.IntNode(node, value="") + + def set_class_params(self, name: str): + self.class_name = name + self.attr_count = 0 + self.func_count = 0 + + def set_feature_params(self, name: str): + self.feature_name = name + self.local_var_count = 0 From c5094dfd66466bdda9a41dcc46912576edc0bde7 Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:44:34 -0500 Subject: [PATCH 170/432] Fix import error --- src/parsing/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsing/parser.py b/src/parsing/parser.py index d949f0b8c..2ee5fb80e 100644 --- a/src/parsing/parser.py +++ b/src/parsing/parser.py @@ -1,5 +1,5 @@ from ply.yacc import yacc -from ast.parser_ast import ( +from asts.parser_ast import ( AssignNode, AttrDeclarationNode, BlocksNode, From 99c11e04aeb7e399d00d0df5669ce61186dfbbfc Mon Sep 17 00:00:00 2001 From: RodroVMS Date: Tue, 4 Jan 2022 13:44:58 -0500 Subject: [PATCH 171/432] Add flake8 config --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..9221b85c5 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +ignore = F811 From 854fd1e06362c24dfe8b8f3f24e3bf63f127852a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 10 Feb 2022 17:29:28 -0500 Subject: [PATCH 172/432] Rewrite ccil ast --- src/asts/ccil_ast.py | 203 +++++++++++++++---------------------------- 1 file changed, 71 insertions(+), 132 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index c620eb749..3b7a1dd99 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -1,169 +1,108 @@ -from typing import List, Tuple - -from code_gen.tools import LocalVar +from typing import Dict, List, Tuple +from __future__ import annotations class Node: def __init__(self, node) -> None: self.line: int = node.line self.col: int = node.col - self.type = None def get_position(self) -> Tuple[int, int]: - return self.line, self.col + return (self.line, self.col) + + +class OperationNode(Node): + """ + Base Class for all operation Nodes + """ + def __init__(self, node) -> None: + super().__init__(node) -class ExpressionNode(Node): - def __init__(self, node, locals: List[LocalVar] = None) -> None: + +class StorageNode(OperationNode): + def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: """ + Node used to store the value of operations done. Parameters: - node <- Node to set this node positon in the original cool program. - locals <- List of local variables needed to be initialized to execute expression. - value <- Name of the local variable where the expresion final value is going to be stored. + node <- Node to maintain knowledge of colummn and position in the original code. + idx <- Id of this node. + opeartion <- The operation this node is storing. """ super().__init__(node) - if locals is None: - locals = [] - - self.locals = locals - - @property - def value(self): - return self.locals[-1] - + self.id = idx + self.operation = operation -class AtomicNode(ExpressionNode): - pass - - -class StringNode(AtomicNode): - pass - - -class IntNode(AtomicNode): - pass +class ReturnOpNode(OperationNode): + def __init__(self, node) -> None: + super().__init__(node) -class VariableNode(ExpressionNode): - pass +class BinaryOpNode(ReturnOpNode): + def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: + """ + Node that represents all binary operation + Parameters: + left <- Left atomic node. + right <- Right atomic node. + """ + super().__init__(node) + self.left = left + self.right = right -class VarDeclarationNode(ExpressionNode): - def __init__(self, expr: ExpressionNode, node, locals: List = None) -> None: - super().__init__(node, locals=locals) - self.expression = expr +class AtomOpNode(ReturnOpNode): + def __init__(self, node) -> None: + """ + AtomNode represents all single value nodes, like ids and constants + """ + super().__init__(node) -class LetNode(ExpressionNode): - pass +class IdNode(AtomOpNode): + def __init__(self, node, idx: str) -> None: + super().__init__(node) + self.id = idx -class LoopNode(ExpressionNode): - pass +class ConstantNode(AtomOpNode): + def __init__(self, node) -> None: + super().__init__(node) -class CaseOptionNode(ExpressionNode): - pass +class FlowControlNode(OperationNode): + """ + Base class for all flow control operations like If, Label, goto, etc... + """ -class CaseNode(ExpressionNode): - def __init__( - self, - case_expr: ExpressionNode, - options: List[CaseOptionNode], - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.case_expr = case_expr - self.options = options + def __init__(self, node) -> None: + super().__init__(node) -class ConditionalNode(ExpressionNode): - def __init__( - self, - condition: ExpressionNode, - then_node: ExpressionNode, - else_node: ExpressionNode, - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.condition = condition - self.then_node = then_node - self.else_node = else_node +class IfNode(FlowControlNode): + def __init__(self, node, eval_value: StorageNode, target: LabelNode) -> None: + super().__init__(node) + self.eval_value = eval_value + self.target = target -class BlocksNode(ExpressionNode): - def __init__( - self, - expression_list: List[ExpressionNode], - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.expression_list = expression_list +class IfFalseNode(IfNode): + def __init__(self, node, eval_value: StorageNode, target: LabelNode) -> None: + super().__init__(node, eval_value, target) -class LetVarDeclarationNode(ExpressionNode): - def __init__(self, expression: ExpressionNode, node, locals=None): - super().__init__(self, node, locals=locals) - self.id = node.id - self.type = node.type - self.expression = expression +class GoToNode(FlowControlNode): + def __init__(self, node, target: LabelNode) -> None: + super().__init__(node) + self.target = target -class DeclarationNode(Node): - pass +class LabelNode(FlowControlNode): + def __init__(self, node, idx: str) -> None: + super().__init__(node) + self.id = idx -class AttrDeclarationNode(DeclarationNode): - def __init__(self, expression: ExpressionNode | None, node) -> None: - super().__init__(node) - self.id = node.id - self.type = node.type - self.expression = expression - self.value = expression.value if expression is not None else None - - -class MethodDeclarationNode(DeclarationNode): - def __init__( - self, - idx: str, - params: List[VarDeclarationNode], - body: ExpressionNode, - node, - ) -> None: - super().__init__(node) - self.idx: str = idx - self.params: List[VarDeclarationNode] = params - self.body: ExpressionNode = body - self.value = body.value - - -class ClassDeclarationNode(Node): - def __init__( - self, - attributes: List[AttrDeclarationNode], - methods: List[MethodDeclarationNode], - feature_info: List, - node, - ) -> None: - super().__init__(node) - self.idx: str = node.id - self.parent: str = node.parent - self.attributes: List[AttrDeclarationNode] = attributes - self.methods: List[MethodDeclarationNode] = methods - self.feature_info: List = feature_info - - -class ProgramNode(Node): - def __init__( - self, - types: List[ClassDeclarationNode], - data: List[str], - node, - ) -> None: - super().__init__(node) - self.types = types - self.data = data +def create_assignation(node, idx: str, target: str): + return StorageNode(node, idx, IdNode(node, target)) From 6b7844cc159b7bd2f2c29e4d2acace433710f157 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 10 Feb 2022 17:33:52 -0500 Subject: [PATCH 173/432] Rewrite ccil generator --- src/code_gen/ccil_gen.py | 167 ++++++++------------------------------- 1 file changed, 32 insertions(+), 135 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a807e23ff..b8a7e140e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,152 +1,49 @@ -from typing import Dict, List -from code_gen.constants import ATTR_NAME from utils import visitor -from asts.types_ast import ( - CaseNode, - CaseOptionNode, - ConditionalNode, - IntNode, - LetNode, - LoopNode, - ProgramNode, - ClassDeclarationNode, - AttrDeclarationNode, - MethodDeclarationNode, - BlocksNode, - StringNode, - VarDeclarationNode, - VariableNode, -) -from code_gen.tools import Feature, make_id -import asts.ccil_ast as ccil +import asts.types_ast as sem_ast # Semantic generated ast +from asts.ccil_ast import * # CCIL generated ast +from typing import Tuple, List +# All operations that define an expression and where it is stored +VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] + +# CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: - def __init__(self) -> None: - self.warnings: List[str] = [] - self.constant_data: List[str] = [] - self.count: Dict[str, int] = {"while": 0, "if": 0, "case": 0, "function": 0} + """ + Using the visitor pattern it goes through the semantics ast and produce a ccil ast + """ - self.class_name: str - self.attr_count: int - self.func_count: int - self.feature_name: str - self.local_var_count: int + def __init__(self) -> None: + pass @visitor.on("node") def visit(self, _): pass - @visitor.when(ProgramNode) - def visit(self, node: ProgramNode) -> ccil.ProgramNode: - class_decl: List[ccil.ClassDeclarationNode] = [] - for declaration in node.declarations: - self.set_class_params(declaration.id) - class_decl.append(self.visit(declaration)) - - return ccil.ProgramNode(class_decl, self.constant_data, node) - - @visitor.when(ClassDeclarationNode) - def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: - class_attr: List[ccil.AttrDeclarationNode] = [] - class_func: List[ccil.MethodDeclarationNode] = [] - class_feat: List[Feature] = [] - - # Sort by putting attributes first, delete if this is the case already - node.features.sort(key=lambda x: isinstance(x, AttrDeclarationNode)) - for feature in node.features: - self.set_feature_params(feature.id) - if isinstance(feature, AttrDeclarationNode): - class_attr.append(self.visit(feature)) - class_feat.append(Feature(feature.id, "ccil_name", True)) - else: - class_func.append(self.visit(feature)) - class_feat.append(Feature(feature.id, "ccil_name", False)) - - return ccil.ClassDeclarationNode(class_attr, class_func, class_feat, node) - - @visitor.when(AttrDeclarationNode) - def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: - ccil_node_name = make_id( - ATTR_NAME, - ) - ccil_node: ccil.AttrDeclarationNode = ccil.AttrDeclarationNode( - node.id, node.type, None - ) - if node.expr is not None: - ccil_node.expression = self.visit(node.expr) - return ccil_node - - @visitor.when(MethodDeclarationNode) - def visit(self, node: MethodDeclarationNode) -> ccil.MethodDeclarationNode: - - for param in node.params: - pass + @visitor.when(sem_ast.ConditionalNode) + def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: + times = self.times(node) - body: ccil.ExpressionNode = self.visit(node.body) - return MethodDeclarationNode() + (if_ops, if_fval) = self.visit(node.condition) + (then_ops, then_fval) = self.visit(node.then_body) + (else_ops, else_fval) = self.visit(node.else_body) - @visitor.when(BlocksNode) - def visit(self, node: BlocksNode) -> ccil.BlocksNode: - expr_list: List[ccil.ExpressionNode] = [ - self.visit(expr) for expr in node.expr_list - ] - return ccil.BlocksNode(expr_list, node) + # translating condition to ccil + label_id = f"ifElse_{times}" + else_label = LabelNode(node, label_id) + if_false = IfFalseNode(node, if_fval, else_label) - @visitor.when(ConditionalNode) - def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: - condition: ccil.ExpressionNode = self.visit(node.condition) - then_body: ccil.ExpressionNode = self.visit(node.then_body) - else_body: ccil.ExpressionNode = self.visit(node.else_body) + # Setting the final operation which will simbolize the return value of this expr + pre_fvalue_id = f"if_{times}_pre_fv" + then_fval.id = else_fval.id = pre_fvalue_id + fvalue_id = f"if_{times}_fv" + fvalue = create_assignation(node, fvalue_id, pre_fvalue_id) - value = self.generate_var_name() - return ccil.ConditionalNode(condition, then_body, else_body, [value]) + return [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue] - @visitor.when(CaseNode) - def visit(self, node: CaseNode) -> ccil.CaseNode: - locals = [] - expressions = [] - - @visitor.when(CaseOptionNode) - def visit(self, node: CaseOptionNode) -> ccil.CaseOptionNode: - pass - - @visitor.when(LoopNode) - def visit(self, node: LoopNode) -> ccil.LoopNode: - pass - - @visitor.when(LetNode) - def visit(self, node: LetNode) -> ccil.LetNode: - new_decl_list: List[VarDeclarationNode] = [] - for let_decl_node in node.var_decl_list: - new_decl_list.append(self.visit(let_decl_node)) - node_expr: ccil.ExpressionNode = self.visit(node.in_expr) - - @visitor.when(VarDeclarationNode) - def visit(self, node: VarDeclarationNode) -> ccil.VarDeclarationNode: - value = self.generate_var_name() - if node.expr is not None: - ccil_node_expr: ccil.ExpressionNode = self.visit(node.expr) - return ccil.VarDeclarationNode(ccil_node_expr, node, value, [value]) - return ccil.VarDeclarationNode(None, node, value, [value]) - - @visitor.when(VariableNode) - def visit(self, node: VariableNode) -> ccil.VariableNode: - return ccil.VariableNode(node, value=node.id) - - @visitor.when(StringNode) - def visit(self, node: StringNode) -> ccil.StringNode: + @visitor.when(sem_ast.ArithmeticExprNode) + def visit(self, node: sem_ast.ArithmeticExprNode): pass - @visitor.when(IntNode) - def visit(self, node: IntNode) -> ccil.IntNode: - return ccil.IntNode(node, value="") - - def set_class_params(self, name: str): - self.class_name = name - self.attr_count = 0 - self.func_count = 0 - - def set_feature_params(self, name: str): - self.feature_name = name - self.local_var_count = 0 + def times(self, node): + return 0 From 7a8dc2f6cbc35ee45d6f7ef2747cf1fd2af399f9 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 10 Feb 2022 17:34:26 -0500 Subject: [PATCH 174/432] Update codegen docs --- src/docs/codegen.md | 114 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 15 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index b73bada78..3874203a5 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -152,7 +152,7 @@ class B inherits A { **Cool Input** -``` +```assembly while () loop pool ``` @@ -180,16 +180,20 @@ if then else fi **CCIL Output** ```assembly -x = -ifFalse x goto else_expr -label then_expr +LOCAL f # Init var which will store if result + # Init all local vars from the condition expression + # Execute the condition +x = # And store it in a local var! +ifFalse x goto else_expr # 0 means True, otherwise False +label then_expr # Not really needed! - +f = goto endif -label else_expr +label else_expr +f = label endif ``` @@ -210,12 +214,17 @@ let :, ... : in ... -# Si existe alguna variable let inicializada con una expresion, ejecutar dicha expresion - - +# Execute expressions of let vars + + + + + ... - + + + ``` @@ -243,9 +252,9 @@ esac x = t = typeof x -label init_case +label init_case # This is not really needed t1 = typeof -b1 = t1 == t +b1 = t1 == t # Comparing types, they must be all equal if b1 goto branch1 t2 = typeof @@ -256,7 +265,8 @@ if b2 goto branch2 tn = typeof bn = tn == t -if bn goto branchn +if bn goto brannch +# It is not possible to avoid pattern matching label branch1 @@ -300,7 +310,7 @@ r = call n **Cool Input** ``` -@(, , ..., ); +@.(, , ..., ); ``` **CCIL Output** @@ -310,7 +320,7 @@ r = call n ... -t = allocate +t = allocate # It needs to give the same attributes that type one has r = vcall t n ``` @@ -370,3 +380,77 @@ function { ``` +#### Arithmetic Expression + +###### Simple + +**Cool Input** + +```c# +3 + 5 +``` + +**CCIL Output** + +``` +t = 3 + 5 +``` + +---- + +###### More than one + +**Cool Input** + +``` +3 + 5 + 7 +``` + +**CCIL Output** + +```assembly +# Naive +t1 = 5 + 7 +t2 = 3 + t1 +# A little better +t1 = 5 + 7 +t1 = 3 + t1 +``` + + + +---- + +###### Using non commutative operations + +```python +3 - 5 - 7 +# -2 -7 +# -9 +``` + +```assembly +t1 = +``` + +---- + +**Cool Input** + +``` +100 / 20 / 5 / 2 +``` + +**CCIL Output** + +``` +``` + + + +## Convenciones de variables en Cool + +Si es una variable definida por el usuario se le agrega el prefijo _user_. Se aplica tanto a variables definidas en un _let in_ como en _atributos_. + +Si es una variable creada cuando se analiza una expresion en particular se convierte en: _\__\___ + From 87dd884fb486a36b889bf656daba8835dfcd9a03 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 10 Feb 2022 17:35:10 -0500 Subject: [PATCH 175/432] Minor change --- src/asts/types_ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index 3589c83d0..bd4224d08 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -1,5 +1,5 @@ -from typing import List, Tuple from __future__ import annotations +from typing import List, Tuple class Node: From dc1dda017bdc428267e0778922675cd6c6f81677 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 10 Feb 2022 17:35:33 -0500 Subject: [PATCH 176/432] Add new misc test --- src/debbuging/tests/Misc/11Sum.cl | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/debbuging/tests/Misc/11Sum.cl diff --git a/src/debbuging/tests/Misc/11Sum.cl b/src/debbuging/tests/Misc/11Sum.cl new file mode 100644 index 000000000..0d904f950 --- /dev/null +++ b/src/debbuging/tests/Misc/11Sum.cl @@ -0,0 +1,9 @@ +class Main inherits IO { + main(): Int { + { + 100 / 2 - 10 / 5; + 100 / 10 / 5 / 2; + } + }; +}; + From 4b38b6b0e46921c8e5575538fa04b9d676a3e0bd Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 11 Feb 2022 11:41:52 -0500 Subject: [PATCH 177/432] Add arithmetic operations node --- src/asts/ccil_ast.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 3b7a1dd99..79da48c32 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -52,6 +52,26 @@ def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: self.right = right +class SumOpNode(ReturnOpNode): + def __init__(self, node) -> None: + super().__init__(node) + + +class MinusOpNode(ReturnOpNode): + def __init__(self, node) -> None: + super().__init__(node) + + +class MultOpNode(ReturnOpNode): + def __init__(self, node) -> None: + super().__init__(node) + + +class DivOpNode(ReturnOpNode): + def __init__(self, node) -> None: + super().__init__(node) + + class AtomOpNode(ReturnOpNode): def __init__(self, node) -> None: """ @@ -81,14 +101,14 @@ def __init__(self, node) -> None: class IfNode(FlowControlNode): - def __init__(self, node, eval_value: StorageNode, target: LabelNode) -> None: + def __init__(self, node, eval_value: AtomOpNode, target: LabelNode) -> None: super().__init__(node) self.eval_value = eval_value self.target = target class IfFalseNode(IfNode): - def __init__(self, node, eval_value: StorageNode, target: LabelNode) -> None: + def __init__(self, node, eval_value: AtomOpNode, target: LabelNode) -> None: super().__init__(node, eval_value, target) @@ -106,3 +126,7 @@ def __init__(self, node, idx: str) -> None: def create_assignation(node, idx: str, target: str): return StorageNode(node, idx, IdNode(node, target)) + + +def extract_id(node, storage_node: StorageNode) -> IdNode: + return IdNode(node, storage_node.id) From a8b823611869baa6c85ccb3db166d6ed6f89abea Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 11 Feb 2022 11:42:38 -0500 Subject: [PATCH 178/432] Add arithmetic and loop from cool to cil translation --- src/code_gen/ccil_gen.py | 64 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index b8a7e140e..676ee3561 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -18,7 +18,7 @@ def __init__(self) -> None: @visitor.on("node") def visit(self, _): - pass + self.time_record: Dict[str, int] = Dict() @visitor.when(sem_ast.ConditionalNode) def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: @@ -39,11 +39,63 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: fvalue_id = f"if_{times}_fv" fvalue = create_assignation(node, fvalue_id, pre_fvalue_id) - return [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue] + return ([*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) - @visitor.when(sem_ast.ArithmeticExprNode) - def visit(self, node: sem_ast.ArithmeticExprNode): - pass + @visitor.when(sem_ast.LoopNode) + def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: + times = self.times(node) + + (cond_ops, cond_fval) = self.visit(node.condition) + (body_ops, body_fval) = self.visit(node.body) + + # Setting control flow labels + loop_label_id = f"loop_{times}" + loop_label = LabelNode(node, loop_label_id) + end_loop_label_id = f"endLoop_{times}" + end_loop_label = LabelNode(node, end_loop_label_id) + + # Setting control flow instructions ifFalse & GoTo + if_false = IfFalseNode(node, cond_fval, end_loop_label) + go_to = GoToNode(node, loop_label) + + # Loop Nodes have void return type, how to express it?? + return ( + [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label], + None, + ) + + @visitor.when(sem_ast.ArithmeticNode) + def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: + times = self.times(node) + + (left_ops, left_fval) = self.visit(node.left) + (right_ops, right_fval) = self.visit(node.right) + + left_id = extract_id(node, left_fval) + right_id = extract_id(node, right_fval) + + op: ReturnOpNode + match node: + case sem_ast.PlusNode: + op = SumOpNode(left_id, right_id) + case sem_ast.MinusNode: + op = MinusOpNode(left_id, right_id) + case sem_ast.StarNode: + op = MultOpNode(left_id, right_id) + case sem_ast.DivNode: + op = DivOpNode(left_id, right_id) + case _: + raise Exception("Pattern match failure visiting artihmetic expression") + + fval_id = f"arith_{times}" + fval = StorageNode(node, fval_id, op) + + return ([*left_ops, *right_ops, fval], fval) def times(self, node): - return 0 + key: str = type(node).__name__ + try: + self.time_record[key] += 1 + except KeyError: + self.time_record[key] = 0 + return self.time_record[key] From 2572677cc9a48572f348c0204e5f3739946990f8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 11 Feb 2022 12:23:53 -0500 Subject: [PATCH 179/432] Add let in translation to ccil --- src/code_gen/ccil_gen.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 676ee3561..a95e042eb 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -7,6 +7,8 @@ # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] +USER = "user" + # CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: """ @@ -20,6 +22,35 @@ def __init__(self) -> None: def visit(self, _): self.time_record: Dict[str, int] = Dict() + @visitor.when(sem_ast.LetNode) + def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: + operations: List[OperationNode] = [] + fvalues: List[StorageNode] = [] + + for var in node.var_decl_list: + (var_ops, var_fv) = self.visit(var) + operations += var_ops + fvalues += var_fv + + (in_ops, in_fval) = self.visit(node.in_expr) + operations += in_ops + + return(operations, in_fval) + + # Still haven't thought have to handle non initialized vars! + @visitor.when(sem_ast.VarDeclarationNode) + def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: + if node.expr is None: + raise Exception("Uninitialized variables are not implemented in CCIL yet!") + + (expr_ops, expr_fv) = self.visit(node.expr) + + fvalue_id:str = USER + node.id + expr_fv.id = fvalue_id + + return (expr_ops, expr_fv) + + @visitor.when(sem_ast.ConditionalNode) def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: times = self.times(node) From d324b25347af5e00b0a044157936b6f008f2ad4c Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 11 Feb 2022 14:01:07 -0500 Subject: [PATCH 180/432] Add more operation nodes and minor bug fix --- src/asts/ccil_ast.py | 58 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 79da48c32..92100eb79 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -39,6 +39,12 @@ def __init__(self, node) -> None: super().__init__(node) +class VoidNode(ReturnOpNode): + """Operation that indicate that the Storage Node is not initialized""" + + pass + + class BinaryOpNode(ReturnOpNode): def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: """ @@ -52,24 +58,48 @@ def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: self.right = right -class SumOpNode(ReturnOpNode): - def __init__(self, node) -> None: - super().__init__(node) +class SumOpNode(BinaryOpNode): + pass -class MinusOpNode(ReturnOpNode): - def __init__(self, node) -> None: - super().__init__(node) +class MinusOpNode(BinaryOpNode): + pass -class MultOpNode(ReturnOpNode): - def __init__(self, node) -> None: - super().__init__(node) +class MultOpNode(BinaryOpNode): + pass -class DivOpNode(ReturnOpNode): - def __init__(self, node) -> None: - super().__init__(node) +class DivOpNode(BinaryOpNode): + pass + + +class EqualOpNode(BinaryOpNode): + pass + + +class LessrOrEqualOpNode(BinaryOpNode): + pass + + +class LesserOpNode(BinaryOpNode): + pass + + +class UnaryOpNode(ReturnOpNode): + pass + + +class GetTypeOpNode(UnaryOpNode): + """Extracts the type of a node""" + + pass + + +class IsVoidNode(UnaryOpNode): + """Operation that returns true if the Storage Node is uninitialized""" + + pass class AtomOpNode(ReturnOpNode): @@ -128,5 +158,9 @@ def create_assignation(node, idx: str, target: str): return StorageNode(node, idx, IdNode(node, target)) +def create_uninitialized_storage(node, idx: str): + return StorageNode(node, idx, VoidNode(node)) + + def extract_id(node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) From d0c9313c6b8a18a1fda8c4f0918da1d2c8acd114 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 11 Feb 2022 14:02:01 -0500 Subject: [PATCH 181/432] Add implementation to handle uninitialized storage variables (void variables) --- src/code_gen/ccil_gen.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a95e042eb..2a1250b99 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -37,19 +37,24 @@ def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: return(operations, in_fval) - # Still haven't thought have to handle non initialized vars! @visitor.when(sem_ast.VarDeclarationNode) def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: + fvalue_id:str = USER + node.id + if node.expr is None: - raise Exception("Uninitialized variables are not implemented in CCIL yet!") + return ([], create_uninitialized_storage(node, fvalue_id)) (expr_ops, expr_fv) = self.visit(node.expr) - - fvalue_id:str = USER + node.id expr_fv.id = fvalue_id return (expr_ops, expr_fv) + @visitor.when(sem_ast.AssignNode) + def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: + (expr_ops, expr_fval) = self.visit(node.expr) + expr_fval.id = USER + node.id + + return (expr_ops, expr_fval) @visitor.when(sem_ast.ConditionalNode) def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: @@ -72,6 +77,10 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: return ([*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) + @visitor.when(sem_ast.CaseNode) + def visit(self, node:sem_ast.CaseNode): + pass + @visitor.when(sem_ast.LoopNode) def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: times = self.times(node) @@ -89,10 +98,11 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) + fval = create_uninitialized_storage(node, f"loop_{times}_fv"), # Loop Nodes have void return type, how to express it?? return ( - [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label], - None, + [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], + fval ) @visitor.when(sem_ast.ArithmeticNode) @@ -106,19 +116,23 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: right_id = extract_id(node, right_fval) op: ReturnOpNode + fval_id: str match node: case sem_ast.PlusNode: op = SumOpNode(left_id, right_id) + fval_id = f"sum_{times}" case sem_ast.MinusNode: op = MinusOpNode(left_id, right_id) + fval_id = f"minus_{times}" case sem_ast.StarNode: op = MultOpNode(left_id, right_id) + fval_id = f"mult_{times}" case sem_ast.DivNode: op = DivOpNode(left_id, right_id) + fval_id = f"div_{times}" case _: raise Exception("Pattern match failure visiting artihmetic expression") - fval_id = f"arith_{times}" fval = StorageNode(node, fval_id, op) return ([*left_ops, *right_ops, fval], fval) From 6f61448dd28373dc2ca412a4cc6c1098caa163ba Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 12 Feb 2022 19:42:25 -0500 Subject: [PATCH 182/432] Add branch type properties to case option nodes --- src/asts/inferencer_ast.py | 3 +- src/asts/types_ast.py | 3 +- src/semantics/inference/back_inferencer.py | 6 +-- src/semantics/inference/hard_inferencer.py | 5 ++- src/semantics/inference/soft_inferencer.py | 2 +- src/semantics/inference/types_inferencer.py | 42 +++++++++++++-------- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/asts/inferencer_ast.py b/src/asts/inferencer_ast.py index bcaa007e1..a8d00ca8b 100644 --- a/src/asts/inferencer_ast.py +++ b/src/asts/inferencer_ast.py @@ -77,11 +77,12 @@ def __init__(self, case_expr, options, node): class CaseOptionNode(ExpressionNode): - def __init__(self, ret_expr, node): + def __init__(self, ret_expr, branch_type, node): Node.__init__(self, node) self.id = node.id self.expr = ret_expr self.decl_type = node.type + self.branch_type = branch_type # For debbuging purposes self.type = node.type diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index bd4224d08..4ee217dbf 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -74,10 +74,11 @@ def __init__(self, case_expr, options, node): class CaseOptionNode(ExpressionNode): - def __init__(self, ret_expr, node): + def __init__(self, ret_expr, branch_type, node): Node.__init__(self, node) self.id = node.id self.decl_type = node.decl_type + self.branch_type = branch_type self.expr = ret_expr diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 0572b409a..81030c2fc 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -98,7 +98,7 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: new_params.append(self.visit(param, scope)) param_types = [ - unify(typex, new_param.inferenced_type ) + unify(typex, new_param.inferenced_type) for new_param, typex in zip(new_params, current_method.param_types) ] current_method.param_types = [i[0] for i in param_types] @@ -169,7 +169,7 @@ def visit(self, node: CaseOptionNode, scope: Scope) -> CaseOptionNode: scope.define_variable(node.id, node_type) new_node_expr = self.visit(node.expr, scope) - new_node = CaseOptionNode(new_node_expr, node) + new_node = CaseOptionNode(new_node_expr, node_type, node) decl_type = node.inferenced_type expr_type = new_node_expr.inferenced_type new_node.inferenced_type, changed = unify(decl_type, expr_type) @@ -245,7 +245,7 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: for arg_expr, param_type in zip(node.args, method.param_types): arg_node = self.visit(arg_expr, scope) arg_node.inferenced_type, changed = unify( - param_type, arg_node.inferenced_type + param_type, arg_node.inferenced_type ) self.changed |= changed new_args.append(arg_node) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index 43bc7935b..efc29000d 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -200,8 +200,11 @@ def visit(self, node, scope: Scope): @visitor.when(CaseOptionNode) def visit(self, node, scope: Scope): expr_node = self.visit(node.expr, scope) - opt_node = CaseOptionNode(expr_node, node) + opt_node = CaseOptionNode(expr_node, node.branch_type, node) + opt_node.inferenced_type = expr_node.inferenced_type + # opt_node.branch_type = node.branch_type + return opt_node @visitor.when(LoopNode) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 8b4b69ef5..9c3f96ed2 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -232,7 +232,7 @@ def visit(self, node, scope: Scope): scope.define_variable(node.id, node_type) expr_node = self.visit(node.expr, scope) - case_opt_node = inf_ast.CaseOptionNode(expr_node, node) + case_opt_node = inf_ast.CaseOptionNode(expr_node, node_type, node) case_opt_node.inferenced_type = expr_node.inferenced_type return case_opt_node diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 137132f58..00e8218f0 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -59,7 +59,9 @@ def visit(self, node: ProgramNode) -> types_ast.ProgramNode: return types_ast.ProgramNode(class_decl, node) @visitor.when(ClassDeclarationNode) - def visit(self, node: ClassDeclarationNode, scope: Scope) -> types_ast.ClassDeclarationNode: + def visit( + self, node: ClassDeclarationNode, scope: Scope + ) -> types_ast.ClassDeclarationNode: features = [] for feature in node.features: features.append(self.visit(feature, scope)) @@ -67,7 +69,9 @@ def visit(self, node: ClassDeclarationNode, scope: Scope) -> types_ast.ClassDecl return types_ast.ClassDeclarationNode(features, node) @visitor.when(AttrDeclarationNode) - def visit(self, node: AttrDeclarationNode, scope: Scope) -> types_ast.AttrDeclarationNode: + def visit( + self, node: AttrDeclarationNode, scope: Scope + ) -> types_ast.AttrDeclarationNode: new_node = types_ast.AttrDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr, scope) @@ -75,17 +79,19 @@ def visit(self, node: AttrDeclarationNode, scope: Scope) -> types_ast.AttrDeclar return new_node @visitor.when(MethodDeclarationNode) - def visit(self, node: MethodDeclarationNode, scope: Scope) -> types_ast.MethodDeclarationNode: + def visit( + self, node: MethodDeclarationNode, scope: Scope + ) -> types_ast.MethodDeclarationNode: scope = scope.create_child() - + for param in node.params: - param_type = self._reduce_to_type(param.inferenced_type,node, general=True) + param_type = self._reduce_to_type(param.inferenced_type, node, general=True) scope.define_variable(param.id, param_type) params = [self.visit(param, scope) for param in node.params] - + body = self.visit(node.body, scope) - + ret_type = self._reduce_to_type(node.inferenced_type, node) return types_ast.MethodDeclarationNode(params, ret_type, body, node) @@ -110,7 +116,7 @@ def visit(self, node: ConditionalNode, scope: Scope) -> types_ast.ConditionalNod @visitor.when(CaseNode) def visit(self, node: CaseNode, scope: Scope) -> types_ast.CaseNode: expr = self.visit(node.case_expr, scope) - + case_options = [] for option in node.options: child_scope = scope.create_child() @@ -122,7 +128,9 @@ def visit(self, node: CaseNode, scope: Scope) -> types_ast.CaseNode: @visitor.when(CaseOptionNode) def visit(self, node: CaseOptionNode, scope: Scope) -> types_ast.CaseOptionNode: - return types_ast.CaseOptionNode(self.visit(node.expr, scope), node) + return types_ast.CaseOptionNode( + self.visit(node.expr, scope), node.branch_type, node + ) @visitor.when(LoopNode) def visit(self, node: LoopNode, scope: Scope) -> types_ast.LoopNode: @@ -136,20 +144,22 @@ def visit(self, node: LoopNode, scope: Scope) -> types_ast.LoopNode: def visit(self, node: LetNode, scope: Scope) -> types_ast.LetNode: scope = scope.create_child() var_decl_list = [self.visit(var_decl, scope) for var_decl in node.var_decl_list] - in_expr = self.visit(node.in_expr,scope) + in_expr = self.visit(node.in_expr, scope) new_node = types_ast.LetNode(var_decl_list, in_expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(VarDeclarationNode) - def visit(self, node: VarDeclarationNode, scope: Scope) -> types_ast.VarDeclarationNode: + def visit( + self, node: VarDeclarationNode, scope: Scope + ) -> types_ast.VarDeclarationNode: new_node = types_ast.VarDeclarationNode(node) if node.expr: new_node.expr = self.visit(node.expr, scope) var_info = scope.find_variable(node.id) - general = var_info is not None # it's a param - new_node.type = self._reduce_to_type(node.inferenced_type,node, general) + general = var_info is not None # it's a param + new_node.type = self._reduce_to_type(node.inferenced_type, node, general) return new_node @@ -171,12 +181,12 @@ def visit(self, node: MethodCallNode, scope: Scope) -> types_ast.MethodCallNode: @visitor.when(VariableNode) def visit(self, node: VariableNode, scope: Scope) -> types_ast.VariableNode: new_node = types_ast.VariableNode(node) - + if node.defined: var_info = scope.find_variable(node.value) general = var_info is not None new_node.type = self._reduce_to_type(node.inferenced_type, node, general) - + return new_node @visitor.when(IsVoidNode) @@ -272,7 +282,7 @@ def _reduce_to_type(self, bag: TypeBag, node: Node, general=False): return self._join_types(higher_index_types) - def _join_types(self, types : List[Type]): + def _join_types(self, types: List[Type]): types_bags = [] for typex in types: types_bags.append(TypeBag({typex}, heads=[typex])) From 238cbeb7cca6e8103c54a7169481980599ae28fb Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 12 Feb 2022 19:43:16 -0500 Subject: [PATCH 183/432] Add new utility functions --- src/asts/ccil_ast.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 92100eb79..f8dd7770e 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -87,7 +87,9 @@ class LesserOpNode(BinaryOpNode): class UnaryOpNode(ReturnOpNode): - pass + def __init__(self, node, atom: AtomOpNode) -> None: + super().__init__(node) + self.atom = atom class GetTypeOpNode(UnaryOpNode): @@ -162,5 +164,13 @@ def create_uninitialized_storage(node, idx: str): return StorageNode(node, idx, VoidNode(node)) +def create_type_of(node, idx: str, target: AtomOpNode): + return StorageNode(node, idx, GetTypeOpNode(node, target)) + + +def create_equality(node, idx, left: AtomOpNode, right: AtomOpNode): + return StorageNode(node, idx, EqualOpNode(node, left, right)) + + def extract_id(node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) From 3ae9538007f537930e00f31b5ce4d20f60abc9c2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 12 Feb 2022 19:43:34 -0500 Subject: [PATCH 184/432] Add block expression translation to ccil --- src/code_gen/ccil_gen.py | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 2a1250b99..a1fe34427 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -22,6 +22,22 @@ def __init__(self) -> None: def visit(self, _): self.time_record: Dict[str, int] = Dict() + @visitor.when(sem_ast.BlocksNode) + def visit(self, node:sem_ast.BlocksNode) -> VISITOR_RESULT: + times = self.times(node) + + operations:List[OperationNode] = [] + fvalues:List[StorageNode] = [] + for expr in node.expr_list: + (expr_ops, expr_fval) = self.visit(expr) + operations += expr_ops + fvalues += expr_fval + + fval = fvalues[-1] + fval.id = f"block_{times}" + + return (operations, fval) + @visitor.when(sem_ast.LetNode) def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: operations: List[OperationNode] = [] @@ -78,8 +94,29 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: return ([*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) @visitor.when(sem_ast.CaseNode) - def visit(self, node:sem_ast.CaseNode): - pass + def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: + times = self.times(node) + + (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) + + type_of = create_type_of( + node, + f"case_{times}_typeOf", + extract_id(node, case_expr_fv) + ) + + operations = [*case_expr_ops, type_of] + + for (i, option) in enumerate(node.options): + option_id = f"case_{times}_option_{i}" + options_st = create_uninitialized_storage(option, option_id) + # The type of the option node must be stored to do the pattern matching! + + @visitor.when(sem_ast.CaseOptionNode) + def visit(self, node:sem_ast.CaseOptionNode) -> VISITOR_RESULT: + times = self.times(node) + + @visitor.when(sem_ast.LoopNode) def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: From 2f632c98ed952a106467f057abba8aac5f59d3c7 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 11:42:46 -0500 Subject: [PATCH 185/432] Add case expression translation to ccil --- src/code_gen/ccil_gen.py | 71 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a1fe34427..7cb2e58e1 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -97,20 +97,83 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: times = self.times(node) + # Visiting case expression (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) + # Storing the type of the resulting case expression type_of = create_type_of( node, f"case_{times}_typeOf", extract_id(node, case_expr_fv) ) - operations = [*case_expr_ops, type_of] + # Final label where all branch must jump to + final_label_id = f"case_{times}_end" + final_label = LabelNode(node, final_label_id) + # Inconditional jump to final label + final_goto = GoToNode(node, final_label) + + # All branch must end in a var named like this + pre_fvalue_id = f"case_{times}_pre_fv" + pattern_match_ops = [] + branch_ops = [] for (i, option) in enumerate(node.options): - option_id = f"case_{times}_option_{i}" - options_st = create_uninitialized_storage(option, option_id) - # The type of the option node must be stored to do the pattern matching! + # Initializing the branch var + branch_var_id = f"case_{times}_option_{i}" + branch_var = create_uninitialized_storage(option, branch_var_id) + branch_var.decl_type = option.branch_type + + # Initializing var which holds the branch var type + branch_var_type_id = f"case_{times}_optionTypeOf_{i}" + branch_var_type_of = create_type_of( + option, + branch_var_type_id, + extract_id(node, branch_var) + ) + + # Initializng var which holds the comparison result between + # the case expression type of and branch var type of + select_branch_id = f"case_{times}_optionSelect_{i}" + select_branch = create_equality( + option, + select_branch_id, + extract_id(node, type_of), + extract_id(node, branch_var_type_of) + ) + + # Label that means the start of this branch logic + branch_label_id = f"case_{times}_branch_{i}" + branch_label = LabelNode(option, branch_label_id) + + # Conditional jump to the right branch label + if_op = IfNode(option, extract_id(option, branch_var_type_of), branch_label) + pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] + + # Visiting the branch logic + (expr_ops, expr_fval) = self.visit(option.expr) + + # Renaming the last stored value of the expression accordingly + expr_fval.id = pre_fvalue_id + + # Storing logic to jump to branch logic if this branch is selected + pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] + + # Translating to ccil of branch logic + branch_ops += [branch_label, *expr_ops, final_goto] + + fval_id = f"case_{times}_fv" + fval = create_assignation(node,fval_id, pre_fvalue_id) + operations = [ + *case_expr_ops, type_of, + *pattern_match_ops, + *branch_ops, + final_label, + fval + ] + return (operations, fval) + + @visitor.when(sem_ast.CaseOptionNode) def visit(self, node:sem_ast.CaseOptionNode) -> VISITOR_RESULT: From 6da29f309a7747a80e80a4565ec908afb9b428fb Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 12:25:01 -0500 Subject: [PATCH 186/432] Format code --- src/code_gen/ccil_gen.py | 71 ++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 7cb2e58e1..edf856957 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -23,11 +23,11 @@ def visit(self, _): self.time_record: Dict[str, int] = Dict() @visitor.when(sem_ast.BlocksNode) - def visit(self, node:sem_ast.BlocksNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: times = self.times(node) - operations:List[OperationNode] = [] - fvalues:List[StorageNode] = [] + operations: List[OperationNode] = [] + fvalues: List[StorageNode] = [] for expr in node.expr_list: (expr_ops, expr_fval) = self.visit(expr) operations += expr_ops @@ -44,23 +44,23 @@ def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: fvalues: List[StorageNode] = [] for var in node.var_decl_list: - (var_ops, var_fv) = self.visit(var) - operations += var_ops - fvalues += var_fv + (var_ops, var_fv) = self.visit(var) + operations += var_ops + fvalues += var_fv (in_ops, in_fval) = self.visit(node.in_expr) operations += in_ops - return(operations, in_fval) + return (operations, in_fval) @visitor.when(sem_ast.VarDeclarationNode) def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: - fvalue_id:str = USER + node.id + fvalue_id: str = USER + node.id if node.expr is None: return ([], create_uninitialized_storage(node, fvalue_id)) - (expr_ops, expr_fv) = self.visit(node.expr) + (expr_ops, expr_fv) = self.visit(node.expr) expr_fv.id = fvalue_id return (expr_ops, expr_fv) @@ -68,7 +68,7 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: @visitor.when(sem_ast.AssignNode) def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: (expr_ops, expr_fval) = self.visit(node.expr) - expr_fval.id = USER + node.id + expr_fval.id = USER + node.id return (expr_ops, expr_fval) @@ -94,7 +94,7 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: return ([*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) @visitor.when(sem_ast.CaseNode) - def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: times = self.times(node) # Visiting case expression @@ -102,10 +102,8 @@ def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: # Storing the type of the resulting case expression type_of = create_type_of( - node, - f"case_{times}_typeOf", - extract_id(node, case_expr_fv) - ) + node, f"case_{times}_typeOf", extract_id(node, case_expr_fv) + ) # Final label where all branch must jump to final_label_id = f"case_{times}_end" @@ -127,20 +125,18 @@ def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" branch_var_type_of = create_type_of( - option, - branch_var_type_id, - extract_id(node, branch_var) - ) + option, branch_var_type_id, extract_id(node, branch_var) + ) # Initializng var which holds the comparison result between # the case expression type of and branch var type of select_branch_id = f"case_{times}_optionSelect_{i}" select_branch = create_equality( - option, - select_branch_id, - extract_id(node, type_of), - extract_id(node, branch_var_type_of) - ) + option, + select_branch_id, + extract_id(node, type_of), + extract_id(node, branch_var_type_of), + ) # Label that means the start of this branch logic branch_label_id = f"case_{times}_branch_{i}" @@ -161,26 +157,23 @@ def visit(self, node:sem_ast.CaseNode) -> VISITOR_RESULT: # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] - + fval_id = f"case_{times}_fv" - fval = create_assignation(node,fval_id, pre_fvalue_id) + fval = create_assignation(node, fval_id, pre_fvalue_id) operations = [ - *case_expr_ops, type_of, - *pattern_match_ops, - *branch_ops, - final_label, - fval - ] + *case_expr_ops, + type_of, + *pattern_match_ops, + *branch_ops, + final_label, + fval, + ] return (operations, fval) - - @visitor.when(sem_ast.CaseOptionNode) - def visit(self, node:sem_ast.CaseOptionNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.CaseOptionNode) -> VISITOR_RESULT: times = self.times(node) - - @visitor.when(sem_ast.LoopNode) def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: times = self.times(node) @@ -198,11 +191,11 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) - fval = create_uninitialized_storage(node, f"loop_{times}_fv"), + fval = (create_uninitialized_storage(node, f"loop_{times}_fv"),) # Loop Nodes have void return type, how to express it?? return ( [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], - fval + fval, ) @visitor.when(sem_ast.ArithmeticNode) From 3d3f55e8f2797f623fda4461de477a9606527b2c Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 12:49:42 -0500 Subject: [PATCH 187/432] Minor refactor and add boolean expression translation --- src/code_gen/ccil_gen.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index edf856957..e09d17a28 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -158,6 +158,8 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] + # Merging all expression operations in correct order + # and saving to expression final value fval_id = f"case_{times}_fv" fval = create_assignation(node, fval_id, pre_fvalue_id) operations = [ @@ -170,10 +172,6 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: ] return (operations, fval) - @visitor.when(sem_ast.CaseOptionNode) - def visit(self, node: sem_ast.CaseOptionNode) -> VISITOR_RESULT: - times = self.times(node) - @visitor.when(sem_ast.LoopNode) def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: times = self.times(node) @@ -198,8 +196,8 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: fval, ) - @visitor.when(sem_ast.ArithmeticNode) - def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: + @visitor.when(sem_ast.BinaryNode) + def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: times = self.times(node) (left_ops, left_fval) = self.visit(node.left) @@ -223,8 +221,17 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: case sem_ast.DivNode: op = DivOpNode(left_id, right_id) fval_id = f"div_{times}" + case sem_ast.EqualsNode: + op = EqualOpNode(left_id, right_id) + fval_id = f"eq_{times}" + case sem_ast.LessNode: + op = LessOpNode(left_id, right_id) + fval_id = f"le_{times}" + case sem_ast.LessOrEqualNode: + op = LessOrEqualOpNode(left_id, right_id) + fval_id = f"leq_{times}" case _: - raise Exception("Pattern match failure visiting artihmetic expression") + raise Exception("Pattern match failure visiting binary expression") fval = StorageNode(node, fval_id, op) From 152eff96dad16d7d3261b8f185367d903cf95a75 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 15:44:43 -0500 Subject: [PATCH 188/432] Add more nodes --- src/asts/ccil_ast.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index f8dd7770e..dff684505 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -32,6 +32,7 @@ def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: super().__init__(node) self.id = idx self.operation = operation + self.decl_type = node.decl_type class ReturnOpNode(OperationNode): @@ -78,11 +79,11 @@ class EqualOpNode(BinaryOpNode): pass -class LessrOrEqualOpNode(BinaryOpNode): +class LessOrEqualOpNode(BinaryOpNode): pass -class LesserOpNode(BinaryOpNode): +class LessOpNode(BinaryOpNode): pass @@ -98,12 +99,20 @@ class GetTypeOpNode(UnaryOpNode): pass -class IsVoidNode(UnaryOpNode): +class IsVoidOpNode(UnaryOpNode): """Operation that returns true if the Storage Node is uninitialized""" pass +class NotOpNode(UnaryOpNode): + pass + + +class NegOpNode(UnaryOpNode): + pass + + class AtomOpNode(ReturnOpNode): def __init__(self, node) -> None: """ From cd5ff5f10d2e7e1ba4b4ea75d3e9428b975f3e2e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 15:45:09 -0500 Subject: [PATCH 189/432] Add unary expression translation to ccil --- src/code_gen/ccil_gen.py | 44 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index e09d17a28..73dc829a9 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -206,9 +206,10 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: left_id = extract_id(node, left_fval) right_id = extract_id(node, right_fval) - op: ReturnOpNode fval_id: str + op: BinaryOpNode match node: + # Arithmetic Binary Nodes case sem_ast.PlusNode: op = SumOpNode(left_id, right_id) fval_id = f"sum_{times}" @@ -221,6 +222,7 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: case sem_ast.DivNode: op = DivOpNode(left_id, right_id) fval_id = f"div_{times}" + # Boolean Binary Nodes case sem_ast.EqualsNode: op = EqualOpNode(left_id, right_id) fval_id = f"eq_{times}" @@ -234,9 +236,47 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: raise Exception("Pattern match failure visiting binary expression") fval = StorageNode(node, fval_id, op) - return ([*left_ops, *right_ops, fval], fval) + @visitor.when(sem_ast.UnaryNode) + def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: + times = self.times(node) + + (expr_op, expr_fval) = self.visit(node.expr) + expr_id = extract_id(node.expr, expr_fval) + + fval_id: str + op: UnaryOpNode + match node: + case sem_ast.IsVoidNode: + fval_id = "isVoid_{times}" + op = IsVoidOpNode(node, expr_id) + case sem_ast.NotNode: + fval_id = "not_{times}" + op = NotOpNode(node, expr_id) + case sem_ast.ComplementNode: + fval_id = "neg_{times}" + op = NegOpNode(node, expr_id) + case _: + raise Exception("Pattern match failure while visiting unary expression") + + fval = StorageNode(node, fval_id, op) + return [*expr_op, fval], fval + + @visitor.when(sem_ast.MethodCallNode) + def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: + times = self.times(node) + + # Translate all call arguments to ccil + args_ops: List[OperationNode] = [] + args_fvals: List[StorageNode] = [] + for arg_expr in node.args: + (arg_op, arg_fval) = self.visit(arg_expr) + args_ops += arg_op + args_fvals += [arg_fval] + + + def times(self, node): key: str = type(node).__name__ try: From 71cb993281f17fa76e10a4614ad58f9430b175d4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 13 Feb 2022 15:45:42 -0500 Subject: [PATCH 190/432] Minor bug fix --- src/code_gen/ccil_gen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 73dc829a9..17e4a287f 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -249,13 +249,13 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: op: UnaryOpNode match node: case sem_ast.IsVoidNode: - fval_id = "isVoid_{times}" + fval_id = f"isVoid_{times}" op = IsVoidOpNode(node, expr_id) case sem_ast.NotNode: - fval_id = "not_{times}" + fval_id = f"not_{times}" op = NotOpNode(node, expr_id) case sem_ast.ComplementNode: - fval_id = "neg_{times}" + fval_id = f"neg_{times}" op = NegOpNode(node, expr_id) case _: raise Exception("Pattern match failure while visiting unary expression") From e57b9a7c9bd86d3705bd800563d1e036243bda0c Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 09:13:29 -0500 Subject: [PATCH 191/432] "Add --- src/asts/ccil_ast.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index dff684505..f1a1ea731 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -1,6 +1,8 @@ from typing import Dict, List, Tuple from __future__ import annotations +from semantics.tools.type import Type + class Node: def __init__(self, node) -> None: @@ -11,6 +13,11 @@ def get_position(self) -> Tuple[int, int]: return (self.line, self.col) +class ClassNode(Node): + def __init__(self, node) -> None: + super().__init__(node) + + class OperationNode(Node): """ Base Class for all operation Nodes @@ -20,6 +27,30 @@ def __init__(self, node) -> None: super().__init__(node) +class LocalNode(OperationNode): + def __init__(self, node, idx: str, typex: Type) -> None: + """ + Node represent initalization instruction" + Parameter: + idx <- node name + type <- node type + """ + super().__init__(node) + self.id: str = idx + self.type: str = typex.name + + +class ParamNode(LocalNode): + def __init__(self, node, idx: str, typex: Type) -> None: + """ + Node represent function parameter initalization instruction" + Parameter: + idx <- node name + type <- node type + """ + super().__init__(node, idx, typex) + + class StorageNode(OperationNode): def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: """ From 35e3544367ce6f5c26d097bd4467fff831405c15 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 10:48:56 -0500 Subject: [PATCH 192/432] Expand class translation to ccil --- src/code_gen/ccil_gen.py | 44 ++++++++++++++++++++++++++++--- src/code_gen/tools.py | 57 +++++++++------------------------------- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 17e4a287f..84c62d89e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -2,6 +2,7 @@ import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast from typing import Tuple, List +from code_gen.tools import * # All operations that define an expression and where it is stored @@ -16,11 +17,44 @@ class CCILGenerator: """ def __init__(self) -> None: - pass + self.types: List[Class] = list() + self.code: List[MethodNode] = list() + self.time_record: Dict[str, int] = dict() @visitor.on("node") def visit(self, _): - self.time_record: Dict[str, int] = Dict() + pass + + @visitor.when(sem_ast.ProgramNode) + def visit(self, node: sem_ast.ProgramNode) -> None: + pass + + @visitor.when(sem_ast.ClassDeclarationNode) + def visit(self, node: sem_ast.ClassDeclarationNode) -> Class: + attributes: List[Attribute] = list() + methods: List[Method] = list() + + init_attr_ops: List[OperationNode] = [] + + for feature in node.features: + if isinstance(feature, sem_ast.AttrDeclarationNode): + attributes.append(Attribute(feature.id, feature.type.name)) + (attr_ops, _) = self.visit(feature) + init_attr_ops += attr_ops + else: + methods.append(feature.id) + method_node = self.visit(feature) + self.code.append(method_node) + + return Class(attributes, methods) + + @visitor.when(sem_ast.AttrDeclarationNode) + def visis(self, node: sem_ast.AttrDeclarationNode): + pass + + @visitor.when(sem_ast.MethodDeclarationNode) + def visit(self, node: sem_ast.MethodDeclarationNode): + pass @visitor.when(sem_ast.BlocksNode) def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: @@ -275,7 +309,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: args_ops += arg_op args_fvals += [arg_fval] - + # it can have an @ or not + if node.at_type is None: + pass + + # It has also an at type def times(self, node): key: str = type(node).__name__ diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 851b3c6fe..0a343e12f 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1,53 +1,22 @@ from dataclasses import dataclass from asts.ccil_ast import ExpressionNode +from typing import List +from __future__ import annotations -@dataclass -class Feature: - cool_name: str - ccil_name: str - attribute: bool +@dataclass(frozen=True) +class Class: + attributes: List[Attribute] + methods: List[Method] - @property - def is_attribute(self): - return self.attribute +@dataclass(frozen=True) +class Attribute: + id: str + type: str -@dataclass -class LocalVar: - cool_name: str - ccil_name: str - boundExpression: ExpressionNode | None - @property - def get_name(self): - assert self.ccil_name != "" - return self.ccil_name - - @staticmethod - def new_temporal_var(name: str, boundExpression: ExpressionNode): - return LocalVar("", name, boundExpression) - - @staticmethod - def new_user_defined_var( - name: str, ccil_name: str, boundExpression: ExpressionNode | None = None - ): - return LocalVar(name, ccil_name, boundExpression) - - -def make_id( - name: str, main_num: int, aux_name: str = "", snd_num: int = -1, thrd_num: int = -1 -): - main_num_str = str(main_num) - snd_num_str = "" - thrd_num_str = "" - - if aux_name != "": - aux_name = f"_{aux_name}" - if snd_num != -1: - snd_num_str = f"_{snd_num}" - if thrd_num != -1: - thrd_num_str = f"_{thrd_num}" - - return f"{name}{aux_name}_{main_num_str}{snd_num_str}{thrd_num_str}" +@dataclass(frozen=True) +class Method: + id: str From 0e7eb6917e4050a35b594a22e92e749486bc1009 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 10:49:39 -0500 Subject: [PATCH 193/432] Improve ccil class node --- src/asts/ccil_ast.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index f1a1ea731..070dd2baa 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -1,5 +1,6 @@ from typing import Dict, List, Tuple from __future__ import annotations +from code_gen.tools import Attribute, Method from semantics.tools.type import Type @@ -14,7 +15,21 @@ def get_position(self) -> Tuple[int, int]: class ClassNode(Node): - def __init__(self, node) -> None: + def __init__( + self, + node, + attributes: List[Attribute], + methods: List[Method], + init_operations: List[OperationNode], + ) -> None: + super().__init__(node) + self.attributes = attributes + self.methods = methods + self.init_operations = init_operations + + +class MethodNode(Node): + def __init__(self, node, idx: str, operations: List[OperationNode]) -> None: super().__init__(node) From 6324e99593700ffd8a33f6af0c7c6edd63e69d53 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 10:52:37 -0500 Subject: [PATCH 194/432] Add Arg node --- src/asts/ccil_ast.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 070dd2baa..dbaa24092 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -66,6 +66,12 @@ def __init__(self, node, idx: str, typex: Type) -> None: super().__init__(node, idx, typex) +class ArgNode(OperationNode): + def __init__(self, node, idx: str) -> None: + super().__init__(node) + self.id = idx + + class StorageNode(OperationNode): def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: """ From c45561d744c7eac34224b262a7af23bc06c53b87 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 11:03:57 -0500 Subject: [PATCH 195/432] Minor change and refactoring to ccil_visitor --- src/code_gen/ccil_gen.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 84c62d89e..8e9e0df44 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -7,6 +7,7 @@ # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] +CLASS_VISITOR_RESULT = Tuple[ClassNode, List[MethodNode]] USER = "user" @@ -18,7 +19,6 @@ class CCILGenerator: def __init__(self) -> None: self.types: List[Class] = list() - self.code: List[MethodNode] = list() self.time_record: Dict[str, int] = dict() @visitor.on("node") @@ -27,14 +27,20 @@ def visit(self, _): @visitor.when(sem_ast.ProgramNode) def visit(self, node: sem_ast.ProgramNode) -> None: - pass + program_types: List[ClassNode] = list() + program_codes: List[MethodNode] = list() + for type in node.declarations: + classx, class_code = self.visit(type) + program_types.append(classx) + program_codes.append(class_code) @visitor.when(sem_ast.ClassDeclarationNode) - def visit(self, node: sem_ast.ClassDeclarationNode) -> Class: + def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: attributes: List[Attribute] = list() methods: List[Method] = list() - init_attr_ops: List[OperationNode] = [] + class_code: List[MethodNode] = list() + init_attr_ops: List[OperationNode] = list() for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): @@ -44,9 +50,9 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> Class: else: methods.append(feature.id) method_node = self.visit(feature) - self.code.append(method_node) + class_code.append(method_node) - return Class(attributes, methods) + return ClassNode(attributes, methods, init_attr_ops), class_code @visitor.when(sem_ast.AttrDeclarationNode) def visis(self, node: sem_ast.AttrDeclarationNode): From 0cf6c2a5b266c528d8ab1bc343d0ca513452a975 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 12:30:38 -0500 Subject: [PATCH 196/432] Add MethodNode to ccil --- src/asts/ccil_ast.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index dbaa24092..a6f1e4869 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -31,6 +31,8 @@ def __init__( class MethodNode(Node): def __init__(self, node, idx: str, operations: List[OperationNode]) -> None: super().__init__(node) + self.id = idx + self.operations = operations class OperationNode(Node): From b41bf0ce5de698c76dbeb702a6c477bb85606214 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 12:31:02 -0500 Subject: [PATCH 197/432] Add translation for methods and attributes --- src/code_gen/ccil_gen.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 8e9e0df44..c2a315b6c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -8,8 +8,10 @@ # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] CLASS_VISITOR_RESULT = Tuple[ClassNode, List[MethodNode]] +METHOD_VISITOR_RESULT = MethodNode USER = "user" +ATTR = "attr" # CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: @@ -44,7 +46,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): - attributes.append(Attribute(feature.id, feature.type.name)) + attributes.append(Attribute(ATTR + feature.id, feature.type.name)) (attr_ops, _) = self.visit(feature) init_attr_ops += attr_ops else: @@ -52,15 +54,35 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: method_node = self.visit(feature) class_code.append(method_node) - return ClassNode(attributes, methods, init_attr_ops), class_code + return ( + ClassNode(attributes, methods, init_attr_ops), + class_code, + ) @visitor.when(sem_ast.AttrDeclarationNode) - def visis(self, node: sem_ast.AttrDeclarationNode): - pass + def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: + fval_id = ATTR + node.id + + if node.expr is None: + op = LocalNode(node, fval_id, node.type.name) + return [op], op + + (expr_op, expr_fval) = self.visit(node.expr) + expr_fval.id = fval_id + + return (expr_op, expr_fval) + @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode): - pass + operations: List[OperationNode] = [] + for param in node.params: + operations.append(ParamNode(param.id, param.type.name)) + + (expr_op, _) = self.visit(node.body) + + operations += expr_op + return MethodNode(node, node.id, operations) @visitor.when(sem_ast.BlocksNode) def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: From 05b171f8f792d4b8c1ef2b0ecb4021c1bc1f4de2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 13:17:18 -0500 Subject: [PATCH 198/432] Add Call and VCall nodes as well utility operations --- src/asts/ccil_ast.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index a6f1e4869..9630074f1 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -94,6 +94,18 @@ def __init__(self, node) -> None: super().__init__(node) +class CallOpNode(OperationNode): + def __init__(self, node, idx: str) -> None: + super().__init__(node) + self.id = idx + + +class VCallOpNode(CallOpNode): + def __init__(self, node, idx: str, type_idx: str) -> None: + super().__init__(node, idx) + self.type = type_idx + + class VoidNode(ReturnOpNode): """Operation that indicate that the Storage Node is not initialized""" @@ -219,6 +231,14 @@ def __init__(self, node, idx: str) -> None: self.id = idx +def create_call(node, storage_idx: str, method_idx: str): + return StorageNode(node, storage_idx, CallOpNode(node, method_idx)) + + +def create_vcall(node, storage_idx: str, method_idx: str, type_idx: str): + return StorageNode(node, storage_idx, VCallOpNode(node, method_idx, type_idx)) + + def create_assignation(node, idx: str, target: str): return StorageNode(node, idx, IdNode(node, target)) From efbe631b9e8d014772df33d2317de65c6a880069 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 13:17:54 -0500 Subject: [PATCH 199/432] Update Call and VCall nodes parent classs --- src/asts/ccil_ast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 9630074f1..6a9de6199 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -94,13 +94,13 @@ def __init__(self, node) -> None: super().__init__(node) -class CallOpNode(OperationNode): +class CallOpNode(ReturnOpNode): def __init__(self, node, idx: str) -> None: super().__init__(node) self.id = idx -class VCallOpNode(CallOpNode): +class VCallOpNode(ReturnOpNode): def __init__(self, node, idx: str, type_idx: str) -> None: super().__init__(node, idx) self.type = type_idx From 0992d4b2c5c2784e38cb8be71e80c8deacd9e0c3 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 13:18:28 -0500 Subject: [PATCH 200/432] Add method call translation to ccil --- src/code_gen/ccil_gen.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index c2a315b6c..a960fe93a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -72,7 +72,6 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: return (expr_op, expr_fval) - @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode): operations: List[OperationNode] = [] @@ -330,18 +329,29 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: times = self.times(node) # Translate all call arguments to ccil + # Name all fvalues as ARG args_ops: List[OperationNode] = [] - args_fvals: List[StorageNode] = [] + args: List[ArgNode] = [] for arg_expr in node.args: (arg_op, arg_fval) = self.visit(arg_expr) args_ops += arg_op - args_fvals += [arg_fval] + args += [ArgNode(arg_expr, arg_fval.id)] + + if node.expr is None: + fval_id = f"call_{times}" + call = create_call(node, fval_id, node.id) + return [*args_ops, *args, call], call + + (expr_ops, expr_fval) = self.visit(node.expr) + + type_idx: str = ( + node.expr.type.name if node.at_type is None else node.at_type.name + ) - # it can have an @ or not - if node.at_type is None: - pass + fval_id = f"fvcall_{times}" + call = create_vcall(node, fval_id, node.id, type_idx) - # It has also an at type + return [*args_ops, *expr_ops, *args, call] def times(self, node): key: str = type(node).__name__ From 1245f246659dc58604cd7f5a47a38d1bbd8431d6 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 15:09:38 -0500 Subject: [PATCH 201/432] A lot of minor changes in semantics Add type checking. Add method to scope that raise exception when no var is found Handle cases when vars were possibly unbound Fix reading and remove redundant if Other minor changes --- src/semantics/inference/hard_inferencer.py | 12 ++++++++---- src/semantics/inference/soft_inferencer.py | 13 ++++++++----- src/semantics/inference/types_inferencer.py | 3 +++ src/semantics/tools/context.py | 14 +++++++++++--- src/semantics/tools/scope.py | 12 ++++++++++-- src/semantics/tools/type.py | 17 ++++++++++------- src/semantics/type_builder.py | 3 ++- 7 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index efc29000d..d116ae54c 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -32,6 +32,7 @@ VarDeclarationNode, VariableNode, ) +from semantics.tools.type import Type from utils import visitor from semantics.tools import ( Context, @@ -51,7 +52,7 @@ def __init__(self, context: Context) -> None: self.context = context self.errors = [] self.pos = set() - self.current_type = None + self.current_type: Type @visitor.on("node") def visit(self, node, scope): @@ -279,7 +280,7 @@ def visit(self, node, scope: Scope): assign_node.defined = True - decl_type = scope.find_variable(node.id).get_type() + decl_type = scope.get_variable(node.id).get_type() expr_type = expr_node.inferenced_type if not equal(expr_type, node.expr.inferenced_type): expr_clone = expr_type.clone() @@ -296,7 +297,7 @@ def visit(self, node, scope: Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): - caller_type = node.caller_type + caller_type: TypeBag = node.caller_type expr_node = None if node.type is not None and node.expr is not None: expr_node = self.visit(node.expr, scope) @@ -393,6 +394,9 @@ def visit(self, node, scope): arith_node = StarNode(left_node, right_node, node) elif isinstance(node, DivNode): arith_node = DivNode(left_node, right_node, node) + else: + raise InternalError("This should never happen") + arith_node.inferenced_type = self.context.get_type("Int") return arith_node @@ -429,7 +433,7 @@ def visit(self, node, scope: Scope): return var_node var_node.defined = True - var = scope.find_variable(node.value) + var = scope.get_variable(node.value) var_node.inferenced_type = var.get_type() return var_node diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 9c3f96ed2..965862f32 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -53,7 +53,7 @@ class SoftInferencer: def __init__(self, context: Context) -> None: self.context = context self.errors = [] - self.current_type = None + self.current_type: Type = None @visitor.on("node") def visit(self, node, scope): @@ -203,7 +203,7 @@ def visit(self, node, scope: Scope): child = scope.create_child() new_options.append(self.visit(option, child)) type_list.append(new_options[-1].inferenced_type) - var_type = child.find_variable(option.id).get_type() + var_type = child.get_variable(option.id).get_type() var_type = var_type.heads[0] if not var_type.error_type else var_type if var_type in types_visited: self.add_error( @@ -316,7 +316,7 @@ def visit(self, node, scope: Scope): assign_node = inf_ast.AssignNode(expr_node, node) var = scope.find_variable(node.id) - if not var: + if var is None: self.add_error( node, f"SemanticError: Cannot assign new value to" @@ -325,8 +325,6 @@ def visit(self, node, scope: Scope): else: decl_type = var.get_type() assign_node.defined = True - - if var is not None: if var.name == "self": self.add_error( node, @@ -352,6 +350,7 @@ def visit(self, node, scope: Scope): @visitor.when(MethodCallNode) def visit(self, node, scope): + caller_type: TypeBag if node.expr is None: expr_node = None caller_type = TypeBag({self.current_type}) @@ -364,6 +363,7 @@ def visit(self, node, scope): node.type, selftype=False, autotype=False ) except SemanticError as err: + caller_type = TypeBag(set()) self.add_error(node, err + " While setting dispatch caller.") expr_node = self.visit(node.expr, scope) @@ -440,6 +440,9 @@ def visit(self, node, scope): arith_node = inf_ast.StarNode(left_node, right_node, node) elif isinstance(node, DivNode): arith_node = inf_ast.DivNode(left_node, right_node, node) + else: + raise Exception("Unknown arithmetic node detected") + arith_node.inferenced_type = self.context.get_type("Int") return arith_node diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 00e8218f0..f4e6fe35d 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,4 +1,5 @@ from typing import List +from semantics.tools.errors import InternalError from semantics.tools.type import Type, join_list from utils import visitor @@ -229,6 +230,8 @@ def visit(self, node, scope: Scope) -> types_ast.BinaryNode: new_node = types_ast.LessOrEqualNode(left, right, node) elif isinstance(node, EqualsNode): new_node = types_ast.EqualsNode(left, right, node) + else: + raise InternalError("This should never happen") new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node diff --git a/src/semantics/tools/context.py b/src/semantics/tools/context.py index 99d5f1590..09f196f38 100644 --- a/src/semantics/tools/context.py +++ b/src/semantics/tools/context.py @@ -1,11 +1,12 @@ from semantics.tools.errors import * from semantics.tools.type import TypeBag, Type, SelfType +from typing import Dict class Context: def __init__(self) -> None: self.types = {} - self.type_graph = None + self.type_graph: Dict = None def create_type(self, name: str) -> Type: if name in self.types: @@ -13,7 +14,13 @@ def create_type(self, name: str) -> Type: typex = self.types[name] = Type(name) return typex - def get_type(self, name: str, selftype=True, autotype=True, unpacked=False) -> Type: + def get_type( + self, + name: str, + selftype=True, + autotype=True, + unpacked=False, + ) -> Type | TypeBag: if selftype and name == "SELF_TYPE": return TypeBag({SelfType()}) # raise TypeError(f"Cannot use SELF_TYPE.") if autotype and name == "AUTO_TYPE": @@ -50,4 +57,5 @@ def __str__(self): ) def __repr__(self): - return str(self) \ No newline at end of file + return str(self) + diff --git a/src/semantics/tools/scope.py b/src/semantics/tools/scope.py index 236e7b0bc..647d2d887 100644 --- a/src/semantics/tools/scope.py +++ b/src/semantics/tools/scope.py @@ -37,7 +37,7 @@ def define_variable(self, vname, vtype): self.locals.append(info) return info - def find_variable(self, vname, index=None): + def find_variable(self, vname, index=None) -> VariableInfo | None: locals = self.locals if index is None else itt.islice(self.locals, index) try: return next(x for x in locals if x.name == vname) @@ -51,6 +51,13 @@ def find_variable(self, vname, index=None): except AttributeError: return None + def get_variable(self, vname, index=None) -> VariableInfo: + var = self.find_variable(vname, index) + if var is None: + raise Exception(f"Could not get variable {vname}.") + + return var + def get_local_by_index(self, index): return self.locals[index] @@ -80,4 +87,5 @@ def get_all_names(self, s: str = "", level: int = 0): s += "\n\n" for child in self.children: s = child.get_all_names(s, level + 1) - return s \ No newline at end of file + return s + diff --git a/src/semantics/tools/type.py b/src/semantics/tools/type.py index eed0442f8..f4d24301f 100644 --- a/src/semantics/tools/type.py +++ b/src/semantics/tools/type.py @@ -209,16 +209,19 @@ def bypass(self): return False def least_common_ancestor(self, other): - this = self + this: Type = self if isinstance(this, ErrorType) or isinstance(other, ErrorType): return ErrorType() while this.index < other.index: other = other.parent + while other.index < this.index: this = this.parent + if not (this and other): return None + while this.name != other.name: this = this.parent other = other.parent @@ -285,13 +288,13 @@ def update_heads(self) -> None: # new_heads = [] # visited = set() # for head in self.heads: - # if head in self.type_set: - # new_heads.append(head) - # continue + # if head in self.type_set: + # new_heads.append(head) + # continue pos_new_head = [] lower_index = 2 ** 32 for typex in self.type_set: - #if typex in visited: + # if typex in visited: # continue if typex.index < lower_index: @@ -299,8 +302,8 @@ def update_heads(self) -> None: lower_index = typex.index elif typex.index == lower_index: pos_new_head.append(typex) - #new_heads += pos_new_head - self.heads = pos_new_head#new_heads + # new_heads += pos_new_head + self.heads = pos_new_head # new_heads def swap_self_type(self, swap_type, back=False): if self.error_type: diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index ee63987bb..03b06adc9 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -1,3 +1,4 @@ +from semantics.tools.type import Type from utils import visitor from asts.parser_ast import ( Node, @@ -13,7 +14,7 @@ class TypeBuilder: def __init__(self, context: Context): self.context = context - self.current_type = None + self.current_type: Type self.errors: list = [] @visitor.on("node") From 5d69e7fb66a4ceb3cf69cfa79532aac68f18c843 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 15:12:31 -0500 Subject: [PATCH 202/432] Add poetest to makefile to test with poetry --- src/makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/makefile b/src/makefile index 30df993f5..6f531b553 100644 --- a/src/makefile +++ b/src/makefile @@ -10,3 +10,5 @@ clean: test: pytest ../tests -v --tb=short -m=${TAG} +poetest: + poetry run make test From 44d37ce17d9cc1fa8e93dbbfea7569b00d1431d9 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 21 Feb 2022 17:27:43 -0500 Subject: [PATCH 203/432] Add param nodes to parsing and semantics --- src/asts/inferencer_ast.py | 9 +- src/asts/parser_ast.py | 9 +- src/asts/types_ast.py | 7 ++ src/parsing/parser.py | 5 +- src/parsing/parsetab.py | 114 ++++++++++---------- src/semantics/inference/back_inferencer.py | 12 ++- src/semantics/inference/hard_inferencer.py | 10 +- src/semantics/inference/soft_inferencer.py | 13 ++- src/semantics/inference/types_inferencer.py | 7 +- 9 files changed, 106 insertions(+), 80 deletions(-) diff --git a/src/asts/inferencer_ast.py b/src/asts/inferencer_ast.py index a8d00ca8b..a521493cb 100644 --- a/src/asts/inferencer_ast.py +++ b/src/asts/inferencer_ast.py @@ -44,13 +44,20 @@ class MethodDeclarationNode(DeclarationNode): def __init__(self, params, return_type, body, node): Node.__init__(self, node) self.id = node.id - self.params: List[VarDeclarationNode] = params + self.params: List[ParamNode] = params self.type = return_type self.body = body # for debbugin purposes # self.params = node.params +class ParamNode(DeclarationNode): + def __init__(self, node, idx: str, typex) -> None: + super().__init__(node) + self.id = idx + self.type = typex + + class ExpressionNode(Node): pass diff --git a/src/asts/parser_ast.py b/src/asts/parser_ast.py index a17b358d7..7b1bb41e8 100644 --- a/src/asts/parser_ast.py +++ b/src/asts/parser_ast.py @@ -44,11 +44,18 @@ class MethodDeclarationNode(DeclarationNode): def __init__(self, idx, params, return_type, body): Node.__init__(self) self.id = idx - self.params: List[VarDeclarationNode] = params + self.params: List[ParamNode] = params self.type = return_type self.body = body +class ParamNode(DeclarationNode): + def __init__(self, idx: str, typex: str) -> None: + Node.__init__(self) + self.id = idx + self.type = typex + + class ExpressionNode(Node): pass diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index 4ee217dbf..2a6548438 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -48,6 +48,13 @@ def __init__(self, params, return_type, body, node): self.body = body +class ParamNode(DeclarationNode): + def __init__(self, node, idx: str, typex) -> None: + super().__init__(node) + self.id = idx + self.type = typex + + class ExpressionNode(Node): pass diff --git a/src/parsing/parser.py b/src/parsing/parser.py index 2ee5fb80e..e8a3b1a95 100644 --- a/src/parsing/parser.py +++ b/src/parsing/parser.py @@ -22,6 +22,7 @@ MethodDeclarationNode, MinusNode, NotNode, + ParamNode, PlusNode, ProgramNode, StarNode, @@ -118,7 +119,7 @@ def p_params_list(self, p): def p_param(self, p): """param : ID ':' TYPE""" - p[0] = VarDeclarationNode(p[1], p[3]) + p[0] = ParamNode(p[1], p[3]) p[0].set_position(p.slice[1].line, p.slice[1].col) def p_expression_list(self, p): @@ -319,7 +320,7 @@ def p_expression_int(self, p): p[0].set_position(p.slice[1].line, p.slice[1].col) def p_empty(self, p): - """empty : """ + """empty :""" p[0] = [] def p_error(self, t): diff --git a/src/parsing/parsetab.py b/src/parsing/parsetab.py index 30b6d6d16..8507e80e7 100644 --- a/src/parsing/parsetab.py +++ b/src/parsing/parsetab.py @@ -6,7 +6,7 @@ _lr_method = 'LALR' -_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'\n | ID '(' empty ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'expression : expression '@' TYPE '.' ID '(' empty ')'\n | expression '.' ID '(' empty ')'\n | ID '(' empty ')'args_list : expression ',' args_list\n | expressionexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty : " +_lr_signature = "rightASSIGNrightNOTnonassocLESSEQ<=left+-left*/rightISVOIDleft~left@left.ASSIGN CASE CLASS ELSE ESAC FALSE FI ID IF IN INHERITS INT ISVOID LESSEQ LET LOOP NEW NOT OF ONELINECOMMENT POOL RET STRING THEN TRUE TYPE WHILEprogram : class_listclass_list : class ';' class_list\n | class ';'class : CLASS TYPE INHERITS TYPE '{' feature_list '}'\n | CLASS TYPE '{' feature_list '}'feature_list : attribute ';' feature_list\n | method ';' feature_list\n | emptyattribute : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEmethod : ID '(' params_list ')' ':' TYPE '{' expression '}'\n | ID '(' empty ')' ':' TYPE '{' expression '}'params_list : param ',' params_list\n | paramparam : ID ':' TYPEexpression_list : expression ';' expression_list\n | expression ';'expression : ID ASSIGN expressionexpression : IF expression THEN expression ELSE expression FIexpression : WHILE expression LOOP expression POOLexpression : '{' expression_list '}'expression : LET let_list IN expressionlet_list : let_single ',' let_list\n | let_singlelet_single : ID ':' TYPE ASSIGN expression\n | ID ':' TYPEexpression : CASE expression OF case_list ESACcase_list : case_single case_list\n | case_singlecase_single : ID ':' TYPE RET expression ';'expression : expression '@' TYPE '.' ID '(' args_list ')'\n | expression '.' ID '(' args_list ')'\n | ID '(' args_list ')'expression : expression '@' TYPE '.' ID '(' empty ')'\n | expression '.' ID '(' empty ')'\n | ID '(' empty ')'args_list : expression ',' args_list\n | expressionexpression : NEW TYPEexpression : ISVOID expressionexpression : NOT expressionexpression : '~' expressionexpression : expression '+' expressionexpression : expression '-' expressionexpression : expression '/' expressionexpression : expression '*' expressionexpression : expression '<' expressionexpression : expression LESSEQ expressionexpression : expression '=' expressionexpression : '(' expression ')'expression : STRINGexpression : IDexpression : TRUEexpression : FALSEexpression : INTempty :" _lr_action_items = {'CLASS':([0,5,],[4,4,]),'$end':([1,2,5,7,],[0,-1,-3,-2,]),';':([3,12,13,17,25,30,36,37,48,49,50,51,70,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,132,133,135,136,142,144,145,146,],[5,18,19,-5,-10,-4,-52,-9,-51,-53,-54,-55,98,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-11,-12,-32,-35,-19,-31,-34,147,]),'TYPE':([4,8,20,32,44,53,54,58,101,131,],[6,10,25,52,76,80,81,86,116,139,]),'INHERITS':([6,],[8,]),'{':([6,10,31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,80,81,95,96,98,99,104,105,108,110,126,128,134,143,],[9,16,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,104,105,40,40,40,40,40,40,40,40,40,40,40,40,]),'ID':([9,16,18,19,21,31,35,38,39,40,41,42,43,45,46,47,56,57,59,60,61,62,63,64,65,66,95,96,98,99,100,102,104,105,108,109,110,118,126,128,134,143,147,],[15,15,15,15,26,36,26,36,36,36,73,36,36,36,36,36,36,36,87,36,36,36,36,36,36,36,36,36,36,36,73,119,36,36,36,123,36,119,36,36,36,36,-30,]),'}':([9,11,14,16,18,19,22,23,24,36,48,49,50,51,69,76,77,78,79,82,88,89,90,91,92,93,94,97,98,103,106,107,113,114,120,121,127,129,135,136,142,144,145,],[-56,17,-8,-56,-56,-56,30,-6,-7,-52,-51,-53,-54,-55,97,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-17,-50,-33,-36,-16,-22,132,133,-20,-27,-32,-35,-19,-31,-34,]),':':([15,26,33,34,73,119,],[20,32,53,54,101,131,]),'(':([15,31,36,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,87,95,96,98,99,104,105,108,110,123,126,128,134,143,],[21,43,57,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,110,43,43,43,43,43,43,43,43,134,43,43,43,43,]),')':([21,27,28,29,36,48,49,50,51,52,55,57,75,76,77,78,79,82,83,84,85,88,89,90,91,92,93,94,97,103,106,107,110,114,122,124,125,127,129,134,135,136,140,141,142,144,145,],[-56,33,34,-14,-52,-51,-53,-54,-55,-15,-13,-56,103,-39,-40,-41,-42,-18,106,107,-38,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-56,-22,-37,135,136,-20,-27,-56,-32,-35,144,145,-19,-31,-34,]),'ASSIGN':([25,36,116,],[31,56,128,]),',':([29,36,48,49,50,51,52,72,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,114,116,127,129,135,136,138,142,144,145,],[35,-52,-51,-53,-54,-55,-15,100,-39,-40,-41,-42,-18,108,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'IF':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,]),'WHILE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,]),'LET':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,]),'CASE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,]),'NEW':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,]),'ISVOID':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,]),'NOT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,]),'~':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,]),'STRING':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,]),'TRUE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,]),'FALSE':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,]),'INT':([31,38,39,40,42,43,45,46,47,56,57,60,61,62,63,64,65,66,95,96,98,99,104,105,108,110,126,128,134,143,],[51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,]),'@':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,58,-51,-53,-54,-55,58,58,58,58,58,-39,58,58,58,58,58,58,58,58,58,58,58,58,-21,-50,-33,-36,58,58,58,58,58,-20,-27,-32,-35,58,58,-19,-31,-34,58,]),'.':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,86,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,59,-51,-53,-54,-55,59,59,59,59,59,-39,59,59,59,59,59,109,59,59,59,59,59,59,59,-21,-50,-33,-36,59,59,59,59,59,-20,-27,-32,-35,59,59,-19,-31,-34,59,]),'+':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,60,-51,-53,-54,-55,60,60,60,60,60,-39,-40,60,-42,60,60,-43,-44,-45,-46,60,60,60,-21,-50,-33,-36,60,60,60,60,60,-20,-27,-32,-35,60,60,-19,-31,-34,60,]),'-':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,61,-51,-53,-54,-55,61,61,61,61,61,-39,-40,61,-42,61,61,-43,-44,-45,-46,61,61,61,-21,-50,-33,-36,61,61,61,61,61,-20,-27,-32,-35,61,61,-19,-31,-34,61,]),'/':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,62,-51,-53,-54,-55,62,62,62,62,62,-39,-40,62,-42,62,62,62,62,-45,-46,62,62,62,-21,-50,-33,-36,62,62,62,62,62,-20,-27,-32,-35,62,62,-19,-31,-34,62,]),'*':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,63,-51,-53,-54,-55,63,63,63,63,63,-39,-40,63,-42,63,63,63,63,-45,-46,63,63,63,-21,-50,-33,-36,63,63,63,63,63,-20,-27,-32,-35,63,63,-19,-31,-34,63,]),'<':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,64,-51,-53,-54,-55,64,64,64,64,64,-39,-40,64,-42,64,64,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,64,64,64,64,64,-20,-27,-32,-35,64,64,-19,-31,-34,64,]),'LESSEQ':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,65,-51,-53,-54,-55,65,65,65,65,65,-39,-40,65,-42,65,65,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,65,65,65,65,65,-20,-27,-32,-35,65,65,-19,-31,-34,65,]),'=':([36,37,48,49,50,51,67,68,70,74,75,76,77,78,79,82,85,88,89,90,91,92,93,94,97,103,106,107,111,112,114,120,121,127,129,135,136,137,138,142,144,145,146,],[-52,66,-51,-53,-54,-55,66,66,66,66,66,-39,-40,66,-42,66,66,-43,-44,-45,-46,None,None,None,-21,-50,-33,-36,66,66,66,66,66,-20,-27,-32,-35,66,66,-19,-31,-34,66,]),'THEN':([36,48,49,50,51,67,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,95,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'LOOP':([36,48,49,50,51,68,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,96,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'OF':([36,48,49,50,51,74,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,102,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,-19,-31,-34,]),'ELSE':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,111,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,126,-22,-20,-27,-32,-35,-19,-31,-34,]),'POOL':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,112,114,127,129,135,136,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,127,-22,-20,-27,-32,-35,-19,-31,-34,]),'FI':([36,48,49,50,51,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,127,129,135,136,137,142,144,145,],[-52,-51,-53,-54,-55,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-20,-27,-32,-35,142,-19,-31,-34,]),'IN':([36,48,49,50,51,71,72,76,77,78,79,82,88,89,90,91,92,93,94,97,103,106,107,114,115,116,127,129,135,136,138,142,144,145,],[-52,-51,-53,-54,-55,99,-24,-39,-40,-41,-42,-18,-43,-44,-45,-46,-47,-48,-49,-21,-50,-33,-36,-22,-23,-26,-20,-27,-32,-35,-25,-19,-31,-34,]),'ESAC':([117,118,130,147,],[129,-29,-28,-30,]),'RET':([139,],[143,]),} @@ -27,60 +27,60 @@ del _lr_goto_items _lr_productions = [ ("S' -> program","S'",1,None,None,None), - ('program -> class_list','program',1,'p_program','parser.py',61), - ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',65), - ('class_list -> class ;','class_list',2,'p_class_list','parser.py',66), - ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',73), - ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',74), - ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',83), - ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',84), - ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',85), - ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',92), - ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',93), - ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',102), - ('method -> ID ( empty ) : TYPE { expression }','method',9,'p_method','parser.py',103), - ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',108), - ('params_list -> param','params_list',1,'p_params_list','parser.py',109), - ('param -> ID : TYPE','param',3,'p_param','parser.py',120), - ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',125), - ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',126), - ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',133), - ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',138), - ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',143), - ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',148), - ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',153), - ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',158), - ('let_list -> let_single','let_list',1,'p_let_list','parser.py',159), - ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',166), - ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',167), - ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',175), - ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',180), - ('case_list -> case_single','case_list',1,'p_case_list','parser.py',181), - ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',188), - ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',193), - ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',194), - ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',195), - ('expression -> expression @ TYPE . ID ( empty )','expression',8,'p_expression_dispatch_empty','parser.py',209), - ('expression -> expression . ID ( empty )','expression',6,'p_expression_dispatch_empty','parser.py',210), - ('expression -> ID ( empty )','expression',4,'p_expression_dispatch_empty','parser.py',211), - ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',225), - ('args_list -> expression','args_list',1,'p_args_list','parser.py',226), - ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',237), - ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',242), - ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',247), - ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',252), - ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',257), - ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',262), - ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',267), - ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',272), - ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',277), - ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',282), - ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',287), - ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',292), - ('expression -> STRING','expression',1,'p_expression_string','parser.py',297), - ('expression -> ID','expression',1,'p_expression_variable','parser.py',302), - ('expression -> TRUE','expression',1,'p_expression_true','parser.py',307), - ('expression -> FALSE','expression',1,'p_expression_false','parser.py',312), - ('expression -> INT','expression',1,'p_expression_int','parser.py',317), - ('empty -> ','empty',0,'p_empty','parser.py',322), + ('program -> class_list','program',1,'p_program','parser.py',62), + ('class_list -> class ; class_list','class_list',3,'p_class_list','parser.py',66), + ('class_list -> class ;','class_list',2,'p_class_list','parser.py',67), + ('class -> CLASS TYPE INHERITS TYPE { feature_list }','class',7,'p_class','parser.py',74), + ('class -> CLASS TYPE { feature_list }','class',5,'p_class','parser.py',75), + ('feature_list -> attribute ; feature_list','feature_list',3,'p_feature_list','parser.py',84), + ('feature_list -> method ; feature_list','feature_list',3,'p_feature_list','parser.py',85), + ('feature_list -> empty','feature_list',1,'p_feature_list','parser.py',86), + ('attribute -> ID : TYPE ASSIGN expression','attribute',5,'p_attribute','parser.py',93), + ('attribute -> ID : TYPE','attribute',3,'p_attribute','parser.py',94), + ('method -> ID ( params_list ) : TYPE { expression }','method',9,'p_method','parser.py',103), + ('method -> ID ( empty ) : TYPE { expression }','method',9,'p_method','parser.py',104), + ('params_list -> param , params_list','params_list',3,'p_params_list','parser.py',109), + ('params_list -> param','params_list',1,'p_params_list','parser.py',110), + ('param -> ID : TYPE','param',3,'p_param','parser.py',121), + ('expression_list -> expression ; expression_list','expression_list',3,'p_expression_list','parser.py',126), + ('expression_list -> expression ;','expression_list',2,'p_expression_list','parser.py',127), + ('expression -> ID ASSIGN expression','expression',3,'p_expression_assigment','parser.py',134), + ('expression -> IF expression THEN expression ELSE expression FI','expression',7,'p_expression_if_then_else','parser.py',139), + ('expression -> WHILE expression LOOP expression POOL','expression',5,'p_expression_while','parser.py',144), + ('expression -> { expression_list }','expression',3,'p_expression_block','parser.py',149), + ('expression -> LET let_list IN expression','expression',4,'p_expression_let_in','parser.py',154), + ('let_list -> let_single , let_list','let_list',3,'p_let_list','parser.py',159), + ('let_list -> let_single','let_list',1,'p_let_list','parser.py',160), + ('let_single -> ID : TYPE ASSIGN expression','let_single',5,'p_let_single','parser.py',167), + ('let_single -> ID : TYPE','let_single',3,'p_let_single','parser.py',168), + ('expression -> CASE expression OF case_list ESAC','expression',5,'p_expression_case','parser.py',176), + ('case_list -> case_single case_list','case_list',2,'p_case_list','parser.py',181), + ('case_list -> case_single','case_list',1,'p_case_list','parser.py',182), + ('case_single -> ID : TYPE RET expression ;','case_single',6,'p_case_single','parser.py',189), + ('expression -> expression @ TYPE . ID ( args_list )','expression',8,'p_expression_dispatch','parser.py',194), + ('expression -> expression . ID ( args_list )','expression',6,'p_expression_dispatch','parser.py',195), + ('expression -> ID ( args_list )','expression',4,'p_expression_dispatch','parser.py',196), + ('expression -> expression @ TYPE . ID ( empty )','expression',8,'p_expression_dispatch_empty','parser.py',210), + ('expression -> expression . ID ( empty )','expression',6,'p_expression_dispatch_empty','parser.py',211), + ('expression -> ID ( empty )','expression',4,'p_expression_dispatch_empty','parser.py',212), + ('args_list -> expression , args_list','args_list',3,'p_args_list','parser.py',226), + ('args_list -> expression','args_list',1,'p_args_list','parser.py',227), + ('expression -> NEW TYPE','expression',2,'p_expression_instatiate','parser.py',238), + ('expression -> ISVOID expression','expression',2,'p_expression_isvoid','parser.py',243), + ('expression -> NOT expression','expression',2,'p_expression_not','parser.py',248), + ('expression -> ~ expression','expression',2,'p_expression_complement','parser.py',253), + ('expression -> expression + expression','expression',3,'p_expression_plus','parser.py',258), + ('expression -> expression - expression','expression',3,'p_expression_minus','parser.py',263), + ('expression -> expression / expression','expression',3,'p_expression_div','parser.py',268), + ('expression -> expression * expression','expression',3,'p_expression_star','parser.py',273), + ('expression -> expression < expression','expression',3,'p_expression_less','parser.py',278), + ('expression -> expression LESSEQ expression','expression',3,'p_expression_lesseq','parser.py',283), + ('expression -> expression = expression','expression',3,'p_expression_equals','parser.py',288), + ('expression -> ( expression )','expression',3,'p_expression_parentheses','parser.py',293), + ('expression -> STRING','expression',1,'p_expression_string','parser.py',298), + ('expression -> ID','expression',1,'p_expression_variable','parser.py',303), + ('expression -> TRUE','expression',1,'p_expression_true','parser.py',308), + ('expression -> FALSE','expression',1,'p_expression_false','parser.py',313), + ('expression -> INT','expression',1,'p_expression_int','parser.py',318), + ('empty -> ','empty',0,'p_empty','parser.py',323), ] diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 81030c2fc..c60361a4c 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -6,6 +6,7 @@ from semantics.tools import Context, Scope, TypeBag, join, join_list, unify from utils import visitor from asts.inferencer_ast import ( + ParamNode, ProgramNode, ClassDeclarationNode, MethodDeclarationNode, @@ -37,7 +38,7 @@ class BackInferencer: def __init__(self, context: Context) -> None: self.context = context self.errors = [] - self.current_type = None + self.current_type: Type self.changed = False @visitor.on("node") @@ -94,11 +95,14 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: current_method: Method = self.current_type.get_method(node.id) new_params = [] - for param in node.params: - new_params.append(self.visit(param, scope)) + for idx, typex, param in zip( + current_method.param_names, current_method.param_types, node.params + ): + scope.define_variable(idx, typex) + new_params.append(ParamNode(param, idx, typex)) param_types = [ - unify(typex, new_param.inferenced_type) + unify(typex, new_param.type) for new_param, typex in zip(new_params, current_method.param_types) ] current_method.param_types = [i[0] for i in param_types] diff --git a/src/semantics/inference/hard_inferencer.py b/src/semantics/inference/hard_inferencer.py index d116ae54c..0c1147ec3 100644 --- a/src/semantics/inference/hard_inferencer.py +++ b/src/semantics/inference/hard_inferencer.py @@ -25,6 +25,7 @@ MinusNode, Node, NotNode, + ParamNode, PlusNode, ProgramNode, StarNode, @@ -114,12 +115,11 @@ def visit(self, node, scopex: Scope): scope: Scope = scopex.next_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) - new_params = [] - for param in node.params: - new_params.append(self.visit(param, scope)) + for idx, typex, param in zip( + current_method.param_names, current_method.param_types, node.params + ): + new_params.append(ParamNode(param, idx, typex)) body_node = self.visit(node.body, scope) body_type = body_node.inferenced_type diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 965862f32..01dab5f9c 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -119,17 +119,16 @@ def visit(self, node, scope): return attr_node @visitor.when(MethodDeclarationNode) - def visit(self, node, scopex: Scope): + def visit(self, node: MethodDeclarationNode, scopex: Scope): 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) - new_params = [] - for param in node.params: - continue - new_params.append(self.visit(param, scope)) + for idx, typex, param in zip( + current_method.param_names, current_method.param_types, node.params + ): + scope.define_variable(idx, typex) + new_params.append(inf_ast.ParamNode(param, idx, typex)) ret_type_decl: TypeBag = current_method.return_type diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index f4e6fe35d..e4a65b55e 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -17,6 +17,7 @@ LessOrEqualNode, MinusNode, NotNode, + ParamNode, PlusNode, ProgramNode, ClassDeclarationNode, @@ -85,11 +86,11 @@ def visit( ) -> types_ast.MethodDeclarationNode: scope = scope.create_child() + params = [] for param in node.params: - param_type = self._reduce_to_type(param.inferenced_type, node, general=True) + param_type = self._reduce_to_type(param.type, node, general=True) scope.define_variable(param.id, param_type) - - params = [self.visit(param, scope) for param in node.params] + params.append(types_ast.ParamNode(param, param.id, param_type)) body = self.visit(node.body, scope) From 96b3e63b0eda1afa9bf69dbf13b17397c1380c66 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 07:54:30 -0500 Subject: [PATCH 204/432] Minor changes --- src/asts/ccil_ast.py | 6 +- src/asts/ccil_ast_old.py | 217 +++++++++++++++++++++++++++++++++++ src/code_gen/ccil_gen.py | 3 +- src/code_gen/ccil_gen_old.py | 152 ++++++++++++++++++++++++ 4 files changed, 375 insertions(+), 3 deletions(-) create mode 100644 src/asts/ccil_ast_old.py create mode 100644 src/code_gen/ccil_gen_old.py diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 6a9de6199..02fb6943b 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -45,7 +45,7 @@ def __init__(self, node) -> None: class LocalNode(OperationNode): - def __init__(self, node, idx: str, typex: Type) -> None: + def __init__(self, node, idx: str, typex: str) -> None: """ Node represent initalization instruction" Parameter: @@ -53,12 +53,14 @@ def __init__(self, node, idx: str, typex: Type) -> None: type <- node type """ super().__init__(node) + assert isinstance(typex, str), "Typex is not string" + self.id: str = idx self.type: str = typex.name class ParamNode(LocalNode): - def __init__(self, node, idx: str, typex: Type) -> None: + def __init__(self, node, idx: str, typex: str) -> None: """ Node represent function parameter initalization instruction" Parameter: diff --git a/src/asts/ccil_ast_old.py b/src/asts/ccil_ast_old.py new file mode 100644 index 000000000..4af46661a --- /dev/null +++ b/src/asts/ccil_ast_old.py @@ -0,0 +1,217 @@ +from typing import List, Tuple + +from code_gen.tools import LocalVar + + +class Node: + def __init__(self, node) -> None: + self.line: int = node.line + self.col: int = node.col + self.type = None + + def get_position(self) -> Tuple[int, int]: + return self.line, self.col + + +class ExpressionNode(Node): + def __init__(self, node, locals: List[LocalVar] = None) -> None: + """ + Parameters: + node <- Node to set this node positon in the original cool program. + locals <- List of local variables needed to be initialized to execute expression. + value <- Name of the local variable where the expresion final value is going to be stored. + """ + super().__init__(node) + if locals is None: + locals = [] + + self.locals = locals + + @property + def value(self): + return self.locals[-1] + + +class FuncCallNode(Node): + def __init__(self, node, idx: str, arg_list: List) -> None: + super().__init__(node) + self.id = idx + self.arg_list = arg_list + + +class VirtualFuncCallNode(FuncCallNode): + def __init__(self, node, idx: str, class_idx: str, arg_list: List) -> None: + super().__init__(node, idx, arg_list) + self.class_idx = class_idx + + +class ReturnOpNode(Node): + def __init__(self, node) -> None: + super().__init__(node) + + +class FlowControlNode(Node): + def __init__(self, node, target) -> None: + super().__init__(node) + + self.target = target + + +class ConditionalFlowControlNode(FlowControlNode): + def __init__(self, node, target, value) -> None: + super().__init__(node, target) + + self.value = value + + +class AtomicNode(ExpressionNode): + pass + + +class StringNode(AtomicNode): + pass + + +class IntNode(AtomicNode): + pass + + +class VariableNode(ExpressionNode): + pass + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, expr: ExpressionNode, node, locals: List = None) -> None: + super().__init__(node, locals=locals) + self.expression = expr + + +class GoToNode(FlowControlNode): + pass + + +class LabelNode(FlowControlNode): + pass + + +class IfGoToNode(ConditionalFlowControlNode): + pass + + +class IfFalseGoToNode(ConditionalFlowControlNode): + pass + + +class LetNode(ExpressionNode): + pass + + +class LoopNode(ExpressionNode): + pass + + +class CaseOptionNode(ExpressionNode): + pass + + +class CaseNode(ExpressionNode): + def __init__( + self, + case_expr: ExpressionNode, + options: List[CaseOptionNode], + node, + locals: List = None, + ) -> None: + super().__init__(node, locals=locals) + self.case_expr = case_expr + self.options = options + + +class ConditionalNode(ExpressionNode): + def __init__( + self, + condition: ExpressionNode, + then_node: ExpressionNode, + else_node: ExpressionNode, + node, + locals: List = None, + ) -> None: + super().__init__(node, locals=locals) + self.condition = condition + self.then_node = then_node + self.else_node = else_node + + +class BlocksNode(ExpressionNode): + def __init__( + self, + expression_list: List[ExpressionNode], + node, + locals: List = None, + ) -> None: + super().__init__(node, locals=locals) + self.expression_list = expression_list + + +class LetVarDeclarationNode(ExpressionNode): + def __init__(self, expression: ExpressionNode, node, locals=None): + super().__init__(node, locals=locals) + self.id = node.id + self.type = node.type + self.expression = expression + + +class DeclarationNode(Node): + pass + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, expression: ExpressionNode | None, node) -> None: + super().__init__(node) + self.id = node.id + self.type = node.type + self.expression = expression + self.value = expression.value if expression is not None else None + + +class MethodDeclarationNode(DeclarationNode): + def __init__( + self, + idx: str, + params: List[VarDeclarationNode], + body: ExpressionNode, + node, + ) -> None: + super().__init__(node) + self.idx: str = idx + self.params: List[VarDeclarationNode] = params + self.body: ExpressionNode = body + self.value = body.value + + +class ClassDeclarationNode(Node): + def __init__( + self, + attributes: List[AttrDeclarationNode], + methods: List[MethodDeclarationNode], + feature_info: List, + node, + ) -> None: + super().__init__(node) + self.idx: str = node.id + self.parent: str = node.parent + self.attributes: List[AttrDeclarationNode] = attributes + self.methods: List[MethodDeclarationNode] = methods + self.feature_info: List = feature_info + + +class ProgramNode(Node): + def __init__( + self, + types: List[ClassDeclarationNode], + data: List[str], + node, + ) -> None: + super().__init__(node) + self.types = types + self.data = data diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a960fe93a..e9d04b9fc 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -150,9 +150,10 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: pre_fvalue_id = f"if_{times}_pre_fv" then_fval.id = else_fval.id = pre_fvalue_id fvalue_id = f"if_{times}_fv" + fvalue_local = LocalNode(node, fvalue_id, node.type.id) fvalue = create_assignation(node, fvalue_id, pre_fvalue_id) - return ([*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) + return ([fvalue_local, *if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) @visitor.when(sem_ast.CaseNode) def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: diff --git a/src/code_gen/ccil_gen_old.py b/src/code_gen/ccil_gen_old.py new file mode 100644 index 000000000..a807e23ff --- /dev/null +++ b/src/code_gen/ccil_gen_old.py @@ -0,0 +1,152 @@ +from typing import Dict, List +from code_gen.constants import ATTR_NAME +from utils import visitor +from asts.types_ast import ( + CaseNode, + CaseOptionNode, + ConditionalNode, + IntNode, + LetNode, + LoopNode, + ProgramNode, + ClassDeclarationNode, + AttrDeclarationNode, + MethodDeclarationNode, + BlocksNode, + StringNode, + VarDeclarationNode, + VariableNode, +) +from code_gen.tools import Feature, make_id +import asts.ccil_ast as ccil + + +class CCILGenerator: + def __init__(self) -> None: + self.warnings: List[str] = [] + self.constant_data: List[str] = [] + self.count: Dict[str, int] = {"while": 0, "if": 0, "case": 0, "function": 0} + + self.class_name: str + self.attr_count: int + self.func_count: int + self.feature_name: str + self.local_var_count: int + + @visitor.on("node") + def visit(self, _): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode) -> ccil.ProgramNode: + class_decl: List[ccil.ClassDeclarationNode] = [] + for declaration in node.declarations: + self.set_class_params(declaration.id) + class_decl.append(self.visit(declaration)) + + return ccil.ProgramNode(class_decl, self.constant_data, node) + + @visitor.when(ClassDeclarationNode) + def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: + class_attr: List[ccil.AttrDeclarationNode] = [] + class_func: List[ccil.MethodDeclarationNode] = [] + class_feat: List[Feature] = [] + + # Sort by putting attributes first, delete if this is the case already + node.features.sort(key=lambda x: isinstance(x, AttrDeclarationNode)) + for feature in node.features: + self.set_feature_params(feature.id) + if isinstance(feature, AttrDeclarationNode): + class_attr.append(self.visit(feature)) + class_feat.append(Feature(feature.id, "ccil_name", True)) + else: + class_func.append(self.visit(feature)) + class_feat.append(Feature(feature.id, "ccil_name", False)) + + return ccil.ClassDeclarationNode(class_attr, class_func, class_feat, node) + + @visitor.when(AttrDeclarationNode) + def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: + ccil_node_name = make_id( + ATTR_NAME, + ) + ccil_node: ccil.AttrDeclarationNode = ccil.AttrDeclarationNode( + node.id, node.type, None + ) + if node.expr is not None: + ccil_node.expression = self.visit(node.expr) + return ccil_node + + @visitor.when(MethodDeclarationNode) + def visit(self, node: MethodDeclarationNode) -> ccil.MethodDeclarationNode: + + for param in node.params: + pass + + body: ccil.ExpressionNode = self.visit(node.body) + return MethodDeclarationNode() + + @visitor.when(BlocksNode) + def visit(self, node: BlocksNode) -> ccil.BlocksNode: + expr_list: List[ccil.ExpressionNode] = [ + self.visit(expr) for expr in node.expr_list + ] + return ccil.BlocksNode(expr_list, node) + + @visitor.when(ConditionalNode) + def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: + condition: ccil.ExpressionNode = self.visit(node.condition) + then_body: ccil.ExpressionNode = self.visit(node.then_body) + else_body: ccil.ExpressionNode = self.visit(node.else_body) + + value = self.generate_var_name() + return ccil.ConditionalNode(condition, then_body, else_body, [value]) + + @visitor.when(CaseNode) + def visit(self, node: CaseNode) -> ccil.CaseNode: + locals = [] + expressions = [] + + @visitor.when(CaseOptionNode) + def visit(self, node: CaseOptionNode) -> ccil.CaseOptionNode: + pass + + @visitor.when(LoopNode) + def visit(self, node: LoopNode) -> ccil.LoopNode: + pass + + @visitor.when(LetNode) + def visit(self, node: LetNode) -> ccil.LetNode: + new_decl_list: List[VarDeclarationNode] = [] + for let_decl_node in node.var_decl_list: + new_decl_list.append(self.visit(let_decl_node)) + node_expr: ccil.ExpressionNode = self.visit(node.in_expr) + + @visitor.when(VarDeclarationNode) + def visit(self, node: VarDeclarationNode) -> ccil.VarDeclarationNode: + value = self.generate_var_name() + if node.expr is not None: + ccil_node_expr: ccil.ExpressionNode = self.visit(node.expr) + return ccil.VarDeclarationNode(ccil_node_expr, node, value, [value]) + return ccil.VarDeclarationNode(None, node, value, [value]) + + @visitor.when(VariableNode) + def visit(self, node: VariableNode) -> ccil.VariableNode: + return ccil.VariableNode(node, value=node.id) + + @visitor.when(StringNode) + def visit(self, node: StringNode) -> ccil.StringNode: + pass + + @visitor.when(IntNode) + def visit(self, node: IntNode) -> ccil.IntNode: + return ccil.IntNode(node, value="") + + def set_class_params(self, name: str): + self.class_name = name + self.attr_count = 0 + self.func_count = 0 + + def set_feature_params(self, name: str): + self.feature_name = name + self.local_var_count = 0 From 66e4ea446fe4a17d68d5e606eef62af69e9a2ce3 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 07:55:54 -0500 Subject: [PATCH 205/432] Delete old ccil ast and visitor --- src/asts/ccil_ast_old.py | 217 ----------------------------------- src/code_gen/ccil_gen_old.py | 152 ------------------------ 2 files changed, 369 deletions(-) delete mode 100644 src/asts/ccil_ast_old.py delete mode 100644 src/code_gen/ccil_gen_old.py diff --git a/src/asts/ccil_ast_old.py b/src/asts/ccil_ast_old.py deleted file mode 100644 index 4af46661a..000000000 --- a/src/asts/ccil_ast_old.py +++ /dev/null @@ -1,217 +0,0 @@ -from typing import List, Tuple - -from code_gen.tools import LocalVar - - -class Node: - def __init__(self, node) -> None: - self.line: int = node.line - self.col: int = node.col - self.type = None - - def get_position(self) -> Tuple[int, int]: - return self.line, self.col - - -class ExpressionNode(Node): - def __init__(self, node, locals: List[LocalVar] = None) -> None: - """ - Parameters: - node <- Node to set this node positon in the original cool program. - locals <- List of local variables needed to be initialized to execute expression. - value <- Name of the local variable where the expresion final value is going to be stored. - """ - super().__init__(node) - if locals is None: - locals = [] - - self.locals = locals - - @property - def value(self): - return self.locals[-1] - - -class FuncCallNode(Node): - def __init__(self, node, idx: str, arg_list: List) -> None: - super().__init__(node) - self.id = idx - self.arg_list = arg_list - - -class VirtualFuncCallNode(FuncCallNode): - def __init__(self, node, idx: str, class_idx: str, arg_list: List) -> None: - super().__init__(node, idx, arg_list) - self.class_idx = class_idx - - -class ReturnOpNode(Node): - def __init__(self, node) -> None: - super().__init__(node) - - -class FlowControlNode(Node): - def __init__(self, node, target) -> None: - super().__init__(node) - - self.target = target - - -class ConditionalFlowControlNode(FlowControlNode): - def __init__(self, node, target, value) -> None: - super().__init__(node, target) - - self.value = value - - -class AtomicNode(ExpressionNode): - pass - - -class StringNode(AtomicNode): - pass - - -class IntNode(AtomicNode): - pass - - -class VariableNode(ExpressionNode): - pass - - -class VarDeclarationNode(ExpressionNode): - def __init__(self, expr: ExpressionNode, node, locals: List = None) -> None: - super().__init__(node, locals=locals) - self.expression = expr - - -class GoToNode(FlowControlNode): - pass - - -class LabelNode(FlowControlNode): - pass - - -class IfGoToNode(ConditionalFlowControlNode): - pass - - -class IfFalseGoToNode(ConditionalFlowControlNode): - pass - - -class LetNode(ExpressionNode): - pass - - -class LoopNode(ExpressionNode): - pass - - -class CaseOptionNode(ExpressionNode): - pass - - -class CaseNode(ExpressionNode): - def __init__( - self, - case_expr: ExpressionNode, - options: List[CaseOptionNode], - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.case_expr = case_expr - self.options = options - - -class ConditionalNode(ExpressionNode): - def __init__( - self, - condition: ExpressionNode, - then_node: ExpressionNode, - else_node: ExpressionNode, - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.condition = condition - self.then_node = then_node - self.else_node = else_node - - -class BlocksNode(ExpressionNode): - def __init__( - self, - expression_list: List[ExpressionNode], - node, - locals: List = None, - ) -> None: - super().__init__(node, locals=locals) - self.expression_list = expression_list - - -class LetVarDeclarationNode(ExpressionNode): - def __init__(self, expression: ExpressionNode, node, locals=None): - super().__init__(node, locals=locals) - self.id = node.id - self.type = node.type - self.expression = expression - - -class DeclarationNode(Node): - pass - - -class AttrDeclarationNode(DeclarationNode): - def __init__(self, expression: ExpressionNode | None, node) -> None: - super().__init__(node) - self.id = node.id - self.type = node.type - self.expression = expression - self.value = expression.value if expression is not None else None - - -class MethodDeclarationNode(DeclarationNode): - def __init__( - self, - idx: str, - params: List[VarDeclarationNode], - body: ExpressionNode, - node, - ) -> None: - super().__init__(node) - self.idx: str = idx - self.params: List[VarDeclarationNode] = params - self.body: ExpressionNode = body - self.value = body.value - - -class ClassDeclarationNode(Node): - def __init__( - self, - attributes: List[AttrDeclarationNode], - methods: List[MethodDeclarationNode], - feature_info: List, - node, - ) -> None: - super().__init__(node) - self.idx: str = node.id - self.parent: str = node.parent - self.attributes: List[AttrDeclarationNode] = attributes - self.methods: List[MethodDeclarationNode] = methods - self.feature_info: List = feature_info - - -class ProgramNode(Node): - def __init__( - self, - types: List[ClassDeclarationNode], - data: List[str], - node, - ) -> None: - super().__init__(node) - self.types = types - self.data = data diff --git a/src/code_gen/ccil_gen_old.py b/src/code_gen/ccil_gen_old.py deleted file mode 100644 index a807e23ff..000000000 --- a/src/code_gen/ccil_gen_old.py +++ /dev/null @@ -1,152 +0,0 @@ -from typing import Dict, List -from code_gen.constants import ATTR_NAME -from utils import visitor -from asts.types_ast import ( - CaseNode, - CaseOptionNode, - ConditionalNode, - IntNode, - LetNode, - LoopNode, - ProgramNode, - ClassDeclarationNode, - AttrDeclarationNode, - MethodDeclarationNode, - BlocksNode, - StringNode, - VarDeclarationNode, - VariableNode, -) -from code_gen.tools import Feature, make_id -import asts.ccil_ast as ccil - - -class CCILGenerator: - def __init__(self) -> None: - self.warnings: List[str] = [] - self.constant_data: List[str] = [] - self.count: Dict[str, int] = {"while": 0, "if": 0, "case": 0, "function": 0} - - self.class_name: str - self.attr_count: int - self.func_count: int - self.feature_name: str - self.local_var_count: int - - @visitor.on("node") - def visit(self, _): - pass - - @visitor.when(ProgramNode) - def visit(self, node: ProgramNode) -> ccil.ProgramNode: - class_decl: List[ccil.ClassDeclarationNode] = [] - for declaration in node.declarations: - self.set_class_params(declaration.id) - class_decl.append(self.visit(declaration)) - - return ccil.ProgramNode(class_decl, self.constant_data, node) - - @visitor.when(ClassDeclarationNode) - def visit(self, node: ClassDeclarationNode) -> ccil.ClassDeclarationNode: - class_attr: List[ccil.AttrDeclarationNode] = [] - class_func: List[ccil.MethodDeclarationNode] = [] - class_feat: List[Feature] = [] - - # Sort by putting attributes first, delete if this is the case already - node.features.sort(key=lambda x: isinstance(x, AttrDeclarationNode)) - for feature in node.features: - self.set_feature_params(feature.id) - if isinstance(feature, AttrDeclarationNode): - class_attr.append(self.visit(feature)) - class_feat.append(Feature(feature.id, "ccil_name", True)) - else: - class_func.append(self.visit(feature)) - class_feat.append(Feature(feature.id, "ccil_name", False)) - - return ccil.ClassDeclarationNode(class_attr, class_func, class_feat, node) - - @visitor.when(AttrDeclarationNode) - def visit(self, node: AttrDeclarationNode) -> ccil.AttrDeclarationNode: - ccil_node_name = make_id( - ATTR_NAME, - ) - ccil_node: ccil.AttrDeclarationNode = ccil.AttrDeclarationNode( - node.id, node.type, None - ) - if node.expr is not None: - ccil_node.expression = self.visit(node.expr) - return ccil_node - - @visitor.when(MethodDeclarationNode) - def visit(self, node: MethodDeclarationNode) -> ccil.MethodDeclarationNode: - - for param in node.params: - pass - - body: ccil.ExpressionNode = self.visit(node.body) - return MethodDeclarationNode() - - @visitor.when(BlocksNode) - def visit(self, node: BlocksNode) -> ccil.BlocksNode: - expr_list: List[ccil.ExpressionNode] = [ - self.visit(expr) for expr in node.expr_list - ] - return ccil.BlocksNode(expr_list, node) - - @visitor.when(ConditionalNode) - def visit(self, node: ConditionalNode) -> ccil.ConditionalNode: - condition: ccil.ExpressionNode = self.visit(node.condition) - then_body: ccil.ExpressionNode = self.visit(node.then_body) - else_body: ccil.ExpressionNode = self.visit(node.else_body) - - value = self.generate_var_name() - return ccil.ConditionalNode(condition, then_body, else_body, [value]) - - @visitor.when(CaseNode) - def visit(self, node: CaseNode) -> ccil.CaseNode: - locals = [] - expressions = [] - - @visitor.when(CaseOptionNode) - def visit(self, node: CaseOptionNode) -> ccil.CaseOptionNode: - pass - - @visitor.when(LoopNode) - def visit(self, node: LoopNode) -> ccil.LoopNode: - pass - - @visitor.when(LetNode) - def visit(self, node: LetNode) -> ccil.LetNode: - new_decl_list: List[VarDeclarationNode] = [] - for let_decl_node in node.var_decl_list: - new_decl_list.append(self.visit(let_decl_node)) - node_expr: ccil.ExpressionNode = self.visit(node.in_expr) - - @visitor.when(VarDeclarationNode) - def visit(self, node: VarDeclarationNode) -> ccil.VarDeclarationNode: - value = self.generate_var_name() - if node.expr is not None: - ccil_node_expr: ccil.ExpressionNode = self.visit(node.expr) - return ccil.VarDeclarationNode(ccil_node_expr, node, value, [value]) - return ccil.VarDeclarationNode(None, node, value, [value]) - - @visitor.when(VariableNode) - def visit(self, node: VariableNode) -> ccil.VariableNode: - return ccil.VariableNode(node, value=node.id) - - @visitor.when(StringNode) - def visit(self, node: StringNode) -> ccil.StringNode: - pass - - @visitor.when(IntNode) - def visit(self, node: IntNode) -> ccil.IntNode: - return ccil.IntNode(node, value="") - - def set_class_params(self, name: str): - self.class_name = name - self.attr_count = 0 - self.func_count = 0 - - def set_feature_params(self, name: str): - self.feature_name = name - self.local_var_count = 0 From e3df58dbc94cbae390b132e139cd611f60d5a1cb Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Mon, 21 Feb 2022 18:35:17 -0500 Subject: [PATCH 206/432] Restructure ccil AST --- src/asts/ccil_ast.py | 54 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 6a9de6199..010075845 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -14,25 +14,71 @@ def get_position(self) -> Tuple[int, int]: return (self.line, self.col) +class CCILProgram: + """Top level class that represents a CCIL program""" + + def __init__( + self, + types_section: List[ClassNode], + code_section: List[FunctionNode], + data_section, # no idea what will be this the node, + ) -> None: + self.types_section = types_section # class/types declaration with methods ( method signature is optional ) and attributes + self.code_section = code_section # functions + self.data_section = data_section # static data like strings or literal numbers + + class ClassNode(Node): + """ + This node represents the .types section in CCIL + """ + def __init__( self, node, + idx: str, attributes: List[Attribute], - methods: List[Method], - init_operations: List[OperationNode], + methods: List[MethodNode], + init_operations: FunctionNode, ) -> None: super().__init__(node) + self.id = idx self.attributes = attributes self.methods = methods self.init_operations = init_operations class MethodNode(Node): - def __init__(self, node, idx: str, operations: List[OperationNode]) -> None: + """ + This node represents a method of a class + """ + + def __init__( + self, node, idx: str, function: str, operations: List[OperationNode] + ) -> None: super().__init__(node) - self.id = idx + self.id = idx # name of method + self.function = function # function that implement this method + + +class FunctionNode(Node): + """ + This class represents funtions in the .code section. This functions are the real implementetion of every class method + """ + + def __init__( + self, + node, + idx: str, + params: List[ParamNode], + operations: List[OperationNode], + ret, + ) -> None: + super().__init__(node) + self.id = idx # identifier for the function ( not the same as the methods it represents ) + self.params = params self.operations = operations + self.ret = ret # not sure if useful yet class OperationNode(Node): From c49077b4539a3add0e2494be51111f388e6451ab Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 22 Feb 2022 08:55:02 -0500 Subject: [PATCH 207/432] Add basic MIPS AST --- src/asts/mips_ast.py | 186 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/asts/mips_ast.py diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py new file mode 100644 index 000000000..1ab7f24f4 --- /dev/null +++ b/src/asts/mips_ast.py @@ -0,0 +1,186 @@ +from __future__ import annotations +from typing import Dict, List, Tuple + + +class Node: + def __init__(self, node) -> None: + if node is not None: + self.line: int = node.line + self.col: int = node.col + + def get_position(self) -> Tuple[int, int]: + return (self.line, self.col) + + +class MIPSProgram(Node): + """ + This node represents the entire MIPS program ( .text and .data sections ) + """ + + def __init__(self, node, text_section: List[InstructionNode], data_section) -> None: + super().__init__(node) + self.text_section = text_section + self.data_section = data_section + + +class TextNode(Node): + """ + This node represents the `.text` section in MIPS + """ + + def __init__(self, node, instructions: List[InstructionNode]) -> None: + super().__init__(node) + if instructions is None: + self.instructions = [] + self.instructions = instructions + + +class DataNode(Node): + """ + This node represents the `.data` section in MIPS + """ + + def __init__( + self, node, data: List[Tuple[LabelDeclaration, AssemblerDirective]] + ) -> None: + super().__init__(node) + if data is None: + self.data = [] + self.data = data + + +class RegisterNode(Node): + """ + This class represents a 4-bytes MIPS' register + """ + + def __init__(self, node, number) -> None: + super().__init__(node) + self.number = number + + +class Label(Node): + """ + This class represents a label declaration in MIPS + """ + + def __init__(self, node, idx) -> None: + super().__init__(node) + self.idx = idx + + +class InstructionNode(Node): + def __init__(self, node) -> None: + super().__init__(node) + + +class LabelDeclaration(InstructionNode): + """ + This class represents a label declaration in MIPS + """ + + def __init__(self, node, idx) -> None: + super().__init__(node) + self.idx = idx + + +class MemoryIndexNode(Node): + """ + This node represents a memory-indexation of the form `
()` + """ + + def __init__(self, node, address, index) -> None: + super().__init__(node) + self.address = address + self.index = index + + +class BinaryOpNode(InstructionNode): + def __init__(self, node, left, right) -> None: + super().__init__(node) + self.left = left + self.right = right + + +class TernaryOpNode(InstructionNode): + def __init__(self, node, left, middle, right) -> None: + super().__init__(node) + self.left = left + self.middle = middle + self.right = right + + +class Move(BinaryOpNode): + """ + This node represents `move` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + +class LoadWord(BinaryOpNode): + """ + This node represents `lw` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + +class StoreWord(BinaryOpNode): + """ + This node represents `sw` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + +class Jump(Node): + """ + This node represents `j` instruction in MIPS + """ + + def __init__(self, node, address) -> None: + super().__init__(node) + self.address = address + + +class JumpRegister(Node): + """ + This node represents `jr` instruction in MIPS + """ + + def __init__(self, node, register) -> None: + super().__init__(node) + self.register = register + + +class JumpAndLink(Node): + """ + This node represents `jal` instruction in MIPS + """ + + def __init__(self, node, address) -> None: + super().__init__(node) + self.address = address + + +class AssemblerDirective(Node): + def __init__(self, node, list) -> None: + super().__init__(node) + if list is None: + list = [] + self.list = list + + +class WordDirective(AssemblerDirective): + """ + This node represents `.word` assembler directive + """ + + def __init__(self, node, list) -> None: + super().__init__(node, list) + + From f0fa97da8c0749b8f384671d88193a77207c7d0c Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 22 Feb 2022 08:55:39 -0500 Subject: [PATCH 208/432] Add mips_gen.py --- src/code_gen/mips_gen.py | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/code_gen/mips_gen.py diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py new file mode 100644 index 000000000..052868a28 --- /dev/null +++ b/src/code_gen/mips_gen.py @@ -0,0 +1,64 @@ +from asts.mips_ast import ( + Label, + LabelDeclaration, + MIPSProgram, + MemoryIndexNode, + Move, + RegisterNode, + TextNode, + DataNode, + WordDirective, +) +from utils import visitor + + +class MIPSGenerator: + """ + This class uses the visitor pattern to convert MIPS AST to a .mips program + """ + + def __init__(self) -> None: + pass + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(MIPSProgram) + def visit(self, node: MIPSProgram) -> str: + global_main = "\t.globl main" + text_section = "\t.text\n" + self.visit(node.text_section) + data_section = "\t.data\n" + self.visit(node.data_section) + return f"{global_main}\n{text_section}\n{data_section}" + + @visitor.when(TextNode) + def visit(self, node: TextNode) -> str: + return "\n".join(self.visit(instruction) for instruction in node.instructions) + + @visitor.when(DataNode) + def visit(self, node: DataNode) -> str: + return "\n".join(self.visit(instruction) for instruction in node.instructions) + + @visitor.when(RegisterNode) + def visit(self, node: RegisterNode) -> str: + return f"${node.number}" + + @visitor.when(LabelDeclaration) + def visit(self, node: LabelDeclaration) -> str: + return f"{node.idx}:" + + @visitor.when(Label) + def visit(self, node: Label) -> str: + return str(node.idx) + + @visitor.when(MemoryIndexNode) + def visit(self, node: MemoryIndexNode) -> str: + return f"{self.visit(node.address)}({self.visit(node.index)})" + + @visitor.when(WordDirective) + def visit(self, node: WordDirective) -> str: + return ".word " + " ".join(self.visit(i) for i in node.list) + + @visitor.when(Move) + def visit(self, node: Move) -> str: + return f"\tmove {self.visit(node.left)}, {self.visit(node.right)}" From 4184f74848f3e8593ecfc8c8b22d1d440fd8a847 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 22 Feb 2022 08:57:04 -0500 Subject: [PATCH 209/432] Add ccil_mips_gen.py --- src/code_gen/ccil_mips_gen.py | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/code_gen/ccil_mips_gen.py diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py new file mode 100644 index 000000000..7d13c52ff --- /dev/null +++ b/src/code_gen/ccil_mips_gen.py @@ -0,0 +1,79 @@ +from typing import Union +import itertools +from asts.mips_ast import ( + DataNode, + InstructionNode, + JumpAndLink, + LabelDeclaration, + MIPSProgram, + MemoryIndexNode, + RegisterNode, + TextNode, + WordDirective, +) +from utils import visitor +from asts.ccil_ast import * + + +class CCILToMIPSGenerator: + def __init__(self) -> None: + self.types_table: List[ClassNode] + self.location: Dict[str, Union[MemoryIndexNode, RegisterNode]] + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(CCILProgram) + def visit(self, node: CCILProgram): + self.types_table = node.types_section + types_table = [self.visit(typex) for typex in node.types_section] + + # TODO: other .data section static data inicializations like strings + functions = list( + itertools.chain([self.visit(func) for func in node.code_section]) + ) + return MIPSProgram(None, TextNode(node, functions), DataNode(node, types_table)) + + @visitor.when(ClassNode) + def visit(self, node: ClassNode): + return ( + LabelDeclaration(node, node.id), + WordDirective(node, [method.function for method in node.methods]), + ) + + @visit.when(FunctionNode) + def visit(self, node: FunctionNode): + label = LabelDeclaration(node, node.id) + self.location = {} + body: List[InstructionNode] = [] + + reg_number = 4 + for param in node.params[:4]: + register = RegisterNode(node, reg_number) + self.location[param] = register + reg_number += 1 + # TODO: params via stack (more than 4 parameters) + + body += [self.visit(op) for op in node.operations] + return [label, *body] + + @visit.when(CallOpNode) + def visit(self, node: CallOpNode): + return JumpAndLink(node, node.id) + + def get_method_index(self, typex: str, method: str) -> int: + for _type in self.types_table: + if _type.id == typex: + for index, _method in enumerate(_type.methods): + if _method.id == method: + return index + return -1 + + def get_class_method(self, typex: str, method: str) -> str: + for _type in self.types_table: + if _type.id == typex: + for index, _method in enumerate(_type.methods): + if _method.id == method: + return _method.function + return "" From 37e24caa23faf7bb289a252c8fefa672497af902 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 22 Feb 2022 09:05:45 -0500 Subject: [PATCH 210/432] Raise exceptions in utils function of CCILToMIPSGenerator when implementation not found --- src/code_gen/ccil_mips_gen.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 7d13c52ff..790954d40 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -62,13 +62,19 @@ def visit(self, node: FunctionNode): def visit(self, node: CallOpNode): return JumpAndLink(node, node.id) + def get_init_function(self, typex: str): + for _type in self.types_table: + if _type.id == typex: + return _type.init_operations + raise Exception("Method inicialization not found") + def get_method_index(self, typex: str, method: str) -> int: for _type in self.types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: return index - return -1 + raise Exception("Method implementetion not found") def get_class_method(self, typex: str, method: str) -> str: for _type in self.types_table: @@ -76,4 +82,4 @@ def get_class_method(self, typex: str, method: str) -> str: for index, _method in enumerate(_type.methods): if _method.id == method: return _method.function - return "" + raise Exception("Method implementetion not found") From 0a9f88b643e6b9186ef9727d1ba87788aee68549 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 22 Feb 2022 09:05:45 -0500 Subject: [PATCH 211/432] Raise exceptions in utils function of CCILToMIPSGenerator when implementation not found --- src/code_gen/ccil_mips_gen.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 7d13c52ff..790954d40 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -62,13 +62,19 @@ def visit(self, node: FunctionNode): def visit(self, node: CallOpNode): return JumpAndLink(node, node.id) + def get_init_function(self, typex: str): + for _type in self.types_table: + if _type.id == typex: + return _type.init_operations + raise Exception("Method inicialization not found") + def get_method_index(self, typex: str, method: str) -> int: for _type in self.types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: return index - return -1 + raise Exception("Method implementetion not found") def get_class_method(self, typex: str, method: str) -> str: for _type in self.types_table: @@ -76,4 +82,4 @@ def get_class_method(self, typex: str, method: str) -> str: for index, _method in enumerate(_type.methods): if _method.id == method: return _method.function - return "" + raise Exception("Method implementetion not found") From 2725cb4ce33a995e3b68e676477db96abcc7ad17 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 10:33:51 -0500 Subject: [PATCH 212/432] Refactor ccil ast, improve readibility and add new functionalities --- src/asts/ccil_ast.py | 145 +++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 82 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index ba4eb6dd1..b90d38e5d 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -1,84 +1,96 @@ -from typing import Dict, List, Tuple from __future__ import annotations -from code_gen.tools import Attribute, Method +from dataclasses import dataclass +from typing import Dict, List, Tuple +from code_gen.tools import Attribute, Method from semantics.tools.type import Type -class Node: - def __init__(self, node) -> None: - self.line: int = node.line - self.col: int = node.col +@dataclass(frozen=True) +class CCILProgram: + """Top level class that represents a CCIL program""" - def get_position(self) -> Tuple[int, int]: - return (self.line, self.col) + types_section: List[Class] + code_section: List[FunctionNode] + data_section: List[str] # no idea what will be this the node, -class CCILProgram: - """Top level class that represents a CCIL program""" +@dataclass(frozen=True) +class Class: + """ + This item represent the .type section in ccil + """ - def __init__( - self, - types_section: List[ClassNode], - code_section: List[FunctionNode], - data_section, # no idea what will be this the node, - ) -> None: - self.types_section = types_section # class/types declaration with methods ( method signature is optional ) and attributes - self.code_section = code_section # functions - self.data_section = data_section # static data like strings or literal numbers + id: str + attributes: List[Attribute] + methods: List[Method] + init_operations: FunctionNode -class ClassNode(Node): +@dataclass(frozen=True) +class BaseVar: """ - This node represents the .types section in CCIL + This item represents the pair common in attributes, parameters and local vars """ - def __init__( - self, - node, - idx: str, - attributes: List[Attribute], - methods: List[MethodNode], - init_operations: FunctionNode, - ) -> None: - super().__init__(node) - self.id = idx - self.attributes = attributes - self.methods = methods - self.init_operations = init_operations + id: str + type: str + + +class Attribute(BaseVar): + pass + + +class Parameter(BaseVar): + pass -class MethodNode(Node): +class Local(BaseVar): + pass + + +@dataclass(frozen=True) +class Method: """ - This node represents a method of a class + This item represent the method of every class """ - def __init__( - self, node, idx: str, function: str, operations: List[OperationNode] - ) -> None: - super().__init__(node) - self.id = idx # name of method - self.function = function # function that implement this method + id: str + function: FunctionNode + + +class Node: + def __init__(self, node) -> None: + self.line: int = node.line + self.col: int = node.col + + def get_position(self) -> Tuple[int, int]: + return (self.line, self.col) class FunctionNode(Node): """ - This class represents funtions in the .code section. This functions are the real implementetion of every class method + This class represents funtions in the .code section. Most of a Cool program is split along this nodes. """ def __init__( self, node, idx: str, - params: List[ParamNode], + params: List[Parameter], + locals: List[Local], operations: List[OperationNode], - ret, + ret: str, ) -> None: super().__init__(node) - self.id = idx # identifier for the function ( not the same as the methods it represents ) + # Function identifier, different than Method identifier + self.id = idx + # Variable that holds the return value + self.ret = ret + # Function operations self.params = params + self.locals = locals self.operations = operations - self.ret = ret # not sure if useful yet class OperationNode(Node): @@ -90,38 +102,6 @@ def __init__(self, node) -> None: super().__init__(node) -class LocalNode(OperationNode): - def __init__(self, node, idx: str, typex: str) -> None: - """ - Node represent initalization instruction" - Parameter: - idx <- node name - type <- node type - """ - super().__init__(node) - assert isinstance(typex, str), "Typex is not string" - - self.id: str = idx - self.type: str = typex.name - - -class ParamNode(LocalNode): - def __init__(self, node, idx: str, typex: str) -> None: - """ - Node represent function parameter initalization instruction" - Parameter: - idx <- node name - type <- node type - """ - super().__init__(node, idx, typex) - - -class ArgNode(OperationNode): - def __init__(self, node, idx: str) -> None: - super().__init__(node) - self.id = idx - - class StorageNode(OperationNode): def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: """ @@ -143,14 +123,15 @@ def __init__(self, node) -> None: class CallOpNode(ReturnOpNode): - def __init__(self, node, idx: str) -> None: + def __init__(self, node, idx: str, args: List[str]) -> None: super().__init__(node) self.id = idx + self.args = args class VCallOpNode(ReturnOpNode): - def __init__(self, node, idx: str, type_idx: str) -> None: - super().__init__(node, idx) + def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: + super().__init__(node, idx, args) self.type = type_idx From bc674eee050b244387bdeda7d0c33a610c9a4bc5 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 11:03:47 -0500 Subject: [PATCH 213/432] Rewrite ccil class declaration translation --- src/code_gen/ccil_gen.py | 61 +++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index e9d04b9fc..4b2c48ed4 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,14 +1,14 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List +from typing import Tuple, List, Dict from code_gen.tools import * # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] -CLASS_VISITOR_RESULT = Tuple[ClassNode, List[MethodNode]] -METHOD_VISITOR_RESULT = MethodNode +CLASS_VISITOR_RESULT = Tuple[Class, List[FunctionNode]] +METHOD_VISITOR_RESULT = FunctionNode USER = "user" ATTR = "attr" @@ -20,8 +20,8 @@ class CCILGenerator: """ def __init__(self) -> None: - self.types: List[Class] = list() self.time_record: Dict[str, int] = dict() + self.locals: Dict[str, str] @visitor.on("node") def visit(self, _): @@ -29,8 +29,8 @@ def visit(self, _): @visitor.when(sem_ast.ProgramNode) def visit(self, node: sem_ast.ProgramNode) -> None: - program_types: List[ClassNode] = list() - program_codes: List[MethodNode] = list() + program_types: List[Class] = list() + program_codes: List[Method] = list() for type in node.declarations: classx, class_code = self.visit(type) program_types.append(classx) @@ -38,24 +38,39 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: + # Class Properties attributes: List[Attribute] = list() methods: List[Method] = list() - - class_code: List[MethodNode] = list() init_attr_ops: List[OperationNode] = list() + # Code in this class + class_code: List[FunctionNode] = list() + + attr_nodes = [] + func_nodes = [] for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): - attributes.append(Attribute(ATTR + feature.id, feature.type.name)) - (attr_ops, _) = self.visit(feature) - init_attr_ops += attr_ops + attr_nodes.append(feature) else: - methods.append(feature.id) - method_node = self.visit(feature) - class_code.append(method_node) + func_nodes.append(feature) + + # Explore all attributes and join their operations in an initializer function + self.locals = dict() + operations = [] + for attr in attr_nodes: + attributes.append(Attribute(ATTR + attr.id, attr.type.name)) + (attr_ops, attr_fval) = self.visit(attr) + operations += attr_ops + # Return type is set as itself? Use selftype maybe? + init_func = FunctionNode(node, f"init_{node.id}", [], self.locals, operations, node.id) + + # Explore all methods + for func in func_nodes: + ccil_func = self.visit(func) + methods.append(Method("some id", ccil_func)) return ( - ClassNode(attributes, methods, init_attr_ops), + Class(attributes, methods, init_func), class_code, ) @@ -81,7 +96,8 @@ def visit(self, node: sem_ast.MethodDeclarationNode): (expr_op, _) = self.visit(node.body) operations += expr_op - return MethodNode(node, node.id, operations) + func_node = FunctionNode() + return MethodNode(node, node.id, expr_op) @visitor.when(sem_ast.BlocksNode) def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: @@ -150,10 +166,12 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: pre_fvalue_id = f"if_{times}_pre_fv" then_fval.id = else_fval.id = pre_fvalue_id fvalue_id = f"if_{times}_fv" - fvalue_local = LocalNode(node, fvalue_id, node.type.id) fvalue = create_assignation(node, fvalue_id, pre_fvalue_id) - return ([fvalue_local, *if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue) + return ( + [fvalue_local, *if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], + fvalue, + ) @visitor.when(sem_ast.CaseNode) def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: @@ -332,19 +350,22 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # Translate all call arguments to ccil # Name all fvalues as ARG args_ops: List[OperationNode] = [] - args: List[ArgNode] = [] + args: List[StorageNode] = [] for arg_expr in node.args: (arg_op, arg_fval) = self.visit(arg_expr) args_ops += arg_op - args += [ArgNode(arg_expr, arg_fval.id)] + args += [arg_fval] + # id(arg1, arg2, ..., argn) if node.expr is None: fval_id = f"call_{times}" call = create_call(node, fval_id, node.id) return [*args_ops, *args, call], call + # .id(arg1, arg2, ..., argn) (expr_ops, expr_fval) = self.visit(node.expr) + # @type.id(arg1, arg2, ..., argn) type_idx: str = ( node.expr.type.name if node.at_type is None else node.at_type.name ) From f383e674dae66b2d7200248b50c1b011aa0aa760 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 11:17:00 -0500 Subject: [PATCH 214/432] Rewrite methods and attribute declaration transaltion to ccil, plus some minor bug fixing --- src/code_gen/ccil_gen.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 4b2c48ed4..43efa2c30 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict +from typing import Set, Tuple, List, Dict from code_gen.tools import * @@ -21,7 +21,7 @@ class CCILGenerator: def __init__(self) -> None: self.time_record: Dict[str, int] = dict() - self.locals: Dict[str, str] + self.locals: Set[Local] @visitor.on("node") def visit(self, _): @@ -55,14 +55,16 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: func_nodes.append(feature) # Explore all attributes and join their operations in an initializer function - self.locals = dict() + self.locals = set() operations = [] for attr in attr_nodes: attributes.append(Attribute(ATTR + attr.id, attr.type.name)) (attr_ops, attr_fval) = self.visit(attr) operations += attr_ops # Return type is set as itself? Use selftype maybe? - init_func = FunctionNode(node, f"init_{node.id}", [], self.locals, operations, node.id) + init_func = FunctionNode( + node, f"init_{node.id}", [], [*self.locals], operations, node.id + ) # Explore all methods for func in func_nodes: @@ -77,27 +79,25 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: fval_id = ATTR + node.id + self.locals.add(Local(fval_id, node.type.name)) if node.expr is None: - op = LocalNode(node, fval_id, node.type.name) - return [op], op + return [] (expr_op, expr_fval) = self.visit(node.expr) expr_fval.id = fval_id - return (expr_op, expr_fval) @visitor.when(sem_ast.MethodDeclarationNode) - def visit(self, node: sem_ast.MethodDeclarationNode): - operations: List[OperationNode] = [] + def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: + params: List[Parameter] = [] for param in node.params: - operations.append(ParamNode(param.id, param.type.name)) + params.append(Parameter(param.id, param.type.name)) - (expr_op, _) = self.visit(node.body) + self.locals = set() + (operations, fval_id) = self.visit(node.body) - operations += expr_op - func_node = FunctionNode() - return MethodNode(node, node.id, expr_op) + return FunctionNode(node, node.id, params, [*self.locals], operations, fval_id) @visitor.when(sem_ast.BlocksNode) def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: From e863078b96c14db74ae1df4650f8297c64ba7bcc Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 18:37:54 -0500 Subject: [PATCH 215/432] Mayor changes Remove Param, Local, and Arg instructions. They are now kept track by parent nodes accordingly. Move helper function from ast module to visitor Minor bug fixing --- src/code_gen/ccil_gen.py | 124 ++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 27 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 43efa2c30..e6e70af06 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -13,6 +13,9 @@ USER = "user" ATTR = "attr" +BOOL = "Bool" +VOID = "Void" + # CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: """ @@ -21,7 +24,7 @@ class CCILGenerator: def __init__(self) -> None: self.time_record: Dict[str, int] = dict() - self.locals: Set[Local] + self.locals: Dict[str, str] @visitor.on("node") def visit(self, _): @@ -55,7 +58,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: func_nodes.append(feature) # Explore all attributes and join their operations in an initializer function - self.locals = set() + self.locals = dict() operations = [] for attr in attr_nodes: attributes.append(Attribute(ATTR + attr.id, attr.type.name)) @@ -63,7 +66,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: operations += attr_ops # Return type is set as itself? Use selftype maybe? init_func = FunctionNode( - node, f"init_{node.id}", [], [*self.locals], operations, node.id + node, f"init_{node.id}", [], [*self.locals.items()], operations, node.id ) # Explore all methods @@ -79,7 +82,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: fval_id = ATTR + node.id - self.locals.add(Local(fval_id, node.type.name)) + self.locals[fval_id] = node.type.name if node.expr is None: return [] @@ -94,10 +97,12 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: for param in node.params: params.append(Parameter(param.id, param.type.name)) - self.locals = set() + self.locals = dict() (operations, fval_id) = self.visit(node.body) - return FunctionNode(node, node.id, params, [*self.locals], operations, fval_id) + return FunctionNode( + node, node.id, params, [*self.locals.items()], operations, fval_id + ) @visitor.when(sem_ast.BlocksNode) def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: @@ -110,8 +115,11 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: operations += expr_ops fvalues += expr_fval - fval = fvalues[-1] - fval.id = f"block_{times}" + block_val = fvalues[-1] + fval_id = f"block_{times}" + + fval = self.create_assignation(node, fval_id, node.type.name, block_val.id) + operations.append(fval) return (operations, fval) @@ -135,9 +143,12 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: fvalue_id: str = USER + node.id if node.expr is None: - return ([], create_uninitialized_storage(node, fvalue_id)) + self.add_local(fvalue_id, node.type.name) + self.locals[fvalue_id] = node.type.name (expr_ops, expr_fv) = self.visit(node.expr) + + self.update_locals(expr_fv.id, fvalue_id) expr_fv.id = fvalue_id return (expr_ops, expr_fv) @@ -145,7 +156,10 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: @visitor.when(sem_ast.AssignNode) def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: (expr_ops, expr_fval) = self.visit(node.expr) - expr_fval.id = USER + node.id + + fval_id = USER + node.id + self.update_locals(expr_fval.id, fval_id) + expr_fval.id = fval_id return (expr_ops, expr_fval) @@ -164,12 +178,15 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: # Setting the final operation which will simbolize the return value of this expr pre_fvalue_id = f"if_{times}_pre_fv" + self.update_locals(then_fval.id, pre_fvalue_id) + self.update_locals(else_fval.id, pre_fvalue_id) then_fval.id = else_fval.id = pre_fvalue_id + fvalue_id = f"if_{times}_fv" - fvalue = create_assignation(node, fvalue_id, pre_fvalue_id) + fvalue = self.create_assignation(node, fvalue_id, node.type.name, pre_fvalue_id) return ( - [fvalue_local, *if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], + [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], fvalue, ) @@ -181,8 +198,8 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) # Storing the type of the resulting case expression - type_of = create_type_of( - node, f"case_{times}_typeOf", extract_id(node, case_expr_fv) + type_of = self.create_type_of( + node, f"case_{times}_typeOf", "not set", extract_id(node, case_expr_fv) ) # Final label where all branch must jump to @@ -211,9 +228,10 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Initializng var which holds the comparison result between # the case expression type of and branch var type of select_branch_id = f"case_{times}_optionSelect_{i}" - select_branch = create_equality( + select_branch = self.create_equality( option, select_branch_id, + BOOL, extract_id(node, type_of), extract_id(node, branch_var_type_of), ) @@ -224,24 +242,20 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Conditional jump to the right branch label if_op = IfNode(option, extract_id(option, branch_var_type_of), branch_label) + # Storing logic to jump to branch logic if this branch is selected pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] # Visiting the branch logic (expr_ops, expr_fval) = self.visit(option.expr) - # Renaming the last stored value of the expression accordingly expr_fval.id = pre_fvalue_id - - # Storing logic to jump to branch logic if this branch is selected - pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] - # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] # Merging all expression operations in correct order - # and saving to expression final value + # and saving all to final value fval_id = f"case_{times}_fv" - fval = create_assignation(node, fval_id, pre_fvalue_id) + fval = self.create_assignation(node, fval_id, node.type.name, pre_fvalue_id) operations = [ *case_expr_ops, type_of, @@ -269,7 +283,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) - fval = (create_uninitialized_storage(node, f"loop_{times}_fv"),) + fval = self.create_uninitialized_storage(node, f"loop_{times}_fv") # Loop Nodes have void return type, how to express it?? return ( [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], @@ -315,7 +329,7 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure visiting binary expression") - fval = StorageNode(node, fval_id, op) + fval = self.create_storage(node, fval_id, node.type.id, op) return ([*left_ops, *right_ops, fval], fval) @visitor.when(sem_ast.UnaryNode) @@ -340,7 +354,7 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure while visiting unary expression") - fval = StorageNode(node, fval_id, op) + fval = self.create_storage(node, fval_id, node.type.id, op) return [*expr_op, fval], fval @visitor.when(sem_ast.MethodCallNode) @@ -359,7 +373,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # id(arg1, arg2, ..., argn) if node.expr is None: fval_id = f"call_{times}" - call = create_call(node, fval_id, node.id) + call = self.create_call(node, fval_id, node.type.id, node.id ) return [*args_ops, *args, call], call # .id(arg1, arg2, ..., argn) @@ -371,7 +385,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ) fval_id = f"fvcall_{times}" - call = create_vcall(node, fval_id, node.id, type_idx) + call = self.create_vcall(node, fval_id, node.type.id, node.id, type_idx) return [*args_ops, *expr_ops, *args, call] @@ -382,3 +396,59 @@ def times(self, node): except KeyError: self.time_record[key] = 0 return self.time_record[key] + + def create_call(self, node, storage_idx: str, type_idx: str, method_idx: str): + self.add_local(storage_idx, type_idx) + return StorageNode(node, storage_idx, CallOpNode(node, method_idx)) + + def create_vcall( + self, + node, + storage_idx: str, + type_idx: str, + method_idx: str, + method_type_idx: str, + ): + self.add_local(storage_idx, type_idx) + return StorageNode( + node, storage_idx, VCallOpNode(node, method_idx, method_type_idx) + ) + + def create_assignation(self, node, idx: str, type_idx: str, target: str): + self.add_local(idx, type_idx) + return StorageNode(node, idx, IdNode(node, target)) + + def create_uninitialized_storage( + self, + node, + idx: str + ): + self.add_local(idx, VOID) + return StorageNode(node, idx, VoidNode(node)) + + def create_storage(self, node, idx:str, type_idx:str, op:ReturnOpNode): + self.add_local(idx, type_idx) + return StorageNode(node, idx, op) + + + def create_type_of(self, node, idx: str, type_idx: str, target: AtomOpNode): + self.add_local(idx, type_idx) + return StorageNode(node, idx, GetTypeOpNode(node, target)) + + def create_equality( + self, node, idx, type_idx: str, left: AtomOpNode, right: AtomOpNode + ): + self.add_local(idx, type_idx) + return StorageNode(node, idx, EqualOpNode(node, left, right)) + + def extract_id(self, node, storage_node: StorageNode) -> IdNode: + return IdNode(node, storage_node.id) + + def update_locals(self, old_id: str, new_id: str): + self.locals[new_id] = self.locals[old_id] + del self.locals[old_id] + + def add_local(self, idx: str, typex: str): + if idx in self.locals: + raise Exception(f"Trying to insert {idx} again as local") + self.locals[idx] = typex From bd9b8bd16333aedf17f8315531f4549309d184e5 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 19:22:03 -0500 Subject: [PATCH 216/432] Delete old methods. They are now in ccil_gen.py --- src/asts/ccil_ast.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index b90d38e5d..de4abbc5e 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -259,30 +259,5 @@ def __init__(self, node, idx: str) -> None: super().__init__(node) self.id = idx - -def create_call(node, storage_idx: str, method_idx: str): - return StorageNode(node, storage_idx, CallOpNode(node, method_idx)) - - -def create_vcall(node, storage_idx: str, method_idx: str, type_idx: str): - return StorageNode(node, storage_idx, VCallOpNode(node, method_idx, type_idx)) - - -def create_assignation(node, idx: str, target: str): - return StorageNode(node, idx, IdNode(node, target)) - - -def create_uninitialized_storage(node, idx: str): - return StorageNode(node, idx, VoidNode(node)) - - -def create_type_of(node, idx: str, target: AtomOpNode): - return StorageNode(node, idx, GetTypeOpNode(node, target)) - - -def create_equality(node, idx, left: AtomOpNode, right: AtomOpNode): - return StorageNode(node, idx, EqualOpNode(node, left, right)) - - def extract_id(node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) From 73d9a86499fb907541d6110064ddbe3e6c6ad7d9 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 19:22:26 -0500 Subject: [PATCH 217/432] Minor bug fixing and refactoring --- src/code_gen/ccil_gen.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index e6e70af06..de46f231a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -16,6 +16,17 @@ BOOL = "Bool" VOID = "Void" +# TODO: +# The result of type of what it is +# How to handle void nodes +# Diference between method id and function id +# Handdle all remaining operations: +# * Saving string to memory +# * Getting and setting attributes +# * IO operations +# * Handle constants and IDs + + # CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: """ @@ -216,13 +227,13 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: for (i, option) in enumerate(node.options): # Initializing the branch var branch_var_id = f"case_{times}_option_{i}" - branch_var = create_uninitialized_storage(option, branch_var_id) + branch_var = self.create_uninitialized_storage(option, branch_var_id) branch_var.decl_type = option.branch_type # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" - branch_var_type_of = create_type_of( - option, branch_var_type_id, extract_id(node, branch_var) + branch_var_type_of = self.create_type_of( + option, branch_var_type_id, option.type.id, extract_id(node, branch_var) ) # Initializng var which holds the comparison result between @@ -245,9 +256,9 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Storing logic to jump to branch logic if this branch is selected pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] - # Visiting the branch logic + # Translating the branch logic (expr_ops, expr_fval) = self.visit(option.expr) - # Renaming the last stored value of the expression accordingly + # Renaming the last stored value of the expression expr_fval.id = pre_fvalue_id # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] @@ -373,7 +384,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # id(arg1, arg2, ..., argn) if node.expr is None: fval_id = f"call_{times}" - call = self.create_call(node, fval_id, node.type.id, node.id ) + call = self.create_call(node, fval_id, node.type.id, node.id) return [*args_ops, *args, call], call # .id(arg1, arg2, ..., argn) @@ -385,7 +396,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ) fval_id = f"fvcall_{times}" - call = self.create_vcall(node, fval_id, node.type.id, node.id, type_idx) + call = self.create_vcall(node, fval_id, node.type.id, node.id, type_idx) return [*args_ops, *expr_ops, *args, call] @@ -418,19 +429,14 @@ def create_assignation(self, node, idx: str, type_idx: str, target: str): self.add_local(idx, type_idx) return StorageNode(node, idx, IdNode(node, target)) - def create_uninitialized_storage( - self, - node, - idx: str - ): + def create_uninitialized_storage(self, node, idx: str): self.add_local(idx, VOID) return StorageNode(node, idx, VoidNode(node)) - def create_storage(self, node, idx:str, type_idx:str, op:ReturnOpNode): + def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, op) - def create_type_of(self, node, idx: str, type_idx: str, target: AtomOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, GetTypeOpNode(node, target)) From 06f3bc39bdf54d6f052dece18cde6899709d8e2d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 09:37:19 -0500 Subject: [PATCH 218/432] Update CCILToMIPSGenerator --- src/code_gen/ccil_mips_gen.py | 121 ++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 34 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 149da40d1..0d33baefd 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1,70 +1,123 @@ from typing import Union -import itertools from asts.mips_ast import ( + Addu, DataNode, InstructionNode, JumpAndLink, LabelDeclaration, + LoadWord, MIPSProgram, MemoryIndexNode, RegisterNode, + StoreWord, + Subu, TextNode, WordDirective, ) from utils import visitor from asts.ccil_ast import * +Location = Dict[str, Union[MemoryIndexNode, RegisterNode]] + class CCILToMIPSGenerator: def __init__(self) -> None: - self.types_table: List[ClassNode] - self.location: Dict[str, Union[MemoryIndexNode, RegisterNode]] + self.types_table: List[Class] # list or dict for classes??? @visitor.on("node") def visit(self, node): pass @visitor.when(CCILProgram) - def visit(self, node: CCILProgram): - self.types_table = node.types_section - types_table = [self.visit(typex) for typex in node.types_section] + def visit(self, node: CCILProgram, location: Location = None): + self.types = node.types_section + + types_table = [] + for classx in node.types_section: + word_directive = [Label(node, classx.id)] + for method in classx.methods: + word_directive.append(method.function.id) + types_table.append( + LabelDeclaration(node, classx.id), WordDirective(node, word_directive) + ) # TODO: other .data section static data inicializations like strings - functions = list( - itertools.chain([self.visit(func) for func in node.code_section]) - ) - return MIPSProgram(None, TextNode(node, functions), DataNode(node, types_table)) - @visitor.when(ClassNode) - def visit(self, node: ClassNode): - return ( - LabelDeclaration(node, node.id), - WordDirective(node, [method.function for method in node.methods]), - ) + functions = [] + for func in node.code_section: + functions += self.visit(func, {}) + + return MIPSProgram(None, TextNode(node, functions), DataNode(node, types_table)) @visit.when(FunctionNode) - def visit(self, node: FunctionNode): + def visit(self, node: FunctionNode, location: Location): label = LabelDeclaration(node, node.id) - self.location = {} body: List[InstructionNode] = [] - reg_number = 4 - for param in node.params[:4]: - register = RegisterNode(node, reg_number) - self.location[param.id] = register - reg_number += 1 - # TODO: params via stack (more than 4 parameters) + frame_size = len(node.params) * 4 + 12 + stack_pointer = RegisterNode(node, 29) + return_address = RegisterNode(node, 31) + frame_pointer = RegisterNode(node, 30) + + index = 0 + for param in node.params: + location[param.id] = MemoryIndexNode(node, index, frame_pointer) + index += 4 + + body.append(Subu(node, stack_pointer, stack_pointer, frame_size)) + body.append( + StoreWord(node, return_address, MemoryIndexNode(node, stack_pointer, 20)) + ) + body.append( + StoreWord(node, frame_pointer, MemoryIndexNode(node, stack_pointer, 16)) + ) + body.append(Addu(node, frame_pointer, frame_pointer, frame_size - 4)) + + for op in node.operations: + body += self.visit(op, location) - body += [self.visit(op) for op in node.operations] return [label, *body] - @visit.when(CallOpNode) - def visit(self, node: CallOpNode): - return JumpAndLink(node, node.id) + @visitor.when(CallOpNode) + def visit(self, node: CallOpNode, location: Location): + stack_pointer = RegisterNode(node, 29) + instructions = [] + index = 4 + for arg in node.args: + arg_location = location[arg] + if isinstance(arg_location, RegisterNode): + instructions.append( + StoreWord(node, arg_location, MemoryIndexNode(index, stack_pointer)) + ) + index += 4 + instructions.append(JumpAndLink(node, node.id)) - @visit.when(VCallOpNode) - def visit(self, node: VCallOpNode) - pass + @visitor.when(VCallOpNode) + def visit(self, node: VCallOpNode, location: Location): + obj_location = location[node.args[0]] + instructions = [] + + # TODO use free register instead of 8 + obj_type = RegisterNode(node, 8) + + if isinstance(obj_location, RegisterNode): + instructions.append( + LoadWord(node, obj_type, MemoryIndexNode(node, 0, obj_location)) + ) + elif isinstance(obj_location, MemoryIndexNode): + instructions.append(LoadWord(node, obj_type, obj_location)) + + function_index = self.get_method_index(node.type, node.id) + + # TODO use free register instead of 9 + register_function = RegisterNode(node, 9) + + instructions.append( + LoadWord( + node, register_function, MemoryIndexNode(node, function_index, obj_type) + ) + ) + instructions.append(JumpAndLink(node, register_function)) def get_init_function(self, typex: str): for _type in self.types_table: @@ -78,12 +131,12 @@ def get_method_index(self, typex: str, method: str) -> int: for index, _method in enumerate(_type.methods): if _method.id == method: return index - raise Exception("Method implementetion not found") + raise Exception("Method implementation not found") def get_class_method(self, typex: str, method: str) -> str: for _type in self.types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: - return _method.function - raise Exception("Method implementetion not found") + return _method.function.id + raise Exception("Method implementation not found") From 61e786e2707a9c58fec7a2a55a34ffd5fc66eda2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 22 Feb 2022 23:20:54 -0500 Subject: [PATCH 219/432] Minor refactoring in ccil visitor --- src/code_gen/ccil_gen.py | 47 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index de46f231a..460c01874 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -52,13 +52,6 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: - # Class Properties - attributes: List[Attribute] = list() - methods: List[Method] = list() - init_attr_ops: List[OperationNode] = list() - - # Code in this class - class_code: List[FunctionNode] = list() attr_nodes = [] func_nodes = [] @@ -70,25 +63,29 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Explore all attributes and join their operations in an initializer function self.locals = dict() - operations = [] + attributes: List[Attribute] = list() + init_attr_ops: List[OperationNode] = [] for attr in attr_nodes: attributes.append(Attribute(ATTR + attr.id, attr.type.name)) - (attr_ops, attr_fval) = self.visit(attr) - operations += attr_ops + (attr_ops, _) = self.visit(attr) + init_attr_ops += attr_ops + # Return type is set as itself? Use selftype maybe? init_func = FunctionNode( - node, f"init_{node.id}", [], [*self.locals.items()], operations, node.id + node, + f"init_{node.id}", + [], + to_vars(self.locals, Parameter), + init_attr_ops, + node.id, ) - # Explore all methods - for func in func_nodes: - ccil_func = self.visit(func) - methods.append(Method("some id", ccil_func)) + # Explore all functions + class_code: List[FunctionNode] = [self.visit(x) for x in func_nodes] + # Store the functions inside the class + methods: List[Method] = [Method("some id", x) for x in class_code] - return ( - Class(attributes, methods, init_func), - class_code, - ) + return (Class(attributes, methods, init_func), class_code) @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: @@ -104,9 +101,9 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: - params: List[Parameter] = [] - for param in node.params: - params.append(Parameter(param.id, param.type.name)) + params: List[Parameter] = [ + Parameter(param.id, param.type.name) for param in node.params + ] self.locals = dict() (operations, fval_id) = self.visit(node.body) @@ -282,7 +279,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: times = self.times(node) (cond_ops, cond_fval) = self.visit(node.condition) - (body_ops, body_fval) = self.visit(node.body) + (body_ops, _) = self.visit(node.body) # Setting control flow labels loop_label_id = f"loop_{times}" @@ -458,3 +455,7 @@ def add_local(self, idx: str, typex: str): if idx in self.locals: raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex + + +def to_vars(dict: Dict[str, str], const=BaseVar): + return map(lambda x: const(*x), dict.items().mapping()) From 04d826454a5751794bdb12ae0c753a02b0901c0b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 10:00:08 -0500 Subject: [PATCH 220/432] Add and redefine Atom CCIl nodes --- src/asts/ccil_ast.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index de4abbc5e..f7d3fb36e 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -141,6 +141,12 @@ class VoidNode(ReturnOpNode): pass +class NewOpNode(ReturnOpNode): + def __init__(self, node, type_idx: str) -> None: + super().__init__(node) + self.type_idx: str = type_idx + + class BinaryOpNode(ReturnOpNode): def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: """ @@ -209,22 +215,27 @@ class NegOpNode(UnaryOpNode): class AtomOpNode(ReturnOpNode): - def __init__(self, node) -> None: + def __init__(self, node, value: str) -> None: """ AtomNode represents all single value nodes, like ids and constants """ super().__init__(node) + self.value = value class IdNode(AtomOpNode): - def __init__(self, node, idx: str) -> None: - super().__init__(node) - self.id = idx + def __init__(self, node, value: str) -> None: + super().__init__(node, value) class ConstantNode(AtomOpNode): - def __init__(self, node) -> None: - super().__init__(node) + def __init__(self, node, value: str) -> None: + super().__init__(node, value) + + +class IntNode(ConstantNode): + def __init__(self, node, value: str) -> None: + super().__init__(node, value) class FlowControlNode(OperationNode): @@ -259,5 +270,6 @@ def __init__(self, node, idx: str) -> None: super().__init__(node) self.id = idx + def extract_id(node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) From a20e1e5f5dc7049497e057298942ca37e92c6565 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 10:02:12 -0500 Subject: [PATCH 221/432] Add barebones for visiting constant values --- src/code_gen/ccil_gen.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 460c01874..023e1e889 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Set, Tuple, List, Dict +from typing import Tuple, List, Dict, Unknown from code_gen.tools import * @@ -17,7 +17,8 @@ VOID = "Void" # TODO: -# The result of type of what it is +# Define cool built in methods +# The result of (type of) what is it # How to handle void nodes # Diference between method id and function id # Handdle all remaining operations: @@ -36,6 +37,7 @@ class CCILGenerator: def __init__(self) -> None: self.time_record: Dict[str, int] = dict() self.locals: Dict[str, str] + self.data: Unknown @visitor.on("node") def visit(self, _): @@ -50,6 +52,8 @@ def visit(self, node: sem_ast.ProgramNode) -> None: program_types.append(classx) program_codes.append(class_code) + return CCILProgram(program_types, program_codes, self.data) + @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: @@ -397,6 +401,27 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: return [*args_ops, *expr_ops, *args, call] + @visitor.when(sem_ast.InstantiateNode) + def visit(self, node:sem_ast.InstantiateNode) -> VISITOR_RESULT: + times = self.times(node) + + fvalue_id = f"newType_{times}" + fvalue = self.create_new_type(node, fvalue_id, node.type.name) + + return [fvalue], fvalue + + @visitor.when(sem_ast.StringNode) + def visit(self, node:sem_ast.StringNode) -> VISITOR_RESULT: + pass + + @visitor.when(sem_ast.IntNode) + def visit(self, node:sem_ast.IntNode) -> VISITOR_RESULT: + pass + + @visitor.when(sem_ast.BooleanNode) + def visit (self, node:sem_ast.BooleanNode) -> VISITOR_RESULT: + pass + def times(self, node): key: str = type(node).__name__ try: @@ -434,6 +459,10 @@ def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, op) + def create_new_type(self, node, idx:str, type_idx:str): + self.add_local(idx, type_idx) + return StorageNode(node, idx, NewOpNode(node, type_idx)) + def create_type_of(self, node, idx: str, type_idx: str, target: AtomOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, GetTypeOpNode(node, target)) From 598bcdfdb4eac262e5f048d57d382119dbe12aa1 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 10:42:12 -0500 Subject: [PATCH 222/432] Fix and improve Call and Vcall --- src/asts/ccil_ast.py | 6 ++-- src/code_gen/ccil_gen.py | 60 +++++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index f7d3fb36e..9cc4f22d5 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -123,16 +123,16 @@ def __init__(self, node) -> None: class CallOpNode(ReturnOpNode): - def __init__(self, node, idx: str, args: List[str]) -> None: + def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: super().__init__(node) self.id = idx + self.type = type_idx self.args = args class VCallOpNode(ReturnOpNode): def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: - super().__init__(node, idx, args) - self.type = type_idx + super().__init__(node, idx, type_idx, args) class VoidNode(ReturnOpNode): diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 023e1e889..1b26cce83 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict, Unknown +from typing import Tuple, List, Dict, Unknown from code_gen.tools import * @@ -35,6 +35,7 @@ class CCILGenerator: """ def __init__(self) -> None: + self.current_type: str self.time_record: Dict[str, int] = dict() self.locals: Dict[str, str] self.data: Unknown @@ -56,6 +57,7 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: + self.current_type = node.id attr_nodes = [] func_nodes = [] @@ -384,42 +386,48 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # id(arg1, arg2, ..., argn) if node.expr is None: - fval_id = f"call_{times}" - call = self.create_call(node, fval_id, node.type.id, node.id) - return [*args_ops, *args, call], call + fval_id = f"vcall_{times}" + call = self.create_vcall( + node, fval_id, node.type.id, node.id, node.caller_type.name + ) + return [*args_ops, call], call - # .id(arg1, arg2, ..., argn) - (expr_ops, expr_fval) = self.visit(node.expr) - # @type.id(arg1, arg2, ..., argn) - type_idx: str = ( - node.expr.type.name if node.at_type is None else node.at_type.name - ) + (expr_ops, _) = self.visit(node.expr) - fval_id = f"fvcall_{times}" - call = self.create_vcall(node, fval_id, node.type.id, node.id, type_idx) + # @type.id(arg1, arg2, ..., argn) + if node.at_type is not None: + fval_id = f"call_{times}" + call = self.create_call( + node, fval_id, node.type.name, node.id, node.caller_type.name + ) + return [*args_ops, *expr_ops, call] + + # .id(arg1, arg2, ..., argn) + fval_id = f"vcall_{times}" + call = self.create_vcall(node, fval_id, node.type.id, node.id, node.caller_type) - return [*args_ops, *expr_ops, *args, call] + return [*args_ops, *expr_ops, call] @visitor.when(sem_ast.InstantiateNode) - def visit(self, node:sem_ast.InstantiateNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: times = self.times(node) fvalue_id = f"newType_{times}" - fvalue = self.create_new_type(node, fvalue_id, node.type.name) + fvalue = self.create_new_type(node, fvalue_id, node.type.name) return [fvalue], fvalue @visitor.when(sem_ast.StringNode) - def visit(self, node:sem_ast.StringNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.StringNode) -> VISITOR_RESULT: pass @visitor.when(sem_ast.IntNode) - def visit(self, node:sem_ast.IntNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: pass @visitor.when(sem_ast.BooleanNode) - def visit (self, node:sem_ast.BooleanNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: pass def times(self, node): @@ -430,9 +438,16 @@ def times(self, node): self.time_record[key] = 0 return self.time_record[key] - def create_call(self, node, storage_idx: str, type_idx: str, method_idx: str): + def create_call( + self, + node, + storage_idx: str, + type_idx: str, + method_idx: str, + args: List[StorageNode], + ): self.add_local(storage_idx, type_idx) - return StorageNode(node, storage_idx, CallOpNode(node, method_idx)) + return StorageNode(node, storage_idx, CallOpNode(node, method_idx, args)) def create_vcall( self, @@ -441,10 +456,11 @@ def create_vcall( type_idx: str, method_idx: str, method_type_idx: str, + args: List[StorageNode], ): self.add_local(storage_idx, type_idx) return StorageNode( - node, storage_idx, VCallOpNode(node, method_idx, method_type_idx) + node, storage_idx, VCallOpNode(node, method_idx, method_type_idx, args) ) def create_assignation(self, node, idx: str, type_idx: str, target: str): @@ -459,7 +475,7 @@ def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, op) - def create_new_type(self, node, idx:str, type_idx:str): + def create_new_type(self, node, idx: str, type_idx: str): self.add_local(idx, type_idx) return StorageNode(node, idx, NewOpNode(node, type_idx)) From 236eebc9eccc7d22ff3d6e5043e9d66a6eda2907 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 10:44:00 -0500 Subject: [PATCH 223/432] Remove helpers which turned out not to be so helpfuls --- src/code_gen/tools.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 0a343e12f..b347fc354 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -3,20 +3,3 @@ from asts.ccil_ast import ExpressionNode from typing import List from __future__ import annotations - - -@dataclass(frozen=True) -class Class: - attributes: List[Attribute] - methods: List[Method] - - -@dataclass(frozen=True) -class Attribute: - id: str - type: str - - -@dataclass(frozen=True) -class Method: - id: str From ff01ddb68791c740f7b3ad4d150b24482d4ce232 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 10:44:45 -0500 Subject: [PATCH 224/432] Minor change in docs --- src/docs/codegen.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 3874203a5..7683f66b0 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -41,6 +41,8 @@ $$ &|& \text{Atom / Atom}\\ &|& \text{not Atom}\\ &|& \text{neg Atom}\\ +&|& \text{typeOf id}\\ +&|& \text{allocate typeId}\\ &|& \text{Atom < Atom}\\ &|& \text{Atom <= Atom}\\ &|& \text{Atom = Atom}\\ @@ -251,11 +253,13 @@ esac x = + +# Pattern Match Logic! t = typeof x label init_case # This is not really needed t1 = typeof b1 = t1 == t # Comparing types, they must be all equal -if b1 goto branch1 +if b1 goto branch1: t2 = typeof b2 = t2 == t @@ -268,6 +272,7 @@ bn = tn == t if bn goto brannch # It is not possible to avoid pattern matching +# Branch Logic label branch1 goto end_case @@ -430,7 +435,8 @@ t1 = 3 + t1 ``` ```assembly -t1 = +t = 3 - 5 +t = t - 7 ``` ---- @@ -444,6 +450,9 @@ t1 = **CCIL Output** ``` +t = 100 / 20 +t = t / 5 +t = t / 2 ``` From 7ebefbea13d6345aa679ee97f1c3aaddb08ca9c4 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 10:51:21 -0500 Subject: [PATCH 225/432] Fix type annotations syntax --- src/semantics/tools/context.py | 4 ++-- src/semantics/tools/scope.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/semantics/tools/context.py b/src/semantics/tools/context.py index 09f196f38..b15a276de 100644 --- a/src/semantics/tools/context.py +++ b/src/semantics/tools/context.py @@ -1,6 +1,6 @@ from semantics.tools.errors import * from semantics.tools.type import TypeBag, Type, SelfType -from typing import Dict +from typing import Dict, Union class Context: @@ -20,7 +20,7 @@ def get_type( selftype=True, autotype=True, unpacked=False, - ) -> Type | TypeBag: + ) -> Union[Type, TypeBag]: if selftype and name == "SELF_TYPE": return TypeBag({SelfType()}) # raise TypeError(f"Cannot use SELF_TYPE.") if autotype and name == "AUTO_TYPE": diff --git a/src/semantics/tools/scope.py b/src/semantics/tools/scope.py index 647d2d887..f1c4ab7db 100644 --- a/src/semantics/tools/scope.py +++ b/src/semantics/tools/scope.py @@ -1,3 +1,4 @@ +from typing import Optional from semantics.tools.type import TypeBag, ErrorType import itertools as itt @@ -37,7 +38,7 @@ def define_variable(self, vname, vtype): self.locals.append(info) return info - def find_variable(self, vname, index=None) -> VariableInfo | None: + def find_variable(self, vname, index=None) -> Optional[VariableInfo]: locals = self.locals if index is None else itt.islice(self.locals, index) try: return next(x for x in locals if x.name == vname) From cb226cbb74030dcb20aedef5d5b4e06e3d3d7fe0 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 12:06:55 -0500 Subject: [PATCH 226/432] Minor changes --- src/semantics/inference/soft_inferencer.py | 4 +++- src/semantics/type_builder.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/semantics/inference/soft_inferencer.py b/src/semantics/inference/soft_inferencer.py index 01dab5f9c..cdf6494ba 100644 --- a/src/semantics/inference/soft_inferencer.py +++ b/src/semantics/inference/soft_inferencer.py @@ -72,10 +72,12 @@ def visit(self, node: ProgramNode) -> inf_ast.ProgramNode: @visitor.when(ClassDeclarationNode) def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: self.current_type = self.context.get_type(node.id, unpacked=True) - scope.define_variable("self", TypeBag({SelfType()})) + scope.define_variable("self", self.context.get_type("SELF_TYPE")) for attr in self.current_type.attributes: if attr.name != "self": + # Is not define, error is given later when visiting + # the attribute scope.define_variable(attr.name, attr.type) new_features = [] diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 03b06adc9..02eacccb7 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -124,7 +124,7 @@ def build_default_classes(self): p_Object = self.context.get_type("Object") p_String = self.context.get_type("String") p_Int = self.context.get_type("Int") - p_Self = TypeBag({SelfType()}) + p_Self = self.context.get_type("SELF_TYPE") # TypeBag({SelfType()}) Object.define_method("abort", [], [], p_Object) Object.define_method("type_name", [], [], p_String) From 7b512251b6cccbd29559a36c88e6e0694e313de8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 17:02:31 -0500 Subject: [PATCH 227/432] Add more Operation as nodes (getAttr, setAttr, load, ...) and Data class to store values from .Data section --- src/asts/ccil_ast.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 9cc4f22d5..77241a5cd 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -49,6 +49,16 @@ class Local(BaseVar): pass +@dataclass(frozen=True) +class Data: + """ + This class hold constant values + """ + + id: str + value: str + + @dataclass(frozen=True) class Method: """ @@ -117,11 +127,26 @@ def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: self.decl_type = node.decl_type +class SetAttrOpNode(OperationNode): + def __init__(self, node, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: + super().__init__(node) + self.type = type_id + self.attr = attr_id + self.source_id = source_id + + class ReturnOpNode(OperationNode): def __init__(self, node) -> None: super().__init__(node) +class GetAttrOpNode(ReturnOpNode): + def __init__(self, node, type_id: str, attr_id: str) -> None: + super().__init__(node) + self.type = type_id + self.attr = attr_id + + class CallOpNode(ReturnOpNode): def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: super().__init__(node) @@ -214,6 +239,12 @@ class NegOpNode(UnaryOpNode): pass +class LoadOpNod(ReturnOpNode): + def __init__(self, node, target: str) -> None: + super().__init__(node) + self.target = target + + class AtomOpNode(ReturnOpNode): def __init__(self, node, value: str) -> None: """ From 91ee178b274f2dbe36786f8361a682b7428fdb04 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 17:03:19 -0500 Subject: [PATCH 228/432] Add a simplified version of semantics scope, to track all cool variables and ccil counterparts across scopes --- src/code_gen/tools.py | 51 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index b347fc354..540866a62 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1,5 +1,54 @@ from dataclasses import dataclass from asts.ccil_ast import ExpressionNode -from typing import List +from typing import Dict, List, Tuple from __future__ import annotations + + +class Scope: + def __init__(self, parent: Scope = None): + self.children: List[Scope] = [] + self.names: Dict[str, str] = dict() + self.parent = parent + + @property + def get_parent(self): + if self.parent is None: + raise Exception("Scope parent is None") + + return self.parent + + def create_child(self): + self.children.append(Scope()) + return self.children[-1] + + def add_new_name_pair(self, key: str, value: str): + if key in self.names: + raise Exception( + f"Re inserting {key} with {value}." + f" Value to be replaced is {self.names[key]}" + ) + self.names[key] = value + + def add_new_names(self, *names: List[Tuple[str, str]]): + for (k, v) in names: + self.add_new_name_pair(k, v) + + def search_value(self, key: str) -> str | None: + (key, _) = self.search_value_position(key) + return key + + def search_value_position(self, key: str) -> Tuple[str, bool] | Tuple[None, None]: + try: + return (self.names[key], self.parent is None) + except KeyError: + return ( + self.parent.search_for(key) if self.parent is not None else (None, None) + ) + + def get_value_position(self, key: str) -> Tuple[str, bool]: + result = self.search_value_position(key) + if any(map(lambda x: x is None, result)): + raise Exception(f"{key} cannot be found") + + return result From 16671c85dde9454fd97fd2706b1909e82d279c13 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 17:03:41 -0500 Subject: [PATCH 229/432] Mayor bug fixing in ccil visitor and some changes Fix many bugs that always casused missmatch in user defined variables and and its ccil counter parts Add track of ccil and cool names Add new translations to Int String and Bool Other minor bugs and refactoring --- src/code_gen/ccil_gen.py | 151 +++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 36 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 1b26cce83..8c4bcbcee 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict, Unknown +from typing import Set, Tuple, List, Dict, Unknown from code_gen.tools import * @@ -10,11 +10,16 @@ CLASS_VISITOR_RESULT = Tuple[Class, List[FunctionNode]] METHOD_VISITOR_RESULT = FunctionNode -USER = "user" +PARAM = "param" +LET = "let" ATTR = "attr" + BOOL = "Bool" +INT = "Int" +STRING = "String" VOID = "Void" +ADDRESS = INT # TODO: # Define cool built in methods @@ -35,10 +40,20 @@ class CCILGenerator: """ def __init__(self) -> None: - self.current_type: str + # To keep track of how many times a certain expression has been evaluated self.time_record: Dict[str, int] = dict() + # Track all constant values. Only strings for now + self.data: List[Data] = list() + + # To keep track of the current class being analysed + self.current_type: str + # Locals defined for each function self.locals: Dict[str, str] - self.data: Unknown + + # Link between cool names and their ccil name. + # It is used as scope to know which cool name it is + # referring when there are equals + self.ccil_cool_names: Scope @visitor.on("node") def visit(self, _): @@ -68,7 +83,8 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: func_nodes.append(feature) # Explore all attributes and join their operations in an initializer function - self.locals = dict() + self.reset_locals() + self.reset_scope() attributes: List[Attribute] = list() init_attr_ops: List[OperationNode] = [] for attr in attr_nodes: @@ -87,6 +103,8 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: ) # Explore all functions + self.reset_scope() + self.ccil_cool_names.add_new_names((a.id, a.type) for a in attributes) class_code: List[FunctionNode] = [self.visit(x) for x in func_nodes] # Store the functions inside the class methods: List[Method] = [Method("some id", x) for x in class_code] @@ -95,27 +113,37 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: + self.ccil_cool_names = self.ccil_cool_names.create_child() + fval_id = ATTR + node.id - self.locals[fval_id] = node.type.name + self.ccil_cool_names.add_new_name_pair(node.id, fval_id) if node.expr is None: + self.add_local(fval_id, node.type.name) return [] (expr_op, expr_fval) = self.visit(node.expr) + + self.update_locals(expr_fval.id, fval_id) expr_fval.id = fval_id + + self.ccil_cool_names = self.ccil_cool_names.get_parent return (expr_op, expr_fval) @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: + self.ccil_cool_names = self.ccil_cool_names.create_child() params: List[Parameter] = [ - Parameter(param.id, param.type.name) for param in node.params + Parameter("self", self.current_type), + *(Parameter(param.id, param.type.name) for param in node.params), ] self.locals = dict() (operations, fval_id) = self.visit(node.body) + self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - node, node.id, params, [*self.locals.items()], operations, fval_id + node, node.id, params, to_vars(self.locals, Parameter), operations, fval_id ) @visitor.when(sem_ast.BlocksNode) @@ -139,6 +167,8 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: @visitor.when(sem_ast.LetNode) def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: + self.ccil_cool_names = self.ccil_cool_names.create_child() + operations: List[OperationNode] = [] fvalues: List[StorageNode] = [] @@ -150,11 +180,15 @@ def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: (in_ops, in_fval) = self.visit(node.in_expr) operations += in_ops + self.ccil_cool_names = self.ccil_cool_names.get_parent return (operations, in_fval) @visitor.when(sem_ast.VarDeclarationNode) def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: - fvalue_id: str = USER + node.id + times = self.times(node, node.id) + + fvalue_id: str = f"{LET}{times}{node.id}" + self.ccil_cool_names.add_new_name_pair(node.id, fvalue_id) if node.expr is None: self.add_local(fvalue_id, node.type.name) @@ -171,10 +205,15 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: (expr_ops, expr_fval) = self.visit(node.expr) - fval_id = USER + node.id - self.update_locals(expr_fval.id, fval_id) - expr_fval.id = fval_id + ccil_id, is_attr = self.ccil_cool_names.get_value_position(node.id) + if is_attr: + # Assignation occurring to an attribute Go update the attribute + set_attr = SetAttrOpNode(node, "self", ccil_id, extract_id(node, expr_fval)) + return [*expr_ops, set_attr], expr_fval + + self.update_locals(expr_fval.id, ccil_id) + expr_fval.id = ccil_id return (expr_ops, expr_fval) @visitor.when(sem_ast.ConditionalNode) @@ -213,7 +252,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Storing the type of the resulting case expression type_of = self.create_type_of( - node, f"case_{times}_typeOf", "not set", extract_id(node, case_expr_fv) + node, f"case_{times}_typeOf", extract_id(node, case_expr_fv) ) # Final label where all branch must jump to @@ -230,13 +269,14 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: for (i, option) in enumerate(node.options): # Initializing the branch var branch_var_id = f"case_{times}_option_{i}" - branch_var = self.create_uninitialized_storage(option, branch_var_id) - branch_var.decl_type = option.branch_type + branch_var = self.create_uninitialized_storage( + option, branch_var_id, option.branch_type.name + ) # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" branch_var_type_of = self.create_type_of( - option, branch_var_type_id, option.type.id, extract_id(node, branch_var) + option, branch_var_type_id, extract_id(node, branch_var) ) # Initializng var which holds the comparison result between @@ -245,7 +285,6 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: select_branch = self.create_equality( option, select_branch_id, - BOOL, extract_id(node, type_of), extract_id(node, branch_var_type_of), ) @@ -262,6 +301,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Translating the branch logic (expr_ops, expr_fval) = self.visit(option.expr) # Renaming the last stored value of the expression + self.update_locals(expr_fval.id, pre_fvalue_id) expr_fval.id = pre_fvalue_id # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] @@ -297,7 +337,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) - fval = self.create_uninitialized_storage(node, f"loop_{times}_fv") + fval = self.create_uninitialized_storage(node, f"loop_{times}_fv", VOID) # Loop Nodes have void return type, how to express it?? return ( [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], @@ -392,7 +432,6 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ) return [*args_ops, call], call - (expr_ops, _) = self.visit(node.expr) # @type.id(arg1, arg2, ..., argn) @@ -402,12 +441,12 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: node, fval_id, node.type.name, node.id, node.caller_type.name ) return [*args_ops, *expr_ops, call] - + # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" call = self.create_vcall(node, fval_id, node.type.id, node.id, node.caller_type) - return [*args_ops, *expr_ops, call] + return [*args_ops, *expr_ops, call] @visitor.when(sem_ast.InstantiateNode) def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: @@ -420,18 +459,37 @@ def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: @visitor.when(sem_ast.StringNode) def visit(self, node: sem_ast.StringNode) -> VISITOR_RESULT: - pass + times = self.times(node) + + data_id = f"dataString_{times}" + self.data.append(Data(data_id, node.value)) + + load_id = f"load_str_{times}" + load_str = self.create_string_load_data(node, load_id, data_id) + return [load_str], load_str @visitor.when(sem_ast.IntNode) def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: - pass + times = self.times(node) + + int_id = f"int_{times}" + int_node = self.create_int(node, int_id, node.value) + + return [int_node], int_node @visitor.when(sem_ast.BooleanNode) def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: - pass + times = self.times(node) + + bool_id = f"bool_{times}" + value = "0" if node.value == "False" else "1" + + bool_node = self.create_int(node, bool_id, value) + return [bool_node], bool_node - def times(self, node): - key: str = type(node).__name__ + + def times(self, node: sem_ast.Node, extra: str = ""): + key: str = type(node).__name__ + extra try: self.time_record[key] += 1 except KeyError: @@ -467,28 +525,38 @@ def create_assignation(self, node, idx: str, type_idx: str, target: str): self.add_local(idx, type_idx) return StorageNode(node, idx, IdNode(node, target)) - def create_uninitialized_storage(self, node, idx: str): - self.add_local(idx, VOID) + def create_uninitialized_storage(self, node, idx: str, type_idx: str): + self.add_local(idx, type_idx) return StorageNode(node, idx, VoidNode(node)) def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, op) + def create_attr_extraction(self, node, idx: str, type_idx: str, attr_idx: str): + self.add_local(idx, type_idx) + return StorageNode(node, idx, GetAttrOpNode(node, type_idx, attr_idx)) + def create_new_type(self, node, idx: str, type_idx: str): self.add_local(idx, type_idx) return StorageNode(node, idx, NewOpNode(node, type_idx)) - def create_type_of(self, node, idx: str, type_idx: str, target: AtomOpNode): - self.add_local(idx, type_idx) + def create_type_of(self, node, idx: str, target: AtomOpNode): + self.add_local(idx, ADDRESS) return StorageNode(node, idx, GetTypeOpNode(node, target)) - def create_equality( - self, node, idx, type_idx: str, left: AtomOpNode, right: AtomOpNode - ): - self.add_local(idx, type_idx) + def create_equality(self, node, idx, left: AtomOpNode, right: AtomOpNode): + self.add_local(idx, BOOL) return StorageNode(node, idx, EqualOpNode(node, left, right)) + def create_string_load_data(self, node, idx: str, target: str): + self.add_local(idx, STRING) + return StorageNode(node, idx, LoadOpNod(node, target)) + + def create_int(self, node, idx: str, value: str): + self.add_local(idx, INT) + return StorageNode(node, idx, IntNode(node, value)) + def extract_id(self, node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) @@ -500,7 +568,18 @@ def add_local(self, idx: str, typex: str): if idx in self.locals: raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex + self.defined_vars.add(idx) + + def reset_locals(self): + """ + Apply at the beginning of every method to reset local vars + """ + self.locals = dict() + self.defined_vars = set() + + def reset_scope(self): + self.scope = Scope() -def to_vars(dict: Dict[str, str], const=BaseVar): - return map(lambda x: const(*x), dict.items().mapping()) +def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: + return list(map(lambda x: const(*x), dict.items().mapping())) From eb490d97d2169e6742538b8b2680639480538ec3 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 17:40:23 -0500 Subject: [PATCH 230/432] Add simple id(VariableNode) translation to ccil --- src/code_gen/ccil_gen.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 8c4bcbcee..9fa19751b 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -27,8 +27,6 @@ # How to handle void nodes # Diference between method id and function id # Handdle all remaining operations: -# * Saving string to memory -# * Getting and setting attributes # * IO operations # * Handle constants and IDs @@ -457,6 +455,22 @@ def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: return [fvalue], fvalue + @visitor.when(sem_ast.VariableNode) + def visit(self, node: sem_ast.VariableNode) -> VISITOR_RESULT: + times = self.times(node) + + id_id = f"id_{times}" + ccil_id, is_attr = self.ccil_cool_names.get_value_position(node.value) + + if is_attr: + get_attr = self.create_attr_extraction( + node, id_id, node.type.name, "self", ccil_id + ) + return [get_attr], get_attr + + fval = self.create_assignation(node, id_id, node.type.name, ccil_id) + return [fval], fval + @visitor.when(sem_ast.StringNode) def visit(self, node: sem_ast.StringNode) -> VISITOR_RESULT: times = self.times(node) @@ -487,7 +501,6 @@ def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: bool_node = self.create_int(node, bool_id, value) return [bool_node], bool_node - def times(self, node: sem_ast.Node, extra: str = ""): key: str = type(node).__name__ + extra try: @@ -533,9 +546,11 @@ def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(node, idx, op) - def create_attr_extraction(self, node, idx: str, type_idx: str, attr_idx: str): + def create_attr_extraction( + self, node, idx: str, type_idx: str, from_idx: str, attr_idx: str + ): self.add_local(idx, type_idx) - return StorageNode(node, idx, GetAttrOpNode(node, type_idx, attr_idx)) + return StorageNode(node, idx, GetAttrOpNode(node, from_idx, attr_idx)) def create_new_type(self, node, idx: str, type_idx: str): self.add_local(idx, type_idx) From 761183571832abdf387d24460920f51212d0619a Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 17:50:10 -0500 Subject: [PATCH 231/432] Remove ExpressionNode --- src/code_gen/tools.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 0a343e12f..a705e388b 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1,8 +1,7 @@ +from __future__ import annotations from dataclasses import dataclass -from asts.ccil_ast import ExpressionNode from typing import List -from __future__ import annotations @dataclass(frozen=True) From 82aa5de20e733f4c12f780fa61573dbf8bc03ff4 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 17:57:25 -0500 Subject: [PATCH 232/432] Handle case where node is None in class Node inicialization --- src/asts/ccil_ast.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index de4abbc5e..d4473dd2e 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -61,8 +61,9 @@ class Method: class Node: def __init__(self, node) -> None: - self.line: int = node.line - self.col: int = node.col + if node is not None: + self.line: int = node.line + self.col: int = node.col def get_position(self) -> Tuple[int, int]: return (self.line, self.col) @@ -131,8 +132,10 @@ def __init__(self, node, idx: str, args: List[str]) -> None: class VCallOpNode(ReturnOpNode): def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: - super().__init__(node, idx, args) + super().__init__(node) + self.id = idx self.type = type_idx + self.args = args class VoidNode(ReturnOpNode): @@ -259,5 +262,6 @@ def __init__(self, node, idx: str) -> None: super().__init__(node) self.id = idx + def extract_id(node, storage_node: StorageNode) -> IdNode: return IdNode(node, storage_node.id) From ee2bf5980d3a79211d69a85d1da730f8e896513e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 19:44:19 -0500 Subject: [PATCH 233/432] fix(ccil_visitor): add param and attributes with old and new id instead of new id and its type --- src/code_gen/ccil_gen.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 9fa19751b..e709b1f4c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -102,10 +102,15 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Explore all functions self.reset_scope() - self.ccil_cool_names.add_new_names((a.id, a.type) for a in attributes) - class_code: List[FunctionNode] = [self.visit(x) for x in func_nodes] - # Store the functions inside the class - methods: List[Method] = [Method("some id", x) for x in class_code] + self.ccil_cool_names.add_new_names( + (n.id, a.id) for (n, a) in zip(attr_nodes, attributes) + ) + class_code: List[FunctionNode] = [] + methods: List[Method] = [] + for func in func_nodes: + f = self.visit(func) + class_code.append(f) + methods.append(Method(func.id, f)) return (Class(attributes, methods, init_func), class_code) @@ -130,11 +135,15 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: + times = self.times(node) self.ccil_cool_names = self.ccil_cool_names.create_child() - params: List[Parameter] = [ - Parameter("self", self.current_type), - *(Parameter(param.id, param.type.name) for param in node.params), - ] + + params: List[Parameter] = [Parameter("self", self.current_type)] + self.ccil_cool_names.add_new_name_pair("self", "self") + for param in node.params: + new_param_id = PARAM + param.id + params.append(Parameter(new_param_id, param.type.name)) + self.ccil_cool_names.add_new_name_pair(param.id, new_param_id) self.locals = dict() (operations, fval_id) = self.visit(node.body) @@ -572,9 +581,6 @@ def create_int(self, node, idx: str, value: str): self.add_local(idx, INT) return StorageNode(node, idx, IntNode(node, value)) - def extract_id(self, node, storage_node: StorageNode) -> IdNode: - return IdNode(node, storage_node.id) - def update_locals(self, old_id: str, new_id: str): self.locals[new_id] = self.locals[old_id] del self.locals[old_id] From 1ee58734f1c65052435fb5d98f8e74893eb62f85 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 23 Feb 2022 21:15:26 -0500 Subject: [PATCH 234/432] Minor changes --- src/code_gen/ccil_gen.py | 4 ++-- src/semantics/type_builder.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index e709b1f4c..b79c77c96 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Set, Tuple, List, Dict, Unknown +from typing import Tuple, List, Dict from code_gen.tools import * @@ -150,7 +150,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - node, node.id, params, to_vars(self.locals, Parameter), operations, fval_id + node, f"f_{times}", params, to_vars(self.locals, Parameter), operations, fval_id ) @visitor.when(sem_ast.BlocksNode) diff --git a/src/semantics/type_builder.py b/src/semantics/type_builder.py index 02eacccb7..6a908f4e5 100644 --- a/src/semantics/type_builder.py +++ b/src/semantics/type_builder.py @@ -8,7 +8,7 @@ AttrDeclarationNode, ) from semantics.tools.errors import SemanticError -from semantics.tools import SelfType, TypeBag, Context +from semantics.tools import TypeBag, Context class TypeBuilder: From f0df4c7a6099d8a50eac8c1e5ca23b0184831e65 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 21:34:18 -0500 Subject: [PATCH 235/432] Update mips_gen.py --- src/code_gen/mips_gen.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 052868a28..4d8befdf5 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -1,10 +1,16 @@ from asts.mips_ast import ( + Addu, + Jump, + JumpAndLink, + JumpRegister, Label, LabelDeclaration, + LoadAddress, MIPSProgram, MemoryIndexNode, Move, RegisterNode, + Subu, TextNode, DataNode, WordDirective, @@ -37,7 +43,10 @@ def visit(self, node: TextNode) -> str: @visitor.when(DataNode) def visit(self, node: DataNode) -> str: - return "\n".join(self.visit(instruction) for instruction in node.instructions) + data_section = "" + for label_decl, directive in node.data: + data_section += f"{self.visit(label_decl)} {self.visit(directive)}\n" + return data_section @visitor.when(RegisterNode) def visit(self, node: RegisterNode) -> str: @@ -51,14 +60,38 @@ def visit(self, node: LabelDeclaration) -> str: def visit(self, node: Label) -> str: return str(node.idx) + @visitor.when(JumpAndLink) + def visit(self, node: JumpAndLink) -> str: + return f"\tjal {node.address}" + + @visitor.when(Jump) + def visit(self, node: Jump) -> str: + return f"\tj {node.address}" + + @visitor.when(JumpRegister) + def visit(self, node: JumpRegister) -> str: + return f"\tj {node.register}" + @visitor.when(MemoryIndexNode) def visit(self, node: MemoryIndexNode) -> str: return f"{self.visit(node.address)}({self.visit(node.index)})" @visitor.when(WordDirective) def visit(self, node: WordDirective) -> str: - return ".word " + " ".join(self.visit(i) for i in node.list) + return ".word " + (" ".join(self.visit(i) for i in node.list)) @visitor.when(Move) def visit(self, node: Move) -> str: return f"\tmove {self.visit(node.left)}, {self.visit(node.right)}" + + @visitor.when(Subu) + def visit(self, node: Subu) -> str: + return f"\tsubu {node.left}, {node.middle}, {node.right}" + + @visitor.when(Addu) + def visit(self, node: Addu) -> str: + return f"\taddu {node.left}, {node.middle}, {node.right}" + + @visitor.when(LoadAddress) + def visit(self, node: LoadAddress) -> str: + return f"\tla {node.left}, {node.right}" From 18a46d0e11f8ed054c5e8c28fbe50f54a3155860 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 23:02:37 -0500 Subject: [PATCH 236/432] Fix function call in ccil_mips_gen.py --- src/asts/mips_ast.py | 43 +++++++++++++++++++----- src/code_gen/ccil_mips_gen.py | 62 ++++++++++++++++++++++++++++++----- src/code_gen/mips_gen.py | 2 +- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 1ab7f24f4..10e6f83b1 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -1,12 +1,15 @@ from __future__ import annotations from typing import Dict, List, Tuple +from asts.parser_ast import BinaryNode + class Node: def __init__(self, node) -> None: - if node is not None: - self.line: int = node.line - self.col: int = node.col + # if node is not None: + # self.line: int = node.line + # self.col: int = node.col + pass def get_position(self) -> Tuple[int, int]: return (self.line, self.col) @@ -110,6 +113,24 @@ def __init__(self, node, left, middle, right) -> None: self.right = right +class Subu(TernaryOpNode): + """ + This node represents `subu` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + +class Addu(TernaryOpNode): + """ + This node represents `addu` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + class Move(BinaryOpNode): """ This node represents `move` instruction in MIPS @@ -128,6 +149,14 @@ def __init__(self, node, left, right) -> None: super().__init__(node, left, right) +class LoadAddress(BinaryNode): + """ + This node represents `la` instruction in MIPS + """ + def __init__(self, left, right): + super().__init__(left, right) + + class StoreWord(BinaryOpNode): """ This node represents `sw` instruction in MIPS @@ -137,7 +166,7 @@ def __init__(self, node, left, right) -> None: super().__init__(node, left, right) -class Jump(Node): +class Jump(InstructionNode): """ This node represents `j` instruction in MIPS """ @@ -147,7 +176,7 @@ def __init__(self, node, address) -> None: self.address = address -class JumpRegister(Node): +class JumpRegister(InstructionNode): """ This node represents `jr` instruction in MIPS """ @@ -157,7 +186,7 @@ def __init__(self, node, register) -> None: self.register = register -class JumpAndLink(Node): +class JumpAndLink(InstructionNode): """ This node represents `jal` instruction in MIPS """ @@ -182,5 +211,3 @@ class WordDirective(AssemblerDirective): def __init__(self, node, list) -> None: super().__init__(node, list) - - diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 0d33baefd..75c53f19b 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1,16 +1,20 @@ from typing import Union +from utils import visitor from asts.mips_ast import ( Addu, DataNode, InstructionNode, JumpAndLink, + JumpRegister, LabelDeclaration, LoadWord, MIPSProgram, MemoryIndexNode, + Move, RegisterNode, StoreWord, Subu, + Label, TextNode, WordDirective, ) @@ -34,27 +38,32 @@ def visit(self, node: CCILProgram, location: Location = None): types_table = [] for classx in node.types_section: - word_directive = [Label(node, classx.id)] + word_directive = [ + Label(node, classx.id), + Label(node, classx.init_operations.id), + ] for method in classx.methods: - word_directive.append(method.function.id) + word_directive.append(Label(node, method.function.id)) types_table.append( - LabelDeclaration(node, classx.id), WordDirective(node, word_directive) + (LabelDeclaration(node, classx.id), WordDirective(node, word_directive)) ) # TODO: other .data section static data inicializations like strings functions = [] + for classx in node.types_section: + functions += self.visit(classx.init_operations, {}) for func in node.code_section: functions += self.visit(func, {}) return MIPSProgram(None, TextNode(node, functions), DataNode(node, types_table)) - @visit.when(FunctionNode) + @visitor.when(FunctionNode) def visit(self, node: FunctionNode, location: Location): label = LabelDeclaration(node, node.id) body: List[InstructionNode] = [] - frame_size = len(node.params) * 4 + 12 + frame_size = (len(node.params) + len(node.locals)) * 4 + 12 stack_pointer = RegisterNode(node, 29) return_address = RegisterNode(node, 31) frame_pointer = RegisterNode(node, 30) @@ -63,19 +72,54 @@ def visit(self, node: FunctionNode, location: Location): for param in node.params: location[param.id] = MemoryIndexNode(node, index, frame_pointer) index += 4 + for local in node.params: + location[local.id] = MemoryIndexNode(node, index, frame_pointer) + index += 4 body.append(Subu(node, stack_pointer, stack_pointer, frame_size)) body.append( - StoreWord(node, return_address, MemoryIndexNode(node, stack_pointer, 20)) + StoreWord( + node, + return_address, + MemoryIndexNode(node, frame_size - 8, stack_pointer), + ) ) body.append( - StoreWord(node, frame_pointer, MemoryIndexNode(node, stack_pointer, 16)) + StoreWord( + node, + frame_pointer, + MemoryIndexNode(node, frame_size - 12, stack_pointer), + ) ) body.append(Addu(node, frame_pointer, frame_pointer, frame_size - 4)) for op in node.operations: body += self.visit(op, location) + ret_location = location[node.ret] + ret_register = RegisterNode(node, 3) + if isinstance(ret_location, RegisterNode): + body.append(Move(node, ret_register, ret_location)) + elif isinstance(ret_location, MemoryIndexNode): + body.append(LoadWord(node, ret_register, ret_location)) + + body.append( + LoadWord( + node, + return_address, + MemoryIndexNode(node, frame_size - 8, stack_pointer), + ) + ) + body.append( + LoadWord( + node, + frame_pointer, + MemoryIndexNode(node, frame_size - 12, stack_pointer), + ) + ) + body.append(Addu(node, stack_pointer, stack_pointer, frame_size)) + body.append(JumpRegister(node, return_address)) + return [label, *body] @visitor.when(CallOpNode) @@ -91,6 +135,7 @@ def visit(self, node: CallOpNode, location: Location): ) index += 4 instructions.append(JumpAndLink(node, node.id)) + return instructions @visitor.when(VCallOpNode) def visit(self, node: VCallOpNode, location: Location): @@ -107,7 +152,7 @@ def visit(self, node: VCallOpNode, location: Location): elif isinstance(obj_location, MemoryIndexNode): instructions.append(LoadWord(node, obj_type, obj_location)) - function_index = self.get_method_index(node.type, node.id) + function_index = self.get_method_index(node.type, node.id) * 4 + 8 # TODO use free register instead of 9 register_function = RegisterNode(node, 9) @@ -118,6 +163,7 @@ def visit(self, node: VCallOpNode, location: Location): ) ) instructions.append(JumpAndLink(node, register_function)) + return instructions def get_init_function(self, typex: str): for _type in self.types_table: diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 4d8befdf5..c465d9995 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -94,4 +94,4 @@ def visit(self, node: Addu) -> str: @visitor.when(LoadAddress) def visit(self, node: LoadAddress) -> str: - return f"\tla {node.left}, {node.right}" + return f"\tla {node.left}, {node.right}" From 2dfb13ff380ba23d800e5abe023c8aba3ee212cb Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 23:34:36 -0500 Subject: [PATCH 237/432] Add syscall node in ast --- src/asts/mips_ast.py | 10 ++++++++++ src/code_gen/mips_gen.py | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 10e6f83b1..1a73329cc 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -153,6 +153,7 @@ class LoadAddress(BinaryNode): """ This node represents `la` instruction in MIPS """ + def __init__(self, left, right): super().__init__(left, right) @@ -211,3 +212,12 @@ class WordDirective(AssemblerDirective): def __init__(self, node, list) -> None: super().__init__(node, list) + + +class Syscall(InstructionNode): + """ + This node represents `syscall` instruction in MIPS + """ + + def __init__(self, node) -> None: + super().__init__(node) diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index c465d9995..31f035eaa 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -11,6 +11,7 @@ Move, RegisterNode, Subu, + Syscall, TextNode, DataNode, WordDirective, @@ -95,3 +96,7 @@ def visit(self, node: Addu) -> str: @visitor.when(LoadAddress) def visit(self, node: LoadAddress) -> str: return f"\tla {node.left}, {node.right}" + + @visitor.when(Syscall) + def visit(self, node: Syscall) -> str: + return f"\tsyscall" From 4621ca7abe49e68488622b6e222fcbce59fe43e6 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 23 Feb 2022 23:35:14 -0500 Subject: [PATCH 238/432] Create __init__.py in code_gen --- src/code_gen/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/code_gen/__init__.py diff --git a/src/code_gen/__init__.py b/src/code_gen/__init__.py new file mode 100644 index 000000000..e69de29bb From 90d156b32425204da2152fffe46daf5b3fc92a7c Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 07:35:10 -0500 Subject: [PATCH 239/432] Add push and pop methods in CCILToMIPSGenerator --- src/code_gen/ccil_mips_gen.py | 239 +++++++++++++++++++++------------- 1 file changed, 147 insertions(+), 92 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 75c53f19b..7e556f8c0 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1,168 +1,223 @@ -from typing import Union +from typing import Union, Dict, List from utils import visitor -from asts.mips_ast import ( - Addu, - DataNode, - InstructionNode, - JumpAndLink, - JumpRegister, - LabelDeclaration, - LoadWord, - MIPSProgram, - MemoryIndexNode, - Move, - RegisterNode, - StoreWord, - Subu, - Label, - TextNode, - WordDirective, -) +from asts import mips_ast, ccil_ast from utils import visitor -from asts.ccil_ast import * -Location = Dict[str, Union[MemoryIndexNode, RegisterNode]] +WORD = 4 +DOUBLE_WORD = 8 +Location = Dict[str, mips_ast.MemoryIndexNode] +Types = Dict[str, str] class CCILToMIPSGenerator: def __init__(self) -> None: - self.types_table: List[Class] # list or dict for classes??? + self.__types_table: List[ccil_ast.Class] # list or dict for classes??? + self.__location: Location + self.__types: Types + self.__current_type: str + self.__current_function: ccil_ast.FunctionNode + + def push_stack(self, node, register: mips_ast.RegisterNode): + stack_pointer = mips_ast.RegisterNode(node, 29) + instructions = [] + instructions.append( + mips_ast.Addi(node, stack_pointer, stack_pointer, -1 * WORD) + ) + instructions.append( + mips_ast.StoreWord( + node, register, mips_ast.MemoryIndexNode(node, 0, stack_pointer) + ) + ) + return instructions + + def pop_stack(self, node, register: mips_ast.RegisterNode): + stack_pointer = mips_ast.RegisterNode(node, 29) + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, register, mips_ast.MemoryIndexNode(node, 0, stack_pointer) + ) + ) + instructions.append(mips_ast.Addi(node, stack_pointer, stack_pointer, WORD)) + return instructions @visitor.on("node") def visit(self, node): pass - @visitor.when(CCILProgram) - def visit(self, node: CCILProgram, location: Location = None): + @visitor.when(ccil_ast.CCILProgram) + def visit(self, node: ccil_ast.CCILProgram): self.types = node.types_section types_table = [] for classx in node.types_section: word_directive = [ - Label(node, classx.id), - Label(node, classx.init_operations.id), + mips_ast.Label(node, classx.id), + mips_ast.Label(node, classx.init_operations.id), ] for method in classx.methods: - word_directive.append(Label(node, method.function.id)) + word_directive.append(mips_ast.Label(node, method.function.id)) types_table.append( - (LabelDeclaration(node, classx.id), WordDirective(node, word_directive)) + ( + mips_ast.LabelDeclaration(node, classx.id), + mips_ast.WordDirective(node, word_directive), + ) ) # TODO: other .data section static data inicializations like strings functions = [] for classx in node.types_section: - functions += self.visit(classx.init_operations, {}) + functions.extend(self.visit(classx.init_operations)) for func in node.code_section: - functions += self.visit(func, {}) + functions.extend(self.visit(func)) - return MIPSProgram(None, TextNode(node, functions), DataNode(node, types_table)) + return mips_ast.MIPSProgram( + None, + mips_ast.TextNode(node, functions), + mips_ast.DataNode(node, types_table), + ) - @visitor.when(FunctionNode) - def visit(self, node: FunctionNode, location: Location): - label = LabelDeclaration(node, node.id) - body: List[InstructionNode] = [] + @visitor.when(ccil_ast.FunctionNode) + def visit(self, node: ccil_ast.FunctionNode): + instructions = [] + instructions.append(mips_ast.LabelDeclaration(node, node.id)) - frame_size = (len(node.params) + len(node.locals)) * 4 + 12 - stack_pointer = RegisterNode(node, 29) - return_address = RegisterNode(node, 31) - frame_pointer = RegisterNode(node, 30) + frame_size = (len(node.locals)) * WORD + 12 + stack_pointer = mips_ast.RegisterNode(node, 29) + return_address = mips_ast.RegisterNode(node, 31) + frame_pointer = mips_ast.RegisterNode(node, 30) index = 0 - for param in node.params: - location[param.id] = MemoryIndexNode(node, index, frame_pointer) - index += 4 + for param in reversed(node.locals): + self.__location[param.id] = mips_ast.MemoryIndexNode( + node, index, frame_pointer + ) + index += WORD + index = 0 for local in node.params: - location[local.id] = MemoryIndexNode(node, index, frame_pointer) - index += 4 + self.__location[local.id] = mips_ast.MemoryIndexNode( + node, -1 * index, frame_pointer + ) + index += WORD - body.append(Subu(node, stack_pointer, stack_pointer, frame_size)) - body.append( - StoreWord( + instructions.append( + mips_ast.Subu(node, stack_pointer, stack_pointer, frame_size) + ) + instructions.append( + mips_ast.StoreWord( node, return_address, - MemoryIndexNode(node, frame_size - 8, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - 2 * WORD, stack_pointer), ) ) - body.append( - StoreWord( + instructions.append( + mips_ast.StoreWord( node, frame_pointer, - MemoryIndexNode(node, frame_size - 12, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - 3 * WORD, stack_pointer), ) ) - body.append(Addu(node, frame_pointer, frame_pointer, frame_size - 4)) + instructions.append( + mips_ast.Addu(node, frame_pointer, frame_pointer, frame_size - WORD) + ) for op in node.operations: - body += self.visit(op, location) + instructions += self.visit(op) - ret_location = location[node.ret] - ret_register = RegisterNode(node, 3) - if isinstance(ret_location, RegisterNode): - body.append(Move(node, ret_register, ret_location)) - elif isinstance(ret_location, MemoryIndexNode): - body.append(LoadWord(node, ret_register, ret_location)) + ret_location = self.__location[node.ret] + ret_register = mips_ast.RegisterNode(node, 3) + instructions.append(mips_ast.LoadWord(node, ret_register, ret_location)) - body.append( - LoadWord( + instructions.append( + mips_ast.LoadWord( node, return_address, - MemoryIndexNode(node, frame_size - 8, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - 8, stack_pointer), ) ) - body.append( - LoadWord( + instructions.append( + mips_ast.LoadWord( node, frame_pointer, - MemoryIndexNode(node, frame_size - 12, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - 12, stack_pointer), ) ) - body.append(Addu(node, stack_pointer, stack_pointer, frame_size)) - body.append(JumpRegister(node, return_address)) + instructions.append( + mips_ast.Addu(node, stack_pointer, stack_pointer, frame_size) + ) + instructions.append(mips_ast.JumpRegister(node, return_address)) - return [label, *body] + return instructions - @visitor.when(CallOpNode) - def visit(self, node: CallOpNode, location: Location): - stack_pointer = RegisterNode(node, 29) + @visitor.when(ccil_ast.CallOpNode) + def visit(self, node: ccil_ast.CallOpNode): + reg = mips_ast.RegisterNode(node, 10) instructions = [] - index = 4 for arg in node.args: - arg_location = location[arg] - if isinstance(arg_location, RegisterNode): - instructions.append( - StoreWord(node, arg_location, MemoryIndexNode(index, stack_pointer)) - ) - index += 4 - instructions.append(JumpAndLink(node, node.id)) + instructions.append(mips_ast.LoadWord(node, reg, self.__location[arg])) + instructions.append(self.push_stack(node, reg)) + instructions.append(mips_ast.JumpAndLink(node, node.id)) + + if len(node.args) > 0: + stack_pointer = mips_ast.RegisterNode(node, 29) + instructions.append( + mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) + ) return instructions - @visitor.when(VCallOpNode) - def visit(self, node: VCallOpNode, location: Location): - obj_location = location[node.args[0]] + @visitor.when(ccil_ast.VCallOpNode) + def visit(self, node: ccil_ast.VCallOpNode): + obj_location = self.__location[node.args[0]] instructions = [] # TODO use free register instead of 8 - obj_type = RegisterNode(node, 8) + obj_type = mips_ast.RegisterNode(node, 8) - if isinstance(obj_location, RegisterNode): + if isinstance(obj_location, mips_ast.RegisterNode): instructions.append( - LoadWord(node, obj_type, MemoryIndexNode(node, 0, obj_location)) + mips_ast.LoadWord( + node, obj_type, mips_ast.MemoryIndexNode(node, 0, obj_location) + ) ) - elif isinstance(obj_location, MemoryIndexNode): - instructions.append(LoadWord(node, obj_type, obj_location)) + elif isinstance(obj_location, mips_ast.MemoryIndexNode): + instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) - function_index = self.get_method_index(node.type, node.id) * 4 + 8 + function_index = self.get_method_index(node.type, node.id) * WORD + DOUBLE_WORD # TODO use free register instead of 9 - register_function = RegisterNode(node, 9) + register_function = mips_ast.RegisterNode(node, 9) instructions.append( - LoadWord( - node, register_function, MemoryIndexNode(node, function_index, obj_type) + mips_ast.LoadWord( + node, + register_function, + mips_ast.MemoryIndexNode(node, function_index, obj_type), ) ) - instructions.append(JumpAndLink(node, register_function)) + instructions.append(mips_ast.JumpAndLink(node, register_function)) + return instructions + + @visitor.when(ccil_ast.StorageNode) + def visit(self, node: ccil_ast.StorageNode): + location_id = self.__location[node.id] + instructions = [] + instructions.append(self.visit(node.operation)) + instructions.append( + mips_ast.LoadWord(node, mips_ast.RegisterNode(node, 3), location_id) + ) + return instructions + + @visitor.when(ccil_ast.SumOpNode) + def visit(self, node: ccil_ast.SumOpNode): + instructions = [] + reg = mips_ast.RegisterNode(node, 10) + reg_left = mips_ast.RegisterNode(node, 11) + reg_rigth = mips_ast.RegisterNode(node, 12) + left_location = self.__location[node.left.value] + right_location = self.__location[node.left.value] + + return instructions def get_init_function(self, typex: str): From 9261a9f9e92a3478660fc1f72fc6fa6dc82c47f5 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 07:49:08 -0500 Subject: [PATCH 240/432] Fix dynamic function call --- src/code_gen/ccil_mips_gen.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 7e556f8c0..ff754318b 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -168,26 +168,14 @@ def visit(self, node: ccil_ast.CallOpNode): @visitor.when(ccil_ast.VCallOpNode) def visit(self, node: ccil_ast.VCallOpNode): - obj_location = self.__location[node.args[0]] instructions = [] - # TODO use free register instead of 8 + obj_location = self.__location[node.args[0]] obj_type = mips_ast.RegisterNode(node, 8) + instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) - if isinstance(obj_location, mips_ast.RegisterNode): - instructions.append( - mips_ast.LoadWord( - node, obj_type, mips_ast.MemoryIndexNode(node, 0, obj_location) - ) - ) - elif isinstance(obj_location, mips_ast.MemoryIndexNode): - instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) - - function_index = self.get_method_index(node.type, node.id) * WORD + DOUBLE_WORD - - # TODO use free register instead of 9 register_function = mips_ast.RegisterNode(node, 9) - + function_index = self.get_method_index(node.type, node.id) * WORD + DOUBLE_WORD instructions.append( mips_ast.LoadWord( node, @@ -195,7 +183,19 @@ def visit(self, node: ccil_ast.VCallOpNode): mips_ast.MemoryIndexNode(node, function_index, obj_type), ) ) + reg_arg = mips_ast.RegisterNode(node, 10) + instructions = [] + for arg in node.args: + instructions.append(mips_ast.LoadWord(node, reg_arg, self.__location[arg])) + instructions.append(self.push_stack(node, reg_arg)) instructions.append(mips_ast.JumpAndLink(node, register_function)) + + if len(node.args) > 0: + stack_pointer = mips_ast.RegisterNode(node, 29) + instructions.append( + mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) + ) + return instructions @visitor.when(ccil_ast.StorageNode) @@ -217,7 +217,6 @@ def visit(self, node: ccil_ast.SumOpNode): left_location = self.__location[node.left.value] right_location = self.__location[node.left.value] - return instructions def get_init_function(self, typex: str): From 62010af81c4e42f2aaba34e650289ce692da5ae6 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 12:06:12 -0500 Subject: [PATCH 241/432] Add new nodes and other changes --- src/asts/ccil_ast.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index c34289384..0a19d80fb 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -71,6 +71,8 @@ class Method: class Node: def __init__(self, node) -> None: + self.line = 0 + self.col = 0 if node is not None: self.line: int = node.line self.col: int = node.col @@ -136,15 +138,33 @@ def __init__(self, node, type_id: str, attr_id: str, source_id: AtomOpNode) -> N self.source_id = source_id +class Abort(OperationNode): + pass + + +class PrintOpNode(OperationNode): + def __init__(self, node, idx: str) -> None: + super().__init__(node) + self.idx = idx + + class ReturnOpNode(OperationNode): def __init__(self, node) -> None: super().__init__(node) +class ReadOpNode(ReturnOpNode): + """ + This nodes reads input from the standard input" + """ + + pass + + class GetAttrOpNode(ReturnOpNode): - def __init__(self, node, type_id: str, attr_id: str) -> None: + def __init__(self, node, instance_id: str, attr_id: str) -> None: super().__init__(node) - self.type = type_id + self.instance = instance_id self.attr = attr_id @@ -243,12 +263,24 @@ class NegOpNode(UnaryOpNode): pass -class LoadOpNod(ReturnOpNode): +class ChainOpNode(ReturnOpNode): def __init__(self, node, target: str) -> None: super().__init__(node) self.target = target +class LoadOpNode(ChainOpNode): + pass + + +class LengthOpNode(ChainOpNode): + pass + + +class StrOpNode(ChainOpNode): + pass + + class AtomOpNode(ReturnOpNode): def __init__(self, node, value: str) -> None: """ From e0f57f07589fecdb36af4e718c2ab2eb9daa2b0b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 12:08:53 -0500 Subject: [PATCH 242/432] Add attibute to GetAttrOpNode --- src/asts/ccil_ast.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 0a19d80fb..d431d836d 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -162,8 +162,11 @@ class ReadOpNode(ReturnOpNode): class GetAttrOpNode(ReturnOpNode): - def __init__(self, node, instance_id: str, attr_id: str) -> None: + def __init__( + self, node, instance_type_id: str, instance_id: str, attr_id: str + ) -> None: super().__init__(node) + self.instance_type_id = instance_type_id self.instance = instance_id self.attr = attr_id From 10bb4b90eb627ce339c4587015ea78e3689e8ec8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 12:10:43 -0500 Subject: [PATCH 243/432] Minor refactoring --- src/code_gen/ccil_gen.py | 33 +++++++++++++++------------------ src/code_gen/constants.py | 15 +++++++++++---- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index b79c77c96..5c6e93b7b 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,34 +1,26 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict +from typing import Tuple, List, Dict from code_gen.tools import * +from constants import * # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] CLASS_VISITOR_RESULT = Tuple[Class, List[FunctionNode]] METHOD_VISITOR_RESULT = FunctionNode -PARAM = "param" -LET = "let" -ATTR = "attr" - - -BOOL = "Bool" -INT = "Int" -STRING = "String" -VOID = "Void" -ADDRESS = INT - # TODO: # Define cool built in methods # The result of (type of) what is it # How to handle void nodes -# Diference between method id and function id -# Handdle all remaining operations: -# * IO operations -# * Handle constants and IDs + +# Define abort nodes with a text +# Add text dynamically .data function, incluiding error messages + +# Test there are no runtimes errors +# Test that results are obtained as expected # CCIL stands for Cool Cows Intermediate Language ;) @@ -150,7 +142,12 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - node, f"f_{times}", params, to_vars(self.locals, Parameter), operations, fval_id + node, + f"f_{times}", + params, + to_vars(self.locals, Parameter), + operations, + fval_id, ) @visitor.when(sem_ast.BlocksNode) @@ -575,7 +572,7 @@ def create_equality(self, node, idx, left: AtomOpNode, right: AtomOpNode): def create_string_load_data(self, node, idx: str, target: str): self.add_local(idx, STRING) - return StorageNode(node, idx, LoadOpNod(node, target)) + return StorageNode(node, idx, LoadOpNode(node, target)) def create_int(self, node, idx: str, value: str): self.add_local(idx, INT) diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index e34a58de4..5db668cbd 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -1,5 +1,12 @@ -ATTR_NAME = "attr" +PARAM = "param" +LET = "let" +ATTR = "attr" -CASE_INIT = "init_case" -CASE_END = "end_case" -CASE_BRANCH = "case_branch" + +OBJECT = "Object" +BOOL = "Bool" +INT = "Int" +STRING = "String" +VOID = "Void" +SELFTYPE = "SELF_TYPE" +ADDRESS = INT From ee51b8fb4d8696a25578057fd9e08078af912397 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 12:12:14 -0500 Subject: [PATCH 244/432] Minor change --- src/asts/ccil_ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index d431d836d..10bee9f70 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -166,7 +166,7 @@ def __init__( self, node, instance_type_id: str, instance_id: str, attr_id: str ) -> None: super().__init__(node) - self.instance_type_id = instance_type_id + self.instance_type = instance_type_id self.instance = instance_id self.attr = attr_id From 13233614e7b7a1f671f76a872c57988745d87e5a Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 12:41:33 -0500 Subject: [PATCH 245/432] Add new nodes --- src/asts/mips_ast.py | 56 ++++++++++++++++++++++++++++++++++++++++ src/code_gen/mips_gen.py | 35 +++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 1a73329cc..2b8c7ffa2 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -51,6 +51,13 @@ def __init__( self.data = [] self.data = data +class Constant(Node): + """ + This class represents a literal integer in MIPS + """ + def __init__(self, node, value : str) -> None: + super().__init__(node) + self.value = value class RegisterNode(Node): """ @@ -122,6 +129,24 @@ def __init__(self, node, left, middle, right) -> None: super().__init__(node, left, middle, right) +class Sub(TernaryOpNode): + """ + This node represents `sub` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + +class Addi(TernaryOpNode): + """ + This node represents `addi` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + class Addu(TernaryOpNode): """ This node represents `addu` instruction in MIPS @@ -131,6 +156,15 @@ def __init__(self, node, left, middle, right) -> None: super().__init__(node, left, middle, right) +class Add(TernaryOpNode): + """ + This node represents `addu` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + class Move(BinaryOpNode): """ This node represents `move` instruction in MIPS @@ -140,6 +174,14 @@ def __init__(self, node, left, right) -> None: super().__init__(node, left, right) +class LoadImmediate(BinaryOpNode): + """ + This node represents `li` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + class LoadWord(BinaryOpNode): """ This node represents `lw` instruction in MIPS @@ -196,6 +238,19 @@ def __init__(self, node, address) -> None: super().__init__(node) self.address = address +class BranchOnEqual(TernaryOpNode): + """ + This node represents `beq` instruction in MIPS + """ + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + +class BranchOnNotEqual(TernaryOpNode): + """ + This node represents `bne` instruction in MIPS + """ + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) class AssemblerDirective(Node): def __init__(self, node, list) -> None: @@ -221,3 +276,4 @@ class Syscall(InstructionNode): def __init__(self, node) -> None: super().__init__(node) + diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 31f035eaa..89b6aff8c 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -1,15 +1,22 @@ from asts.mips_ast import ( + Add, + Addi, Addu, + BranchOnEqual, + BranchOnNotEqual, + Constant, Jump, JumpAndLink, JumpRegister, Label, LabelDeclaration, LoadAddress, + LoadImmediate, MIPSProgram, MemoryIndexNode, Move, RegisterNode, + Sub, Subu, Syscall, TextNode, @@ -53,6 +60,10 @@ def visit(self, node: DataNode) -> str: def visit(self, node: RegisterNode) -> str: return f"${node.number}" + @visitor.when(Constant) + def visit(self, node: Constant) -> str: + return str(node.value) + @visitor.when(LabelDeclaration) def visit(self, node: LabelDeclaration) -> str: return f"{node.idx}:" @@ -89,6 +100,10 @@ def visit(self, node: Move) -> str: def visit(self, node: Subu) -> str: return f"\tsubu {node.left}, {node.middle}, {node.right}" + @visitor.when(Sub) + def visit(self, node: Sub) -> str: + return f"\tsub {node.left}, {node.middle}, {node.right}" + @visitor.when(Addu) def visit(self, node: Addu) -> str: return f"\taddu {node.left}, {node.middle}, {node.right}" @@ -97,6 +112,26 @@ def visit(self, node: Addu) -> str: def visit(self, node: LoadAddress) -> str: return f"\tla {node.left}, {node.right}" + @visitor.when(LoadImmediate) + def visit(self, node: LoadImmediate) -> str: + return f"\tli {node.left}, {node.right}" + @visitor.when(Syscall) def visit(self, node: Syscall) -> str: return f"\tsyscall" + + @visitor.when(Add) + def visit(self, node: Add) -> str: + return f"\tadd {node.left}, {node.middle}, {node.right}" + + @visitor.when(Addi) + def visit(self, node: Addi) -> str: + return f"\taddi {node.left}, {node.middle}, {node.right}" + + @visitor.when(BranchOnEqual) + def visit(self, node: BranchOnEqual) -> str: + return f"\tbeq {node.left}, {node.middle}, {node.right}" + @visitor.when(BranchOnEqual) + + def visit(self, node: BranchOnNotEqual) -> str: + return f"\tbne {node.left}, {node.middle}, {node.right}" From bcdf7a8132b5aeef2de9c514a75a92a2e4c1660d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 13:07:15 -0500 Subject: [PATCH 246/432] Add register in constants.py --- src/code_gen/constants.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index e34a58de4..384be712e 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -3,3 +3,36 @@ CASE_INIT = "init_case" CASE_END = "end_case" CASE_BRANCH = "case_branch" +# Registers +ZERO = 0 +AT = 1 +V0 = 2 +V1 = 3 +A0 = 4 +A1 = 5 +A2 = 6 +A3 = 7 +T0 = 8 +T1 = 9 +T2 = 10 +T3 = 11 +T4 = 12 +T5 = 13 +T6 = 14 +T7 = 15 +S0 = 16 +S1 = 17 +S2 = 18 +S3 = 19 +S4 = 20 +S5 = 21 +S6 = 22 +T7 = 23 +T8 = 24 +T9 = 25 +K0 = 26 +K1 = 27 +GP = 28 +SP = 29 +FP = 30 +RA = 31 From 46d7f855242c633613112e8460bff5e9e69d050d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 14:04:31 -0500 Subject: [PATCH 247/432] Add new nodes to visitor --- src/code_gen/ccil_mips_gen.py | 195 +++++++++++++++++++++++++++++----- 1 file changed, 168 insertions(+), 27 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index ff754318b..fb8a88af6 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -2,6 +2,7 @@ from utils import visitor from asts import mips_ast, ccil_ast from utils import visitor +from constants import * WORD = 4 DOUBLE_WORD = 8 @@ -18,7 +19,7 @@ def __init__(self) -> None: self.__current_function: ccil_ast.FunctionNode def push_stack(self, node, register: mips_ast.RegisterNode): - stack_pointer = mips_ast.RegisterNode(node, 29) + stack_pointer = mips_ast.RegisterNode(node, SP) instructions = [] instructions.append( mips_ast.Addi(node, stack_pointer, stack_pointer, -1 * WORD) @@ -31,7 +32,7 @@ def push_stack(self, node, register: mips_ast.RegisterNode): return instructions def pop_stack(self, node, register: mips_ast.RegisterNode): - stack_pointer = mips_ast.RegisterNode(node, 29) + stack_pointer = mips_ast.RegisterNode(node, SP) instructions = [] instructions.append( mips_ast.LoadWord( @@ -84,9 +85,9 @@ def visit(self, node: ccil_ast.FunctionNode): instructions.append(mips_ast.LabelDeclaration(node, node.id)) frame_size = (len(node.locals)) * WORD + 12 - stack_pointer = mips_ast.RegisterNode(node, 29) - return_address = mips_ast.RegisterNode(node, 31) - frame_pointer = mips_ast.RegisterNode(node, 30) + stack_pointer = mips_ast.RegisterNode(node, SP) + return_address = mips_ast.RegisterNode(node, RA) + frame_pointer = mips_ast.RegisterNode(node, FP) index = 0 for param in reversed(node.locals): @@ -133,14 +134,14 @@ def visit(self, node: ccil_ast.FunctionNode): mips_ast.LoadWord( node, return_address, - mips_ast.MemoryIndexNode(node, frame_size - 8, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - WORD, stack_pointer), ) ) instructions.append( mips_ast.LoadWord( node, frame_pointer, - mips_ast.MemoryIndexNode(node, frame_size - 12, stack_pointer), + mips_ast.MemoryIndexNode(node, frame_size - 3 * WORD, stack_pointer), ) ) instructions.append( @@ -150,6 +151,16 @@ def visit(self, node: ccil_ast.FunctionNode): return instructions + @visitor.when(ccil_ast.StorageNode) + def visit(self, node: ccil_ast.StorageNode): + location_id = self.__location[node.id] + instructions = [] + instructions.append(self.visit(node.operation)) + instructions.append( + mips_ast.StoreWord(node, mips_ast.RegisterNode(node, 2), location_id) + ) + return instructions + @visitor.when(ccil_ast.CallOpNode) def visit(self, node: ccil_ast.CallOpNode): reg = mips_ast.RegisterNode(node, 10) @@ -160,7 +171,7 @@ def visit(self, node: ccil_ast.CallOpNode): instructions.append(mips_ast.JumpAndLink(node, node.id)) if len(node.args) > 0: - stack_pointer = mips_ast.RegisterNode(node, 29) + stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) ) @@ -171,11 +182,11 @@ def visit(self, node: ccil_ast.VCallOpNode): instructions = [] obj_location = self.__location[node.args[0]] - obj_type = mips_ast.RegisterNode(node, 8) + obj_type = mips_ast.RegisterNode(node, T0) instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) - register_function = mips_ast.RegisterNode(node, 9) - function_index = self.get_method_index(node.type, node.id) * WORD + DOUBLE_WORD + register_function = mips_ast.RegisterNode(node, T1) + function_index = self.get_method_index(node.type, node.id) instructions.append( mips_ast.LoadWord( node, @@ -183,7 +194,7 @@ def visit(self, node: ccil_ast.VCallOpNode): mips_ast.MemoryIndexNode(node, function_index, obj_type), ) ) - reg_arg = mips_ast.RegisterNode(node, 10) + reg_arg = mips_ast.RegisterNode(node, T2) instructions = [] for arg in node.args: instructions.append(mips_ast.LoadWord(node, reg_arg, self.__location[arg])) @@ -191,50 +202,180 @@ def visit(self, node: ccil_ast.VCallOpNode): instructions.append(mips_ast.JumpAndLink(node, register_function)) if len(node.args) > 0: - stack_pointer = mips_ast.RegisterNode(node, 29) + stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) ) return instructions - @visitor.when(ccil_ast.StorageNode) - def visit(self, node: ccil_ast.StorageNode): - location_id = self.__location[node.id] + @visitor.when(ccil_ast.NewOpNode) + def visit(self, node: ccil_ast.NewOpNode): + instructions = [] + # TODO: SELF_TYPE + size = self.get_attr_count(node.type_idx) + 2 * WORD + instructions.append( + mips_ast.LoadImmediate( + node, + mips_ast.RegisterNode(node, A0), + mips_ast.Constant(node, str(size)), + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V1), mips_ast.Constant(node, "9") + ) + ) + instructions.append(mips_ast.Syscall(node)) + + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T0), + mips_ast.Label(node, node.type_idx), + ) + ) + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T0), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, "0"), mips_ast.RegisterNode(node, V0) + ), + ) + ) + return instructions + + @visitor.when(ccil_ast.GetAttrOpNode) + def visit(self, node: ccil_ast.GetAttrOpNode): + instructions = [] + attr_offset = self.get_attr_index(node.instance_type, node.attr) + location_object = self.__location[node.instance] + + instructions.append( + mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), location_object) + ) + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, V0), + mips_ast.MemoryIndexNode( + node, + mips_ast.Constant(node, str(attr_offset)), + mips_ast.RegisterNode(node, T0), + ), + ) + ) + + return instructions + + @visitor.when(ccil_ast.GetTypeOpNode) + def visit(self, node: ccil_ast.GetTypeOpNode): instructions = [] - instructions.append(self.visit(node.operation)) instructions.append( - mips_ast.LoadWord(node, mips_ast.RegisterNode(node, 3), location_id) + mips_ast.LoadWord( + node, mips_ast.RegisterNode(node, T0), self.__location[node.atom.value] + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, V0), + mips_ast.MemoryIndexNode(node, 0, mips_ast.RegisterNode(node, T0)), + ) ) return instructions @visitor.when(ccil_ast.SumOpNode) def visit(self, node: ccil_ast.SumOpNode): instructions = [] - reg = mips_ast.RegisterNode(node, 10) - reg_left = mips_ast.RegisterNode(node, 11) - reg_rigth = mips_ast.RegisterNode(node, 12) - left_location = self.__location[node.left.value] - right_location = self.__location[node.left.value] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Add(node, reg_ret, reg_left, reg_right)) return instructions + @visitor.when(ccil_ast.IfFalseNode) + def visit(self, node: ccil_ast.IfFalseNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T0), + self.__location[node.eval_value.value], + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, 9), mips_ast.Constant(node, "0") + ) + ) + instructions.append( + mips_ast.BranchOnEqual( + node, + mips_ast.RegisterNode(node, 9), + mips_ast.RegisterNode(node, T0), + mips_ast.Label(node, node.target.id), + ) + ) + return instructions + + @visitor.when(ccil_ast.GoToNode) + def visit(self, node: ccil_ast.GoToNode): + instructions = [] + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, node.target.id))) + return instructions + + def get_attr_index(self, typex: str, attr: str): + for _type in self.__types_table: + if _type.id == typex: + for index, _attr in enumerate(_type.attributes): + if _attr.id == attr: + return index + WORD + raise Exception(f"Attribute {attr} not found in type {typex}") + + def get_attr_count(self, typex: str): + for _type in self.__types_table: + if _type.id == typex: + return len(_type.attributes) + raise Exception("Type declaration not found") + def get_init_function(self, typex: str): - for _type in self.types_table: + for _type in self.__types_table: if _type.id == typex: return _type.init_operations raise Exception("Type's function for inicialization not found") def get_method_index(self, typex: str, method: str) -> int: - for _type in self.types_table: + for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: - return index + return index * WORD + DOUBLE_WORD raise Exception("Method implementation not found") def get_class_method(self, typex: str, method: str) -> str: - for _type in self.types_table: + for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: From 2614527ad8dbe68dd9c1265da2dd4aabbf82edac Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 14:45:16 -0500 Subject: [PATCH 248/432] Remove node from the constructor of all ccil ast nodes --- src/asts/ccil_ast.py | 89 ++++++++++++++++++---------------------- src/code_gen/ccil_gen.py | 62 +++++++++++++++++----------- 2 files changed, 78 insertions(+), 73 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 10bee9f70..1c8984875 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -70,15 +70,7 @@ class Method: class Node: - def __init__(self, node) -> None: - self.line = 0 - self.col = 0 - if node is not None: - self.line: int = node.line - self.col: int = node.col - - def get_position(self) -> Tuple[int, int]: - return (self.line, self.col) + pass class FunctionNode(Node): @@ -88,14 +80,13 @@ class FunctionNode(Node): def __init__( self, - node, idx: str, params: List[Parameter], locals: List[Local], operations: List[OperationNode], ret: str, ) -> None: - super().__init__(node) + super().__init__() # Function identifier, different than Method identifier self.id = idx # Variable that holds the return value @@ -111,12 +102,12 @@ class OperationNode(Node): Base Class for all operation Nodes """ - def __init__(self, node) -> None: - super().__init__(node) + def __init__(self) -> None: + super().__init__() class StorageNode(OperationNode): - def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: + def __init__(self, idx: str, operation: ReturnOpNode) -> None: """ Node used to store the value of operations done. Parameters: @@ -124,15 +115,13 @@ def __init__(self, node, idx: str, operation: ReturnOpNode) -> None: idx <- Id of this node. opeartion <- The operation this node is storing. """ - super().__init__(node) + super().__init__() self.id = idx self.operation = operation - self.decl_type = node.decl_type class SetAttrOpNode(OperationNode): - def __init__(self, node, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: - super().__init__(node) + def __init__(self, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: self.type = type_id self.attr = attr_id self.source_id = source_id @@ -143,14 +132,16 @@ class Abort(OperationNode): class PrintOpNode(OperationNode): - def __init__(self, node, idx: str) -> None: - super().__init__(node) + def __init__(self, idx: str) -> None: + super().__init__() self.idx = idx class ReturnOpNode(OperationNode): - def __init__(self, node) -> None: - super().__init__(node) + def __init__( + self, + ) -> None: + super().__init__() class ReadOpNode(ReturnOpNode): @@ -162,26 +153,24 @@ class ReadOpNode(ReturnOpNode): class GetAttrOpNode(ReturnOpNode): - def __init__( - self, node, instance_type_id: str, instance_id: str, attr_id: str - ) -> None: - super().__init__(node) + def __init__(self, instance_type_id: str, instance_id: str, attr_id: str) -> None: + super().__init__() self.instance_type = instance_type_id self.instance = instance_id self.attr = attr_id class CallOpNode(ReturnOpNode): - def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: - super().__init__(node) + def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: + super().__init__() self.id = idx self.type = type_idx self.args = args class VCallOpNode(ReturnOpNode): - def __init__(self, node, idx: str, type_idx: str, args: List[str]) -> None: - super().__init__(node) + def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: + super().__init__() self.id = idx self.type = type_idx self.args = args @@ -194,20 +183,20 @@ class VoidNode(ReturnOpNode): class NewOpNode(ReturnOpNode): - def __init__(self, node, type_idx: str) -> None: - super().__init__(node) + def __init__(self, type_idx: str) -> None: + super().__init__() self.type_idx: str = type_idx class BinaryOpNode(ReturnOpNode): - def __init__(self, node, left: AtomOpNode, right: AtomOpNode) -> None: + def __init__(self, left: AtomOpNode, right: AtomOpNode) -> None: """ Node that represents all binary operation Parameters: left <- Left atomic node. right <- Right atomic node. """ - super().__init__(node) + super().__init__() self.left = left self.right = right @@ -241,8 +230,8 @@ class LessOpNode(BinaryOpNode): class UnaryOpNode(ReturnOpNode): - def __init__(self, node, atom: AtomOpNode) -> None: - super().__init__(node) + def __init__(self, atom: AtomOpNode) -> None: + super().__init__() self.atom = atom @@ -267,8 +256,8 @@ class NegOpNode(UnaryOpNode): class ChainOpNode(ReturnOpNode): - def __init__(self, node, target: str) -> None: - super().__init__(node) + def __init__(self, target: str) -> None: + super().__init__() self.target = target @@ -285,11 +274,11 @@ class StrOpNode(ChainOpNode): class AtomOpNode(ReturnOpNode): - def __init__(self, node, value: str) -> None: + def __init__(self, value: str) -> None: """ AtomNode represents all single value nodes, like ids and constants """ - super().__init__(node) + super().__init__() self.value = value @@ -318,28 +307,28 @@ def __init__(self, node) -> None: class IfNode(FlowControlNode): - def __init__(self, node, eval_value: AtomOpNode, target: LabelNode) -> None: - super().__init__(node) + def __init__(self, eval_value: AtomOpNode, target: LabelNode) -> None: + super().__init__() self.eval_value = eval_value self.target = target class IfFalseNode(IfNode): - def __init__(self, node, eval_value: AtomOpNode, target: LabelNode) -> None: - super().__init__(node, eval_value, target) + def __init__(self, eval_value: AtomOpNode, target: LabelNode) -> None: + super().__init__(eval_value, target) class GoToNode(FlowControlNode): - def __init__(self, node, target: LabelNode) -> None: - super().__init__(node) + def __init__(self, target: LabelNode) -> None: + super().__init__() self.target = target class LabelNode(FlowControlNode): - def __init__(self, node, idx: str) -> None: - super().__init__(node) + def __init__(self, idx: str) -> None: + super().__init__() self.id = idx -def extract_id(node, storage_node: StorageNode) -> IdNode: - return IdNode(node, storage_node.id) +def extract_id(storage_node: StorageNode) -> IdNode: + return IdNode(storage_node.id) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5c6e93b7b..3d63c8649 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -16,7 +16,13 @@ # The result of (type of) what is it # How to handle void nodes -# Define abort nodes with a text +# Define abort nodes with a text: +# * Dispacth on a void class +# * No pattern match in case +# * Division by zero +# * Substring out of range +# * Heap Overflow (don't know yet how to handle this) + # Add text dynamically .data function, incluiding error messages # Test there are no runtimes errors @@ -517,18 +523,16 @@ def times(self, node: sem_ast.Node, extra: str = ""): def create_call( self, - node, storage_idx: str, type_idx: str, method_idx: str, args: List[StorageNode], ): self.add_local(storage_idx, type_idx) - return StorageNode(node, storage_idx, CallOpNode(node, method_idx, args)) + return StorageNode( storage_idx, CallOpNode( method_idx, args)) def create_vcall( self, - node, storage_idx: str, type_idx: str, method_idx: str, @@ -537,46 +541,58 @@ def create_vcall( ): self.add_local(storage_idx, type_idx) return StorageNode( - node, storage_idx, VCallOpNode(node, method_idx, method_type_idx, args) + storage_idx, VCallOpNode( method_idx, method_type_idx, args) ) - def create_assignation(self, node, idx: str, type_idx: str, target: str): + def define_built_ins(self): + self.reset_scope() + self.reset_locals() + + params = self.init_func_params() + abort_msg = Data("abort_msg", "Execution aborted") + + load = self.create_string_load_data() + + def init_func_params(self, typex: str): + return [Parameter("self", typex)] + + def create_assignation(self, idx: str, type_idx: str, target: str): self.add_local(idx, type_idx) - return StorageNode(node, idx, IdNode(node, target)) + return StorageNode( idx, IdNode( target)) - def create_uninitialized_storage(self, node, idx: str, type_idx: str): + def create_uninitialized_storage(self, idx: str, type_idx: str): self.add_local(idx, type_idx) - return StorageNode(node, idx, VoidNode(node)) + return StorageNode( idx, VoidNode()) - def create_storage(self, node, idx: str, type_idx: str, op: ReturnOpNode): + def create_storage(self, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) - return StorageNode(node, idx, op) + return StorageNode( idx, op) def create_attr_extraction( - self, node, idx: str, type_idx: str, from_idx: str, attr_idx: str + self, idx: str, type_idx: str, from_idx: str, attr_idx: str ): self.add_local(idx, type_idx) - return StorageNode(node, idx, GetAttrOpNode(node, from_idx, attr_idx)) + return StorageNode( idx, GetAttrOpNode( from_idx, attr_idx)) - def create_new_type(self, node, idx: str, type_idx: str): + def create_new_type(self, idx: str, type_idx: str): self.add_local(idx, type_idx) - return StorageNode(node, idx, NewOpNode(node, type_idx)) + return StorageNode( idx, NewOpNode( type_idx)) - def create_type_of(self, node, idx: str, target: AtomOpNode): + def create_type_of(self, idx: str, target: AtomOpNode): self.add_local(idx, ADDRESS) - return StorageNode(node, idx, GetTypeOpNode(node, target)) + return StorageNode( idx, GetTypeOpNode( target)) - def create_equality(self, node, idx, left: AtomOpNode, right: AtomOpNode): + def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): self.add_local(idx, BOOL) - return StorageNode(node, idx, EqualOpNode(node, left, right)) + return StorageNode( idx, EqualOpNode( left, right)) - def create_string_load_data(self, node, idx: str, target: str): + def create_string_load_data(self, idx: str, target: str): self.add_local(idx, STRING) - return StorageNode(node, idx, LoadOpNode(node, target)) + return StorageNode( idx, LoadOpNode( target)) - def create_int(self, node, idx: str, value: str): + def create_int(self, idx: str, value: str): self.add_local(idx, INT) - return StorageNode(node, idx, IntNode(node, value)) + return StorageNode( idx, IntNode( value)) def update_locals(self, old_id: str, new_id: str): self.locals[new_id] = self.locals[old_id] From 94d12d8a32e6c8c73c8b9af2a57d8d52afb79237 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 16:10:21 -0500 Subject: [PATCH 249/432] Add Multiply node --- src/asts/mips_ast.py | 21 +++++++++-- src/code_gen/ccil_mips_gen.py | 70 +++++++++++++++++++++++++++++++++++ src/code_gen/mips_gen.py | 7 +++- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 2b8c7ffa2..18edbd945 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -51,14 +51,17 @@ def __init__( self.data = [] self.data = data + class Constant(Node): """ - This class represents a literal integer in MIPS + This class represents a literal integer in MIPS """ - def __init__(self, node, value : str) -> None: + + def __init__(self, node, value: str) -> None: super().__init__(node) self.value = value + class RegisterNode(Node): """ This class represents a 4-bytes MIPS' register @@ -120,6 +123,13 @@ def __init__(self, node, left, middle, right) -> None: self.right = right +class Multiply(TernaryOpNode): + """ + This node represents `mul` instruction in MIPS + """ + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + class Subu(TernaryOpNode): """ This node represents `subu` instruction in MIPS @@ -182,6 +192,7 @@ class LoadImmediate(BinaryOpNode): def __init__(self, node, left, right) -> None: super().__init__(node, left, right) + class LoadWord(BinaryOpNode): """ This node represents `lw` instruction in MIPS @@ -238,20 +249,25 @@ def __init__(self, node, address) -> None: super().__init__(node) self.address = address + class BranchOnEqual(TernaryOpNode): """ This node represents `beq` instruction in MIPS """ + def __init__(self, node, left, middle, right) -> None: super().__init__(node, left, middle, right) + class BranchOnNotEqual(TernaryOpNode): """ This node represents `bne` instruction in MIPS """ + def __init__(self, node, left, middle, right) -> None: super().__init__(node, left, middle, right) + class AssemblerDirective(Node): def __init__(self, node, list) -> None: super().__init__(node) @@ -276,4 +292,3 @@ class Syscall(InstructionNode): def __init__(self, node) -> None: super().__init__(node) - diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index fb8a88af6..f271db198 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -286,6 +286,18 @@ def visit(self, node: ccil_ast.GetTypeOpNode): ) return instructions + @visitor.when(ccil_ast.SetAttrOpNode) + def visist(self, node: ccil_ast.SetAttrOpNode): + instructions = [] + + # TODO missing object location + attr_offset = self.get_attr_index(node.type, node.attr) + object_location = self.__location[node.source_id.value] + + instructions.append( + mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), object_location) + ) + @visitor.when(ccil_ast.SumOpNode) def visit(self, node: ccil_ast.SumOpNode): instructions = [] @@ -315,6 +327,64 @@ def visit(self, node: ccil_ast.SumOpNode): return instructions + @visitor.when(ccil_ast.MinusOpNode) + def visit(self, node: ccil_ast.MinusOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Sub(node, reg_ret, reg_left, reg_right)) + + return instructions + + @visitor.when(ccil_ast.MultOpNode) + def visit(self, node: ccil_ast.MultOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Multiply(node, reg_ret, reg_left, reg_right)) + + return instructions + @visitor.when(ccil_ast.IfFalseNode) def visit(self, node: ccil_ast.IfFalseNode): instructions = [] diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 89b6aff8c..529d99ebb 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -15,6 +15,8 @@ MIPSProgram, MemoryIndexNode, Move, + Multiply, + MultiplyOpNode, RegisterNode, Sub, Subu, @@ -128,10 +130,13 @@ def visit(self, node: Add) -> str: def visit(self, node: Addi) -> str: return f"\taddi {node.left}, {node.middle}, {node.right}" + @visitor.when(Multiply) + def visit(self, node: Multiply) -> str: + @visitor.when(BranchOnEqual) def visit(self, node: BranchOnEqual) -> str: return f"\tbeq {node.left}, {node.middle}, {node.right}" - @visitor.when(BranchOnEqual) + @visitor.when(BranchOnEqual) def visit(self, node: BranchOnNotEqual) -> str: return f"\tbne {node.left}, {node.middle}, {node.right}" From 9d8646fa0659209da21f3c0238bbbcf55676daf2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 17:14:40 -0500 Subject: [PATCH 250/432] Add more operation nodes to ccil ast --- src/asts/ccil_ast.py | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 1c8984875..bf001691d 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -144,14 +144,20 @@ def __init__( super().__init__() -class ReadOpNode(ReturnOpNode): +class ReadStrNode(ReturnOpNode): """ - This nodes reads input from the standard input" + This nodes reads a string from the standard input """ pass +class ReadIntNode(ReturnOpNode): + """ + This nodes reads an int from the standard input + """ + + class GetAttrOpNode(ReturnOpNode): def __init__(self, instance_type_id: str, instance_id: str, attr_id: str) -> None: super().__init__() @@ -273,6 +279,19 @@ class StrOpNode(ChainOpNode): pass +class ConcatOpNode(ChainOpNode): + def __init__(self, source: str, target: str) -> None: + super().__init__(target) + self.source = source + + +class SubstringOpNode(ReturnOpNode): + def __init__(self, start: AtomOpNode, length: AtomOpNode) -> None: + super().__init__() + self.start = start + self.length = length + + class AtomOpNode(ReturnOpNode): def __init__(self, value: str) -> None: """ @@ -283,18 +302,18 @@ def __init__(self, value: str) -> None: class IdNode(AtomOpNode): - def __init__(self, node, value: str) -> None: - super().__init__(node, value) + def __init__(self, value: str) -> None: + super().__init__(value) class ConstantNode(AtomOpNode): - def __init__(self, node, value: str) -> None: - super().__init__(node, value) + def __init__(self, value: str) -> None: + super().__init__(value) class IntNode(ConstantNode): - def __init__(self, node, value: str) -> None: - super().__init__(node, value) + def __init__(self, value: str) -> None: + super().__init__(value) class FlowControlNode(OperationNode): @@ -306,6 +325,11 @@ def __init__(self, node) -> None: super().__init__(node) +class CurrentTypeNameNode(ReturnOpNode): + def __init__(self) -> None: + super().__init__() + + class IfNode(FlowControlNode): def __init__(self, eval_value: AtomOpNode, target: LabelNode) -> None: super().__init__() From 261dadfac9de5c83dadcd5921ab6ea29a2ca26e9 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 17:15:11 -0500 Subject: [PATCH 251/432] Add definition for built in classess --- src/code_gen/ccil_gen.py | 215 ++++++++++++++++++++++++++++++++++----- 1 file changed, 190 insertions(+), 25 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 3d63c8649..47d1afb52 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict +from typing import IO, Tuple, List, Dict from code_gen.tools import * from constants import * @@ -69,6 +69,7 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.current_type = node.id + self.add_data(f"class_{node.id}", node.id) attr_nodes = [] func_nodes = [] @@ -529,7 +530,7 @@ def create_call( args: List[StorageNode], ): self.add_local(storage_idx, type_idx) - return StorageNode( storage_idx, CallOpNode( method_idx, args)) + return StorageNode(storage_idx, CallOpNode(method_idx, args)) def create_vcall( self, @@ -540,59 +541,223 @@ def create_vcall( args: List[StorageNode], ): self.add_local(storage_idx, type_idx) - return StorageNode( - storage_idx, VCallOpNode( method_idx, method_type_idx, args) - ) + return StorageNode(storage_idx, VCallOpNode(method_idx, method_type_idx, args)) def define_built_ins(self): self.reset_scope() self.reset_locals() + params = self.init_func_params(OBJECT) + abort_msg = self.add_data("abort_msg", "Execution aborted") + load = self.create_string_load_data("abort_temp", abort_msg.id) + [print, abort] = self.notifiy_and_abort(load.id) + abort_func = FunctionNode( + "abort", params, to_vars(self.locals), [load, print, abort], "self" + ) + self.reset_locals() + params = self.init_func_params(OBJECT) + get_name = self.create_current_type_name("get_name") + type_name_func = FunctionNode( + "type_name", params, self.locals, [get_name], get_name.id + ) + self.reset_locals() + params = self.init_func_params(OBJECT) + new_instance = self.create_new_type("copy", SELFTYPE) + copy_func = FunctionNode( + "copy", params, to_vars(self.locals), [new_instance], new_instance.id + ) + object_class = Class( + OBJECT, + [], + [ + Method("abort", abort_func), + Method("type_name", type_name_func), + Method("copy", copy_func), + ], + ) - params = self.init_func_params() - abort_msg = Data("abort_msg", "Execution aborted") + self.reset_scope() + self.reset_locals() + params = self.init_func_params(IO) + str_input = Parameter("x", STRING) + params.append(str_input) + print = PrintOpNode(str_input.id) + out_string_func = FunctionNode( + "out_string", params, to_vars(self.locals), [print], "self" + ) + self.reset_locals() + params = self.init_func_params(IO) + int_input = Parameter("x", INT) + params.append(int_input) + int_to_str = self.create_int_to_str("int_to_str", int_input.id) + print = PrintOpNode(int_to_str.id) + out_int_func = FunctionNode( + "out_int", params, to_vars(self.locals), [int_to_str, print], "self" + ) + self.reset_locals() + params = self.init_func_params(IO) + read = self.create_read_str("read_str") + in_string_func = FunctionNode("in_string", params, self.locals, [read], read.id) + self.reset_locals() + params = self.init_func_params(IO) + read = self.create_read_int("read_int") + in_int_func = FunctionNode("in_int", params, self.locals, [read], read.id) + io_class = Class( + IO, + [], + [ + Method("out_string", out_string_func), + Method("out_int", out_int_func), + Method("in_string", in_string_func), + Method("in_int", in_int_func), + ], + ) - load = self.create_string_load_data() + self.reset_scope() + self.reset_locals() + params = self.init_func_params(STRING) + length = self.create_length("lenght_var", "self") + lenght_func = FunctionNode("length", params, self.locals, [length], length.id) + self.reset_locals() + params = self.init_func_params(STRING) + input_s = Parameter("s", STRING) + params.append(input_s) + concat = self.create_storage( + "concat_var", STRING, ConcatOpNode("self", input_s.id) + ) + concat_func = FunctionNode("concat", params, self.locals, [concat], concat.id) + self.reset_locals() + params = self.init_func_params(STRING) + start_index = Parameter("s", INT) + take = Parameter("l", INT) + params += [start_index, take] + length = self.create_length("length_var", "self") + max_take = self.create_storage( + "max_take", INT, SumOpNode(IdNode(start_index.id), IdNode(take.id)) + ) + upper_bound = self.create_storage( + "upper_bound", LessOpNode(extract_id(length), extract_id(max_take)) + ) + lesser_bound = self.create_storage( + "lesser_bound", LessOpNode(IdNode(start_index.id), IntNode("0")) + ) + error_label = LabelNode("substring_error") + ok_label = LabelNode("substring_success") + if_upper_bound = IfNode(extract_id(upper_bound), error_label) + if_lesser_bound = IfNode(extract_id(lesser_bound), error_label) + print_and_abort = self.notifiy_and_abort("Index out of range exception") + substr = self.create_storage( + "substr_var", + STRING, + SubstringOpNode(IdNode(start_index.id), IdNode(take.id)), + ) + goto_ok = GoToNode(ok_label) + operations = [ + length, + max_take, + upper_bound, + lesser_bound, + if_upper_bound, + if_lesser_bound, + substr, + goto_ok, + error_label, + *print_and_abort, + ok_label, + ] + substr_func = FunctionNode("substr", params, self.locals, operations, substr.id) + string_class = Class( + STRING, + [], + [ + Method("length", lenght_func), + Method("concat", concat_func), + Method("substr", substr_func), + ], + ) + + return [object_class, io_class, string_class], [ + abort_func, + type_name_func, + copy_func, + out_string_func, + out_int_func, + in_string_func, + in_int_func, + lenght_func, + concat_func, + substr_func, + ] def init_func_params(self, typex: str): return [Parameter("self", typex)] def create_assignation(self, idx: str, type_idx: str, target: str): self.add_local(idx, type_idx) - return StorageNode( idx, IdNode( target)) + return StorageNode(idx, IdNode(target)) - def create_uninitialized_storage(self, idx: str, type_idx: str): + def create_uninitialized_storage(self, idx: str, type_idx: str): self.add_local(idx, type_idx) - return StorageNode( idx, VoidNode()) + return StorageNode(idx, VoidNode()) - def create_storage(self, idx: str, type_idx: str, op: ReturnOpNode): + def create_storage(self, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) - return StorageNode( idx, op) + return StorageNode(idx, op) def create_attr_extraction( - self, idx: str, type_idx: str, from_idx: str, attr_idx: str + self, idx: str, type_idx: str, from_idx: str, attr_idx: str ): self.add_local(idx, type_idx) - return StorageNode( idx, GetAttrOpNode( from_idx, attr_idx)) + return StorageNode(idx, GetAttrOpNode(from_idx, attr_idx)) - def create_new_type(self, idx: str, type_idx: str): + def create_new_type(self, idx: str, type_idx: str): self.add_local(idx, type_idx) - return StorageNode( idx, NewOpNode( type_idx)) + return StorageNode(idx, NewOpNode(type_idx)) - def create_type_of(self, idx: str, target: AtomOpNode): + def create_type_of(self, idx: str, target: AtomOpNode): self.add_local(idx, ADDRESS) - return StorageNode( idx, GetTypeOpNode( target)) + return StorageNode(idx, GetTypeOpNode(target)) - def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): + def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): self.add_local(idx, BOOL) - return StorageNode( idx, EqualOpNode( left, right)) + return StorageNode(idx, EqualOpNode(left, right)) + + def notifiy_and_abort(self, target: str): + print = PrintOpNode(target) + abort = Abort() + return [print, abort] - def create_string_load_data(self, idx: str, target: str): + def create_string_load_data(self, idx: str, target: str): self.add_local(idx, STRING) - return StorageNode( idx, LoadOpNode( target)) + return StorageNode(idx, LoadOpNode(target)) - def create_int(self, idx: str, value: str): + def create_int(self, idx: str, value: str): self.add_local(idx, INT) - return StorageNode( idx, IntNode( value)) + return StorageNode(idx, IntNode(value)) + + def create_int_to_str(self, idx: str, target: str): + self.add_local(str, STRING) + return StorageNode(idx, StrOpNode(target)) + + def create_read_str(self, idx: str): + self.add_local(idx, STRING) + return StorageNode(idx, ReadStrNode()) + + def create_read_int(self, idx: str): + self.add_local(idx, INT) + return StorageNode(idx, ReadIntNode()) + + def create_current_type_name(self, idx: str): + self.add_local(idx, STRING) + return StorageNode(idx, CurrentTypeNameNode()) + + def create_length(self, idx: str, target: str): + self.add_local(idx, INT) + return StorageNode(idx, LengthOpNode(target)) + + def add_data(self, idx: str, value: str): + data = Data(idx, value) + self.data.append(data) + return data def update_locals(self, old_id: str, new_id: str): self.locals[new_id] = self.locals[old_id] From 86a03c2eeed3605b3d6485f547d0640c2c2b0d18 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 17:23:14 -0500 Subject: [PATCH 252/432] Bug fixing and minor changes --- src/code_gen/ccil_gen.py | 48 +++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 47d1afb52..797e2ec9a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -12,19 +12,15 @@ METHOD_VISITOR_RESULT = FunctionNode # TODO: -# Define cool built in methods -# The result of (type of) what is it -# How to handle void nodes - # Define abort nodes with a text: # * Dispacth on a void class # * No pattern match in case # * Division by zero -# * Substring out of range +# * Substring out of range (Done) # * Heap Overflow (don't know yet how to handle this) -# Add text dynamically .data function, incluiding error messages +# BOSS: # Test there are no runtimes errors # Test that results are obtained as expected @@ -171,7 +167,7 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: block_val = fvalues[-1] fval_id = f"block_{times}" - fval = self.create_assignation(node, fval_id, node.type.name, block_val.id) + fval = self.create_assignation( fval_id, node.type.name, block_val.id) operations.append(fval) return (operations, fval) @@ -247,7 +243,7 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: then_fval.id = else_fval.id = pre_fvalue_id fvalue_id = f"if_{times}_fv" - fvalue = self.create_assignation(node, fvalue_id, node.type.name, pre_fvalue_id) + fvalue = self.create_assignation( fvalue_id, node.type.name, pre_fvalue_id) return ( [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], @@ -263,7 +259,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Storing the type of the resulting case expression type_of = self.create_type_of( - node, f"case_{times}_typeOf", extract_id(node, case_expr_fv) + f"case_{times}_typeOf", extract_id(node, case_expr_fv) ) # Final label where all branch must jump to @@ -281,20 +277,19 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Initializing the branch var branch_var_id = f"case_{times}_option_{i}" branch_var = self.create_uninitialized_storage( - option, branch_var_id, option.branch_type.name + branch_var_id, option.branch_type.name ) # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" branch_var_type_of = self.create_type_of( - option, branch_var_type_id, extract_id(node, branch_var) + branch_var_type_id, extract_id(node, branch_var) ) # Initializng var which holds the comparison result between # the case expression type of and branch var type of select_branch_id = f"case_{times}_optionSelect_{i}" select_branch = self.create_equality( - option, select_branch_id, extract_id(node, type_of), extract_id(node, branch_var_type_of), @@ -320,7 +315,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Merging all expression operations in correct order # and saving all to final value fval_id = f"case_{times}_fv" - fval = self.create_assignation(node, fval_id, node.type.name, pre_fvalue_id) + fval = self.create_assignation( fval_id, node.type.name, pre_fvalue_id) operations = [ *case_expr_ops, type_of, @@ -348,7 +343,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) - fval = self.create_uninitialized_storage(node, f"loop_{times}_fv", VOID) + fval = self.create_uninitialized_storage( f"loop_{times}_fv", VOID) # Loop Nodes have void return type, how to express it?? return ( [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], @@ -394,7 +389,7 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure visiting binary expression") - fval = self.create_storage(node, fval_id, node.type.id, op) + fval = self.create_storage( fval_id, node.type.id, op) return ([*left_ops, *right_ops, fval], fval) @visitor.when(sem_ast.UnaryNode) @@ -419,7 +414,7 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure while visiting unary expression") - fval = self.create_storage(node, fval_id, node.type.id, op) + fval = self.create_storage( fval_id, node.type.id, op) return [*expr_op, fval], fval @visitor.when(sem_ast.MethodCallNode) @@ -439,7 +434,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.expr is None: fval_id = f"vcall_{times}" call = self.create_vcall( - node, fval_id, node.type.id, node.id, node.caller_type.name + fval_id, node.type.id, node.id, node.caller_type.name ) return [*args_ops, call], call @@ -449,13 +444,13 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.at_type is not None: fval_id = f"call_{times}" call = self.create_call( - node, fval_id, node.type.name, node.id, node.caller_type.name + fval_id, node.type.name, node.id, node.caller_type.name ) return [*args_ops, *expr_ops, call] # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" - call = self.create_vcall(node, fval_id, node.type.id, node.id, node.caller_type) + call = self.create_vcall( fval_id, node.type.id, node.id, node.caller_type) return [*args_ops, *expr_ops, call] @@ -464,7 +459,7 @@ def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: times = self.times(node) fvalue_id = f"newType_{times}" - fvalue = self.create_new_type(node, fvalue_id, node.type.name) + fvalue = self.create_new_type( fvalue_id, node.type.name) return [fvalue], fvalue @@ -477,11 +472,11 @@ def visit(self, node: sem_ast.VariableNode) -> VISITOR_RESULT: if is_attr: get_attr = self.create_attr_extraction( - node, id_id, node.type.name, "self", ccil_id + id_id, node.type.name, "self", ccil_id ) return [get_attr], get_attr - fval = self.create_assignation(node, id_id, node.type.name, ccil_id) + fval = self.create_assignation( id_id, node.type.name, ccil_id) return [fval], fval @visitor.when(sem_ast.StringNode) @@ -492,7 +487,7 @@ def visit(self, node: sem_ast.StringNode) -> VISITOR_RESULT: self.data.append(Data(data_id, node.value)) load_id = f"load_str_{times}" - load_str = self.create_string_load_data(node, load_id, data_id) + load_str = self.create_string_load_data( load_id, data_id) return [load_str], load_str @visitor.when(sem_ast.IntNode) @@ -500,7 +495,7 @@ def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: times = self.times(node) int_id = f"int_{times}" - int_node = self.create_int(node, int_id, node.value) + int_node = self.create_int( int_id, node.value) return [int_node], int_node @@ -511,7 +506,7 @@ def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: bool_id = f"bool_{times}" value = "0" if node.value == "False" else "1" - bool_node = self.create_int(node, bool_id, value) + bool_node = self.create_int( bool_id, value) return [bool_node], bool_node def times(self, node: sem_ast.Node, extra: str = ""): @@ -544,6 +539,7 @@ def create_vcall( return StorageNode(storage_idx, VCallOpNode(method_idx, method_type_idx, args)) def define_built_ins(self): + # Defining Object class methods self.reset_scope() self.reset_locals() params = self.init_func_params(OBJECT) @@ -575,6 +571,7 @@ def define_built_ins(self): ], ) + # Defining IO class methods self.reset_scope() self.reset_locals() params = self.init_func_params(IO) @@ -612,6 +609,7 @@ def define_built_ins(self): ], ) + # Defining substring class methods self.reset_scope() self.reset_locals() params = self.init_func_params(STRING) From 608a0ebef7abfec2247d937e04611155828748b3 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 18:32:19 -0500 Subject: [PATCH 253/432] Add more nodes to CCILToMIPSGenerator --- src/asts/mips_ast.py | 56 ++++++++++++ src/code_gen/ccil_mips_gen.py | 156 ++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 18edbd945..ea6dd9a22 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -123,13 +123,69 @@ def __init__(self, node, left, middle, right) -> None: self.right = right +class Div(BinaryOpNode): + """ + This node represents `div` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + +class Xori(TernaryOpNode): + """ + This node represents `xori` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + +class Not(BinaryOpNode): + """ + This node represents `not` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + +class Equal(TernaryOpNode): + """ + This node represents `seq` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + +class LessOrEqual(TernaryOpNode): + """ + This node represents `sle` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + +class Less(TernaryOpNode): + """ + This node represents `slt` instruction in MIPS + """ + + def __init__(self, node, left, middle, right) -> None: + super().__init__(node, left, middle, right) + + class Multiply(TernaryOpNode): """ This node represents `mul` instruction in MIPS """ + def __init__(self, node, left, middle, right) -> None: super().__init__(node, left, middle, right) + class Subu(TernaryOpNode): """ This node represents `subu` instruction in MIPS diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index f271db198..6e05cb0d5 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -385,6 +385,162 @@ def visit(self, node: ccil_ast.MultOpNode): return instructions + @visitor.when(ccil_ast.DivOpNode) + def visit(self, node: ccil_ast.DivOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Div(node, reg_left, reg_right)) + instructions.append( + mips_ast.Move(node, reg_ret, mips_ast.RegisterNode(node, "lo")) + ) + return instructions + + @visitor.when(ccil_ast.LessOpNode) + def visit(self, node: ccil_ast.LessOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Less(node, reg_ret, reg_left, reg_right)) + + return instructions + + @visitor.when(ccil_ast.LessOrEqualOpNode) + def visit(self, node: ccil_ast.LessOrEqualOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.LessOrEqual(node, reg_ret, reg_left, reg_right)) + + return instructions + + @visitor.when(ccil_ast.EqualOpNode) + def visit(self, node: ccil_ast.EqualOpNode): + instructions = [] + + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate(node, reg_right, node.right.value) + ) + else: + raise Exception("Invalid type of ccil node") + + reg_ret = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.Equal(node, reg_ret, reg_left, reg_right)) + + return instructions + + @visitor.when(ccil_ast.NotOpNode) + def visit(self, node: ccil_ast.NotOpNode): + instructions = [] + + reg = mips_ast.RegisterNode(node, V0) + if isinstance(node.atom, ccil_ast.IntNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg, mips_ast.Constant(node, node.atom.value) + ) + ) + elif isinstance(node.atom, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg, self.__location[node.atom.value]) + ) + instructions.append(mips_ast.Not(node, reg, reg)) + + return instructions + + @visitor.when(ccil_ast.NegOpNode) + def visit(self, node: ccil_ast.NegOpNode): + instructions = [] + + reg = mips_ast.RegisterNode(node, V0) + if isinstance(node.atom, ccil_ast.IntNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg, mips_ast.Constant(node, node.atom.value) + ) + ) + elif isinstance(node.atom, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg, self.__location[node.atom.value]) + ) + instructions.append(mips_ast.Xori(node, reg, reg, mips_ast.Constant(node, "1"))) + + return instructions + @visitor.when(ccil_ast.IfFalseNode) def visit(self, node: ccil_ast.IfFalseNode): instructions = [] From 217dcf3d63598535e287b567696a3c1c8b6bc5e4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 18:44:26 -0500 Subject: [PATCH 254/432] Bug fixing --- src/code_gen/ccil_gen.py | 16 +++++++--------- src/code_gen/tools.py | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 797e2ec9a..47ddd15d6 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -4,7 +4,7 @@ from typing import IO, Tuple, List, Dict from code_gen.tools import * -from constants import * +from code_gen.constants import * # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] @@ -48,7 +48,7 @@ def __init__(self) -> None: self.ccil_cool_names: Scope @visitor.on("node") - def visit(self, _): + def visit(self, node): pass @visitor.when(sem_ast.ProgramNode) @@ -58,7 +58,7 @@ def visit(self, node: sem_ast.ProgramNode) -> None: for type in node.declarations: classx, class_code = self.visit(type) program_types.append(classx) - program_codes.append(class_code) + program_codes += class_code return CCILProgram(program_types, program_codes, self.data) @@ -87,7 +87,6 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Return type is set as itself? Use selftype maybe? init_func = FunctionNode( - node, f"init_{node.id}", [], to_vars(self.locals, Parameter), @@ -98,7 +97,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Explore all functions self.reset_scope() self.ccil_cool_names.add_new_names( - (n.id, a.id) for (n, a) in zip(attr_nodes, attributes) + *[(n.id, a.id) for (n, a) in zip(attr_nodes, attributes)] ) class_code: List[FunctionNode] = [] methods: List[Method] = [] @@ -107,7 +106,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: class_code.append(f) methods.append(Method(func.id, f)) - return (Class(attributes, methods, init_func), class_code) + return (Class(node.id, attributes, methods, init_func), class_code) @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: @@ -145,7 +144,6 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - node, f"f_{times}", params, to_vars(self.locals, Parameter), @@ -775,8 +773,8 @@ def reset_locals(self): self.defined_vars = set() def reset_scope(self): - self.scope = Scope() + self.ccil_cool_names = Scope() def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: - return list(map(lambda x: const(*x), dict.items().mapping())) + return list(map(lambda x: const(*x), dict.items())) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 6a3870530..8f92c80c1 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -1,5 +1,4 @@ from __future__ import annotations -from dataclasses import dataclass from typing import Dict, List, Tuple @@ -18,6 +17,7 @@ def get_parent(self): def create_child(self): self.children.append(Scope()) + self.children[-1].parent = self return self.children[-1] def add_new_name_pair(self, key: str, value: str): From bcf6b4d17216eb19aa898115c8a5388ee6672716 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 18:44:45 -0500 Subject: [PATCH 255/432] Add string representation to some ccil nodes --- src/asts/ccil_ast.py | 71 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index bf001691d..06f2d4175 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from typing import Dict, List, Tuple -from code_gen.tools import Attribute, Method from semantics.tools.type import Type @@ -14,6 +13,12 @@ class CCILProgram: code_section: List[FunctionNode] data_section: List[str] # no idea what will be this the node, + def __str__(self) -> str: + types = "\n".join(str(type) for type in self.types_section) + data = "\n".join(str(data) for data in self.data_section) + code = "\n".join(str(func) for func in self.code_section) + return f"TYPES:\n{types}\nDATA:\n{data}\nCODE:\n{code} " + @dataclass(frozen=True) class Class: @@ -26,6 +31,11 @@ class Class: methods: List[Method] init_operations: FunctionNode + def __str__(self) -> str: + attributes = "\n".join(str(a) for a in self.attributes) + methods = "\n".join(str(m) for m in self.methods) + return f"\ttype {self.id} {{ {attributes} \n {methods} \n\t}}" + @dataclass(frozen=True) class BaseVar: @@ -36,17 +46,23 @@ class BaseVar: id: str type: str + def __str__(self) -> str: + return f"{self.id} : {self.type}" + class Attribute(BaseVar): - pass + def __str__(self) -> str: + return "\t\tattr " + super().__str__() class Parameter(BaseVar): - pass + def __str__(self) -> str: + return "\t\tparam " + super().__str__() class Local(BaseVar): - pass + def __str__(self) -> str: + return "\t\tlocal " + super().__str__() @dataclass(frozen=True) @@ -58,6 +74,9 @@ class Data: id: str value: str + def __str__(self) -> str: + return f"\t{self.id} : '{self.value}'" + @dataclass(frozen=True) class Method: @@ -68,6 +87,9 @@ class Method: id: str function: FunctionNode + def __str__(self) -> str: + return f"\t\tmethod {self.id} : {self.function.id}" + class Node: pass @@ -96,6 +118,13 @@ def __init__( self.locals = locals self.operations = operations + def __str__(self) -> str: + params = "\n".join(str(p) for p in self.params) + locals = "\n".join(str(l) for l in self.locals) + ops = "\n".join(str(o) for o in self.operations) + + return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops}" + class OperationNode(Node): """ @@ -119,6 +148,9 @@ def __init__(self, idx: str, operation: ReturnOpNode) -> None: self.id = idx self.operation = operation + def __str__(self) -> str: + return f"\t\t{self.id} = {str(self.operation)}" + class SetAttrOpNode(OperationNode): def __init__(self, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: @@ -128,13 +160,17 @@ def __init__(self, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: class Abort(OperationNode): - pass + def __str__(self) -> str: + return "abort" class PrintOpNode(OperationNode): def __init__(self, idx: str) -> None: super().__init__() - self.idx = idx + self.id = idx + + def __str__(self) -> str: + return f"print {self.id}" class ReturnOpNode(OperationNode): @@ -284,6 +320,9 @@ def __init__(self, source: str, target: str) -> None: super().__init__(target) self.source = source + def __str__(self) -> str: + return f"concat {self.source} {self.target}" + class SubstringOpNode(ReturnOpNode): def __init__(self, start: AtomOpNode, length: AtomOpNode) -> None: @@ -291,6 +330,9 @@ def __init__(self, start: AtomOpNode, length: AtomOpNode) -> None: self.start = start self.length = length + def __str__(self) -> str: + return f"substr {self.start.value} {self.length.value}" + class AtomOpNode(ReturnOpNode): def __init__(self, value: str) -> None: @@ -298,7 +340,10 @@ def __init__(self, value: str) -> None: AtomNode represents all single value nodes, like ids and constants """ super().__init__() - self.value = value + self.value = str(value) + + def __str__(self) -> str: + return self.value class IdNode(AtomOpNode): @@ -336,23 +381,35 @@ def __init__(self, eval_value: AtomOpNode, target: LabelNode) -> None: self.eval_value = eval_value self.target = target + def __str__(self) -> str: + return f"if {self.eval_value.value} goto {self.target.id}" + class IfFalseNode(IfNode): def __init__(self, eval_value: AtomOpNode, target: LabelNode) -> None: super().__init__(eval_value, target) + def __str__(self) -> str: + return f"ifFalse {self.eval_value.value} goto {self.target.id}" + class GoToNode(FlowControlNode): def __init__(self, target: LabelNode) -> None: super().__init__() self.target = target + def __str__(self) -> str: + return f"goto {self.target.id}" + class LabelNode(FlowControlNode): def __init__(self, idx: str) -> None: super().__init__() self.id = idx + def __str__(self) -> str: + return f"label {self.id}" + def extract_id(storage_node: StorageNode) -> IdNode: return IdNode(storage_node.id) From 850a5d2dd8559e501efcd7b251a570b6d0454dbf Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 18:45:27 -0500 Subject: [PATCH 256/432] Add simple ccil test --- src/debbuging/tests_ccil/simple.cl | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/debbuging/tests_ccil/simple.cl diff --git a/src/debbuging/tests_ccil/simple.cl b/src/debbuging/tests_ccil/simple.cl new file mode 100644 index 000000000..73ab05054 --- /dev/null +++ b/src/debbuging/tests_ccil/simple.cl @@ -0,0 +1,5 @@ + class Main { + main(): Int { + 3 + }; +}; From 53f1442f20252c825f4cab6ee99c4a1649483b88 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 18:49:03 -0500 Subject: [PATCH 257/432] Add return to function string representation --- src/asts/ccil_ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 06f2d4175..d9718254d 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -123,7 +123,7 @@ def __str__(self) -> str: locals = "\n".join(str(l) for l in self.locals) ops = "\n".join(str(o) for o in self.operations) - return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops}" + return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops} \n \t\treturn {self.ret.id}" class OperationNode(Node): From 996462e35110fee893c6c8d7393783c85bb5bbe9 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 18:57:22 -0500 Subject: [PATCH 258/432] Update setAttr attributes --- src/asts/ccil_ast.py | 9 ++++++--- src/code_gen/ccil_gen.py | 32 +++++++++++++++++--------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index d9718254d..0d5cdc8b6 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -153,10 +153,13 @@ def __str__(self) -> str: class SetAttrOpNode(OperationNode): - def __init__(self, type_id: str, attr_id: str, source_id: AtomOpNode) -> None: - self.type = type_id + def __init__( + self, instance_id: str, attr_id: str, new_value: AtomOpNode, instance_type: str + ) -> None: + self.instance_type = instance_type + self.new_value = new_value self.attr = attr_id - self.source_id = source_id + self.instance = instance_id class Abort(OperationNode): diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 47ddd15d6..a8d47ce6c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -165,7 +165,7 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: block_val = fvalues[-1] fval_id = f"block_{times}" - fval = self.create_assignation( fval_id, node.type.name, block_val.id) + fval = self.create_assignation(fval_id, node.type.name, block_val.id) operations.append(fval) return (operations, fval) @@ -214,7 +214,9 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: if is_attr: # Assignation occurring to an attribute Go update the attribute - set_attr = SetAttrOpNode(node, "self", ccil_id, extract_id(node, expr_fval)) + set_attr = SetAttrOpNode( + node, "self", ccil_id, extract_id(node, expr_fval), SELFTYPE + ) return [*expr_ops, set_attr], expr_fval self.update_locals(expr_fval.id, ccil_id) @@ -241,7 +243,7 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: then_fval.id = else_fval.id = pre_fvalue_id fvalue_id = f"if_{times}_fv" - fvalue = self.create_assignation( fvalue_id, node.type.name, pre_fvalue_id) + fvalue = self.create_assignation(fvalue_id, node.type.name, pre_fvalue_id) return ( [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], @@ -257,7 +259,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Storing the type of the resulting case expression type_of = self.create_type_of( - f"case_{times}_typeOf", extract_id(node, case_expr_fv) + f"case_{times}_typeOf", extract_id(node, case_expr_fv) ) # Final label where all branch must jump to @@ -313,7 +315,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Merging all expression operations in correct order # and saving all to final value fval_id = f"case_{times}_fv" - fval = self.create_assignation( fval_id, node.type.name, pre_fvalue_id) + fval = self.create_assignation(fval_id, node.type.name, pre_fvalue_id) operations = [ *case_expr_ops, type_of, @@ -341,7 +343,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(node, cond_fval, end_loop_label) go_to = GoToNode(node, loop_label) - fval = self.create_uninitialized_storage( f"loop_{times}_fv", VOID) + fval = self.create_uninitialized_storage(f"loop_{times}_fv", VOID) # Loop Nodes have void return type, how to express it?? return ( [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], @@ -387,7 +389,7 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure visiting binary expression") - fval = self.create_storage( fval_id, node.type.id, op) + fval = self.create_storage(fval_id, node.type.id, op) return ([*left_ops, *right_ops, fval], fval) @visitor.when(sem_ast.UnaryNode) @@ -412,7 +414,7 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: case _: raise Exception("Pattern match failure while visiting unary expression") - fval = self.create_storage( fval_id, node.type.id, op) + fval = self.create_storage(fval_id, node.type.id, op) return [*expr_op, fval], fval @visitor.when(sem_ast.MethodCallNode) @@ -448,7 +450,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" - call = self.create_vcall( fval_id, node.type.id, node.id, node.caller_type) + call = self.create_vcall(fval_id, node.type.id, node.id, node.caller_type) return [*args_ops, *expr_ops, call] @@ -457,7 +459,7 @@ def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: times = self.times(node) fvalue_id = f"newType_{times}" - fvalue = self.create_new_type( fvalue_id, node.type.name) + fvalue = self.create_new_type(fvalue_id, node.type.name) return [fvalue], fvalue @@ -470,11 +472,11 @@ def visit(self, node: sem_ast.VariableNode) -> VISITOR_RESULT: if is_attr: get_attr = self.create_attr_extraction( - id_id, node.type.name, "self", ccil_id + id_id, node.type.name, "self", ccil_id ) return [get_attr], get_attr - fval = self.create_assignation( id_id, node.type.name, ccil_id) + fval = self.create_assignation(id_id, node.type.name, ccil_id) return [fval], fval @visitor.when(sem_ast.StringNode) @@ -485,7 +487,7 @@ def visit(self, node: sem_ast.StringNode) -> VISITOR_RESULT: self.data.append(Data(data_id, node.value)) load_id = f"load_str_{times}" - load_str = self.create_string_load_data( load_id, data_id) + load_str = self.create_string_load_data(load_id, data_id) return [load_str], load_str @visitor.when(sem_ast.IntNode) @@ -493,7 +495,7 @@ def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: times = self.times(node) int_id = f"int_{times}" - int_node = self.create_int( int_id, node.value) + int_node = self.create_int(int_id, node.value) return [int_node], int_node @@ -504,7 +506,7 @@ def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: bool_id = f"bool_{times}" value = "0" if node.value == "False" else "1" - bool_node = self.create_int( bool_id, value) + bool_node = self.create_int(bool_id, value) return [bool_node], bool_node def times(self, node: sem_ast.Node, extra: str = ""): From 06b430c2f01eea7de581b49a9626ced767c4053b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 19:08:57 -0500 Subject: [PATCH 259/432] Add more string representations for ccil nodes --- src/asts/ccil_ast.py | 49 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 0d5cdc8b6..58eaad139 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -188,7 +188,8 @@ class ReadStrNode(ReturnOpNode): This nodes reads a string from the standard input """ - pass + def __str__(self) -> str: + return "read_str" class ReadIntNode(ReturnOpNode): @@ -196,6 +197,9 @@ class ReadIntNode(ReturnOpNode): This nodes reads an int from the standard input """ + def __str__(self) -> str: + return "read_int" + class GetAttrOpNode(ReturnOpNode): def __init__(self, instance_type_id: str, instance_id: str, attr_id: str) -> None: @@ -204,6 +208,9 @@ def __init__(self, instance_type_id: str, instance_id: str, attr_id: str) -> Non self.instance = instance_id self.attr = attr_id + def __str__(self) -> str: + return f"get_attr {self.instance}({self.instance_type}) {self.attr}" + class CallOpNode(ReturnOpNode): def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: @@ -212,6 +219,10 @@ def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: self.type = type_idx self.args = args + def __str__(self) -> str: + args = ", ".join(f"arg {a}" for a in self.args) + return f"call {self.id} : {self.type} ({args})" + class VCallOpNode(ReturnOpNode): def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: @@ -220,17 +231,25 @@ def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: self.type = type_idx self.args = args + def __str__(self) -> str: + args = ", ".join(f"arg {a}" for a in self.args) + return f"vcall {self.id} : {self.type} ({args})" + class VoidNode(ReturnOpNode): """Operation that indicate that the Storage Node is not initialized""" - pass + def __str__(self) -> str: + return "" class NewOpNode(ReturnOpNode): def __init__(self, type_idx: str) -> None: super().__init__() - self.type_idx: str = type_idx + self.type: str = type_idx + + def __str__(self) -> str: + return f"new {self.type}" class BinaryOpNode(ReturnOpNode): @@ -245,6 +264,9 @@ def __init__(self, left: AtomOpNode, right: AtomOpNode) -> None: self.left = left self.right = right + def __str__(self) -> str: + return f"{self.left.value} op {self.right.value}" + class SumOpNode(BinaryOpNode): pass @@ -283,21 +305,25 @@ def __init__(self, atom: AtomOpNode) -> None: class GetTypeOpNode(UnaryOpNode): """Extracts the type of a node""" - pass + def __str__(self) -> str: + return f"typeof {self.atom.value}" class IsVoidOpNode(UnaryOpNode): """Operation that returns true if the Storage Node is uninitialized""" - pass + def __str__(self) -> str: + return f"isvoid {self.atom.value}" class NotOpNode(UnaryOpNode): - pass + def __str__(self) -> str: + return f"not {self.atom.value}" class NegOpNode(UnaryOpNode): - pass + def __str__(self) -> str: + return f"neg {self.atom.value}" class ChainOpNode(ReturnOpNode): @@ -307,15 +333,18 @@ def __init__(self, target: str) -> None: class LoadOpNode(ChainOpNode): - pass + def __str__(self) -> str: + return f"load {self.target}" class LengthOpNode(ChainOpNode): - pass + def __str__(self) -> str: + return f"length {self.target}" class StrOpNode(ChainOpNode): - pass + def __str__(self) -> str: + return f"str {self.target}" class ConcatOpNode(ChainOpNode): From 2621484081ecbf63b2e02d4cac73129ee78dd23f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 21:06:28 -0500 Subject: [PATCH 260/432] Bug fixing and improve node to string representation --- src/asts/ccil_ast.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 58eaad139..b2b7a0974 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -34,7 +34,7 @@ class Class: def __str__(self) -> str: attributes = "\n".join(str(a) for a in self.attributes) methods = "\n".join(str(m) for m in self.methods) - return f"\ttype {self.id} {{ {attributes} \n {methods} \n\t}}" + return f"\ttype {self.id} {{\n {attributes} \n {methods} \n\t}}" @dataclass(frozen=True) @@ -52,17 +52,17 @@ def __str__(self) -> str: class Attribute(BaseVar): def __str__(self) -> str: - return "\t\tattr " + super().__str__() + return "attr " + super().__str__() class Parameter(BaseVar): def __str__(self) -> str: - return "\t\tparam " + super().__str__() + return "param " + super().__str__() class Local(BaseVar): def __str__(self) -> str: - return "\t\tlocal " + super().__str__() + return "local " + super().__str__() @dataclass(frozen=True) @@ -119,11 +119,12 @@ def __init__( self.operations = operations def __str__(self) -> str: - params = "\n".join(str(p) for p in self.params) - locals = "\n".join(str(l) for l in self.locals) - ops = "\n".join(str(o) for o in self.operations) + indent = "\t\t" + params = "\n".join(indent + str(p) for p in self.params) + locals = "\n".join(indent + str(l) for l in self.locals) + ops = "\n".join(indent + str(o) for o in self.operations) - return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops} \n \t\treturn {self.ret.id}" + return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops} \n {indent}return {self.ret.id}" class OperationNode(Node): @@ -149,7 +150,7 @@ def __init__(self, idx: str, operation: ReturnOpNode) -> None: self.operation = operation def __str__(self) -> str: - return f"\t\t{self.id} = {str(self.operation)}" + return f"{self.id} = {str(self.operation)}" class SetAttrOpNode(OperationNode): @@ -161,6 +162,9 @@ def __init__( self.attr = attr_id self.instance = instance_id + def __str__(self) -> str: + return f"set_attr {self.instance}({self.instance_type}) {self.attr} {self.new_value}" + class Abort(OperationNode): def __str__(self) -> str: @@ -398,8 +402,8 @@ class FlowControlNode(OperationNode): Base class for all flow control operations like If, Label, goto, etc... """ - def __init__(self, node) -> None: - super().__init__(node) + def __init__(self) -> None: + super().__init__() class CurrentTypeNameNode(ReturnOpNode): From 08e67df9a1d8b2a75ee3f468664d4c7772affae1 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 21:07:16 -0500 Subject: [PATCH 261/432] Fix several bugs --- src/code_gen/ccil_gen.py | 70 +++++++++++++++++++++++----------------- src/code_gen/tools.py | 4 ++- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a8d47ce6c..b3d6cd378 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -89,7 +89,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: init_func = FunctionNode( f"init_{node.id}", [], - to_vars(self.locals, Parameter), + to_vars(self.locals, Local), init_attr_ops, node.id, ) @@ -117,7 +117,7 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: if node.expr is None: self.add_local(fval_id, node.type.name) - return [] + return ([], None) (expr_op, expr_fval) = self.visit(node.expr) @@ -146,7 +146,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: return FunctionNode( f"f_{times}", params, - to_vars(self.locals, Parameter), + to_vars(self.locals, Local), operations, fval_id, ) @@ -160,7 +160,7 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: for expr in node.expr_list: (expr_ops, expr_fval) = self.visit(expr) operations += expr_ops - fvalues += expr_fval + fvalues.append(expr_fval) block_val = fvalues[-1] fval_id = f"block_{times}" @@ -214,9 +214,7 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: if is_attr: # Assignation occurring to an attribute Go update the attribute - set_attr = SetAttrOpNode( - node, "self", ccil_id, extract_id(node, expr_fval), SELFTYPE - ) + set_attr = SetAttrOpNode("self", ccil_id, extract_id(expr_fval), SELFTYPE) return [*expr_ops, set_attr], expr_fval self.update_locals(expr_fval.id, ccil_id) @@ -233,8 +231,11 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: # translating condition to ccil label_id = f"ifElse_{times}" - else_label = LabelNode(node, label_id) - if_false = IfFalseNode(node, if_fval, else_label) + else_label = LabelNode(label_id) + if_false = IfFalseNode(extract_id(if_fval), else_label) + + endif_label = LabelNode("endIf") + goto_endif = GoToNode(endif_label) # Setting the final operation which will simbolize the return value of this expr pre_fvalue_id = f"if_{times}_pre_fv" @@ -246,7 +247,16 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: fvalue = self.create_assignation(fvalue_id, node.type.name, pre_fvalue_id) return ( - [*if_ops, if_false, *then_ops, else_label, *else_ops, fvalue], + [ + *if_ops, + if_false, + *then_ops, + goto_endif, + else_label, + *else_ops, + endif_label, + fvalue, + ], fvalue, ) @@ -259,15 +269,15 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Storing the type of the resulting case expression type_of = self.create_type_of( - f"case_{times}_typeOf", extract_id(node, case_expr_fv) + f"case_{times}_typeOf", extract_id( case_expr_fv) ) # Final label where all branch must jump to final_label_id = f"case_{times}_end" - final_label = LabelNode(node, final_label_id) + final_label = LabelNode( final_label_id) # Inconditional jump to final label - final_goto = GoToNode(node, final_label) + final_goto = GoToNode( final_label) # All branch must end in a var named like this pre_fvalue_id = f"case_{times}_pre_fv" @@ -283,7 +293,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" branch_var_type_of = self.create_type_of( - branch_var_type_id, extract_id(node, branch_var) + branch_var_type_id, extract_id( branch_var) ) # Initializng var which holds the comparison result between @@ -291,16 +301,16 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: select_branch_id = f"case_{times}_optionSelect_{i}" select_branch = self.create_equality( select_branch_id, - extract_id(node, type_of), - extract_id(node, branch_var_type_of), + extract_id( type_of), + extract_id( branch_var_type_of), ) # Label that means the start of this branch logic branch_label_id = f"case_{times}_branch_{i}" - branch_label = LabelNode(option, branch_label_id) + branch_label = LabelNode( branch_label_id) # Conditional jump to the right branch label - if_op = IfNode(option, extract_id(option, branch_var_type_of), branch_label) + if_op = IfNode( extract_id( branch_var_type_of), branch_label) # Storing logic to jump to branch logic if this branch is selected pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] @@ -357,12 +367,12 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: (left_ops, left_fval) = self.visit(node.left) (right_ops, right_fval) = self.visit(node.right) - left_id = extract_id(node, left_fval) - right_id = extract_id(node, right_fval) + left_id = extract_id(left_fval) + right_id = extract_id(right_fval) fval_id: str op: BinaryOpNode - match node: + match type(node): # Arithmetic Binary Nodes case sem_ast.PlusNode: op = SumOpNode(left_id, right_id) @@ -387,9 +397,11 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: op = LessOrEqualOpNode(left_id, right_id) fval_id = f"leq_{times}" case _: - raise Exception("Pattern match failure visiting binary expression") + raise Exception( + f"Pattern match failure visiting binary expression with {type(node).__name__}" + ) - fval = self.create_storage(fval_id, node.type.id, op) + fval = self.create_storage(fval_id, node.type.name, op) return ([*left_ops, *right_ops, fval], fval) @visitor.when(sem_ast.UnaryNode) @@ -397,24 +409,24 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: times = self.times(node) (expr_op, expr_fval) = self.visit(node.expr) - expr_id = extract_id(node.expr, expr_fval) + expr_id = extract_id(expr_fval) fval_id: str op: UnaryOpNode - match node: + match type(node): case sem_ast.IsVoidNode: fval_id = f"isVoid_{times}" - op = IsVoidOpNode(node, expr_id) + op = IsVoidOpNode(expr_id) case sem_ast.NotNode: fval_id = f"not_{times}" - op = NotOpNode(node, expr_id) + op = NotOpNode(expr_id) case sem_ast.ComplementNode: fval_id = f"neg_{times}" - op = NegOpNode(node, expr_id) + op = NegOpNode(expr_id) case _: raise Exception("Pattern match failure while visiting unary expression") - fval = self.create_storage(fval_id, node.type.id, op) + fval = self.create_storage(fval_id, node.type.name, op) return [*expr_op, fval], fval @visitor.when(sem_ast.MethodCallNode) diff --git a/src/code_gen/tools.py b/src/code_gen/tools.py index 8f92c80c1..1b4f6eebf 100644 --- a/src/code_gen/tools.py +++ b/src/code_gen/tools.py @@ -41,7 +41,9 @@ def search_value_position(self, key: str) -> Tuple[str, bool] | Tuple[None, None return (self.names[key], self.parent is None) except KeyError: return ( - self.parent.search_for(key) if self.parent is not None else (None, None) + self.parent.search_value_position(key) + if self.parent is not None + else (None, None) ) def get_value_position(self, key: str) -> Tuple[str, bool]: From 987118e80ba6cba311c5eef0f8d5261417e7060e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 21:07:51 -0500 Subject: [PATCH 262/432] Add new tests --- src/debbuging/tests_ccil/aritmetica1.cl | 5 +++++ src/debbuging/tests_ccil/aritmetica2.cl | 5 +++++ src/debbuging/tests_ccil/aritmetica3.cl | 5 +++++ src/debbuging/tests_ccil/if1.cl | 6 ++++++ src/debbuging/tests_ccil/instantiate1.cl | 13 +++++++++++++ 5 files changed, 34 insertions(+) create mode 100644 src/debbuging/tests_ccil/aritmetica1.cl create mode 100644 src/debbuging/tests_ccil/aritmetica2.cl create mode 100644 src/debbuging/tests_ccil/aritmetica3.cl create mode 100644 src/debbuging/tests_ccil/if1.cl create mode 100644 src/debbuging/tests_ccil/instantiate1.cl diff --git a/src/debbuging/tests_ccil/aritmetica1.cl b/src/debbuging/tests_ccil/aritmetica1.cl new file mode 100644 index 000000000..8a476c242 --- /dev/null +++ b/src/debbuging/tests_ccil/aritmetica1.cl @@ -0,0 +1,5 @@ + class Main { + main(): Int { + 3 + 4 + 5 + }; +}; diff --git a/src/debbuging/tests_ccil/aritmetica2.cl b/src/debbuging/tests_ccil/aritmetica2.cl new file mode 100644 index 000000000..744e6f62a --- /dev/null +++ b/src/debbuging/tests_ccil/aritmetica2.cl @@ -0,0 +1,5 @@ + class Main { + main(): Int { + 3 - 4 - 5 + }; +}; diff --git a/src/debbuging/tests_ccil/aritmetica3.cl b/src/debbuging/tests_ccil/aritmetica3.cl new file mode 100644 index 000000000..40e87765f --- /dev/null +++ b/src/debbuging/tests_ccil/aritmetica3.cl @@ -0,0 +1,5 @@ + class Main { + main(): Int { + 3 / 4 * 5 + }; +}; diff --git a/src/debbuging/tests_ccil/if1.cl b/src/debbuging/tests_ccil/if1.cl new file mode 100644 index 000000000..81d592d10 --- /dev/null +++ b/src/debbuging/tests_ccil/if1.cl @@ -0,0 +1,6 @@ + class Main { + main(): Int { + if true then 1 else 2 fi + }; +}; + diff --git a/src/debbuging/tests_ccil/instantiate1.cl b/src/debbuging/tests_ccil/instantiate1.cl new file mode 100644 index 000000000..9046024dc --- /dev/null +++ b/src/debbuging/tests_ccil/instantiate1.cl @@ -0,0 +1,13 @@ +class Main{ + a: A; + + main(): A { + a <- new A + }; +}; + +class A { + method(): Int{ + 1 + }; +}; From 63540d39a07c1638ef4e9defb8a9b7d0dd7e8656 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 24 Feb 2022 21:16:32 -0500 Subject: [PATCH 263/432] Fix mips to string generator --- src/code_gen/mips_gen.py | 56 ++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 529d99ebb..bb6cc93a5 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -5,18 +5,22 @@ BranchOnEqual, BranchOnNotEqual, Constant, + Div, + Equal, Jump, JumpAndLink, JumpRegister, Label, LabelDeclaration, + Less, + LessOrEqual, LoadAddress, LoadImmediate, MIPSProgram, MemoryIndexNode, Move, Multiply, - MultiplyOpNode, + Not, RegisterNode, Sub, Subu, @@ -24,6 +28,7 @@ TextNode, DataNode, WordDirective, + Xori, ) from utils import visitor @@ -76,15 +81,15 @@ def visit(self, node: Label) -> str: @visitor.when(JumpAndLink) def visit(self, node: JumpAndLink) -> str: - return f"\tjal {node.address}" + return f"\tjal {self.visit(node.address)}" @visitor.when(Jump) def visit(self, node: Jump) -> str: - return f"\tj {node.address}" + return f"\tj {self.visit(node.address)}" @visitor.when(JumpRegister) def visit(self, node: JumpRegister) -> str: - return f"\tj {node.register}" + return f"\tj {self.visit(node.register)}" @visitor.when(MemoryIndexNode) def visit(self, node: MemoryIndexNode) -> str: @@ -100,23 +105,23 @@ def visit(self, node: Move) -> str: @visitor.when(Subu) def visit(self, node: Subu) -> str: - return f"\tsubu {node.left}, {node.middle}, {node.right}" + return f"\tsubu {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(Sub) def visit(self, node: Sub) -> str: - return f"\tsub {node.left}, {node.middle}, {node.right}" + return f"\tsub {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(Addu) def visit(self, node: Addu) -> str: - return f"\taddu {node.left}, {node.middle}, {node.right}" + return f"\taddu {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(LoadAddress) def visit(self, node: LoadAddress) -> str: - return f"\tla {node.left}, {node.right}" + return f"\tla {self.visit(node.left)}, {self.visit(node.right)}" @visitor.when(LoadImmediate) def visit(self, node: LoadImmediate) -> str: - return f"\tli {node.left}, {node.right}" + return f"\tli {self.visit(node.left)}, {self.visit(node.right)}" @visitor.when(Syscall) def visit(self, node: Syscall) -> str: @@ -124,19 +129,44 @@ def visit(self, node: Syscall) -> str: @visitor.when(Add) def visit(self, node: Add) -> str: - return f"\tadd {node.left}, {node.middle}, {node.right}" + return f"\tadd {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(Addi) def visit(self, node: Addi) -> str: - return f"\taddi {node.left}, {node.middle}, {node.right}" + return f"\taddi {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(Multiply) def visit(self, node: Multiply) -> str: + return f"\tmul {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(Div) + def visit(self, node: Div) -> str: + return f"\tdiv {self.visit(node.left)}, {self.visit(node.right)}" @visitor.when(BranchOnEqual) def visit(self, node: BranchOnEqual) -> str: - return f"\tbeq {node.left}, {node.middle}, {node.right}" + return f"\tbeq {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" @visitor.when(BranchOnEqual) def visit(self, node: BranchOnNotEqual) -> str: - return f"\tbne {node.left}, {node.middle}, {node.right}" + return f"\tbne {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(Less) + def visit(self, node: Less) -> str: + return f"\tslt {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(LessOrEqual) + def visit(self, node: LessOrEqual) -> str: + return f"\tsle {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(Equal) + def visit(self, node: Equal) -> str: + return f"\tseq {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(Xori) + def visit(self, node: Xori) -> str: + return f"\txori {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" + + @visitor.when(Not) + def visit(self, node: Not) -> str: + return f"\tnot {self.visit(node.left)}, {self.visit(node.right)}" From a7c3038c7cc0c4e0a6d46d2c57c2b3bdc1c07ef8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 22:16:43 -0500 Subject: [PATCH 264/432] Add runtime error if no case branch is executed --- src/code_gen/ccil_gen.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index b3d6cd378..664fcafd3 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -322,6 +322,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] + # Merging all expression operations in correct order # and saving all to final value fval_id = f"case_{times}_fv" @@ -330,6 +331,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: *case_expr_ops, type_of, *pattern_match_ops, + *self.notifiy_and_abort(f"Pattern match failure in {node.row}, {node.col}") *branch_ops, final_label, fval, From e1d961aaa68716b56e2fbacebba2e531ee4ba4de Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 22:21:07 -0500 Subject: [PATCH 265/432] Change pattern matching for if else expressions --- src/code_gen/ccil_gen.py | 103 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 664fcafd3..48c006236 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -268,16 +268,14 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) # Storing the type of the resulting case expression - type_of = self.create_type_of( - f"case_{times}_typeOf", extract_id( case_expr_fv) - ) + type_of = self.create_type_of(f"case_{times}_typeOf", extract_id(case_expr_fv)) # Final label where all branch must jump to final_label_id = f"case_{times}_end" - final_label = LabelNode( final_label_id) + final_label = LabelNode(final_label_id) # Inconditional jump to final label - final_goto = GoToNode( final_label) + final_goto = GoToNode(final_label) # All branch must end in a var named like this pre_fvalue_id = f"case_{times}_pre_fv" @@ -293,7 +291,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Initializing var which holds the branch var type branch_var_type_id = f"case_{times}_optionTypeOf_{i}" branch_var_type_of = self.create_type_of( - branch_var_type_id, extract_id( branch_var) + branch_var_type_id, extract_id(branch_var) ) # Initializng var which holds the comparison result between @@ -301,16 +299,16 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: select_branch_id = f"case_{times}_optionSelect_{i}" select_branch = self.create_equality( select_branch_id, - extract_id( type_of), - extract_id( branch_var_type_of), + extract_id(type_of), + extract_id(branch_var_type_of), ) # Label that means the start of this branch logic branch_label_id = f"case_{times}_branch_{i}" - branch_label = LabelNode( branch_label_id) + branch_label = LabelNode(branch_label_id) # Conditional jump to the right branch label - if_op = IfNode( extract_id( branch_var_type_of), branch_label) + if_op = IfNode(extract_id(branch_var_type_of), branch_label) # Storing logic to jump to branch logic if this branch is selected pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] @@ -322,7 +320,6 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] - # Merging all expression operations in correct order # and saving all to final value fval_id = f"case_{times}_fv" @@ -332,7 +329,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: type_of, *pattern_match_ops, *self.notifiy_and_abort(f"Pattern match failure in {node.row}, {node.col}") - *branch_ops, + * branch_ops, final_label, fval, ] @@ -374,34 +371,35 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: fval_id: str op: BinaryOpNode - match type(node): - # Arithmetic Binary Nodes - case sem_ast.PlusNode: - op = SumOpNode(left_id, right_id) - fval_id = f"sum_{times}" - case sem_ast.MinusNode: - op = MinusOpNode(left_id, right_id) - fval_id = f"minus_{times}" - case sem_ast.StarNode: - op = MultOpNode(left_id, right_id) - fval_id = f"mult_{times}" - case sem_ast.DivNode: - op = DivOpNode(left_id, right_id) - fval_id = f"div_{times}" - # Boolean Binary Nodes - case sem_ast.EqualsNode: - op = EqualOpNode(left_id, right_id) - fval_id = f"eq_{times}" - case sem_ast.LessNode: - op = LessOpNode(left_id, right_id) - fval_id = f"le_{times}" - case sem_ast.LessOrEqualNode: - op = LessOrEqualOpNode(left_id, right_id) - fval_id = f"leq_{times}" - case _: - raise Exception( - f"Pattern match failure visiting binary expression with {type(node).__name__}" - ) + + # Arithmetic Binary Nodes + node_type = type(node) + if node_type == sem_ast.PlusNode: + op = SumOpNode(left_id, right_id) + fval_id = f"sum_{times}" + elif node_type == sem_ast.MinusNode: + op = MinusOpNode(left_id, right_id) + fval_id = f"minus_{times}" + elif node_type == sem_ast.StarNode: + op = MultOpNode(left_id, right_id) + fval_id = f"mult_{times}" + elif node_type == sem_ast.DivNode: + op = DivOpNode(left_id, right_id) + fval_id = f"div_{times}" + # Boolean Binary Nodes + elif node_type == sem_ast.EqualsNode: + op = EqualOpNode(left_id, right_id) + fval_id = f"eq_{times}" + elif node_type == sem_ast.LessNode: + op = LessOpNode(left_id, right_id) + fval_id = f"le_{times}" + elif node_type == sem_ast.LessOrEqualNode: + op = LessOrEqualOpNode(left_id, right_id) + fval_id = f"leq_{times}" + else: + raise Exception( + f"Pattern match failure visiting binary expression with {type(node).__name__}" + ) fval = self.create_storage(fval_id, node.type.name, op) return ([*left_ops, *right_ops, fval], fval) @@ -415,18 +413,19 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: fval_id: str op: UnaryOpNode - match type(node): - case sem_ast.IsVoidNode: - fval_id = f"isVoid_{times}" - op = IsVoidOpNode(expr_id) - case sem_ast.NotNode: - fval_id = f"not_{times}" - op = NotOpNode(expr_id) - case sem_ast.ComplementNode: - fval_id = f"neg_{times}" - op = NegOpNode(expr_id) - case _: - raise Exception("Pattern match failure while visiting unary expression") + + node_type = type(node) + if node_type == sem_ast.IsVoidNode: + fval_id = f"isVoid_{times}" + op = IsVoidOpNode(expr_id) + elif node_type == sem_ast.NotNode: + fval_id = f"not_{times}" + op = NotOpNode(expr_id) + elif node_type == sem_ast.ComplementNode: + fval_id = f"neg_{times}" + op = NegOpNode(expr_id) + else: + raise Exception("Pattern match failure while visiting unary expression") fval = self.create_storage(fval_id, node.type.name, op) return [*expr_op, fval], fval From a3a6169ceb997ed1e7b53a06a44ece4ea6041a1f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 22:29:01 -0500 Subject: [PATCH 266/432] Fix bug in ccil pattern match error handling --- src/code_gen/ccil_gen.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 48c006236..2b3c58f2e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -322,14 +322,20 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Merging all expression operations in correct order # and saving all to final value + + err_msg = self.add_data( + f"case_error_msg_{times}", + f"Pattern match failure in {node.line}, {node.col}", + ) + fval_id = f"case_{times}_fv" fval = self.create_assignation(fval_id, node.type.name, pre_fvalue_id) operations = [ *case_expr_ops, type_of, *pattern_match_ops, - *self.notifiy_and_abort(f"Pattern match failure in {node.row}, {node.col}") - * branch_ops, + *self.notifiy_and_abort(err_msg.id), + *branch_ops, final_label, fval, ] From af33df9e0baa3754d3634e9014537e8dbef49c79 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 22:29:42 -0500 Subject: [PATCH 267/432] Add simple case test --- src/debbuging/tests_ccil/case1.cl | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/debbuging/tests_ccil/case1.cl diff --git a/src/debbuging/tests_ccil/case1.cl b/src/debbuging/tests_ccil/case1.cl new file mode 100644 index 000000000..8eb0575b4 --- /dev/null +++ b/src/debbuging/tests_ccil/case1.cl @@ -0,0 +1,11 @@ +class Main inherits IO { + main(): Int + { + case 3 + 5 of + n : Bool => 1; + n : Int => 2; + n : String => 3; + esac + + }; +}; From 56f656fb04e954d50bcddb524e5938b9fae2efbc Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 23:29:14 -0500 Subject: [PATCH 268/432] Minor hierarchy change --- src/asts/ccil_ast.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index b2b7a0974..e56ebd83a 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -272,31 +272,39 @@ def __str__(self) -> str: return f"{self.left.value} op {self.right.value}" -class SumOpNode(BinaryOpNode): +class ArithmeticOpNode(BinaryOpNode): pass -class MinusOpNode(BinaryOpNode): +class SumOpNode(ArithmeticOpNode): pass -class MultOpNode(BinaryOpNode): +class MinusOpNode(ArithmeticOpNode): pass -class DivOpNode(BinaryOpNode): +class MultOpNode(ArithmeticOpNode): pass -class EqualOpNode(BinaryOpNode): +class DivOpNode(ArithmeticOpNode): pass -class LessOrEqualOpNode(BinaryOpNode): +class ComparisonOpNode(BinaryOpNode): pass -class LessOpNode(BinaryOpNode): +class EqualOpNode(ComparisonOpNode): + pass + + +class LessOrEqualOpNode(ComparisonOpNode): + pass + + +class LessOpNode(ComparisonOpNode): pass From b844fc1ad09b224c2644cba9356528119e658ba5 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 23:31:42 -0500 Subject: [PATCH 269/432] Add division by zero error detection and other bug fix --- src/code_gen/ccil_gen.py | 59 ++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 2b3c58f2e..514cffffa 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -13,8 +13,8 @@ # TODO: # Define abort nodes with a text: -# * Dispacth on a void class -# * No pattern match in case +# * Dispatch on a void class +# * No pattern match in case (Done) # * Division by zero # * Substring out of range (Done) # * Heap Overflow (don't know yet how to handle this) @@ -327,6 +327,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: f"case_error_msg_{times}", f"Pattern match failure in {node.line}, {node.col}", ) + err_var = self.create_string_load_data(f"case_error_var_{times}", err_msg.id) fval_id = f"case_{times}_fv" fval = self.create_assignation(fval_id, node.type.name, pre_fvalue_id) @@ -334,7 +335,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: *case_expr_ops, type_of, *pattern_match_ops, - *self.notifiy_and_abort(err_msg.id), + *self.notifiy_and_abort(err_var.id), *branch_ops, final_label, fval, @@ -365,10 +366,9 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: fval, ) - @visitor.when(sem_ast.BinaryNode) - def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: + @visitor.when(sem_ast.ArithmeticNode) + def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: times = self.times(node) - (left_ops, left_fval) = self.visit(node.left) (right_ops, right_fval) = self.visit(node.right) @@ -376,9 +376,10 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: right_id = extract_id(right_fval) fval_id: str - op: BinaryOpNode + op: ArithmeticOpNode # Arithmetic Binary Nodes + extra_ops: List[OperationNode] = [] node_type = type(node) if node_type == sem_ast.PlusNode: op = SumOpNode(left_id, right_id) @@ -392,8 +393,50 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: elif node_type == sem_ast.DivNode: op = DivOpNode(left_id, right_id) fval_id = f"div_{times}" + # Generating divison by zero warning + ok_label = LabelNode(f"ok_div_{times}") + right_id_is_zero = self.create_equality( + f"check_right_zero_{times}", left_id, IntNode("0") + ) + if_id_is_not_zero = IfFalseNode(extract_id(right_id_is_zero), ok_label) + error_msg = self.add_data( + f"error_msg_div_zero_{times}", + f"Error. Zero division detected on {node.line}, {node.col}.", + ) + error_var = self.create_string_load_data(f"error_var_{times}", error_msg.id) + extra_ops = [ + right_id_is_zero, + if_id_is_not_zero, + error_var, + *self.notifiy_and_abort(error_var.id), + ok_label, + ] + + else: + raise Exception( + f"Pattern match failure visiting arithmetic expression" + f" with {type(node).__name__}" + ) + + fval = self.create_storage(fval_id, node.type.name, op) + return ([*left_ops, *right_ops, *extra_ops, fval], fval) + + @visitor.when(sem_ast.ComparerNode) + def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: + times = self.times(node) + + (left_ops, left_fval) = self.visit(node.left) + (right_ops, right_fval) = self.visit(node.right) + + left_id = extract_id(left_fval) + right_id = extract_id(right_fval) + + fval_id: str + op: BinaryOpNode + # Arithmetic Binary Nodes + node_type = type(node) # Boolean Binary Nodes - elif node_type == sem_ast.EqualsNode: + if node_type == sem_ast.EqualsNode: op = EqualOpNode(left_id, right_id) fval_id = f"eq_{times}" elif node_type == sem_ast.LessNode: From 56bb966ab1fe795920fd69461233b6ffbaf1b02d Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 24 Feb 2022 23:56:30 -0500 Subject: [PATCH 270/432] Add default init values when declaring new attributes and variables. Change init class function inner workings --- src/code_gen/ccil_gen.py | 43 +++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 514cffffa..0b475f310 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -10,6 +10,9 @@ VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] CLASS_VISITOR_RESULT = Tuple[Class, List[FunctionNode]] METHOD_VISITOR_RESULT = FunctionNode +ATTR_VISITOR_RESULT = List[OperationNode] + +DEFAULT_STR = Data("default_str", "") # TODO: # Define abort nodes with a text: @@ -35,7 +38,7 @@ def __init__(self) -> None: # To keep track of how many times a certain expression has been evaluated self.time_record: Dict[str, int] = dict() # Track all constant values. Only strings for now - self.data: List[Data] = list() + self.data: List[Data] # To keep track of the current class being analysed self.current_type: str @@ -55,6 +58,8 @@ def visit(self, node): def visit(self, node: sem_ast.ProgramNode) -> None: program_types: List[Class] = list() program_codes: List[Method] = list() + + self.data = [DEFAULT_STR] for type in node.declarations: classx, class_code = self.visit(type) program_types.append(classx) @@ -78,6 +83,8 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Explore all attributes and join their operations in an initializer function self.reset_locals() self.reset_scope() + init_params = self.init_func_params(node.id) + self.ccil_cool_names.add_new_name_pair("self", node.type.name) attributes: List[Attribute] = list() init_attr_ops: List[OperationNode] = [] for attr in attr_nodes: @@ -85,13 +92,14 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: (attr_ops, _) = self.visit(attr) init_attr_ops += attr_ops - # Return type is set as itself? Use selftype maybe? + dummy_return = self.create_storage(f"init_type_{node.id}_ret", INT, IntNode(0)) + init_attr_ops.append(dummy_return) init_func = FunctionNode( f"init_{node.id}", - [], + init_params, to_vars(self.locals, Local), init_attr_ops, - node.id, + dummy_return.id, ) # Explore all functions @@ -109,23 +117,26 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: return (Class(node.id, attributes, methods, init_func), class_code) @visitor.when(sem_ast.AttrDeclarationNode) - def visit(self, node: sem_ast.AttrDeclarationNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.AttrDeclarationNode) -> ATTR_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.create_child() - fval_id = ATTR + node.id - self.ccil_cool_names.add_new_name_pair(node.id, fval_id) + attr_id = ATTR + node.id + self.ccil_cool_names.add_new_name_pair(node.id, attr_id) if node.expr is None: - self.add_local(fval_id, node.type.name) - return ([], None) + if node.type.name != STRING: + value_0 = self.create_storage("zero", INT, IntNode("0")) + else: + value_0 = self.create_string_load_data("empty", DEFAULT_STR.id) + set_attr = SetAttrOpNode("self", attr_id, extract_id(value_0), SELFTYPE) + return [value_0, set_attr] (expr_op, expr_fval) = self.visit(node.expr) - self.update_locals(expr_fval.id, fval_id) - expr_fval.id = fval_id + set_attr = SetAttrOpNode("self", attr_id, expr_fval.id, SELFTYPE) self.ccil_cool_names = self.ccil_cool_names.get_parent - return (expr_op, expr_fval) + return [*expr_op, set_attr] @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: @@ -196,8 +207,12 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: self.ccil_cool_names.add_new_name_pair(node.id, fvalue_id) if node.expr is None: - self.add_local(fvalue_id, node.type.name) - self.locals[fvalue_id] = node.type.name + if node.type.name != STRING: + value_0 = self.create_storage("zero", INT, IntNode("0")) + else: + value_0 = self.create_string_load_data("empty", DEFAULT_STR.id) + fval = self.create_assignation(fvalue_id, node.type.name, value_0.id) + return [fval], fval (expr_ops, expr_fv) = self.visit(node.expr) From c962d97a21276f35a47ed90c9cb4a0d1cbcbdb0b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 00:02:56 -0500 Subject: [PATCH 271/432] Fix bug where FunctionNode ret attribute has wrong value --- src/asts/ccil_ast.py | 5 +++-- src/code_gen/ccil_gen.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index e56ebd83a..7f3560fc3 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -34,7 +34,8 @@ class Class: def __str__(self) -> str: attributes = "\n".join(str(a) for a in self.attributes) methods = "\n".join(str(m) for m in self.methods) - return f"\ttype {self.id} {{\n {attributes} \n {methods} \n\t}}" + init_function = str(self.init_operations) + return f"\ttype {self.id} {{\n {attributes} \n {methods} \n \n {init_function}\n\t}}" @dataclass(frozen=True) @@ -124,7 +125,7 @@ def __str__(self) -> str: locals = "\n".join(indent + str(l) for l in self.locals) ops = "\n".join(indent + str(o) for o in self.operations) - return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops} \n {indent}return {self.ret.id}" + return f"\tfunc {self.id}:\n {params}\n {locals} \n {ops} \n {indent}return {self.ret}" class OperationNode(Node): diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 0b475f310..840ab344c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -84,7 +84,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.reset_locals() self.reset_scope() init_params = self.init_func_params(node.id) - self.ccil_cool_names.add_new_name_pair("self", node.type.name) + self.ccil_cool_names.add_new_name_pair("self", node.id) attributes: List[Attribute] = list() init_attr_ops: List[OperationNode] = [] for attr in attr_nodes: @@ -151,7 +151,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names.add_new_name_pair(param.id, new_param_id) self.locals = dict() - (operations, fval_id) = self.visit(node.body) + (operations, fval) = self.visit(node.body) self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( @@ -159,7 +159,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: params, to_vars(self.locals, Local), operations, - fval_id, + fval.id, ) @visitor.when(sem_ast.BlocksNode) From 410c227ea08486676c1cddaccc72ab07861d21d6 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 00:22:21 -0500 Subject: [PATCH 272/432] Update attr, locals and param prefix --- src/code_gen/constants.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index fdb1cca54..443f7faea 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -1,6 +1,6 @@ -PARAM = "param" -LET = "let" -ATTR = "attr" +PARAM = "param_" +LET = "let_" +ATTR = "attr_" CASE_INIT = "init_case" CASE_END = "end_case" From 80f238ca2271aa8f169d626fe78b1d11d16fffa2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 00:22:46 -0500 Subject: [PATCH 273/432] Improve and fix errors on class init function --- src/code_gen/ccil_gen.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 840ab344c..1ca513a8a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -86,10 +86,13 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: init_params = self.init_func_params(node.id) self.ccil_cool_names.add_new_name_pair("self", node.id) attributes: List[Attribute] = list() - init_attr_ops: List[OperationNode] = [] + init_attr_ops: List[OperationNode] = [ + self.create_storage("zero", INT, IntNode("0")), + self.create_string_load_data("empty", DEFAULT_STR.id), + ] for attr in attr_nodes: attributes.append(Attribute(ATTR + attr.id, attr.type.name)) - (attr_ops, _) = self.visit(attr) + attr_ops = self.visit(attr) init_attr_ops += attr_ops dummy_return = self.create_storage(f"init_type_{node.id}_ret", INT, IntNode(0)) @@ -125,15 +128,15 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> ATTR_VISITOR_RESULT: if node.expr is None: if node.type.name != STRING: - value_0 = self.create_storage("zero", INT, IntNode("0")) + value_0 = IdNode("zero") else: - value_0 = self.create_string_load_data("empty", DEFAULT_STR.id) - set_attr = SetAttrOpNode("self", attr_id, extract_id(value_0), SELFTYPE) - return [value_0, set_attr] + value_0 = IdNode("empty") + set_attr = SetAttrOpNode("self", attr_id, value_0, self.current_type) + return [set_attr] (expr_op, expr_fval) = self.visit(node.expr) - set_attr = SetAttrOpNode("self", attr_id, expr_fval.id, SELFTYPE) + set_attr = SetAttrOpNode("self", attr_id, expr_fval.id, self.current_type) self.ccil_cool_names = self.ccil_cool_names.get_parent return [*expr_op, set_attr] @@ -782,7 +785,7 @@ def create_attr_extraction( self, idx: str, type_idx: str, from_idx: str, attr_idx: str ): self.add_local(idx, type_idx) - return StorageNode(idx, GetAttrOpNode(from_idx, attr_idx)) + return StorageNode(idx, GetAttrOpNode(type_idx, from_idx, attr_idx)) def create_new_type(self, idx: str, type_idx: str): self.add_local(idx, type_idx) From 7566d3ddc34a5141dbcd930823a0b8070e671087 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 00:23:37 -0500 Subject: [PATCH 274/432] Add attribute test --- src/debbuging/tests_ccil/atributos1.cl | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/debbuging/tests_ccil/atributos1.cl diff --git a/src/debbuging/tests_ccil/atributos1.cl b/src/debbuging/tests_ccil/atributos1.cl new file mode 100644 index 000000000..6c0fa8411 --- /dev/null +++ b/src/debbuging/tests_ccil/atributos1.cl @@ -0,0 +1,12 @@ + class Main { + p1: Int <- 5; + p2: Int <- 10 + 5; + p3: Int; + p4: String; + p5: Bool; + main() : Int + { + p1 + }; +}; + From ba09161a82af07acb78d252ab6474061ec21f093 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 01:12:01 -0500 Subject: [PATCH 275/432] Minor refactoring and string representation improvements --- src/asts/ccil_ast.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 7f3560fc3..1ce889196 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -14,8 +14,9 @@ class CCILProgram: data_section: List[str] # no idea what will be this the node, def __str__(self) -> str: - types = "\n".join(str(type) for type in self.types_section) - data = "\n".join(str(data) for data in self.data_section) + ident = "\t" + types = "\n".join(ident + str(type) for type in self.types_section) + data = "\n".join(ident + str(data) for data in self.data_section) code = "\n".join(str(func) for func in self.code_section) return f"TYPES:\n{types}\nDATA:\n{data}\nCODE:\n{code} " @@ -32,10 +33,13 @@ class Class: init_operations: FunctionNode def __str__(self) -> str: - attributes = "\n".join(str(a) for a in self.attributes) - methods = "\n".join(str(m) for m in self.methods) + ident = "\t\t" + attributes = "\n".join(ident + str(a) for a in self.attributes) + methods = "\n".join(ident + str(m) for m in self.methods) init_function = str(self.init_operations) - return f"\ttype {self.id} {{\n {attributes} \n {methods} \n \n {init_function}\n\t}}" + return ( + f"type {self.id} {{\n {attributes} \n {methods} \n \n {init_function}\n\t}}" + ) @dataclass(frozen=True) @@ -76,7 +80,7 @@ class Data: value: str def __str__(self) -> str: - return f"\t{self.id} : '{self.value}'" + return f"{self.id} : '{self.value}'" @dataclass(frozen=True) @@ -89,7 +93,7 @@ class Method: function: FunctionNode def __str__(self) -> str: - return f"\t\tmethod {self.id} : {self.function.id}" + return f"method {self.id} : {self.function.id}" class Node: From 798776d506c915cca0fbe5e01e7384e6939174b6 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 01:12:54 -0500 Subject: [PATCH 276/432] Bug fix when getting attributes and correctly initialized unitiliazed vars --- src/code_gen/ccil_gen.py | 47 ++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 1ca513a8a..abb184965 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -13,12 +13,18 @@ ATTR_VISITOR_RESULT = List[OperationNode] DEFAULT_STR = Data("default_str", "") +ZERO = "zero" +EMPTY = "empty" # TODO: +# Define how equality is handled +# Define how isVoid is handled +# See built in classes methods are correctly executed +# See how typeof should work, a special kind of equality? # Define abort nodes with a text: # * Dispatch on a void class # * No pattern match in case (Done) -# * Division by zero +# * Division by zero (Done) # * Substring out of range (Done) # * Heap Overflow (don't know yet how to handle this) @@ -86,10 +92,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: init_params = self.init_func_params(node.id) self.ccil_cool_names.add_new_name_pair("self", node.id) attributes: List[Attribute] = list() - init_attr_ops: List[OperationNode] = [ - self.create_storage("zero", INT, IntNode("0")), - self.create_string_load_data("empty", DEFAULT_STR.id), - ] + init_attr_ops: List[OperationNode] = self.init_default_values() for attr in attr_nodes: attributes.append(Attribute(ATTR + attr.id, attr.type.name)) attr_ops = self.visit(attr) @@ -128,9 +131,9 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> ATTR_VISITOR_RESULT: if node.expr is None: if node.type.name != STRING: - value_0 = IdNode("zero") + value_0 = IdNode(ZERO) else: - value_0 = IdNode("empty") + value_0 = IdNode(EMPTY) set_attr = SetAttrOpNode("self", attr_id, value_0, self.current_type) return [set_attr] @@ -188,7 +191,7 @@ def visit(self, node: sem_ast.BlocksNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.create_child() - operations: List[OperationNode] = [] + operations: List[OperationNode] = self.init_default_values() fvalues: List[StorageNode] = [] for var in node.var_decl_list: @@ -211,10 +214,10 @@ def visit(self, node: sem_ast.VarDeclarationNode) -> VISITOR_RESULT: if node.expr is None: if node.type.name != STRING: - value_0 = self.create_storage("zero", INT, IntNode("0")) + value_0 = IdNode(ZERO) else: - value_0 = self.create_string_load_data("empty", DEFAULT_STR.id) - fval = self.create_assignation(fvalue_id, node.type.name, value_0.id) + value_0 = IdNode(EMPTY) + fval = self.create_assignation(fvalue_id, node.type.name, value_0.value) return [fval], fval (expr_ops, expr_fv) = self.visit(node.expr) @@ -297,7 +300,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # All branch must end in a var named like this pre_fvalue_id = f"case_{times}_pre_fv" - pattern_match_ops = [] + pattern_match_ops = [self.init_default_values()] branch_ops = [] for (i, option) in enumerate(node.options): # Initializing the branch var @@ -411,7 +414,7 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: elif node_type == sem_ast.DivNode: op = DivOpNode(left_id, right_id) fval_id = f"div_{times}" - # Generating divison by zero warning + # Generating divison by zero runtime error ok_label = LabelNode(f"ok_div_{times}") right_id_is_zero = self.create_equality( f"check_right_zero_{times}", left_id, IntNode("0") @@ -552,7 +555,7 @@ def visit(self, node: sem_ast.VariableNode) -> VISITOR_RESULT: if is_attr: get_attr = self.create_attr_extraction( - id_id, node.type.name, "self", ccil_id + id_id, node.type.name, "self", ccil_id, self.current_type ) return [get_attr], get_attr @@ -775,17 +778,17 @@ def create_assignation(self, idx: str, type_idx: str, target: str): def create_uninitialized_storage(self, idx: str, type_idx: str): self.add_local(idx, type_idx) - return StorageNode(idx, VoidNode()) + return StorageNode(idx, ZERO if type_idx != STRING else EMPTY) def create_storage(self, idx: str, type_idx: str, op: ReturnOpNode): self.add_local(idx, type_idx) return StorageNode(idx, op) def create_attr_extraction( - self, idx: str, type_idx: str, from_idx: str, attr_idx: str + self, idx: str, type_idx: str, from_idx: str, attr_idx: str, from_type_idx: str ): self.add_local(idx, type_idx) - return StorageNode(idx, GetAttrOpNode(type_idx, from_idx, attr_idx)) + return StorageNode(idx, GetAttrOpNode(from_type_idx, from_idx, attr_idx)) def create_new_type(self, idx: str, type_idx: str): self.add_local(idx, type_idx) @@ -832,6 +835,14 @@ def create_length(self, idx: str, target: str): self.add_local(idx, INT) return StorageNode(idx, LengthOpNode(target)) + def init_default_values(self): + if not ZERO in self.locals and not EMPTY in self.locals: + return [ + self.create_storage(ZERO, INT, IntNode("0")), + self.create_string_load_data(EMPTY, DEFAULT_STR.id), + ] + return [] + def add_data(self, idx: str, value: str): data = Data(idx, value) self.data.append(data) @@ -845,14 +856,12 @@ def add_local(self, idx: str, typex: str): if idx in self.locals: raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex - self.defined_vars.add(idx) def reset_locals(self): """ Apply at the beginning of every method to reset local vars """ self.locals = dict() - self.defined_vars = set() def reset_scope(self): self.ccil_cool_names = Scope() From 4ccd479928b21940f1cdd12d6eae6b404a2ea12a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 08:07:10 -0500 Subject: [PATCH 277/432] Add runtime error detection when calling from void expresion Fix other minor bugs --- src/code_gen/ccil_gen.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index abb184965..fefff24be 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -17,12 +17,13 @@ EMPTY = "empty" # TODO: +# Define how inherited attributes are executed in inherited class # Define how equality is handled # Define how isVoid is handled # See built in classes methods are correctly executed # See how typeof should work, a special kind of equality? # Define abort nodes with a text: -# * Dispatch on a void class +# * Dispatch on a void class (Done) # * No pattern match in case (Done) # * Division by zero (Done) # * Substring out of range (Done) @@ -300,7 +301,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # All branch must end in a var named like this pre_fvalue_id = f"case_{times}_pre_fv" - pattern_match_ops = [self.init_default_values()] + pattern_match_ops = self.init_default_values() branch_ops = [] for (i, option) in enumerate(node.options): # Initializing the branch var @@ -341,15 +342,17 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] - # Merging all expression operations in correct order - # and saving all to final value + self.locals[pre_fvalue_id] = node.type.name + # Error handling when there is not pattern match err_msg = self.add_data( f"case_error_msg_{times}", f"Pattern match failure in {node.line}, {node.col}", ) err_var = self.create_string_load_data(f"case_error_var_{times}", err_msg.id) + # Merging all expression operations in correct order + # and saving all to final value fval_id = f"case_{times}_fv" fval = self.create_assignation(fval_id, node.type.name, pre_fvalue_id) operations = [ @@ -521,7 +524,29 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ) return [*args_ops, call], call - (expr_ops, _) = self.visit(node.expr) + (expr_ops, expr_fval) = self.visit(node.expr) + + # Runtime error depending if expr is void or not + error_ops = [] + if node.expr.type.name not in {INT, STRING, BOOL}: + expr_fval_is_void = self.create_equality( + "expr_is_void", extract_id(expr_fval), IntNode("0") + ) + ok_label = LabelNode(f"expr_is_not_void") + if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) + error_msg = self.add_data( + "caller_void_err", + f"RuntimeError: expresion in {node.line}, {node.col} is void", + ) + load_err = self.create_string_load_data("callor_void_err_var", error_msg.id) + print_and_abort = self.notifiy_and_abort(load_err.id) + error_ops = [ + expr_fval_is_void, + if_is_not_void, + load_err, + *print_and_abort, + ok_label, + ] # @type.id(arg1, arg2, ..., argn) if node.at_type is not None: @@ -529,13 +554,13 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: call = self.create_call( fval_id, node.type.name, node.id, node.caller_type.name ) - return [*args_ops, *expr_ops, call] + return [*expr_ops, *error_ops, *args_ops, call] # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" call = self.create_vcall(fval_id, node.type.id, node.id, node.caller_type) - return [*args_ops, *expr_ops, call] + return [*expr_ops, *error_ops, *args_ops, call] @visitor.when(sem_ast.InstantiateNode) def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: From 9419d590e6b20f5fa582d6cd781bedbc16bbda6b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 08:33:10 -0500 Subject: [PATCH 278/432] Update ccil ast --- src/asts/ccil_ast.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 1ce889196..26dae28bb 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -176,13 +176,18 @@ def __str__(self) -> str: return "abort" -class PrintOpNode(OperationNode): +class PrintStrNode(OperationNode): def __init__(self, idx: str) -> None: super().__init__() self.id = idx def __str__(self) -> str: - return f"print {self.id}" + return f"print_str {self.id}" + + +class PrintIntNode(PrintStrNode): + def __str__(self) -> str: + return f"print_int {self.id}" class ReturnOpNode(OperationNode): @@ -301,7 +306,11 @@ class ComparisonOpNode(BinaryOpNode): pass -class EqualOpNode(ComparisonOpNode): +class EqualIntNode(ComparisonOpNode): + pass + + +class EqualStrNode(ComparisonOpNode): pass From 4bb8e482e102efa82665e81c4a392e888ed9b936 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 08:33:27 -0500 Subject: [PATCH 279/432] Minor improvements --- src/code_gen/ccil_gen.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index fefff24be..a074ab5a4 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -446,7 +446,7 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: return ([*left_ops, *right_ops, *extra_ops, fval], fval) @visitor.when(sem_ast.ComparerNode) - def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: + def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: times = self.times(node) (left_ops, left_fval) = self.visit(node.left) @@ -457,11 +457,14 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: fval_id: str op: BinaryOpNode - # Arithmetic Binary Nodes node_type = type(node) # Boolean Binary Nodes if node_type == sem_ast.EqualsNode: - op = EqualOpNode(left_id, right_id) + op = ( + EqualOpNode(left_id, right_id) + if node.left.type.name != STRING + else EqualStrNode(left_id, right_id) + ) fval_id = f"eq_{times}" elif node_type == sem_ast.LessNode: op = LessOpNode(left_id, right_id) @@ -477,6 +480,10 @@ def visit(self, node: sem_ast.BinaryNode) -> VISITOR_RESULT: fval = self.create_storage(fval_id, node.type.name, op) return ([*left_ops, *right_ops, fval], fval) + @visitor.when(sem_ast.EqualsNode) + def visit(self, node: sem_ast.EqualsNode) -> VISITOR_RESULT: + pass + @visitor.when(sem_ast.UnaryNode) def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: times = self.times(node) From d2fa0cffe0fcc49963305f12eab4cc3a379872c2 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 08:52:40 -0500 Subject: [PATCH 280/432] Fix location of locals id relative to functions --- src/code_gen/ccil_mips_gen.py | 258 +++++++++++++++++++++++++--------- 1 file changed, 190 insertions(+), 68 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 6e05cb0d5..934155a91 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1,32 +1,33 @@ -from typing import Union, Dict, List +from typing import Tuple, Union, Dict, List from utils import visitor from asts import mips_ast, ccil_ast from utils import visitor -from constants import * +from .constants import * WORD = 4 DOUBLE_WORD = 8 -Location = Dict[str, mips_ast.MemoryIndexNode] -Types = Dict[str, str] +Location = Dict[Tuple[str, str], mips_ast.MemoryIndexNode] class CCILToMIPSGenerator: def __init__(self) -> None: - self.__types_table: List[ccil_ast.Class] # list or dict for classes??? - self.__location: Location - self.__types: Types - self.__current_type: str + self.__types_table: List[ccil_ast.Class] = [] # list or dict for classes??? + self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode def push_stack(self, node, register: mips_ast.RegisterNode): stack_pointer = mips_ast.RegisterNode(node, SP) instructions = [] instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, -1 * WORD) + mips_ast.Addi(node, stack_pointer, stack_pointer, -1 * DOUBLE_WORD) ) instructions.append( mips_ast.StoreWord( - node, register, mips_ast.MemoryIndexNode(node, 0, stack_pointer) + node, + register, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), stack_pointer + ), ) ) return instructions @@ -36,10 +37,16 @@ def pop_stack(self, node, register: mips_ast.RegisterNode): instructions = [] instructions.append( mips_ast.LoadWord( - node, register, mips_ast.MemoryIndexNode(node, 0, stack_pointer) + node, + register, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), stack_pointer + ), ) ) - instructions.append(mips_ast.Addi(node, stack_pointer, stack_pointer, WORD)) + instructions.append( + mips_ast.Addi(node, stack_pointer, stack_pointer, DOUBLE_WORD) + ) return instructions @visitor.on("node") @@ -68,8 +75,8 @@ def visit(self, node: ccil_ast.CCILProgram): # TODO: other .data section static data inicializations like strings functions = [] - for classx in node.types_section: - functions.extend(self.visit(classx.init_operations)) + # for classx in node.types_section: + # functions.extend(self.visit(classx.init_operations)) for func in node.code_section: functions.extend(self.visit(func)) @@ -81,52 +88,74 @@ def visit(self, node: ccil_ast.CCILProgram): @visitor.when(ccil_ast.FunctionNode) def visit(self, node: ccil_ast.FunctionNode): + self.__current_function = node instructions = [] instructions.append(mips_ast.LabelDeclaration(node, node.id)) - frame_size = (len(node.locals)) * WORD + 12 + frame_size = (len(node.locals)) * DOUBLE_WORD + 2 * DOUBLE_WORD stack_pointer = mips_ast.RegisterNode(node, SP) return_address = mips_ast.RegisterNode(node, RA) frame_pointer = mips_ast.RegisterNode(node, FP) index = 0 for param in reversed(node.locals): - self.__location[param.id] = mips_ast.MemoryIndexNode( - node, index, frame_pointer + self.set_relative_location( + param.id, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, index), frame_pointer + ), ) - index += WORD + index += DOUBLE_WORD index = 0 for local in node.params: - self.__location[local.id] = mips_ast.MemoryIndexNode( - node, -1 * index, frame_pointer + self.set_relative_location( + local.id, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, -1 * index), frame_pointer + ), ) - index += WORD + index += DOUBLE_WORD instructions.append( - mips_ast.Subu(node, stack_pointer, stack_pointer, frame_size) + mips_ast.Subu( + node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) + ) ) instructions.append( mips_ast.StoreWord( node, return_address, - mips_ast.MemoryIndexNode(node, frame_size - 2 * WORD, stack_pointer), + mips_ast.MemoryIndexNode( + node, + mips_ast.Constant(node, frame_size - DOUBLE_WORD), + stack_pointer, + ), ) ) instructions.append( mips_ast.StoreWord( node, frame_pointer, - mips_ast.MemoryIndexNode(node, frame_size - 3 * WORD, stack_pointer), + mips_ast.MemoryIndexNode( + node, + mips_ast.Constant(node, frame_size - 2 * DOUBLE_WORD), + stack_pointer, + ), ) ) instructions.append( - mips_ast.Addu(node, frame_pointer, frame_pointer, frame_size - WORD) + mips_ast.Addu( + node, + frame_pointer, + frame_pointer, + mips_ast.Constant(node, frame_size - WORD), + ) ) for op in node.operations: - instructions += self.visit(op) + instructions.extend(self.visit(op)) - ret_location = self.__location[node.ret] + ret_location = self.__location[node.ret.id] ret_register = mips_ast.RegisterNode(node, 3) instructions.append(mips_ast.LoadWord(node, ret_register, ret_location)) @@ -134,18 +163,28 @@ def visit(self, node: ccil_ast.FunctionNode): mips_ast.LoadWord( node, return_address, - mips_ast.MemoryIndexNode(node, frame_size - WORD, stack_pointer), + mips_ast.MemoryIndexNode( + node, + mips_ast.Constant(node, frame_size - DOUBLE_WORD), + stack_pointer, + ), ) ) instructions.append( mips_ast.LoadWord( node, frame_pointer, - mips_ast.MemoryIndexNode(node, frame_size - 3 * WORD, stack_pointer), + mips_ast.MemoryIndexNode( + node, + mips_ast.Constant(node, frame_size - 2 * DOUBLE_WORD), + stack_pointer, + ), ) ) instructions.append( - mips_ast.Addu(node, stack_pointer, stack_pointer, frame_size) + mips_ast.Addu( + node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) + ) ) instructions.append(mips_ast.JumpRegister(node, return_address)) @@ -153,11 +192,23 @@ def visit(self, node: ccil_ast.FunctionNode): @visitor.when(ccil_ast.StorageNode) def visit(self, node: ccil_ast.StorageNode): - location_id = self.__location[node.id] + location_id = self.get_relative_location(node.id) instructions = [] - instructions.append(self.visit(node.operation)) + instructions.extend(self.visit(node.operation)) instructions.append( - mips_ast.StoreWord(node, mips_ast.RegisterNode(node, 2), location_id) + mips_ast.StoreWord(node, mips_ast.RegisterNode(node, V0), location_id) + ) + return instructions + + @visitor.when(ccil_ast.IntNode) + def visit(self, node: ccil_ast.IntNode): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, + mips_ast.RegisterNode(node, V0), + mips_ast.Constant(node, node.value), + ) ) return instructions @@ -166,7 +217,7 @@ def visit(self, node: ccil_ast.CallOpNode): reg = mips_ast.RegisterNode(node, 10) instructions = [] for arg in node.args: - instructions.append(mips_ast.LoadWord(node, reg, self.__location[arg])) + instructions.append(mips_ast.LoadWord(node, reg, self.get_relative_location(arg))) instructions.append(self.push_stack(node, reg)) instructions.append(mips_ast.JumpAndLink(node, node.id)) @@ -181,7 +232,7 @@ def visit(self, node: ccil_ast.CallOpNode): def visit(self, node: ccil_ast.VCallOpNode): instructions = [] - obj_location = self.__location[node.args[0]] + obj_location = self.get_relative_location(node.args[0]) obj_type = mips_ast.RegisterNode(node, T0) instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) @@ -191,20 +242,22 @@ def visit(self, node: ccil_ast.VCallOpNode): mips_ast.LoadWord( node, register_function, - mips_ast.MemoryIndexNode(node, function_index, obj_type), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, function_index), obj_type + ), ) ) reg_arg = mips_ast.RegisterNode(node, T2) instructions = [] for arg in node.args: - instructions.append(mips_ast.LoadWord(node, reg_arg, self.__location[arg])) + instructions.append(mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg))) instructions.append(self.push_stack(node, reg_arg)) instructions.append(mips_ast.JumpAndLink(node, register_function)) if len(node.args) > 0: stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) + mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * DOUBLE_WORD) ) return instructions @@ -213,7 +266,7 @@ def visit(self, node: ccil_ast.VCallOpNode): def visit(self, node: ccil_ast.NewOpNode): instructions = [] # TODO: SELF_TYPE - size = self.get_attr_count(node.type_idx) + 2 * WORD + size = self.get_attr_count(node.type) + WORD instructions.append( mips_ast.LoadImmediate( node, @@ -223,7 +276,7 @@ def visit(self, node: ccil_ast.NewOpNode): ) instructions.append( mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, V1), mips_ast.Constant(node, "9") + node, mips_ast.RegisterNode(node, V1), mips_ast.Constant(node, 9) ) ) instructions.append(mips_ast.Syscall(node)) @@ -232,7 +285,7 @@ def visit(self, node: ccil_ast.NewOpNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, T0), - mips_ast.Label(node, node.type_idx), + mips_ast.Label(node, node.type), ) ) instructions.append( @@ -240,7 +293,7 @@ def visit(self, node: ccil_ast.NewOpNode): node, mips_ast.RegisterNode(node, T0), mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, "0"), mips_ast.RegisterNode(node, V0) + node, mips_ast.Constant(node, 0), mips_ast.RegisterNode(node, V0) ), ) ) @@ -250,7 +303,7 @@ def visit(self, node: ccil_ast.NewOpNode): def visit(self, node: ccil_ast.GetAttrOpNode): instructions = [] attr_offset = self.get_attr_index(node.instance_type, node.attr) - location_object = self.__location[node.instance] + location_object = self.get_relative_location(node.instance) instructions.append( mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), location_object) @@ -274,30 +327,55 @@ def visit(self, node: ccil_ast.GetTypeOpNode): instructions = [] instructions.append( mips_ast.LoadWord( - node, mips_ast.RegisterNode(node, T0), self.__location[node.atom.value] + node, mips_ast.RegisterNode(node, T0), self.get_relative_location(node.atom.value) ) ) instructions.append( mips_ast.LoadWord( node, mips_ast.RegisterNode(node, V0), - mips_ast.MemoryIndexNode(node, 0, mips_ast.RegisterNode(node, T0)), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), mips_ast.RegisterNode(node, T0) + ), ) ) return instructions @visitor.when(ccil_ast.SetAttrOpNode) - def visist(self, node: ccil_ast.SetAttrOpNode): + def visit(self, node: ccil_ast.SetAttrOpNode): instructions = [] - # TODO missing object location - attr_offset = self.get_attr_index(node.type, node.attr) - object_location = self.__location[node.source_id.value] + attr_offset = self.get_attr_index(node.instance_type, node.attr) + object_location = self.get_relative_location(node.instance) instructions.append( mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), object_location) ) + reg_new_value = mips_ast.RegisterNode(node, T0) + if isinstance(node.new_value, ccil_ast.IntNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg_new_value, mips_ast.Constant(node, node.new_value.value) + ) + ) + elif isinstance(node.new_value, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord( + node, reg_new_value, self.get_relative_location(node.new_value.value) + ) + ) + instructions.append( + mips_ast.StoreWord( + node, + reg_new_value, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, attr_offset), object_location + ), + ) + ) + return instructions + @visitor.when(ccil_ast.SumOpNode) def visit(self, node: ccil_ast.SumOpNode): instructions = [] @@ -305,7 +383,7 @@ def visit(self, node: ccil_ast.SumOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -313,7 +391,7 @@ def visit(self, node: ccil_ast.SumOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -334,7 +412,7 @@ def visit(self, node: ccil_ast.MinusOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -342,7 +420,7 @@ def visit(self, node: ccil_ast.MinusOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -363,7 +441,7 @@ def visit(self, node: ccil_ast.MultOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -371,7 +449,7 @@ def visit(self, node: ccil_ast.MultOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -392,7 +470,7 @@ def visit(self, node: ccil_ast.DivOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -400,7 +478,7 @@ def visit(self, node: ccil_ast.DivOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -423,7 +501,7 @@ def visit(self, node: ccil_ast.LessOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -431,7 +509,7 @@ def visit(self, node: ccil_ast.LessOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -452,7 +530,7 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -460,7 +538,7 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -481,7 +559,7 @@ def visit(self, node: ccil_ast.EqualOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.__location[node.left.value]) + mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -489,7 +567,7 @@ def visit(self, node: ccil_ast.EqualOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.__location[node.right.value]) + mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -516,7 +594,7 @@ def visit(self, node: ccil_ast.NotOpNode): ) elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg, self.__location[node.atom.value]) + mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) ) instructions.append(mips_ast.Not(node, reg, reg)) @@ -535,12 +613,50 @@ def visit(self, node: ccil_ast.NegOpNode): ) elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg, self.__location[node.atom.value]) + mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) ) instructions.append(mips_ast.Xori(node, reg, reg, mips_ast.Constant(node, "1"))) return instructions + @visitor.when(ccil_ast.IsVoidOpNode) + def visit(self, node: ccil_ast.IsVoidOpNode): + instructions = [] + + reg = mips_ast.RegisterNode(node, T1) + if isinstance(node.atom, ccil_ast.IntNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg, mips_ast.Constant(node, node.atom.value) + ) + ) + elif isinstance(node.atom, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) + ) + + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, T0), mips_ast.Constant(node, "0") + ) + ) + instructions.append( + mips_ast.Equal( + node, + mips_ast.RegisterNode(node, V0), + reg, + mips_ast.RegisterNode(node, T0), + ) + ) + + return instructions + + @visitor.when(ccil_ast.LoadOpNode) + def visit(self, node: ccil_ast.LoadOpNode): + instructions = [] + + return instructions + @visitor.when(ccil_ast.IfFalseNode) def visit(self, node: ccil_ast.IfFalseNode): instructions = [] @@ -548,12 +664,12 @@ def visit(self, node: ccil_ast.IfFalseNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, T0), - self.__location[node.eval_value.value], + self.get_relative_location(node.eval_value.value), ) ) instructions.append( mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, 9), mips_ast.Constant(node, "0") + node, mips_ast.RegisterNode(node, 9), mips_ast.Constant(node, 0) ) ) instructions.append( @@ -603,7 +719,13 @@ def get_method_index(self, typex: str, method: str) -> int: def get_class_method(self, typex: str, method: str) -> str: for _type in self.__types_table: if _type.id == typex: - for index, _method in enumerate(_type.methods): + for _method in _type.methods: if _method.id == method: return _method.function.id raise Exception("Method implementation not found") + + def get_relative_location(self, id: str): + return self.__location[self.__current_function.id, id] + + def set_relative_location(self, id: str, memory: mips_ast.MemoryIndexNode): + self.__location[self.__current_function.id, id] = memory From 71d470b8986d572ff3c966531db86ea4243815b1 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 09:04:57 -0500 Subject: [PATCH 281/432] Minor refactoring --- src/asts/ccil_ast.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 26dae28bb..b1e64beef 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -227,27 +227,23 @@ def __str__(self) -> str: class CallOpNode(ReturnOpNode): - def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: + def __init__(self, idx: str, type_idx: str, args: List[IdNode]) -> None: super().__init__() self.id = idx self.type = type_idx self.args = args def __str__(self) -> str: - args = ", ".join(f"arg {a}" for a in self.args) - return f"call {self.id} : {self.type} ({args})" + args = ", ".join(f"{a.value}" for a in self.args) + return f"call {self.id} : {self.type} (args: {args})" -class VCallOpNode(ReturnOpNode): - def __init__(self, idx: str, type_idx: str, args: List[str]) -> None: - super().__init__() - self.id = idx - self.type = type_idx - self.args = args +class VCallOpNode(CallOpNode): + def __init__(self, idx: str, type_idx: str, args: List[IdNode]) -> None: + super().__init__(idx, type_idx, args) def __str__(self) -> str: - args = ", ".join(f"arg {a}" for a in self.args) - return f"vcall {self.id} : {self.type} ({args})" + return "v" + super().__str__() class VoidNode(ReturnOpNode): From c88c901d6e1d7a6ad58c9c78d4d702bb7ca3ecb8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 09:05:25 -0500 Subject: [PATCH 282/432] Refactoring and minor bug fix --- src/code_gen/ccil_gen.py | 133 ++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 56 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index a074ab5a4..3c851fbdb 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -81,33 +81,16 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: attr_nodes = [] func_nodes = [] + attributes: List[Attribute] = list() for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): + attributes.append(Attribute(ATTR + feature.id, feature.type.name)) attr_nodes.append(feature) else: func_nodes.append(feature) - # Explore all attributes and join their operations in an initializer function - self.reset_locals() - self.reset_scope() - init_params = self.init_func_params(node.id) - self.ccil_cool_names.add_new_name_pair("self", node.id) - attributes: List[Attribute] = list() - init_attr_ops: List[OperationNode] = self.init_default_values() - for attr in attr_nodes: - attributes.append(Attribute(ATTR + attr.id, attr.type.name)) - attr_ops = self.visit(attr) - init_attr_ops += attr_ops - - dummy_return = self.create_storage(f"init_type_{node.id}_ret", INT, IntNode(0)) - init_attr_ops.append(dummy_return) - init_func = FunctionNode( - f"init_{node.id}", - init_params, - to_vars(self.locals, Local), - init_attr_ops, - dummy_return.id, - ) + # Create init func using attributes and their expressions + init_func = self.create_class_init_func(node, attr_nodes) # Explore all functions self.reset_scope() @@ -461,7 +444,7 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: # Boolean Binary Nodes if node_type == sem_ast.EqualsNode: op = ( - EqualOpNode(left_id, right_id) + EqualIntNode(left_id, right_id) if node.left.type.name != STRING else EqualStrNode(left_id, right_id) ) @@ -517,11 +500,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # Translate all call arguments to ccil # Name all fvalues as ARG args_ops: List[OperationNode] = [] - args: List[StorageNode] = [] + args: List[IdNode] = [] for arg_expr in node.args: (arg_op, arg_fval) = self.visit(arg_expr) args_ops += arg_op - args += [arg_fval] + args += [extract_id(arg_fval)] # id(arg1, arg2, ..., argn) if node.expr is None: @@ -619,39 +602,48 @@ def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: times = self.times(node) bool_id = f"bool_{times}" - value = "0" if node.value == "False" else "1" + value = "0" if node.value == "false" else "1" bool_node = self.create_int(bool_id, value) return [bool_node], bool_node - def times(self, node: sem_ast.Node, extra: str = ""): - key: str = type(node).__name__ + extra - try: - self.time_record[key] += 1 - except KeyError: - self.time_record[key] = 0 - return self.time_record[key] - - def create_call( + def create_class_init_func( self, - storage_idx: str, - type_idx: str, - method_idx: str, - args: List[StorageNode], + node: sem_ast.ClassDeclarationNode, + attr_nodes: List[sem_ast.AttrDeclarationNode], ): - self.add_local(storage_idx, type_idx) - return StorageNode(storage_idx, CallOpNode(method_idx, args)) + self.reset_locals() + self.reset_scope() - def create_vcall( - self, - storage_idx: str, - type_idx: str, - method_idx: str, - method_type_idx: str, - args: List[StorageNode], - ): - self.add_local(storage_idx, type_idx) - return StorageNode(storage_idx, VCallOpNode(method_idx, method_type_idx, args)) + init_params = self.init_func_params(node.id) + self.ccil_cool_names.add_new_name_pair("self", node.id) + + # First operation, initalizing parent attributes + init_parent = self.create_call( + f"call_parent_{node.parent}", + INT, + f"init_{node.parent}", + node.parent, + [IdNode("self")], + ) + + # Execute all attributes operation and set them + init_attr_ops: List[OperationNode] = [init_parent, *self.init_default_values()] + for attr in attr_nodes: + attr_ops = self.visit(attr) + init_attr_ops += attr_ops + + dummy_return = self.create_storage(f"init_type_{node.id}_ret", INT, IntNode(0)) + init_attr_ops.append(dummy_return) + + # return init function + return FunctionNode( + f"init_{node.id}", + init_params, + to_vars(self.locals, Local), + init_attr_ops, + dummy_return.id, + ) def define_built_ins(self): # Defining Object class methods @@ -692,7 +684,7 @@ def define_built_ins(self): params = self.init_func_params(IO) str_input = Parameter("x", STRING) params.append(str_input) - print = PrintOpNode(str_input.id) + print = PrintStrNode(str_input.id) out_string_func = FunctionNode( "out_string", params, to_vars(self.locals), [print], "self" ) @@ -700,10 +692,9 @@ def define_built_ins(self): params = self.init_func_params(IO) int_input = Parameter("x", INT) params.append(int_input) - int_to_str = self.create_int_to_str("int_to_str", int_input.id) - print = PrintOpNode(int_to_str.id) + print = PrintIntNode(int_input.id) out_int_func = FunctionNode( - "out_int", params, to_vars(self.locals), [int_to_str, print], "self" + "out_int", params, to_vars(self.locals), [print], "self" ) self.reset_locals() params = self.init_func_params(IO) @@ -826,16 +817,38 @@ def create_new_type(self, idx: str, type_idx: str): self.add_local(idx, type_idx) return StorageNode(idx, NewOpNode(type_idx)) + def create_call( + self, + storage_idx: str, + type_idx: str, + method_idx: str, + method_type_idx: str, + args: List[StorageNode], + ): + self.add_local(storage_idx, type_idx) + return StorageNode(storage_idx, CallOpNode(method_idx, method_type_idx, args)) + + def create_vcall( + self, + storage_idx: str, + type_idx: str, + method_idx: str, + method_type_idx: str, + args: List[StorageNode], + ): + self.add_local(storage_idx, type_idx) + return StorageNode(storage_idx, VCallOpNode(method_idx, method_type_idx, args)) + def create_type_of(self, idx: str, target: AtomOpNode): self.add_local(idx, ADDRESS) return StorageNode(idx, GetTypeOpNode(target)) def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): self.add_local(idx, BOOL) - return StorageNode(idx, EqualOpNode(left, right)) + return StorageNode(idx, EqualIntNode(left, right)) def notifiy_and_abort(self, target: str): - print = PrintOpNode(target) + print = PrintStrNode(target) abort = Abort() return [print, abort] @@ -875,6 +888,14 @@ def init_default_values(self): ] return [] + def times(self, node: sem_ast.Node, extra: str = ""): + key: str = type(node).__name__ + extra + try: + self.time_record[key] += 1 + except KeyError: + self.time_record[key] = 0 + return self.time_record[key] + def add_data(self, idx: str, value: str): data = Data(idx, value) self.data.append(data) From c7944c4607266f5497d2eb0b718cdb3571827638 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 09:40:51 -0500 Subject: [PATCH 283/432] Rework is void expressions + add warnings + improve error texts --- src/code_gen/ccil_gen.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 3c851fbdb..8032ffee3 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -17,9 +17,6 @@ EMPTY = "empty" # TODO: -# Define how inherited attributes are executed in inherited class -# Define how equality is handled -# Define how isVoid is handled # See built in classes methods are correctly executed # See how typeof should work, a special kind of equality? # Define abort nodes with a text: @@ -29,6 +26,10 @@ # * Substring out of range (Done) # * Heap Overflow (don't know yet how to handle this) +# TEST: +# * Let nodes +# * Built in methods + # BOSS: # Test there are no runtimes errors @@ -46,6 +47,8 @@ def __init__(self) -> None: self.time_record: Dict[str, int] = dict() # Track all constant values. Only strings for now self.data: List[Data] + # Notify about possible but senseless combination of expressions + self.warnings: List[str] = [] # To keep track of the current class being analysed self.current_type: str @@ -330,7 +333,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Error handling when there is not pattern match err_msg = self.add_data( f"case_error_msg_{times}", - f"Pattern match failure in {node.line}, {node.col}", + f"RuntimeError: Pattern match failure in {node.line}, {node.col}", ) err_var = self.create_string_load_data(f"case_error_var_{times}", err_msg.id) @@ -408,7 +411,7 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: if_id_is_not_zero = IfFalseNode(extract_id(right_id_is_zero), ok_label) error_msg = self.add_data( f"error_msg_div_zero_{times}", - f"Error. Zero division detected on {node.line}, {node.col}.", + f"RuntimeError: Zero division detected on {node.line}, {node.col}.", ) error_var = self.create_string_load_data(f"error_var_{times}", error_msg.id) extra_ops = [ @@ -479,8 +482,14 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: node_type = type(node) if node_type == sem_ast.IsVoidNode: - fval_id = f"isVoid_{times}" - op = IsVoidOpNode(expr_id) + fval_id = f"is_void_fv_{times}" + if node.expr.type.name in {BOOL, INT, STRING}: + self.add_warning( + "Warning: Redundant isVoid expression, alway evaluate to false" + ) + op = IntNode("0") + else: + op = EqualIntNode(IdNode(fval_id), IntNode("0")) elif node_type == sem_ast.NotNode: fval_id = f"not_{times}" op = NotOpNode(expr_id) @@ -650,7 +659,7 @@ def define_built_ins(self): self.reset_scope() self.reset_locals() params = self.init_func_params(OBJECT) - abort_msg = self.add_data("abort_msg", "Execution aborted") + abort_msg = self.add_data("abort_msg", "RuntimeError: Execution aborted") load = self.create_string_load_data("abort_temp", abort_msg.id) [print, abort] = self.notifiy_and_abort(load.id) abort_func = FunctionNode( @@ -748,7 +757,9 @@ def define_built_ins(self): ok_label = LabelNode("substring_success") if_upper_bound = IfNode(extract_id(upper_bound), error_label) if_lesser_bound = IfNode(extract_id(lesser_bound), error_label) - print_and_abort = self.notifiy_and_abort("Index out of range exception") + print_and_abort = self.notifiy_and_abort( + "RuntimeError: Index out of range exception" + ) substr = self.create_storage( "substr_var", STRING, @@ -910,6 +921,9 @@ def add_local(self, idx: str, typex: str): raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex + def add_warning(self, msg: str): + self.add_warning(msg) + def reset_locals(self): """ Apply at the beginning of every method to reset local vars From a22edef2e8694acd8df92d3eb53d4a42dbdc8275 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 09:41:54 -0500 Subject: [PATCH 284/432] Remove isVoid node --- src/asts/ccil_ast.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index b1e64beef..2e9d3a2b5 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -331,13 +331,6 @@ def __str__(self) -> str: return f"typeof {self.atom.value}" -class IsVoidOpNode(UnaryOpNode): - """Operation that returns true if the Storage Node is uninitialized""" - - def __str__(self) -> str: - return f"isvoid {self.atom.value}" - - class NotOpNode(UnaryOpNode): def __str__(self) -> str: return f"not {self.atom.value}" From 1d681f4e4495664d5dccd7a3c9ad71bc82e77d8b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 09:43:34 -0500 Subject: [PATCH 285/432] Add new tests --- src/debbuging/tests_ccil/case2.cl | 11 ++++++++ src/debbuging/tests_ccil/classess1.cl | 37 +++++++++++++++++++++++++++ src/debbuging/tests_ccil/isvoid1.cl | 5 ++++ src/debbuging/tests_ccil/isvoid2.cl | 5 ++++ 4 files changed, 58 insertions(+) create mode 100644 src/debbuging/tests_ccil/case2.cl create mode 100644 src/debbuging/tests_ccil/classess1.cl create mode 100644 src/debbuging/tests_ccil/isvoid1.cl create mode 100644 src/debbuging/tests_ccil/isvoid2.cl diff --git a/src/debbuging/tests_ccil/case2.cl b/src/debbuging/tests_ccil/case2.cl new file mode 100644 index 000000000..4080c7fad --- /dev/null +++ b/src/debbuging/tests_ccil/case2.cl @@ -0,0 +1,11 @@ +class Main inherits IO { + main(): Object + { + case 3 + 5 of + n : Bool => 1; + n : Int => "estao"; + n : String => 3; + esac + + }; +}; diff --git a/src/debbuging/tests_ccil/classess1.cl b/src/debbuging/tests_ccil/classess1.cl new file mode 100644 index 000000000..5a5cd42ce --- /dev/null +++ b/src/debbuging/tests_ccil/classess1.cl @@ -0,0 +1,37 @@ +class Main +{ + h:AUTO_TYPE <- new A; + a:AUTO_TYPE <- new D; + main(): Int + { + { + 3; + } + }; +}; + + +class A +{ + b:Int; +}; + +class B inherits A +{ + c:Int; +}; + +class C inherits B +{ + e:Int; +}; + +class D inherits C +{ + f:Int; +}; + +class F inherits D +{ + g:Int; +}; diff --git a/src/debbuging/tests_ccil/isvoid1.cl b/src/debbuging/tests_ccil/isvoid1.cl new file mode 100644 index 000000000..75aa06d9c --- /dev/null +++ b/src/debbuging/tests_ccil/isvoid1.cl @@ -0,0 +1,5 @@ + class Main { + main(): Bool { + isVoid 3 + }; +}; diff --git a/src/debbuging/tests_ccil/isvoid2.cl b/src/debbuging/tests_ccil/isvoid2.cl new file mode 100644 index 000000000..44a79d06b --- /dev/null +++ b/src/debbuging/tests_ccil/isvoid2.cl @@ -0,0 +1,5 @@ + class Main { + main(): Bool { + isVoid (new Object) + }; +}; From 2b6b8a05493a2e9161aca1bf0a6278439bc2af7e Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 09:20:29 -0500 Subject: [PATCH 286/432] Add lw and sw to MIPS string generator --- src/code_gen/ccil_mips_gen.py | 123 ++++++++++++++++++++++++++-------- src/code_gen/mips_gen.py | 10 +++ 2 files changed, 106 insertions(+), 27 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 934155a91..3e8c90327 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -106,7 +106,7 @@ def visit(self, node: ccil_ast.FunctionNode): ), ) index += DOUBLE_WORD - index = 0 + index = DOUBLE_WORD for local in node.params: self.set_relative_location( local.id, @@ -148,15 +148,15 @@ def visit(self, node: ccil_ast.FunctionNode): node, frame_pointer, frame_pointer, - mips_ast.Constant(node, frame_size - WORD), + mips_ast.Constant(node, frame_size - DOUBLE_WORD), ) ) for op in node.operations: instructions.extend(self.visit(op)) - ret_location = self.__location[node.ret.id] - ret_register = mips_ast.RegisterNode(node, 3) + ret_location = self.get_relative_location(node.ret) + ret_register = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.LoadWord(node, ret_register, ret_location)) instructions.append( @@ -217,7 +217,9 @@ def visit(self, node: ccil_ast.CallOpNode): reg = mips_ast.RegisterNode(node, 10) instructions = [] for arg in node.args: - instructions.append(mips_ast.LoadWord(node, reg, self.get_relative_location(arg))) + instructions.append( + mips_ast.LoadWord(node, reg, self.get_relative_location(arg)) + ) instructions.append(self.push_stack(node, reg)) instructions.append(mips_ast.JumpAndLink(node, node.id)) @@ -250,14 +252,18 @@ def visit(self, node: ccil_ast.VCallOpNode): reg_arg = mips_ast.RegisterNode(node, T2) instructions = [] for arg in node.args: - instructions.append(mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg))) + instructions.append( + mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg)) + ) instructions.append(self.push_stack(node, reg_arg)) instructions.append(mips_ast.JumpAndLink(node, register_function)) if len(node.args) > 0: stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * DOUBLE_WORD) + mips_ast.Addi( + node, stack_pointer, stack_pointer, len(node.args) * DOUBLE_WORD + ) ) return instructions @@ -327,7 +333,9 @@ def visit(self, node: ccil_ast.GetTypeOpNode): instructions = [] instructions.append( mips_ast.LoadWord( - node, mips_ast.RegisterNode(node, T0), self.get_relative_location(node.atom.value) + node, + mips_ast.RegisterNode(node, T0), + self.get_relative_location(node.atom.value), ) ) instructions.append( @@ -362,7 +370,9 @@ def visit(self, node: ccil_ast.SetAttrOpNode): elif isinstance(node.new_value, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_new_value, self.get_relative_location(node.new_value.value) + node, + reg_new_value, + self.get_relative_location(node.new_value.value), ) ) instructions.append( @@ -383,7 +393,9 @@ def visit(self, node: ccil_ast.SumOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -391,7 +403,9 @@ def visit(self, node: ccil_ast.SumOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -412,7 +426,9 @@ def visit(self, node: ccil_ast.MinusOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -420,7 +436,9 @@ def visit(self, node: ccil_ast.MinusOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -441,7 +459,9 @@ def visit(self, node: ccil_ast.MultOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -449,7 +469,9 @@ def visit(self, node: ccil_ast.MultOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -470,7 +492,9 @@ def visit(self, node: ccil_ast.DivOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -478,7 +502,9 @@ def visit(self, node: ccil_ast.DivOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -501,7 +527,9 @@ def visit(self, node: ccil_ast.LessOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -509,7 +537,9 @@ def visit(self, node: ccil_ast.LessOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -530,7 +560,9 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -538,7 +570,9 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -559,7 +593,9 @@ def visit(self, node: ccil_ast.EqualOpNode): reg_left = mips_ast.RegisterNode(node, T3) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_left, self.get_relative_location(node.left.value)) + mips_ast.LoadWord( + node, reg_left, self.get_relative_location(node.left.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) @@ -567,7 +603,9 @@ def visit(self, node: ccil_ast.EqualOpNode): reg_right = mips_ast.RegisterNode(node, T4) if isinstance(node.left, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg_right, self.get_relative_location(node.right.value)) + mips_ast.LoadWord( + node, reg_right, self.get_relative_location(node.right.value) + ) ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( @@ -594,7 +632,9 @@ def visit(self, node: ccil_ast.NotOpNode): ) elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) + mips_ast.LoadWord( + node, reg, self.get_relative_location(node.atom.value) + ) ) instructions.append(mips_ast.Not(node, reg, reg)) @@ -613,7 +653,9 @@ def visit(self, node: ccil_ast.NegOpNode): ) elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) + mips_ast.LoadWord( + node, reg, self.get_relative_location(node.atom.value) + ) ) instructions.append(mips_ast.Xori(node, reg, reg, mips_ast.Constant(node, "1"))) @@ -632,7 +674,9 @@ def visit(self, node: ccil_ast.IsVoidOpNode): ) elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( - mips_ast.LoadWord(node, reg, self.get_relative_location(node.atom.value)) + mips_ast.LoadWord( + node, reg, self.get_relative_location(node.atom.value) + ) ) instructions.append( @@ -688,6 +732,31 @@ def visit(self, node: ccil_ast.GoToNode): instructions.append(mips_ast.Jump(node, mips_ast.Label(node, node.target.id))) return instructions + @visitor.when(ccil_ast.LabelNode) + def visit(self, node: ccil_ast.LabelNode): + instructions = [] + instructions.append(mips_ast.LabelDeclaration(node, node.id)) + return instructions + + @visitor.when(ccil_ast.PrintIntNode) + def visit(self, node: ccil_ast.PrintIntNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, A0), + self.get_relative_location(node.id), + ) + ) + + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 1) + ) + ) + instructions.append(mips_ast.Syscall(node)) + return instructions + def get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: @@ -719,7 +788,7 @@ def get_method_index(self, typex: str, method: str) -> int: def get_class_method(self, typex: str, method: str) -> str: for _type in self.__types_table: if _type.id == typex: - for _method in _type.methods: + for _method in _type.methods: if _method.id == method: return _method.function.id raise Exception("Method implementation not found") diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index bb6cc93a5..29340b0da 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -16,12 +16,14 @@ LessOrEqual, LoadAddress, LoadImmediate, + LoadWord, MIPSProgram, MemoryIndexNode, Move, Multiply, Not, RegisterNode, + StoreWord, Sub, Subu, Syscall, @@ -103,6 +105,14 @@ def visit(self, node: WordDirective) -> str: def visit(self, node: Move) -> str: return f"\tmove {self.visit(node.left)}, {self.visit(node.right)}" + @visitor.when(StoreWord) + def visit(self, node: StoreWord) -> str: + return f"\tsw {self.visit(node.left)}, {self.visit(node.right)}" + + @visitor.when(LoadWord) + def visit(self, node: LoadWord) -> str: + return f"\tlw {self.visit(node.left)}, {self.visit(node.right)}" + @visitor.when(Subu) def visit(self, node: Subu) -> str: return f"\tsubu {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" From e0c1d46ec7d279eb720626a8ba6db452ff7ee152 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 09:53:38 -0500 Subject: [PATCH 287/432] Add function_call test --- src/debbuging/tests_ccil/function_call.cl | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/debbuging/tests_ccil/function_call.cl diff --git a/src/debbuging/tests_ccil/function_call.cl b/src/debbuging/tests_ccil/function_call.cl new file mode 100644 index 000000000..7a484e224 --- /dev/null +++ b/src/debbuging/tests_ccil/function_call.cl @@ -0,0 +1,9 @@ + class Main { + main(): Int { + f(1) + }; + + f(a : Int): Int { + a + }; +}; From bff5f44b1e371f8e3d2738d0622920d0e1d3f7e2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 10:03:43 -0500 Subject: [PATCH 288/432] Fix minor bug in semantics where let node expression was not being stored --- src/semantics/inference/back_inferencer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index c60361a4c..9a1774ba8 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -217,6 +217,7 @@ def visit(self, node: VarDeclarationNode, scope: Scope) -> VarDeclarationNode: if node.expr: new_expr_node = self.visit(node.expr, scope) + new_node.expr = new_expr_node decl_type = node.inferenced_type expr_type = new_expr_node.inferenced_type new_node.inferenced_type, changed = unify(decl_type, expr_type) From ec26a612f11168c766e8bf0db35508f364561647 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 10:07:13 -0500 Subject: [PATCH 289/432] Fix type error --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 8032ffee3..b527dd783 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -184,7 +184,7 @@ def visit(self, node: sem_ast.LetNode) -> VISITOR_RESULT: for var in node.var_decl_list: (var_ops, var_fv) = self.visit(var) operations += var_ops - fvalues += var_fv + fvalues.append(var_fv) (in_ops, in_fval) = self.visit(node.in_expr) operations += in_ops From cbba10c936c80fc91c4a95bd9f4a582738259f42 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 10:07:33 -0500 Subject: [PATCH 290/432] Add tests using let expessions --- src/debbuging/tests_ccil/let1.cl | 7 +++++++ src/debbuging/tests_ccil/let2.cl | 12 ++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/debbuging/tests_ccil/let1.cl create mode 100644 src/debbuging/tests_ccil/let2.cl diff --git a/src/debbuging/tests_ccil/let1.cl b/src/debbuging/tests_ccil/let1.cl new file mode 100644 index 000000000..4f4576693 --- /dev/null +++ b/src/debbuging/tests_ccil/let1.cl @@ -0,0 +1,7 @@ + class Main { + main(): Int { + let x : Int <- 3, + y : Int + in x + y + }; +}; diff --git a/src/debbuging/tests_ccil/let2.cl b/src/debbuging/tests_ccil/let2.cl new file mode 100644 index 000000000..642d87469 --- /dev/null +++ b/src/debbuging/tests_ccil/let2.cl @@ -0,0 +1,12 @@ + class Main { + main(): Int { + let x : Int <- 3, + y : Int + in let x: Int, + y: Int <- 4, + z: Int <- 3, + w: Int + in + x + y + z + w + }; +}; From 80ca6184e278a81d5d9163efeb75507420eb5aa1 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 10:56:54 -0500 Subject: [PATCH 291/432] Fix bugs in define_built_ins and refactored code --- src/code_gen/ccil_gen.py | 81 ++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index b527dd783..1c66ecb1e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -27,7 +27,6 @@ # * Heap Overflow (don't know yet how to handle this) # TEST: -# * Let nodes # * Built in methods @@ -66,10 +65,13 @@ def visit(self, node): @visitor.when(sem_ast.ProgramNode) def visit(self, node: sem_ast.ProgramNode) -> None: - program_types: List[Class] = list() - program_codes: List[Method] = list() - self.data = [DEFAULT_STR] + self.reset_locals() + + builtin_classes, builtin_methods = self.define_built_ins() + program_types: List[Class] = builtin_classes + program_codes: List[FunctionNode] = builtin_methods + for type in node.declarations: classx, class_code = self.visit(type) program_types.append(classx) @@ -150,7 +152,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: return FunctionNode( f"f_{times}", params, - to_vars(self.locals, Local), + self.dump_locals(), operations, fval.id, ) @@ -657,25 +659,22 @@ def create_class_init_func( def define_built_ins(self): # Defining Object class methods self.reset_scope() - self.reset_locals() params = self.init_func_params(OBJECT) abort_msg = self.add_data("abort_msg", "RuntimeError: Execution aborted") load = self.create_string_load_data("abort_temp", abort_msg.id) [print, abort] = self.notifiy_and_abort(load.id) abort_func = FunctionNode( - "abort", params, to_vars(self.locals), [load, print, abort], "self" + "abort", params, self.dump_locals(), [load, print, abort], "self" ) - self.reset_locals() params = self.init_func_params(OBJECT) get_name = self.create_current_type_name("get_name") type_name_func = FunctionNode( - "type_name", params, self.locals, [get_name], get_name.id + "type_name", params, self.dump_locals(), [get_name], get_name.id ) - self.reset_locals() params = self.init_func_params(OBJECT) new_instance = self.create_new_type("copy", SELFTYPE) copy_func = FunctionNode( - "copy", params, to_vars(self.locals), [new_instance], new_instance.id + "copy", params, self.dump_locals(), [new_instance], new_instance.id ) object_class = Class( OBJECT, @@ -685,34 +684,35 @@ def define_built_ins(self): Method("type_name", type_name_func), Method("copy", copy_func), ], + self.define_empty_init_func(OBJECT), ) # Defining IO class methods self.reset_scope() - self.reset_locals() params = self.init_func_params(IO) str_input = Parameter("x", STRING) params.append(str_input) print = PrintStrNode(str_input.id) out_string_func = FunctionNode( - "out_string", params, to_vars(self.locals), [print], "self" + "out_string", params, self.dump_locals(), [print], "self" ) - self.reset_locals() params = self.init_func_params(IO) int_input = Parameter("x", INT) params.append(int_input) print = PrintIntNode(int_input.id) out_int_func = FunctionNode( - "out_int", params, to_vars(self.locals), [print], "self" + "out_int", params, self.dump_locals(), [print], "self" ) - self.reset_locals() params = self.init_func_params(IO) read = self.create_read_str("read_str") - in_string_func = FunctionNode("in_string", params, self.locals, [read], read.id) - self.reset_locals() + in_string_func = FunctionNode( + "in_string", params, self.dump_locals(), [read], read.id + ) params = self.init_func_params(IO) read = self.create_read_int("read_int") - in_int_func = FunctionNode("in_int", params, self.locals, [read], read.id) + in_int_func = FunctionNode( + "in_int", params, self.dump_locals(), [read], read.id + ) io_class = Class( IO, [], @@ -722,14 +722,16 @@ def define_built_ins(self): Method("in_string", in_string_func), Method("in_int", in_int_func), ], + self.define_empty_init_func(IO), ) # Defining substring class methods self.reset_scope() - self.reset_locals() params = self.init_func_params(STRING) length = self.create_length("lenght_var", "self") - lenght_func = FunctionNode("length", params, self.locals, [length], length.id) + lenght_func = FunctionNode( + "length", params, self.dump_locals(), [length], length.id + ) self.reset_locals() params = self.init_func_params(STRING) input_s = Parameter("s", STRING) @@ -737,7 +739,9 @@ def define_built_ins(self): concat = self.create_storage( "concat_var", STRING, ConcatOpNode("self", input_s.id) ) - concat_func = FunctionNode("concat", params, self.locals, [concat], concat.id) + concat_func = FunctionNode( + "concat", params, self.dump_locals(), [concat], concat.id + ) self.reset_locals() params = self.init_func_params(STRING) start_index = Parameter("s", INT) @@ -748,10 +752,10 @@ def define_built_ins(self): "max_take", INT, SumOpNode(IdNode(start_index.id), IdNode(take.id)) ) upper_bound = self.create_storage( - "upper_bound", LessOpNode(extract_id(length), extract_id(max_take)) + "upper_bound", INT, LessOpNode(extract_id(length), extract_id(max_take)) ) lesser_bound = self.create_storage( - "lesser_bound", LessOpNode(IdNode(start_index.id), IntNode("0")) + "lesser_bound", INT, LessOpNode(IdNode(start_index.id), IntNode("0")) ) error_label = LabelNode("substring_error") ok_label = LabelNode("substring_success") @@ -779,7 +783,9 @@ def define_built_ins(self): *print_and_abort, ok_label, ] - substr_func = FunctionNode("substr", params, self.locals, operations, substr.id) + substr_func = FunctionNode( + "substr", params, self.dump_locals(), operations, substr.id + ) string_class = Class( STRING, [], @@ -788,6 +794,7 @@ def define_built_ins(self): Method("concat", concat_func), Method("substr", substr_func), ], + self.define_empty_init_func(STRING) ) return [object_class, io_class, string_class], [ @@ -899,6 +906,19 @@ def init_default_values(self): ] return [] + def define_empty_init_func(self, class_name: str): + params = self.init_func_params(class_name) + dummy_return = self.create_storage( + f"init_type_{class_name}_ret", INT, IntNode(0) + ) + return FunctionNode( + f"init_{class_name}", + params, + self.dump_locals(), + [dummy_return], + dummy_return.id, + ) + def times(self, node: sem_ast.Node, extra: str = ""): key: str = type(node).__name__ + extra try: @@ -921,18 +941,23 @@ def add_local(self, idx: str, typex: str): raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex - def add_warning(self, msg: str): - self.add_warning(msg) - def reset_locals(self): """ Apply at the beginning of every method to reset local vars """ self.locals = dict() + def dump_locals(self): + var_locals = to_vars(self.locals, Local) + self.locals = dict() + return var_locals + def reset_scope(self): self.ccil_cool_names = Scope() + def add_warning(self, msg: str): + self.add_warning(msg) + def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: return list(map(lambda x: const(*x), dict.items())) From 7ee90738dc80f46e21346a70d6781e1ab46aa42d Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 11:15:52 -0500 Subject: [PATCH 292/432] Fix MethodCall expression value when none --- src/semantics/inference/types_inferencer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index e4a65b55e..1d4686622 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -175,7 +175,7 @@ def visit(self, node: AssignNode, scope: Scope) -> types_ast.AssignNode: @visitor.when(MethodCallNode) def visit(self, node: MethodCallNode, scope: Scope) -> types_ast.MethodCallNode: args = [self.visit(arg, scope) for arg in node.args] - caller_expr = self.visit(node.expr, scope) + caller_expr = self.visit(node.expr, scope) if node.expr is not None else None new_node = types_ast.MethodCallNode(node.caller_type, caller_expr, args, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node From 208ebee9dc4bab90e0f87af4bba18bc5132f33ed Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 11:16:06 -0500 Subject: [PATCH 293/432] Fix bugs in Call and Vcall --- src/code_gen/ccil_gen.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 1c66ecb1e..44e2ce9ae 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -521,10 +521,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.expr is None: fval_id = f"vcall_{times}" call = self.create_vcall( - fval_id, node.type.id, node.id, node.caller_type.name + fval_id, node.type.name, node.id, node.caller_type.name, args ) return [*args_ops, call], call + print("nn", node.expr) (expr_ops, expr_fval) = self.visit(node.expr) # Runtime error depending if expr is void or not @@ -553,13 +554,13 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.at_type is not None: fval_id = f"call_{times}" call = self.create_call( - fval_id, node.type.name, node.id, node.caller_type.name + fval_id, node.type.name, node.id, node.caller_type.name, args ) return [*expr_ops, *error_ops, *args_ops, call] # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" - call = self.create_vcall(fval_id, node.type.id, node.id, node.caller_type) + call = self.create_vcall(fval_id, node.type.id, node.id, node.caller_type, args) return [*expr_ops, *error_ops, *args_ops, call] @@ -794,7 +795,7 @@ def define_built_ins(self): Method("concat", concat_func), Method("substr", substr_func), ], - self.define_empty_init_func(STRING) + self.define_empty_init_func(STRING), ) return [object_class, io_class, string_class], [ From 7c788831e2490d743b7bd824ae098c96fc002a9b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 11:24:42 -0500 Subject: [PATCH 294/432] Fix naming and instruction on substring built in function --- src/code_gen/ccil_gen.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 44e2ce9ae..55f908aad 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -762,8 +762,12 @@ def define_built_ins(self): ok_label = LabelNode("substring_success") if_upper_bound = IfNode(extract_id(upper_bound), error_label) if_lesser_bound = IfNode(extract_id(lesser_bound), error_label) + error_msg = self.add_data( + "substr_error", "RuntimeError: Index out of range exception" + ) + error_var = self.create_string_load_data("substr_error_var", error_msg.id) print_and_abort = self.notifiy_and_abort( - "RuntimeError: Index out of range exception" + error_var.id ) substr = self.create_storage( "substr_var", @@ -781,6 +785,7 @@ def define_built_ins(self): substr, goto_ok, error_label, + error_var, *print_and_abort, ok_label, ] From b951dde03c4282879acc73f0559b59e225c0d412 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 11:47:45 -0500 Subject: [PATCH 295/432] Add flag to print or not buil ins --- src/asts/ccil_ast.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 2e9d3a2b5..4f334e1b3 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -13,11 +13,17 @@ class CCILProgram: code_section: List[FunctionNode] data_section: List[str] # no idea what will be this the node, - def __str__(self) -> str: + def __str__(self, all=False) -> str: + types_section = self.types_section + code_section = self.code_section + if not all: + types_section = self.types_section[3:] + code_section = self.code_section[10:] + ident = "\t" - types = "\n".join(ident + str(type) for type in self.types_section) + types = "\n".join(ident + str(type) for type in types_section) data = "\n".join(ident + str(data) for data in self.data_section) - code = "\n".join(str(func) for func in self.code_section) + code = "\n".join(str(func) for func in code_section) return f"TYPES:\n{types}\nDATA:\n{data}\nCODE:\n{code} " @@ -32,14 +38,12 @@ class Class: methods: List[Method] init_operations: FunctionNode - def __str__(self) -> str: + def __str__(self, all=True) -> str: ident = "\t\t" attributes = "\n".join(ident + str(a) for a in self.attributes) methods = "\n".join(ident + str(m) for m in self.methods) - init_function = str(self.init_operations) - return ( - f"type {self.id} {{\n {attributes} \n {methods} \n \n {init_function}\n\t}}" - ) + init_function = "\n" + str(self.init_operations) + "\n" if all else "" + return f"type {self.id} {{\n {attributes} \n {methods} \n {init_function}\t}}" @dataclass(frozen=True) From 10c07150b2d7d594f4172ab0a84ec702a5a6570d Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 11:48:17 -0500 Subject: [PATCH 296/432] Refactoring and warning improvement --- src/code_gen/ccil_gen.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 55f908aad..f2d00e218 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -17,7 +17,6 @@ EMPTY = "empty" # TODO: -# See built in classes methods are correctly executed # See how typeof should work, a special kind of equality? # Define abort nodes with a text: # * Dispatch on a void class (Done) @@ -31,8 +30,8 @@ # BOSS: -# Test there are no runtimes errors -# Test that results are obtained as expected +# Test there are no runtimes errors during generation +# Test that generation is correct # CCIL stands for Cool Cows Intermediate Language ;) @@ -487,7 +486,8 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: fval_id = f"is_void_fv_{times}" if node.expr.type.name in {BOOL, INT, STRING}: self.add_warning( - "Warning: Redundant isVoid expression, alway evaluate to false" + f"Warning: Redundant isVoid expression in {node.line}, {node.col}." + " It will always evaluate to false" ) op = IntNode("0") else: @@ -766,9 +766,7 @@ def define_built_ins(self): "substr_error", "RuntimeError: Index out of range exception" ) error_var = self.create_string_load_data("substr_error_var", error_msg.id) - print_and_abort = self.notifiy_and_abort( - error_var.id - ) + print_and_abort = self.notifiy_and_abort(error_var.id) substr = self.create_storage( "substr_var", STRING, From 7a131e1eabff2f61d9242c2e89a0e6cfb39c8b63 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 13:08:43 -0500 Subject: [PATCH 297/432] Minor bug fixing --- src/asts/ccil_ast.py | 2 +- src/code_gen/ccil_gen.py | 5 ++--- src/code_gen/constants.py | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 4f334e1b3..2f8518995 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -13,7 +13,7 @@ class CCILProgram: code_section: List[FunctionNode] data_section: List[str] # no idea what will be this the node, - def __str__(self, all=False) -> str: + def __str__(self, all=True) -> str: types_section = self.types_section code_section = self.code_section if not all: diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index f2d00e218..03a0318fe 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import IO, Tuple, List, Dict +from typing import Tuple, List, Dict from code_gen.tools import * from code_gen.constants import * @@ -134,7 +134,6 @@ def visit(self, node: sem_ast.AttrDeclarationNode) -> ATTR_VISITOR_RESULT: @visitor.when(sem_ast.MethodDeclarationNode) def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: - times = self.times(node) self.ccil_cool_names = self.ccil_cool_names.create_child() params: List[Parameter] = [Parameter("self", self.current_type)] @@ -149,7 +148,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - f"f_{times}", + f"f_{self.times(node)}" if node.id != "main" else "main", params, self.dump_locals(), operations, diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index 443f7faea..2027ce702 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -46,4 +46,5 @@ STRING = "String" VOID = "Void" SELFTYPE = "SELF_TYPE" +IO = "IO" ADDRESS = INT From 9fb2e739416b9fd2be1a135898cd972c3944a3d9 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 14:24:55 -0500 Subject: [PATCH 298/432] Fix frame_pointer setting during function call --- src/code_gen/ccil_mips_gen.py | 235 ++++++++++++++++++++++------------ 1 file changed, 151 insertions(+), 84 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 3e8c90327..b73ca994b 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -19,7 +19,12 @@ def push_stack(self, node, register: mips_ast.RegisterNode): stack_pointer = mips_ast.RegisterNode(node, SP) instructions = [] instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, -1 * DOUBLE_WORD) + mips_ast.Addi( + node, + stack_pointer, + stack_pointer, + mips_ast.Constant(node, -1 * DOUBLE_WORD), + ) ) instructions.append( mips_ast.StoreWord( @@ -45,7 +50,9 @@ def pop_stack(self, node, register: mips_ast.RegisterNode): ) ) instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, DOUBLE_WORD) + mips_ast.Addi( + node, stack_pointer, stack_pointer, mips_ast.Constant(node, DOUBLE_WORD) + ) ) return instructions @@ -55,8 +62,7 @@ def visit(self, node): @visitor.when(ccil_ast.CCILProgram) def visit(self, node: ccil_ast.CCILProgram): - self.types = node.types_section - + self.__types_table = node.types_section types_table = [] for classx in node.types_section: word_directive = [ @@ -75,10 +81,15 @@ def visit(self, node: ccil_ast.CCILProgram): # TODO: other .data section static data inicializations like strings functions = [] - # for classx in node.types_section: - # functions.extend(self.visit(classx.init_operations)) + functions.extend( + [self.visit(func) for func in node.code_section if func.id == "main"][0] + ) + + for classx in node.types_section: + functions.extend(self.visit(classx.init_operations)) for func in node.code_section: - functions.extend(self.visit(func)) + if func.id != "main": + functions.extend(self.visit(func)) return mips_ast.MIPSProgram( None, @@ -102,7 +113,7 @@ def visit(self, node: ccil_ast.FunctionNode): self.set_relative_location( param.id, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, index), frame_pointer + node, mips_ast.Constant(node, -1*index), frame_pointer ), ) index += DOUBLE_WORD @@ -111,7 +122,7 @@ def visit(self, node: ccil_ast.FunctionNode): self.set_relative_location( local.id, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, -1 * index), frame_pointer + node, mips_ast.Constant(node, index), frame_pointer ), ) index += DOUBLE_WORD @@ -147,7 +158,7 @@ def visit(self, node: ccil_ast.FunctionNode): mips_ast.Addu( node, frame_pointer, - frame_pointer, + stack_pointer, mips_ast.Constant(node, frame_size - DOUBLE_WORD), ) ) @@ -186,7 +197,15 @@ def visit(self, node: ccil_ast.FunctionNode): node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) ) ) - instructions.append(mips_ast.JumpRegister(node, return_address)) + if node.id == "main": + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 10) + ) + ) + instructions.append(mips_ast.Syscall(node)) + else: + instructions.append(mips_ast.JumpRegister(node, return_address)) return instructions @@ -218,15 +237,20 @@ def visit(self, node: ccil_ast.CallOpNode): instructions = [] for arg in node.args: instructions.append( - mips_ast.LoadWord(node, reg, self.get_relative_location(arg)) + mips_ast.LoadWord(node, reg, self.get_relative_location(arg.value)) ) - instructions.append(self.push_stack(node, reg)) - instructions.append(mips_ast.JumpAndLink(node, node.id)) + instructions.extend(self.push_stack(node, reg)) + instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, node.id))) if len(node.args) > 0: stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( - mips_ast.Addi(node, stack_pointer, stack_pointer, len(node.args) * WORD) + mips_ast.Addi( + node, + stack_pointer, + stack_pointer, + mips_ast.Constant(node, len(node.args) * WORD), + ) ) return instructions @@ -234,7 +258,7 @@ def visit(self, node: ccil_ast.CallOpNode): def visit(self, node: ccil_ast.VCallOpNode): instructions = [] - obj_location = self.get_relative_location(node.args[0]) + obj_location = self.get_relative_location(node.args[0].value) obj_type = mips_ast.RegisterNode(node, T0) instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) @@ -253,16 +277,19 @@ def visit(self, node: ccil_ast.VCallOpNode): instructions = [] for arg in node.args: instructions.append( - mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg)) + mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg.value)) ) - instructions.append(self.push_stack(node, reg_arg)) + instructions.extend(self.push_stack(node, reg_arg)) instructions.append(mips_ast.JumpAndLink(node, register_function)) if len(node.args) > 0: stack_pointer = mips_ast.RegisterNode(node, SP) instructions.append( mips_ast.Addi( - node, stack_pointer, stack_pointer, len(node.args) * DOUBLE_WORD + node, + stack_pointer, + stack_pointer, + mips_ast.Constant(node, len(node.args) * DOUBLE_WORD), ) ) @@ -271,13 +298,16 @@ def visit(self, node: ccil_ast.VCallOpNode): @visitor.when(ccil_ast.NewOpNode) def visit(self, node: ccil_ast.NewOpNode): instructions = [] + # TODO: SELF_TYPE + if node.type == "SELF_TYPE": + return [] size = self.get_attr_count(node.type) + WORD instructions.append( mips_ast.LoadImmediate( node, mips_ast.RegisterNode(node, A0), - mips_ast.Constant(node, str(size)), + mips_ast.Constant(node, size), ) ) instructions.append( @@ -398,18 +428,24 @@ def visit(self, node: ccil_ast.SumOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -431,18 +467,24 @@ def visit(self, node: ccil_ast.MinusOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -464,18 +506,24 @@ def visit(self, node: ccil_ast.MultOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -497,18 +545,24 @@ def visit(self, node: ccil_ast.DivOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(ndoe, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -532,18 +586,24 @@ def visit(self, node: ccil_ast.LessOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -565,18 +625,24 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -586,8 +652,8 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): return instructions - @visitor.when(ccil_ast.EqualOpNode) - def visit(self, node: ccil_ast.EqualOpNode): + @visitor.when(ccil_ast.EqualIntNode) + def visit(self, node: ccil_ast.EqualIntNode): instructions = [] reg_left = mips_ast.RegisterNode(node, T3) @@ -598,18 +664,24 @@ def visit(self, node: ccil_ast.EqualOpNode): ) ) elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append(mips_ast.LoadImmediate(node, reg_left, node.left.value)) + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.left, ccil_ast.IdNode): + if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( node, reg_right, self.get_relative_location(node.right.value) ) ) - elif isinstance(node.left, ccil_ast.ConstantNode): + elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( - mips_ast.LoadImmediate(node, reg_right, node.right.value) + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) ) else: raise Exception("Invalid type of ccil node") @@ -661,40 +733,6 @@ def visit(self, node: ccil_ast.NegOpNode): return instructions - @visitor.when(ccil_ast.IsVoidOpNode) - def visit(self, node: ccil_ast.IsVoidOpNode): - instructions = [] - - reg = mips_ast.RegisterNode(node, T1) - if isinstance(node.atom, ccil_ast.IntNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg, mips_ast.Constant(node, node.atom.value) - ) - ) - elif isinstance(node.atom, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg, self.get_relative_location(node.atom.value) - ) - ) - - instructions.append( - mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, T0), mips_ast.Constant(node, "0") - ) - ) - instructions.append( - mips_ast.Equal( - node, - mips_ast.RegisterNode(node, V0), - reg, - mips_ast.RegisterNode(node, T0), - ) - ) - - return instructions - @visitor.when(ccil_ast.LoadOpNode) def visit(self, node: ccil_ast.LoadOpNode): instructions = [] @@ -757,6 +795,35 @@ def visit(self, node: ccil_ast.PrintIntNode): instructions.append(mips_ast.Syscall(node)) return instructions + @visitor.when(ccil_ast.PrintStrNode) + def visit(self, node: ccil_ast.PrintStrNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, A0), + self.get_relative_location(node.id), + ) + ) + + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 4) + ) + ) + instructions.append(mips_ast.Syscall(node)) + return instructions + + @visitor.when(ccil_ast.ReadIntNode) + def visit(self, node: ccil_ast.ReadIntNode): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 5) + ) + ) + return instructions + def get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: From aac722a0927e87c2be949c5a37f9a9bb8c12eafe Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 14:41:40 -0500 Subject: [PATCH 299/432] Add print_int test --- src/debbuging/tests_ccil/print_int.cl | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/debbuging/tests_ccil/print_int.cl diff --git a/src/debbuging/tests_ccil/print_int.cl b/src/debbuging/tests_ccil/print_int.cl new file mode 100644 index 000000000..fd356d991 --- /dev/null +++ b/src/debbuging/tests_ccil/print_int.cl @@ -0,0 +1,5 @@ + class Main inherits IO{ + main(): Main { + out_int(3 + 4 + 5) + }; +}; From 23973a71316817364e19560f5c0cfae716458724 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 14:43:38 -0500 Subject: [PATCH 300/432] Minor docs improvmenets --- src/docs/codegen.md | 76 +++++++++++++++++-------- src/docs/semantic and type inference.md | 56 ++++++++++++++++++ 2 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 src/docs/semantic and type inference.md diff --git a/src/docs/codegen.md b/src/docs/codegen.md index 7683f66b0..acbf05bd2 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -1,10 +1,46 @@ -# Generacion de Codigo Intermedio +# Generación de Código Intermedio -Despues de realizado el chequeo semantico se procede a realizar la generacion de codigo con el ast obtenido como resultado. +Se utliza el partron visitor para generar un árbol en CCIL (Cool Cows Intermediate Language). Por cada expresion de Cool se desglosa y traduce en operaciones (o instrucciones) de CIL. -Se utiliza un nuevo ast para esta parte del compilador _codegen_ast.py_. +Cada instruccion cumple un propositio. Cada instruccion hace de las suyas. -Cada nodo de este nuevo AST se representa a si mismo en ccil (cool cows intermediate language). +Tambien se genera el codigo que hace runtime exception + +El codigo built ini de las clases esta definido aqui tambien. + + + +El nodo programa se divide en 3 secciones + +Una seccion de tipos donde se almacenan con todos sus atributos + sus funciones + +Una secciond de datos donde se almacenan todos los string producidos + +Una seccion de codigo donde estan almacenados todos los codigos dsitribuidos por una funcion + +La function esta compuesta por operaciones que son el resultado de desglosar las expresiones interiores + +Para trabajar con sub expresiones estas se trabajan primero que las expresiones grandes, y se alamcena su valor en un lugar conocido, ya sea una variable interna o una definida por el usuario. + +Los primeras operaciones de toda funcion es nombrar sus parametros de entrada y las variables locales necesarias que necesita inicializadas. + +Todas las variables definidas por el usuario tienen una traduccion a cil. + +Variables con mismo nombre en scopes distintos tienen diferentes nombres en cil + + + +Todas las funciones se les define una init_func que se encarga de inicializar todos sus atributos. Esta funcon recibe un parametro self que indica el tipo en runtime al que se le van actualizar los atributos + +Despues de calculadas las expresiones se setean los atributos + + + + + +## Lenguage CCIL + +Definicion del lenguage CCIL. Tomamos como No Terminales todos los simbolos que empiezen con palabras mayusculas. El resto se considera como Terminales. $$ \begin{array}{rcl} \text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ @@ -13,27 +49,22 @@ $$ \text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ &|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ \\ -\text{CodeList} &\rarr& \text{AttrCode }|\text{ FuncCode }|\text{ CodeList }| \space\epsilon\\ -&|& \text{ AttrCode; CodeList } | \text{ FuncCode; CodeList}\\ -\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList Expression} \}\\ +\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ \text{FuncCode} &\rarr& \text{id }\{\\ &&\text{ParamList}\\ &&\text{LocalList}\\ -&&\text{Expression}\\ -&&\text{\}}\\ +&&\text{OperationList} \text{\}}\\ \\ -\text{Expression} &\rarr& \text{id = ReturnOp}\\ +\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ +\text{Operation} &\rarr& \text{id = ReturnOp}\\ &|& \text{goto id}\\ &|& \text{label id}\\ &|& \text{return Atom}\\ &|& \text{setattr id id Atom}\\ &|& \text{if Atom goto id}\\ &|& \text{ifFalse Atom goto id}\\ -&|& \text{ArgList id = call id integer}\\ -&|& \text{ArgList id = vcall id id integer }\\ -&|& \text{ExpressionList}\\ -\text{ExpressionList} &\rarr& \text{Expression; ExpressionList } | \text{ Expression} \\ -\text{ArgList} &\rarr& \text{arg id; ArgList } | \space\epsilon \\ +&|& \text{arg id}\\ \text{ReturnOp} &\rarr& \text{Atom + Atom}\\ &|& \text{Atom - Atom}\\ @@ -41,16 +72,19 @@ $$ &|& \text{Atom / Atom}\\ &|& \text{not Atom}\\ &|& \text{neg Atom}\\ -&|& \text{typeOf id}\\ +&|& \text{call id}\\ +&|& \text{vcall typeId id}\\ +&|& \text{typeof id}\\ +&|& \text{getatrr id id}\\ &|& \text{allocate typeId}\\ &|& \text{Atom < Atom}\\ &|& \text{Atom <= Atom}\\ &|& \text{Atom = Atom}\\ -&|& \text{allocate id}\\ +&|& \text{allocate typeId}\\ &|& \text{getattr id id}\\ &|& \text{Atom}\\ \text{Atom} &\rarr& \text{Constant } | \text{ id}\\ -\text{Constant} &\rarr& \text{ integer } | \text{ string } | \text{ boolean } +\text{Constant} &\rarr& \text{ integer } | \text{ string } \end{array} $$ @@ -457,9 +491,3 @@ t = t / 2 -## Convenciones de variables en Cool - -Si es una variable definida por el usuario se le agrega el prefijo _user_. Se aplica tanto a variables definidas en un _let in_ como en _atributos_. - -Si es una variable creada cuando se analiza una expresion en particular se convierte en: _\__\___ - diff --git a/src/docs/semantic and type inference.md b/src/docs/semantic and type inference.md new file mode 100644 index 000000000..9f91cb818 --- /dev/null +++ b/src/docs/semantic and type inference.md @@ -0,0 +1,56 @@ +# Inferencia + +La idea principal para realizar la inferencia es considerar todo declaración como AUTO_TYPE no como un tipo especifico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como Int o String se consideran conjuntos con un solo elemento. + +La inferencia se realiza varias veces por visitores distintos que explicaremos mas adelante. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas estas se realizan también durante la inferencia, distribuida a lo largo de los visitores. + +Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger existe alguno que no tiene un ancestro comun mas general con los demas. + +## Funcionamiento + +El inferenciador se ejecuta varias veces, en cada una realizando un chequeo distinto. + +### Soft Inferencer + +Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. + +Aplica las reglas de cool para realizar la infererencia. Este permite que haya ambiguedad y que un tipo por determinar puede tener varios ancestros sin nada en comun. + +En el lenguage cool esto se evidencia cuando se hace un llamado a una funcion del estilo + +``` +a.func(); +``` + +donde el tipo de _a_ no es definido. El inferenciador buscara todas las clases con un metodo de nombre func y cantidad de parametro determinad y los tendra como posibles tipos para _a_. En estos casos _a_ puede ser de varios tipos no relacionados por ejemplo cuando: + +``` +class A { + method func():Int{ + 3 + 3 + } +}; +class B { + method func():String{ + "3 + 3" + } +}; +``` + +$a \in \{A, B\}$ donde A hereda de B y viceversa $a \notin \text{Object}$. pues Object no tiene un metodo func que recibe 0 argumentos. + +Debido a que las variables pueden tener varios tipos no relacionados tampoco se revisa las comparaciones de igual. + +### Hard Inferenecer + +Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. + +En esta parte el inferenicador realiza las misma acciones que en el Soft Inferencer, excepto que ya una variable $a$ no puede tener tipos de datos no relacionados. Se revisa que las comparaciones de igualdad que ambos miembros sean del mismo tipo. + +### Back Inferencer + +Este se encarga de inferir el tipo de una variable a base del valor de la expresion. + +### Types Inferencer + +Pasa una ultima vez por todas las expresiones From 664b62c10f2f039886501bc38c6557d1dc188e88 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 14:43:53 -0500 Subject: [PATCH 301/432] delete old docs --- src/docs/inference.md | 48 ------------------------------------------- src/docs/semantics.md | 2 -- 2 files changed, 50 deletions(-) delete mode 100644 src/docs/inference.md delete mode 100644 src/docs/semantics.md diff --git a/src/docs/inference.md b/src/docs/inference.md deleted file mode 100644 index 191039c0a..000000000 --- a/src/docs/inference.md +++ /dev/null @@ -1,48 +0,0 @@ -# Inferencia - -Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger existe alguno que no tiene un ancestro comun mas general con los demas. - -## Funcionamiento - -El inferenciador se ejecuta varias veces, en cada una realizando un chequeo distinto. - -### Soft Inferencer - -Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. - -Aplica las reglas de cool para realizar la infererencia. Este permite que haya ambiguedad y que un tipo por determinar puede tener varios ancestros sin nada en comun. - -En el lenguage cool esto se evidencia cuando se hace un llamado a una funcion del estilo - -``` -a.func(); -``` - -donde el tipo de _a_ no es definido. El inferenciador buscara todas las clases con un metodo de nombre func y cantidad de parametro determinad y los tendra como posibles tipos para _a_. En estos casos _a_ puede ser de varios tipos no relacionados por ejemplo cuando: - -``` -class A { - method func():Int{ - 3 + 3 - } -}; -class B { - method func():String{ - "3 + 3" - } -}; -``` - -$a \in \{A, B\}$ donde A hereda de B y viceversa $a \notin \text{Object}$. pues Object no tiene un metodo func que recibe 0 argumentos. - -Debido a que las variables pueden tener varios tipos no relacionados tampoco se revisa las comparaciones de igual. - -### Hard Inferenecer - -Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. - -En esta parte el inferenicador realiza las misma acciones que en el Soft Inferencer, excepto que ya una variable $a$ no puede tener tipos de datos no relacionados. Se revisa que las comparaciones de igualdad que ambos miembros sean del mismo tipo. - -### Back Inferencer - -Este se encarga de inferir el tipo de una variable a base del valor de la expresion. diff --git a/src/docs/semantics.md b/src/docs/semantics.md deleted file mode 100644 index 2b9137abb..000000000 --- a/src/docs/semantics.md +++ /dev/null @@ -1,2 +0,0 @@ -# Semantica - From 1a103f07c0d9718a1705b30c502d9efd029b4655 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 14:44:11 -0500 Subject: [PATCH 302/432] Minor refactoring --- src/code_gen/ccil_gen.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 03a0318fe..98530c7de 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -485,8 +485,8 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: fval_id = f"is_void_fv_{times}" if node.expr.type.name in {BOOL, INT, STRING}: self.add_warning( - f"Warning: Redundant isVoid expression in {node.line}, {node.col}." - " It will always evaluate to false" + f"Redundant isVoid expression in {node.line}, {node.col}." + f" Type {node.expr.type.name} will always evaluate to false" ) op = IntNode("0") else: @@ -567,7 +567,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: times = self.times(node) - fvalue_id = f"newType_{times}" + fvalue_id = f"new_type_{times}" fvalue = self.create_new_type(fvalue_id, node.type.name) return [fvalue], fvalue @@ -959,7 +959,7 @@ def reset_scope(self): self.ccil_cool_names = Scope() def add_warning(self, msg: str): - self.add_warning(msg) + self.add_warning(f"Warning: {msg}") def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: From c98238b63f4aac7f2c40d3e4bb38bae7a94ccfd1 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 14:59:39 -0500 Subject: [PATCH 303/432] Add mflo instruction to MIPS AST --- src/asts/mips_ast.py | 13 +++++++++++-- src/code_gen/mips_gen.py | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index ea6dd9a22..3d2e25f0f 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import Dict, List, Tuple +from typing import Dict, List, Tuple, Union from asts.parser_ast import BinaryNode @@ -57,7 +57,7 @@ class Constant(Node): This class represents a literal integer in MIPS """ - def __init__(self, node, value: str) -> None: + def __init__(self, node, value: Union[str, int]) -> None: super().__init__(node) self.value = value @@ -123,6 +123,15 @@ def __init__(self, node, left, middle, right) -> None: self.right = right +class MoveFromLo(InstructionNode): + """ + This node represents `mflo` instruction in MIPS + """ + def __init__(self, node, register) -> None: + super().__init__(node) + self.register = register + + class Div(BinaryOpNode): """ This node represents `div` instruction in MIPS diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 29340b0da..5fd06f3de 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -20,6 +20,7 @@ MIPSProgram, MemoryIndexNode, Move, + MoveFromLo, Multiply, Not, RegisterNode, @@ -180,3 +181,7 @@ def visit(self, node: Xori) -> str: @visitor.when(Not) def visit(self, node: Not) -> str: return f"\tnot {self.visit(node.left)}, {self.visit(node.right)}" + + @visitor.when(MoveFromLo) + def visit(self, node: MoveFromLo) -> str: + return f"\tmflo {self.visit(node.register)}" From 7e03832a2d2017bc725004ec6e514f16732ce11b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 15:03:44 -0500 Subject: [PATCH 304/432] Fix bug, not swapping SELF_TYPE method return type for caller type --- src/semantics/inference/back_inferencer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 9a1774ba8..42ce2b005 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -257,8 +257,10 @@ def visit(self, node: MethodCallNode, scope) -> MethodCallNode: new_expr = self.visit(node.expr, scope) if node.expr else None new_node = MethodCallNode(node.caller_type, new_expr, new_args, node) + + method_return_type = method.return_type.clone().swap_self_type(caller_type) new_node.inferenced_type, changed = unify( - node.inferenced_type, method.return_type + node.inferenced_type, method_return_type ) self.changed |= changed return new_node From 9f0a2a4d07100bf537e198e1f54b775ff63315a2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 15:57:32 -0500 Subject: [PATCH 305/432] All types now have all signatures from their ancestors --- src/code_gen/ccil_gen.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 98530c7de..df5bb80a7 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,8 +1,9 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import Tuple, List, Dict +from typing import OrderedDict, Tuple, List, Dict from code_gen.tools import * +from collections import OrderedDict from code_gen.constants import * @@ -41,6 +42,8 @@ class CCILGenerator: """ def __init__(self) -> None: + self.program_types: List[Class] + self.program_codes: List[FunctionNode] # To keep track of how many times a certain expression has been evaluated self.time_record: Dict[str, int] = dict() # Track all constant values. Only strings for now @@ -67,25 +70,29 @@ def visit(self, node: sem_ast.ProgramNode) -> None: self.data = [DEFAULT_STR] self.reset_locals() - builtin_classes, builtin_methods = self.define_built_ins() - program_types: List[Class] = builtin_classes - program_codes: List[FunctionNode] = builtin_methods + [obj, io, str], builtin_methods = self.define_built_ins() + self.program_types = OrderedDict({OBJECT: obj, IO: io, STRING: str}) + self.program_codes: List[FunctionNode] = builtin_methods for type in node.declarations: classx, class_code = self.visit(type) - program_types.append(classx) - program_codes += class_code + self.program_types[classx.id] = classx + self.program_codes += class_code - return CCILProgram(program_types, program_codes, self.data) + return CCILProgram( + list(self.program_types.values()), self.program_codes, self.data + ) @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: + print(node.parent, type(node.parent)) self.current_type = node.id self.add_data(f"class_{node.id}", node.id) + attributes, methods = self.get_inherited_features(node) + attr_nodes = [] func_nodes = [] - attributes: List[Attribute] = list() for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): attributes.append(Attribute(ATTR + feature.id, feature.type.name)) @@ -102,7 +109,6 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: *[(n.id, a.id) for (n, a) in zip(attr_nodes, attributes)] ) class_code: List[FunctionNode] = [] - methods: List[Method] = [] for func in func_nodes: f = self.visit(func) class_code.append(f) @@ -717,6 +723,7 @@ def define_built_ins(self): IO, [], [ + *object_class.methods, Method("out_string", out_string_func), Method("out_int", out_int_func), Method("in_string", in_string_func), @@ -793,6 +800,7 @@ def define_built_ins(self): STRING, [], [ + *object_class.methods, Method("length", lenght_func), Method("concat", concat_func), Method("substr", substr_func), @@ -961,6 +969,16 @@ def reset_scope(self): def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") + def get_inherited_features(self, node: sem_ast.ClassDeclarationNode): + inherited_attr: List[Attribute] = [] + inherited_methods: List[Method] = [] + if node.parent is not None: + parent_class: Class = self.program_types[node.parent] + inherited_attr = [a for a in parent_class.attributes] + inherited_methods = [m for m in parent_class.methods] + + return inherited_attr, inherited_methods + def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: return list(map(lambda x: const(*x), dict.items())) From de9f90b752e5b5ee5a62db3fcbd300ac0bc0520e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 16:14:19 -0500 Subject: [PATCH 306/432] Add entry function --- src/code_gen/ccil_gen.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index df5bb80a7..d9fe062b2 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -80,7 +80,10 @@ def visit(self, node: sem_ast.ProgramNode) -> None: self.program_codes += class_code return CCILProgram( - list(self.program_types.values()), self.program_codes, self.data + self.define_entry_func(), + list(self.program_types.values()), + self.program_codes, + self.data, ) @visitor.when(sem_ast.ClassDeclarationNode) @@ -917,6 +920,15 @@ def init_default_values(self): ] return [] + def define_entry_func(self): + program = self.create_new_type("program", "Main") + execute = self.create_call( + "execute_program", INT, "main", INT, [IdNode(program.id)] + ) + return FunctionNode( + "entry", [], self.dump_locals(), [program, execute], execute.id + ) + def define_empty_init_func(self, class_name: str): params = self.init_func_params(class_name) dummy_return = self.create_storage( From d93b57150132498132f07d41eda0a597d6d53740 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 16:24:05 -0500 Subject: [PATCH 307/432] Hot fix in entry func and delete some prints --- src/code_gen/ccil_gen.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index d9fe062b2..ad6071a5f 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -88,7 +88,6 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: - print(node.parent, type(node.parent)) self.current_type = node.id self.add_data(f"class_{node.id}", node.id) @@ -533,7 +532,6 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ) return [*args_ops, call], call - print("nn", node.expr) (expr_ops, expr_fval) = self.visit(node.expr) # Runtime error depending if expr is void or not @@ -921,6 +919,7 @@ def init_default_values(self): return [] def define_entry_func(self): + self.reset_locals() program = self.create_new_type("program", "Main") execute = self.create_call( "execute_program", INT, "main", INT, [IdNode(program.id)] From fbcf0ec6d4fb0983e9dfa92a8195bf4b37694ba3 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 16:39:48 -0500 Subject: [PATCH 308/432] add entry func --- src/asts/ccil_ast.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 2f8518995..6e0904424 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -9,11 +9,12 @@ class CCILProgram: """Top level class that represents a CCIL program""" + entry_func: FunctionNode types_section: List[Class] code_section: List[FunctionNode] data_section: List[str] # no idea what will be this the node, - def __str__(self, all=True) -> str: + def __str__(self, all=False) -> str: types_section = self.types_section code_section = self.code_section if not all: @@ -38,7 +39,7 @@ class Class: methods: List[Method] init_operations: FunctionNode - def __str__(self, all=True) -> str: + def __str__(self, all=False) -> str: ident = "\t\t" attributes = "\n".join(ident + str(a) for a in self.attributes) methods = "\n".join(ident + str(m) for m in self.methods) From 158d2f7288488d782f3d413531d82630cbe4230c Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 16:42:53 -0500 Subject: [PATCH 309/432] Add entry function to mips code --- src/code_gen/ccil_mips_gen.py | 16 ++++++++++------ src/code_gen/mips_gen.py | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index b73ca994b..1036dad1c 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -81,6 +81,7 @@ def visit(self, node: ccil_ast.CCILProgram): # TODO: other .data section static data inicializations like strings functions = [] + functions.extend(self.visit(node.entry_func)) functions.extend( [self.visit(func) for func in node.code_section if func.id == "main"][0] ) @@ -113,7 +114,7 @@ def visit(self, node: ccil_ast.FunctionNode): self.set_relative_location( param.id, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, -1*index), frame_pointer + node, mips_ast.Constant(node, -1 * index), frame_pointer ), ) index += DOUBLE_WORD @@ -233,7 +234,7 @@ def visit(self, node: ccil_ast.IntNode): @visitor.when(ccil_ast.CallOpNode) def visit(self, node: ccil_ast.CallOpNode): - reg = mips_ast.RegisterNode(node, 10) + reg = mips_ast.RegisterNode(node, T0) instructions = [] for arg in node.args: instructions.append( @@ -390,7 +391,7 @@ def visit(self, node: ccil_ast.SetAttrOpNode): mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), object_location) ) - reg_new_value = mips_ast.RegisterNode(node, T0) + reg_new_value = mips_ast.RegisterNode(node, T1) if isinstance(node.new_value, ccil_ast.IntNode): instructions.append( mips_ast.LoadImmediate( @@ -410,7 +411,9 @@ def visit(self, node: ccil_ast.SetAttrOpNode): node, reg_new_value, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, attr_offset), object_location + node, + mips_ast.Constant(node, attr_offset), + mips_ast.RegisterNode(node, T0), ), ) ) @@ -561,7 +564,7 @@ def visit(self, node: ccil_ast.DivOpNode): elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(ndoe, node.right.value) + node, reg_right, mips_ast.Constant(node, node.right.value) ) ) else: @@ -570,7 +573,8 @@ def visit(self, node: ccil_ast.DivOpNode): reg_ret = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.Div(node, reg_left, reg_right)) instructions.append( - mips_ast.Move(node, reg_ret, mips_ast.RegisterNode(node, "lo")) + # mips_ast.Move(node, reg_ret, mips_ast.RegisterNode(node, "lo")) + mips_ast.MoveFromLo(node, reg_ret) ) return instructions diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 5fd06f3de..dca6ce983 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -50,7 +50,7 @@ def visit(self, node): @visitor.when(MIPSProgram) def visit(self, node: MIPSProgram) -> str: - global_main = "\t.globl main" + global_main = "\t.globl entry" text_section = "\t.text\n" + self.visit(node.text_section) data_section = "\t.data\n" + self.visit(node.data_section) return f"{global_main}\n{text_section}\n{data_section}" From c1a193ecff901102607486b49f6387e835611522 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 17:41:16 -0500 Subject: [PATCH 310/432] Add simple_attr test --- src/debbuging/tests_ccil/simple_attr.cl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/debbuging/tests_ccil/simple_attr.cl diff --git a/src/debbuging/tests_ccil/simple_attr.cl b/src/debbuging/tests_ccil/simple_attr.cl new file mode 100644 index 000000000..a2caaf3f0 --- /dev/null +++ b/src/debbuging/tests_ccil/simple_attr.cl @@ -0,0 +1,15 @@ + class Main { + main() : Int + { + let a : A <- new A in a.f() + }; +}; + +class A { + + f () : Int { + 12 + }; +}; + + From b437dba4ed54676bc79288d9d9a36b60499431cb Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 17:53:25 -0500 Subject: [PATCH 311/432] Change entry func name to main and minor other fix --- src/code_gen/ccil_gen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index ad6071a5f..289219fb4 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -156,7 +156,7 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - f"f_{self.times(node)}" if node.id != "main" else "main", + f"f_{self.times(node)}", params, self.dump_locals(), operations, @@ -566,7 +566,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" - call = self.create_vcall(fval_id, node.type.id, node.id, node.caller_type, args) + call = self.create_vcall(fval_id, node.type.name, node.id, node.caller_type, args) return [*expr_ops, *error_ops, *args_ops, call] @@ -925,7 +925,7 @@ def define_entry_func(self): "execute_program", INT, "main", INT, [IdNode(program.id)] ) return FunctionNode( - "entry", [], self.dump_locals(), [program, execute], execute.id + "main", [], self.dump_locals(), [program, execute], execute.id ) def define_empty_init_func(self, class_name: str): From 7f81db886adbe35e56a1eb185c1ed994e066add0 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 17:53:39 -0500 Subject: [PATCH 312/432] Update docs --- src/docs/semantic and type inference.md | 29 +++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/docs/semantic and type inference.md b/src/docs/semantic and type inference.md index 9f91cb818..ee4c40cab 100644 --- a/src/docs/semantic and type inference.md +++ b/src/docs/semantic and type inference.md @@ -2,9 +2,27 @@ La idea principal para realizar la inferencia es considerar todo declaración como AUTO_TYPE no como un tipo especifico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como Int o String se consideran conjuntos con un solo elemento. -La inferencia se realiza varias veces por visitores distintos que explicaremos mas adelante. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas estas se realizan también durante la inferencia, distribuida a lo largo de los visitores. +La inferencia se realiza varias veces por visitores distintos que explicaremos mas adelante. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par durante la inferencia, distribuido a lo largo de los visitores. -Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger existe alguno que no tiene un ancestro comun mas general con los demas. +En el COOL original la mayoría de los nodos del árbol tienen un tipo estático declarado al igual que una expresión, donde el tipo de dicha expresión debe conformarse con el tipo estatico. Este es el caso para la declaracion de variables, la asignacion, cuando se pasan como argumentos, o una expresion con el retorno declarado. + +Cuando el valor declarado es un tipo bien nombrado (diferente de AUTO_TYPE) y el valor inferido es un conjunto de tipos se truncan los que no conforman con el tipo estatico + +Cuando el valor declarado es un tipo auto type, entonces tiene que ser algo a lo que se pueda conforma el expresion type + +Cuando ambos son autotypes, ambos tienen que conformarse entre ellos, pero la cosa se pone sucia + +Por estas razones el inferenciador se debido en dos partes, la primera parte trata de conformar los autotypes al tipo declarado (ya este sea otro autotyepe). + +Esta primera parte se divide en dos partes tambien, una que llamamos inferencia suave, donde el conjunto de tipos puede tener elementos disjuntos y no se aplican casi reglas del chequeo semantico + +La segunda parte de la primera parte llammos inferencia dura, donde no se es permisivo con violaciones de la regla semantica. Una vez termiando este recorrido, el conjunto de valores de expresiones debe estar lo mas reducido posible. + +En la segunda parte falta reducir los conjutnos de elementos que se han declarado estaticamente como autotypes. (Ojo estos elementos pueden haberse reducido antes de llegar aqui si participan en una operacion aritmetica o dispatch). (Este se ejcuta n veces, xq era?) + +Luego de de terminar la inferencia se recorre un utlimo vistor. Este setea los tipos de acuerdo a su ancestro comun mas cercano. + +Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger escoge siempre el mas general, el tipo raiz de todos. En caso de que sea para valor de retorno de un parametro, esocoge el "menor" ancestro comun. ## Funcionamiento @@ -25,6 +43,13 @@ a.func(); donde el tipo de _a_ no es definido. El inferenciador buscara todas las clases con un metodo de nombre func y cantidad de parametro determinad y los tendra como posibles tipos para _a_. En estos casos _a_ puede ser de varios tipos no relacionados por ejemplo cuando: ``` +class Main { + a : AUTO_TYPE; + method main():AUTO_TYPE { + a.func() + } +} + class A { method func():Int{ 3 + 3 From 15a27ebf09d175de73645d3fba7cabecf4a04eae Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 17:58:36 -0500 Subject: [PATCH 313/432] Fix register during syscall to allacate memory --- src/code_gen/ccil_mips_gen.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 1036dad1c..ff363cbf7 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -81,7 +81,7 @@ def visit(self, node: ccil_ast.CCILProgram): # TODO: other .data section static data inicializations like strings functions = [] - functions.extend(self.visit(node.entry_func)) + # functions.extend(self.visit(node.entry_func)) functions.extend( [self.visit(func) for func in node.code_section if func.id == "main"][0] ) @@ -313,7 +313,7 @@ def visit(self, node: ccil_ast.NewOpNode): ) instructions.append( mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, V1), mips_ast.Constant(node, 9) + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) ) ) instructions.append(mips_ast.Syscall(node)) @@ -839,6 +839,7 @@ def get_attr_index(self, typex: str, attr: str): def get_attr_count(self, typex: str): for _type in self.__types_table: if _type.id == typex: + print(_type.attributes) return len(_type.attributes) raise Exception("Type declaration not found") From 30d0b43f27e0b0e54effda7375ef36a25412819e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 18:02:37 -0500 Subject: [PATCH 314/432] Minor fix in return --- src/code_gen/ccil_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 289219fb4..cb8e6ab0a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -562,13 +562,13 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: call = self.create_call( fval_id, node.type.name, node.id, node.caller_type.name, args ) - return [*expr_ops, *error_ops, *args_ops, call] + return [*expr_ops, *error_ops, *args_ops, call], call # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" call = self.create_vcall(fval_id, node.type.name, node.id, node.caller_type, args) - return [*expr_ops, *error_ops, *args_ops, call] + return [*expr_ops, *error_ops, *args_ops, call], call @visitor.when(sem_ast.InstantiateNode) def visit(self, node: sem_ast.InstantiateNode) -> VISITOR_RESULT: From 936681eb80a3a5f579dd62a5e6776a654b7f45ec Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 18:31:01 -0500 Subject: [PATCH 315/432] Hotfix, change method id for function id in entry call --- src/code_gen/ccil_gen.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index cb8e6ab0a..404e26ab0 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -42,7 +42,7 @@ class CCILGenerator: """ def __init__(self) -> None: - self.program_types: List[Class] + self.program_types: Dict[str, Class] self.program_codes: List[FunctionNode] # To keep track of how many times a certain expression has been evaluated self.time_record: Dict[str, int] = dict() @@ -566,7 +566,9 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" - call = self.create_vcall(fval_id, node.type.name, node.id, node.caller_type, args) + call = self.create_vcall( + fval_id, node.type.name, node.id, node.caller_type, args + ) return [*expr_ops, *error_ops, *args_ops, call], call @@ -922,7 +924,11 @@ def define_entry_func(self): self.reset_locals() program = self.create_new_type("program", "Main") execute = self.create_call( - "execute_program", INT, "main", INT, [IdNode(program.id)] + "execute_program", + INT, + "main", + INT, + [IdNode(self.find_function_id("Main", "main"))], ) return FunctionNode( "main", [], self.dump_locals(), [program, execute], execute.id @@ -990,6 +996,12 @@ def get_inherited_features(self, node: sem_ast.ClassDeclarationNode): return inherited_attr, inherited_methods + def find_function_id(self, class_name: str, method_name: str): + for method in self.program_types[class_name].methods: + if method.id == method_name: + return method.function.id + raise Exception(f"Method: {method_name} was not found in {class_name}") + def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: return list(map(lambda x: const(*x), dict.items())) From e5ee4d50502d05147e50c001bd660582fa9e8120 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 18:40:06 -0500 Subject: [PATCH 316/432] Bug fix --- src/code_gen/ccil_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 404e26ab0..05f5aecb3 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -926,9 +926,9 @@ def define_entry_func(self): execute = self.create_call( "execute_program", INT, - "main", + self.find_function_id("Main", "main"), INT, - [IdNode(self.find_function_id("Main", "main"))], + [IdNode(program.id)], ) return FunctionNode( "main", [], self.dump_locals(), [program, execute], execute.id From 7b4cfb49674c22219f6dcf38d883302ec9aa225f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 21:12:10 -0500 Subject: [PATCH 317/432] Add caller to self first arg of vcalls --- src/code_gen/ccil_gen.py | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 05f5aecb3..62541f50c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1,7 +1,7 @@ from utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import OrderedDict, Tuple, List, Dict +from typing import OrderedDict, Set, Tuple, List, Dict from code_gen.tools import * from collections import OrderedDict @@ -146,17 +146,18 @@ def visit(self, node: sem_ast.MethodDeclarationNode) -> METHOD_VISITOR_RESULT: params: List[Parameter] = [Parameter("self", self.current_type)] self.ccil_cool_names.add_new_name_pair("self", "self") + for param in node.params: new_param_id = PARAM + param.id params.append(Parameter(new_param_id, param.type.name)) self.ccil_cool_names.add_new_name_pair(param.id, new_param_id) - self.locals = dict() + self.reset_locals() (operations, fval) = self.visit(node.body) self.ccil_cool_names = self.ccil_cool_names.get_parent return FunctionNode( - f"f_{self.times(node)}", + f"f_{node.id}_{self.current_type}", params, self.dump_locals(), operations, @@ -528,7 +529,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.expr is None: fval_id = f"vcall_{times}" call = self.create_vcall( - fval_id, node.type.name, node.id, node.caller_type.name, args + fval_id, + node.type.name, + node.id, + node.caller_type.name, + [IdNode("self"), *args], ) return [*args_ops, call], call @@ -546,7 +551,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: "caller_void_err", f"RuntimeError: expresion in {node.line}, {node.col} is void", ) - load_err = self.create_string_load_data("callor_void_err_var", error_msg.id) + load_err = self.create_string_load_data("caller_void_err_var", error_msg.id) print_and_abort = self.notifiy_and_abort(load_err.id) error_ops = [ expr_fval_is_void, @@ -560,7 +565,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: if node.at_type is not None: fval_id = f"call_{times}" call = self.create_call( - fval_id, node.type.name, node.id, node.caller_type.name, args + fval_id, + node.type.name, + make_unique_func_id(node.id, node.caller_type.name), + node.caller_type.name, + [extract_id(expr_fval), *args], ) return [*expr_ops, *error_ops, *args_ops, call], call @@ -926,7 +935,7 @@ def define_entry_func(self): execute = self.create_call( "execute_program", INT, - self.find_function_id("Main", "main"), + make_unique_func_id("main", "Main"), INT, [IdNode(program.id)], ) @@ -986,13 +995,19 @@ def reset_scope(self): def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") - def get_inherited_features(self, node: sem_ast.ClassDeclarationNode): + def get_inherited_features( + self, node: sem_ast.ClassDeclarationNode, node_methods: List[Method] + ): + node_methods: Set[str] = {m.id for m in node_methods} + inherited_attr: List[Attribute] = [] inherited_methods: List[Method] = [] if node.parent is not None: parent_class: Class = self.program_types[node.parent] inherited_attr = [a for a in parent_class.attributes] - inherited_methods = [m for m in parent_class.methods] + inherited_methods = [ + m for m in parent_class.methods if m.id not in node_methods + ] return inherited_attr, inherited_methods @@ -1003,5 +1018,9 @@ def find_function_id(self, class_name: str, method_name: str): raise Exception(f"Method: {method_name} was not found in {class_name}") +def make_unique_func_id(method_name: str, class_name: str): + return f"f_{method_name}_{class_name}" + + def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: return list(map(lambda x: const(*x), dict.items())) From 537787425a6679e2a768b968860b31d3783dbcff Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 21:14:03 -0500 Subject: [PATCH 318/432] Add caller to vcall --- src/code_gen/ccil_gen.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 62541f50c..484eb2bb1 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -576,7 +576,11 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # .id(arg1, arg2, ..., argn) fval_id = f"vcall_{times}" call = self.create_vcall( - fval_id, node.type.name, node.id, node.caller_type, args + fval_id, + node.type.name, + node.id, + node.caller_type, + [extract_id(expr_fval), *args], ) return [*expr_ops, *error_ops, *args_ops, call], call From a2c3fc8aa8bda6503fdec23ac2b66ac06cc0de1a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 21:15:49 -0500 Subject: [PATCH 319/432] Commented half developed code --- src/code_gen/ccil_gen.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 484eb2bb1..5a3054b95 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1000,18 +1000,16 @@ def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") def get_inherited_features( - self, node: sem_ast.ClassDeclarationNode, node_methods: List[Method] + self, node: sem_ast.ClassDeclarationNode#, node_methods: List[Method] ): - node_methods: Set[str] = {m.id for m in node_methods} + # node_methods: Set[str] = {m.id for m in node_methods} inherited_attr: List[Attribute] = [] inherited_methods: List[Method] = [] if node.parent is not None: parent_class: Class = self.program_types[node.parent] inherited_attr = [a for a in parent_class.attributes] - inherited_methods = [ - m for m in parent_class.methods if m.id not in node_methods - ] + inherited_methods = [m for m in parent_class.methods] return inherited_attr, inherited_methods From ced1b505672a3f4d4e47993f8af7c8ba65617675 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 25 Feb 2022 21:39:08 -0500 Subject: [PATCH 320/432] Add allocation_call test --- src/debbuging/tests_ccil/allocation_call.cl | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/debbuging/tests_ccil/allocation_call.cl diff --git a/src/debbuging/tests_ccil/allocation_call.cl b/src/debbuging/tests_ccil/allocation_call.cl new file mode 100644 index 000000000..a313b756c --- /dev/null +++ b/src/debbuging/tests_ccil/allocation_call.cl @@ -0,0 +1,13 @@ + class Main { + main() : Int + { + (new A).f() + }; + f() : Int{ + 1 +}; +}; + +class A { + f(): Int { 4 }; +}; From f55791ebbbe56a1977278305fef94cedcc8f63bd Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 21:39:20 -0500 Subject: [PATCH 321/432] Improve docs --- src/docs/codegen.md | 221 +++++++++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 96 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index acbf05bd2..e7d3de2f8 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -1,98 +1,73 @@ # Generación de Código Intermedio -Se utliza el partron visitor para generar un árbol en CCIL (Cool Cows Intermediate Language). Por cada expresion de Cool se desglosa y traduce en operaciones (o instrucciones) de CIL. +Para producir código CIL se toma como principal el guia el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. -Cada instruccion cumple un propositio. Cada instruccion hace de las suyas. +El programa original se divide en tres secciones: -Tambien se genera el codigo que hace runtime exception +* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. +* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. +* En **code** se encuentra el quivalente en CIL de las funciones definidas en Cool. Cada funcion en vez de tener expresiones y sub expresiones complejas tienen una sequencia de operaciones más sencillas que producen un resultado equivalente. -El codigo built ini de las clases esta definido aqui tambien. +## Types +Contiene solo el nombre de la clase, los metodos y su identificador único para buscarlo cuando se necesite llamar a un metodo y los atributos de la misma. Los tipos tambien contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. +## Data -El nodo programa se divide en 3 secciones +Se almacenan todos los string definidos por el usuario en el programa Cool. Ademas se tiene tambien la cadena vacia para inicializar strings por defecto apuntando a ella. -Una seccion de tipos donde se almacenan con todos sus atributos + sus funciones +El program se representa a traves de un nuevo ast. Donde antes habia una expresion +ahora la sustituyen varias operaciones sencillas en CIL. -Una secciond de datos donde se almacenan todos los string producidos +Todas las expresiones tienen en comun que su resultado final siempre se guarda en +memoria en alguna variable local. -Una seccion de codigo donde estan almacenados todos los codigos dsitribuidos por una funcion +Algunas expresiones desaperecen desaparecen, como `isVoid x` que se transforma +en preguntar si el valor final de la expresion `x` es 0 (Representamos el 0 +como Void) y el tipo estatico no es `Int`, `String` o `Bool` -La function esta compuesta por operaciones que son el resultado de desglosar las expresiones interiores +Para todas las clases se les genera una funcion `init` donde se setean los +valores inciales de todos sus atributos. Si el atributo tienen una expresion +su valor es el resultado de evaluar esa expresion, si no es un valor por +defecto, una direccion de memoria apuntando a una cadena vacia "" si es +de tipo String y 0 si es de culaquier otro tipo. -Para trabajar con sub expresiones estas se trabajan primero que las expresiones grandes, y se alamcena su valor en un lugar conocido, ya sea una variable interna o una definida por el usuario. +Se genera alrededor de las expresiones pertinentes casos para lanzar +runtime error, cuando se tiene division por cero, el substring tiene +indices incorrectos fuera de rango. Cuando la instancia que llama a una +funcion es Void. -Los primeras operaciones de toda funcion es nombrar sus parametros de entrada y las variables locales necesarias que necesita inicializadas. +Las clases predefinidas de Cool se implementan tambien en CIL. -Todas las variables definidas por el usuario tienen una traduccion a cil. +La manera de trabajar con sub expresiones es que estas se generan, y despues +la expresion padre las ubica en donde las considere pertinente. La expresion +padre tambien tiene acceso a la variable local donde esta alamacenado el +resultado final de sus subexpresiones pudiendo modificar, ubicar donde +considere necesario. -Variables con mismo nombre en scopes distintos tienen diferentes nombres en cil +Ante el problema de ocurrencia de variables con el mismo nombre se utiliza +un calse Scope como la de las semantica pero mucho mas sencillo con el +objetivo de tener segun el contexto la variable y su traduccion a cool. +Luego dado el nombre de una variable en cool y el contexto actual puedo +saber a que local de CIL me quiero referir - -Todas las funciones se les define una init_func que se encarga de inicializar todos sus atributos. Esta funcon recibe un parametro self que indica el tipo en runtime al que se le van actualizar los atributos - -Despues de calculadas las expresiones se setean los atributos - - - - - -## Lenguage CCIL - -Definicion del lenguage CCIL. Tomamos como No Terminales todos los simbolos que empiezen con palabras mayusculas. El resto se considera como Terminales. -$$ -\begin{array}{rcl} -\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ -\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ -\text{Type} &\rarr& \text{FeatureList}\\ -\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ -&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ -\\ -\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ -\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ -\text{FuncCode} &\rarr& \text{id }\{\\ -&&\text{ParamList}\\ -&&\text{LocalList}\\ -&&\text{OperationList} \text{\}}\\ -\\ -\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ -\text{Operation} &\rarr& \text{id = ReturnOp}\\ -&|& \text{goto id}\\ -&|& \text{label id}\\ -&|& \text{return Atom}\\ -&|& \text{setattr id id Atom}\\ -&|& \text{if Atom goto id}\\ -&|& \text{ifFalse Atom goto id}\\ -&|& \text{arg id}\\ - -\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ -&|& \text{Atom - Atom}\\ -&|& \text{Atom * Atom}\\ -&|& \text{Atom / Atom}\\ -&|& \text{not Atom}\\ -&|& \text{neg Atom}\\ -&|& \text{call id}\\ -&|& \text{vcall typeId id}\\ -&|& \text{typeof id}\\ -&|& \text{getatrr id id}\\ -&|& \text{allocate typeId}\\ -&|& \text{Atom < Atom}\\ -&|& \text{Atom <= Atom}\\ -&|& \text{Atom = Atom}\\ -&|& \text{allocate typeId}\\ -&|& \text{getattr id id}\\ -&|& \text{Atom}\\ -\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ -\text{Constant} &\rarr& \text{ integer } | \text{ string } -\end{array} -$$ +```assembly +# COOL +let x:int = 3 + in let x:int = 4 + in x +# CIL +local let_x_0 +local let_x_1 +... +``` ## Transformaciones -#### Program Declaration +### Clases -**Cool Input** +#### Cool Input ```haskell class A1 { ... } @@ -101,9 +76,18 @@ class A2 { ... } class AN { ... } ``` -**CCIL Output** +#### CCIL Output ```assembly +.TYPES: + +class A1 { + attr a1 + attr a2 + ... + method m1 + +} ... @@ -116,11 +100,11 @@ class AN { ... } ; ... ak: ; - + -- Functions f1() { } f2() { } ... fn() { } - + } ``` -**CCIL Output** +#### CCIL Output ```assembly type C { @@ -154,22 +138,22 @@ type C { attribute aq; ... attribute ak; - + method f1 : ; ... method fn : ; } ``` -#### Class Inheritance +### Herencia de Clases Se annade sobre la que ya tiene A, como se maneja la memoria, se annaden los atributos de B, despues de las funciones de A, o despues de los atributos de A -**Cool Input** +#### Cool Input ```haskell class A { - + } class B inherits A { @@ -177,14 +161,13 @@ class B inherits A { } ``` -**CCIL Output** +#### CCIL Output ``` -``` - +``` -#### While Loop +### While Loop **Cool Input** @@ -324,7 +307,7 @@ goto end_case label end_case ``` -El typeof tambien se conforma con un ancestro. Que evaluaria la operacion de igualdad para escoger la rama adecuada? Lanzar un runtime error si no se escoge ninguna rama(eso puede pasar despues del cheque semantico?) +El typeof tambien se conforma con un ancestro. Que evaluaria la operacion de igualdad para escoger la rama adecuada? Lanzar un runtime error si no se escoge ninguna rama(eso puede pasar despues del cheque semantico?) #### Function Static Call @@ -421,7 +404,7 @@ function { #### Arithmetic Expression -###### Simple +###### Simple **Cool Input** @@ -435,7 +418,7 @@ function { t = 3 + 5 ``` ----- +--- ###### More than one @@ -450,15 +433,13 @@ t = 3 + 5 ```assembly # Naive t1 = 5 + 7 -t2 = 3 + t1 +t2 = 3 + t1 # A little better t1 = 5 + 7 t1 = 3 + t1 ``` - - ----- +--- ###### Using non commutative operations @@ -470,10 +451,10 @@ t1 = 3 + t1 ```assembly t = 3 - 5 -t = t - 7 +t = t - 7 ``` ----- +--- **Cool Input** @@ -489,5 +470,53 @@ t = t / 5 t = t / 2 ``` +## Lenguage CCIL +Definicion del lenguage CCIL. Tomamos como No Terminales todos los simbolos que empiezen con palabras mayusculas. El resto se considera como Terminales. + +$$ +\begin{array}{rcl} +\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ +\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ +\text{Type} &\rarr& \text{FeatureList}\\ +\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ +&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ +\\ +\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ +\text{FuncCode} &\rarr& \text{id }\{\\ +&&\text{ParamList}\\ +&&\text{LocalList}\\ +&&\text{OperationList} \text{\}}\\ +\\ +\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ +\text{Operation} &\rarr& \text{id = ReturnOp}\\ +&|& \text{goto id}\\ +&|& \text{label id}\\ +&|& \text{return Atom}\\ +&|& \text{setattr id id Atom}\\ +&|& \text{if Atom goto id}\\ +&|& \text{ifFalse Atom goto id}\\ +&|& \text{arg id}\\ +\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ +&|& \text{Atom - Atom}\\ +&|& \text{Atom * Atom}\\ +&|& \text{Atom / Atom}\\ +&|& \text{not Atom}\\ +&|& \text{neg Atom}\\ +&|& \text{call id}\\ +&|& \text{vcall typeId id}\\ +&|& \text{typeof id}\\ +&|& \text{getatrr id id}\\ +&|& \text{allocate typeId}\\ +&|& \text{Atom < Atom}\\ +&|& \text{Atom <= Atom}\\ +&|& \text{Atom = Atom}\\ +&|& \text{allocate typeId}\\ +&|& \text{getattr id id}\\ +&|& \text{Atom}\\ +\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ +\text{Constant} &\rarr& \text{ integer } | \text{ string } +\end{array} +$$ From fc39b16b58cedef2ad55394e0c5ac2afb31a9a02 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 25 Feb 2022 21:56:51 -0500 Subject: [PATCH 322/432] Bug fix --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5a3054b95..8738c7acb 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -579,7 +579,7 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: fval_id, node.type.name, node.id, - node.caller_type, + node.caller_type.name, [extract_id(expr_fval), *args], ) From ba777a79fac382a5b9391a503bc5b054539a2c54 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 26 Feb 2022 00:21:24 -0500 Subject: [PATCH 323/432] Update codegen docs --- src/docs/codegen.md | 220 +++++++++++++++++--------------------------- 1 file changed, 84 insertions(+), 136 deletions(-) diff --git a/src/docs/codegen.md b/src/docs/codegen.md index e7d3de2f8..540f07c93 100644 --- a/src/docs/codegen.md +++ b/src/docs/codegen.md @@ -1,110 +1,67 @@ # Generación de Código Intermedio -Para producir código CIL se toma como principal el guia el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. +Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. El programa original se divide en tres secciones: * En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. * **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. -* En **code** se encuentra el quivalente en CIL de las funciones definidas en Cool. Cada funcion en vez de tener expresiones y sub expresiones complejas tienen una sequencia de operaciones más sencillas que producen un resultado equivalente. +* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. ## Types -Contiene solo el nombre de la clase, los metodos y su identificador único para buscarlo cuando se necesite llamar a un metodo y los atributos de la misma. Los tipos tambien contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. +Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. + +Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. + +En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. + +La función `init` se ejecuta siempre que se instancie una clase. ## Data -Se almacenan todos los string definidos por el usuario en el programa Cool. Ademas se tiene tambien la cadena vacia para inicializar strings por defecto apuntando a ella. +Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. -El program se representa a traves de un nuevo ast. Donde antes habia una expresion -ahora la sustituyen varias operaciones sencillas en CIL. +## Code -Todas las expresiones tienen en comun que su resultado final siempre se guarda en -memoria en alguna variable local. +Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. -Algunas expresiones desaperecen desaparecen, como `isVoid x` que se transforma -en preguntar si el valor final de la expresion `x` es 0 (Representamos el 0 -como Void) y el tipo estatico no es `Int`, `String` o `Bool` +Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: -Para todas las clases se les genera una funcion `init` donde se setean los -valores inciales de todos sus atributos. Si el atributo tienen una expresion -su valor es el resultado de evaluar esa expresion, si no es un valor por -defecto, una direccion de memoria apuntando a una cadena vacia "" si es -de tipo String y 0 si es de culaquier otro tipo. +1. Produce las operaciones de todas sus sub-expresiones +2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. +3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna -Se genera alrededor de las expresiones pertinentes casos para lanzar -runtime error, cuando se tiene division por cero, el substring tiene -indices incorrectos fuera de rango. Cuando la instancia que llama a una -funcion es Void. +Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. -Las clases predefinidas de Cool se implementan tambien en CIL. +Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. -La manera de trabajar con sub expresiones es que estas se generan, y despues -la expresion padre las ubica en donde las considere pertinente. La expresion -padre tambien tiene acceso a la variable local donde esta alamacenado el -resultado final de sus subexpresiones pudiendo modificar, ubicar donde -considere necesario. +Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: -Ante el problema de ocurrencia de variables con el mismo nombre se utiliza -un calse Scope como la de las semantica pero mucho mas sencillo con el -objetivo de tener segun el contexto la variable y su traduccion a cool. ++ División por cero ++ El despacho ocurre desde un tipo sin inicializar (`Void`) ++ El rango del substring no es válido ++ Ninguna rama de algún `case of` es igual al tipo de la expresión -Luego dado el nombre de una variable en cool y el contexto actual puedo -saber a que local de CIL me quiero referir +Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: ```assembly # COOL let x:int = 3 - in let x:int = 4 - in x + in (let x:int = 4 in x) + x # CIL local let_x_0 local let_x_1 ... ``` -## Transformaciones - -### Clases +### Transformaciones -#### Cool Input +Ejemplos de traducción de Cool a CIL -```haskell -class A1 { ... } -class A2 { ... } -... -class AN { ... } -``` +#### Declaración de Clase -#### CCIL Output - -```assembly -.TYPES: - -class A1 { - attr a1 - attr a2 - ... - method m1 - -} - -... - - -# Pending, should string literals be added here? - - - -... - <- ; ... am: <- ; - -- Uninitialized attributes - aq: ; - ... - ak: ; -- Functions f1() { } @@ -127,17 +80,13 @@ class C { } ``` -#### CCIL Output +**CCIL Output** ```assembly type C { - # Initialized and uninitialized attributes together attribute a1; ... attribute am; - attribute aq; - ... - attribute ak; method f1 : ; ... @@ -145,29 +94,39 @@ type C { } ``` -### Herencia de Clases - -Se annade sobre la que ya tiene A, como se maneja la memoria, se annaden los atributos de B, despues de las funciones de A, o despues de los atributos de A +#### Herencia de Clases -#### Cool Input + **Cool Input** ```haskell class A { - + a1: + f1():{...} } class B inherits A { - + b1: + g1():{...} } ``` -#### CCIL Output +**CCIL Output** -``` +```assembly +type A { + attr a1; + method f1 : f_f1_A +} +type B { + attr a1; + attr b1; + method f1: f_f1_A + method g1: f_g1_B +} ``` -### While Loop +#### While Loop **Cool Input** @@ -199,20 +158,18 @@ if then else fi **CCIL Output** ```assembly -LOCAL f # Init var which will store if result - # Init all local vars from the condition expression - # Execute the condition -x = # And store it in a local var! -ifFalse x goto else_expr # 0 means True, otherwise False - -label then_expr # Not really needed! + # Produce todas las operaciones de la expr de la cond. inicial +x = # Guarda ese valor +ifFalse x goto else_expr +# x = 1 -f = +f = # El resultado final de la expresion if goto endif +# x = 0 label else_expr -f = +f = # El resultado final de la expresion if label endif ``` @@ -228,23 +185,14 @@ let :, ... : in **CCIL Output** ```assembly - - -... - - -# Execute expressions of let vars - - - - - +# Inicializa todas las variables let, tengan expresión o no + + ... - - - - - + +# traduce la expresion en operacions + +f = # Almacena el resultado final de la expresion let ``` #### Case Of @@ -270,36 +218,41 @@ esac x = - -# Pattern Match Logic! t = typeof x -label init_case # This is not really needed + +# Analiznado rama 1 t1 = typeof -b1 = t1 == t # Comparing types, they must be all equal -if b1 goto branch1: +b1 = t1 == t # Comparando tipos +if b1 goto branch1: # En caso de exito ve a la rama +# Analizando rama 2 t2 = typeof b2 = t2 == t if b2 goto branch2 ... +# Analizando rama n tn = typeof bn = tn == t if bn goto brannch -# It is not possible to avoid pattern matching -# Branch Logic + # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama + + +# Realizando logica the rama1 label branch1 goto end_case +# Realizando logica the rama2 label branch2 goto end_case ... +# Realizando logica the raman label branchn goto end_case @@ -307,9 +260,7 @@ goto end_case label end_case ``` -El typeof tambien se conforma con un ancestro. Que evaluaria la operacion de igualdad para escoger la rama adecuada? Lanzar un runtime error si no se escoge ninguna rama(eso puede pasar despues del cheque semantico?) - -#### Function Static Call +#### Despacho Estático **Cool Input** @@ -327,7 +278,7 @@ El typeof tambien se conforma con un ancestro. Que evaluaria la operacion de igu r = call n ``` -#### Function Dynamic Call +#### Despacho Dinámico **Cool Input** @@ -346,7 +297,7 @@ t = allocate # It needs to give the same attributes that type one has r = vcall t n ``` -#### Method Declaration +#### Declaración de un método **Cool Input** @@ -375,7 +326,7 @@ function { } ``` -#### Expression Block +#### Expresión de Bloque **Cool Input** @@ -402,9 +353,7 @@ function { ``` -#### Arithmetic Expression - -###### Simple +#### Expresiones Aritméticas **Cool Input** @@ -434,9 +383,6 @@ t = 3 + 5 # Naive t1 = 5 + 7 t2 = 3 + t1 -# A little better -t1 = 5 + 7 -t1 = 3 + t1 ``` --- @@ -470,9 +416,11 @@ t = t / 5 t = t / 2 ``` -## Lenguage CCIL -Definicion del lenguage CCIL. Tomamos como No Terminales todos los simbolos que empiezen con palabras mayusculas. El resto se considera como Terminales. + +## Lenguaje CCIL + +Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. $$ \begin{array}{rcl} From 98fd3c286ece464a10e2b295468b43faf4e9c95f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 26 Feb 2022 00:21:43 -0500 Subject: [PATCH 324/432] Update semantic and inference docs --- src/docs/semantic and type inference.md | 81 +++++++++---------------- 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/src/docs/semantic and type inference.md b/src/docs/semantic and type inference.md index ee4c40cab..12668efa0 100644 --- a/src/docs/semantic and type inference.md +++ b/src/docs/semantic and type inference.md @@ -1,81 +1,60 @@ -# Inferencia +# Semántica e Inferencia -La idea principal para realizar la inferencia es considerar todo declaración como AUTO_TYPE no como un tipo especifico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como Int o String se consideran conjuntos con un solo elemento. +Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. -La inferencia se realiza varias veces por visitores distintos que explicaremos mas adelante. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par durante la inferencia, distribuido a lo largo de los visitores. +La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. -En el COOL original la mayoría de los nodos del árbol tienen un tipo estático declarado al igual que una expresión, donde el tipo de dicha expresión debe conformarse con el tipo estatico. Este es el caso para la declaracion de variables, la asignacion, cuando se pasan como argumentos, o una expresion con el retorno declarado. +En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: -Cuando el valor declarado es un tipo bien nombrado (diferente de AUTO_TYPE) y el valor inferido es un conjunto de tipos se truncan los que no conforman con el tipo estatico +1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. -Cuando el valor declarado es un tipo auto type, entonces tiene que ser algo a lo que se pueda conforma el expresion type +2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. -Cuando ambos son autotypes, ambos tienen que conformarse entre ellos, pero la cosa se pone sucia +3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. -Por estas razones el inferenciador se debido en dos partes, la primera parte trata de conformar los autotypes al tipo declarado (ya este sea otro autotyepe). +Para tratar cada caso el inferenciador se divide en tres partes: -Esta primera parte se divide en dos partes tambien, una que llamamos inferencia suave, donde el conjunto de tipos puede tener elementos disjuntos y no se aplican casi reglas del chequeo semantico +1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. +2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. +3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaracion de variables) +4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. -La segunda parte de la primera parte llammos inferencia dura, donde no se es permisivo con violaciones de la regla semantica. Una vez termiando este recorrido, el conjunto de valores de expresiones debe estar lo mas reducido posible. +Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. -En la segunda parte falta reducir los conjutnos de elementos que se han declarado estaticamente como autotypes. (Ojo estos elementos pueden haberse reducido antes de llegar aqui si participan en una operacion aritmetica o dispatch). (Este se ejcuta n veces, xq era?) +## Soft Inferencer -Luego de de terminar la inferencia se recorre un utlimo vistor. Este setea los tipos de acuerdo a su ancestro comun mas cercano. +El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. -Se infieren los tipos lo mas posbile aplicando las reglas de la semantica de cool. Cuando el inferenciador debe elegir entre varios tipos a asignar a una variable, escoge el mas general. El inferenciador da errores si entre los tipos que tiene a esocoger escoge siempre el mas general, el tipo raiz de todos. En caso de que sea para valor de retorno de un parametro, esocoge el "menor" ancestro comun. +En este ejemplo no funcional (Lanza `RuntimeError` debido a que `a` es `Void`) donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. -## Funcionamiento +Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. -El inferenciador se ejecuta varias veces, en cada una realizando un chequeo distinto. - -### Soft Inferencer - -Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. - -Aplica las reglas de cool para realizar la infererencia. Este permite que haya ambiguedad y que un tipo por determinar puede tener varios ancestros sin nada en comun. - -En el lenguage cool esto se evidencia cuando se hace un llamado a una funcion del estilo - -``` -a.func(); -``` - -donde el tipo de _a_ no es definido. El inferenciador buscara todas las clases con un metodo de nombre func y cantidad de parametro determinad y los tendra como posibles tipos para _a_. En estos casos _a_ puede ser de varios tipos no relacionados por ejemplo cuando: - -``` +```c# class Main { a : AUTO_TYPE; method main():AUTO_TYPE { - a.func() + { + a.f(); // Boom si no es el soft inferencer + a.g(); // Solucionado + } } } - class A { - method func():Int{ + method f():Int{ 3 + 3 } + metod g():String{ + "yisus" + } + }; class B { - method func():String{ + method f():String{ "3 + 3" } }; ``` -$a \in \{A, B\}$ donde A hereda de B y viceversa $a \notin \text{Object}$. pues Object no tiene un metodo func que recibe 0 argumentos. - -Debido a que las variables pueden tener varios tipos no relacionados tampoco se revisa las comparaciones de igual. - -### Hard Inferenecer - -Infiere el tipo de la expresion a base del tipo de la variable a la que esta asignada. Ya sea como asignacion o el valor de retorno esperado de una funcion. - -En esta parte el inferenicador realiza las misma acciones que en el Soft Inferencer, excepto que ya una variable $a$ no puede tener tipos de datos no relacionados. Se revisa que las comparaciones de igualdad que ambos miembros sean del mismo tipo. - -### Back Inferencer - -Este se encarga de inferir el tipo de una variable a base del valor de la expresion. - -### Types Inferencer +## SELF_TYPE -Pasa una ultima vez por todas las expresiones +La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. From 77de5a539513a5c3a2bc5d5ea46b9e011191cf5a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 26 Feb 2022 00:22:45 -0500 Subject: [PATCH 325/432] Update rodro's github user name --- doc/team.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/team.yml b/doc/team.yml index 2169aab60..c62382945 100644 --- a/doc/team.yml +++ b/doc/team.yml @@ -3,5 +3,5 @@ members: github: adrian13579 group: C412 - name: Rdrigo Pino - github: RodroVMS + github: rodrigo-pino group: C412 From 3ebbdd053f038b32372fa5553d6207d89d28b4a4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 26 Feb 2022 00:27:28 -0500 Subject: [PATCH 326/432] Add tilde --- src/docs/semantic and type inference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/semantic and type inference.md b/src/docs/semantic and type inference.md index 12668efa0..687b7c72a 100644 --- a/src/docs/semantic and type inference.md +++ b/src/docs/semantic and type inference.md @@ -16,7 +16,7 @@ Para tratar cada caso el inferenciador se divide en tres partes: 1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. 2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. -3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaracion de variables) +3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) 4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. From e872a33949742cf85e60a04148be4a80382b1df4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sat, 26 Feb 2022 00:28:01 -0500 Subject: [PATCH 327/432] Add initial report --- doc/report.md | 539 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/report.pdf | Bin 0 -> 204104 bytes 2 files changed, 539 insertions(+) create mode 100644 doc/report.md create mode 100644 doc/report.pdf diff --git a/doc/report.md b/doc/report.md new file mode 100644 index 000000000..3deb4a937 --- /dev/null +++ b/doc/report.md @@ -0,0 +1,539 @@ +# REPORTE + +_Rodrigo Pino C412_ + +*Adrián Portales C412* + +# Semántica e Inferencia + +Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. + +La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. + +En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: + +1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. + +2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. + +3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. + +Para tratar cada caso el inferenciador se divide en tres partes: + +1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. +2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. +3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) +4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. + +Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. + +## Soft Inferencer + +El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. + +En este ejemplo no funcional (Lanza `RuntimeError` debido a que `a` es `Void`) donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. + +Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. + +```c# +class Main { + a : AUTO_TYPE; + method main():AUTO_TYPE { + { + a.f(); // Boom si no es el soft inferencer + a.g(); // Solucionado + } + } +} +class A { + method f():Int{ + 3 + 3 + } + metod g():String{ + "yisus" + } + +}; +class B { + method f():String{ + "3 + 3" + } +}; +``` + +## SELF_TYPE + +La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. + + + +# Generación de Código Intermedio + +Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. + +El programa original se divide en tres secciones: + +* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. +* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. +* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. + +## Types + +Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. + +Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. + +En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. + +La función `init` se ejecuta siempre que se instancie una clase. + +## Data + +Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. + +## Code + +Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. + +Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: + +1. Produce las operaciones de todas sus sub-expresiones +2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. +3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna + +Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. + +Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. + +Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: + ++ División por cero ++ El despacho ocurre desde un tipo sin inicializar (`Void`) ++ El rango del substring no es válido ++ Ninguna rama de algún `case of` es igual al tipo de la expresión + +Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: + +```assembly +# COOL +let x:int = 3 + in (let x:int = 4 in x) + x +# CIL +local let_x_0 +local let_x_1 +... +``` + +### Transformaciones + +Ejemplos de traducción de Cool a CIL + +#### Declaración de Clase + + **Cool Input** + +```haskell +class C { + -- Initialized attributes + a1: <- ; + a2: <- ; + ... + am: <- ; + + -- Functions + f1() { } + f2() { } + ... + fn() { } + +} +``` + +**CCIL Output** + +```assembly +type C { + attribute a1; + ... + attribute am; + + method f1 : ; + ... + method fn : ; +} +``` + +#### Herencia de Clases + + **Cool Input** + +```haskell +class A { + a1: + f1():{...} +} + +class B inherits A { + b1: + g1():{...} +} +``` + +**CCIL Output** + +```assembly +type A { + attr a1; + method f1 : f_f1_A +} + +type B { + attr a1; + attr b1; + method f1: f_f1_A + method g1: f_g1_B +} +``` + +#### While Loop + +**Cool Input** + +```assembly +while () loop pool +``` + +**CCIL Output** + +```assembly +label while_init +x = +ifFalse x goto while_end + + + +goto while_init +label while_end +``` + +#### If Then Else + +**Cool Input** + +``` +if then else fi +``` + +**CCIL Output** + +```assembly + # Produce todas las operaciones de la expr de la cond. inicial +x = # Guarda ese valor +ifFalse x goto else_expr +# x = 1 + +f = # El resultado final de la expresion if +goto endif + +# x = 0 +label else_expr + +f = # El resultado final de la expresion if + +label endif +``` + +#### Let In + +**Cool Input** + +``` +let :, ... : in +``` + +**CCIL Output** + +```assembly +# Inicializa todas las variables let, tengan expresión o no + + +... + +# traduce la expresion en operacions + +f = # Almacena el resultado final de la expresion let +``` + +#### Case Of + +**Cool Input** + +``` +case of + : => + : => + ... + : => +esac +``` + +**CCIL Output** + +```assembly + + +... + + + +x = +t = typeof x + +# Analiznado rama 1 +t1 = typeof +b1 = t1 == t # Comparando tipos +if b1 goto branch1: # En caso de exito ve a la rama + +# Analizando rama 2 +t2 = typeof +b2 = t2 == t +if b2 goto branch2 + +... + +# Analizando rama n +tn = typeof +bn = tn == t +if bn goto brannch + + # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama + + +# Realizando logica the rama1 +label branch1 + +goto end_case + +# Realizando logica the rama2 +label branch2 + +goto end_case + +... + +# Realizando logica the raman +label branchn + +goto end_case + +label end_case +``` + +#### Despacho Estático + +**Cool Input** + +``` +(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +r = call n +``` + +#### Despacho Dinámico + +**Cool Input** + +``` +@.(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +t = allocate # It needs to give the same attributes that type one has +r = vcall t n +``` + +#### Declaración de un método + +**Cool Input** + +``` +(:, ..., :) : +{ + +} +``` + +**CCIL Output** + +```assembly +function { + param + param + ... + param + local + local + ... + local + + r = + return r +} +``` + +#### Expresión de Bloque + +**Cool Input** + +``` +{ + ; + ; + ... + ; +} +``` + +**CCIL Output** + +``` + + +... + + + + +... + +``` + +#### Expresiones Aritméticas + +**Cool Input** + +```c# +3 + 5 +``` + +**CCIL Output** + +``` +t = 3 + 5 +``` + +--- + +###### More than one + +**Cool Input** + +``` +3 + 5 + 7 +``` + +**CCIL Output** + +```assembly +# Naive +t1 = 5 + 7 +t2 = 3 + t1 +``` + +--- + +###### Using non commutative operations + +```python +3 - 5 - 7 +# -2 -7 +# -9 +``` + +```assembly +t = 3 - 5 +t = t - 7 +``` + +--- + +**Cool Input** + +``` +100 / 20 / 5 / 2 +``` + +**CCIL Output** + +``` +t = 100 / 20 +t = t / 5 +t = t / 2 +``` + + + +## Lenguaje CCIL + +Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. + +$$ +\begin{array}{rcl} +\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ +\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ +\text{Type} &\rarr& \text{FeatureList}\\ +\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ +&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ +\\ +\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ +\text{FuncCode} &\rarr& \text{id }\{\\ +&&\text{ParamList}\\ +&&\text{LocalList}\\ +&&\text{OperationList} \text{\}}\\ +\\ +\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ +\text{Operation} &\rarr& \text{id = ReturnOp}\\ +&|& \text{goto id}\\ +&|& \text{label id}\\ +&|& \text{return Atom}\\ +&|& \text{setattr id id Atom}\\ +&|& \text{if Atom goto id}\\ +&|& \text{ifFalse Atom goto id}\\ +&|& \text{arg id}\\ + +\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ +&|& \text{Atom - Atom}\\ +&|& \text{Atom * Atom}\\ +&|& \text{Atom / Atom}\\ +&|& \text{not Atom}\\ +&|& \text{neg Atom}\\ +&|& \text{call id}\\ +&|& \text{vcall typeId id}\\ +&|& \text{typeof id}\\ +&|& \text{getatrr id id}\\ +&|& \text{allocate typeId}\\ +&|& \text{Atom < Atom}\\ +&|& \text{Atom <= Atom}\\ +&|& \text{Atom = Atom}\\ +&|& \text{allocate typeId}\\ +&|& \text{getattr id id}\\ +&|& \text{Atom}\\ +\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ +\text{Constant} &\rarr& \text{ integer } | \text{ string } +\end{array} +$$ \ No newline at end of file diff --git a/doc/report.pdf b/doc/report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..37d7dfb9c3d074ac2aab22a7b3721813a45bb253 GIT binary patch literal 204104 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 ia5a|qAM-I?nnpDu7 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

4WTYIkI#wCY>2ETCgpC) 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%0Dxz0%ep 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

Y zmW!fTs@ChS{|Lfnfyi>h>qKlE8ioP7%99;CU&;kL59EUtqWKw~EaQwh@T^P9e!FBo zHb)Li6?PX*x)To-e-RcDP-+r(RnDv0a6)mnS$>FIZD#SwYod-`r%|4GfDV>zk4>GO zr*={06`dv2QJK%MHL3S{U9C&Jz#m@M;1klohNX*=Ht)J#nIbJ4cz{+aOzHV=o;f@H ze|qNso9Z$%Gyl(>yUZMHO#g+*Uvd5i)lKew&k$nDxSq!js87RX!6cBn7sn(}_nXf% zbOPecHW&BvaJ9;_02leSOFX zhb$Al?oitkhp72kbyggrab~mC)^&IDMXC6@=Dqj)NB5_KQi2}YRtWH|e@S<_+i+Nt z?{IOo<_i?8(dmBie*M`AeJFlITBKW7{80kPn|KGT6+9@=)8i>+`))g!YoIHdz5;87 zv&HZmBnlwts_@zOyyLG*gS@Jbch-N>cMtau&^)VijX|N~_H01<6 zWN==Ij;YvA#FAu8Efl2pI)H1M=!d(}Uq&iA9_Y)kmr!J0v;c?%hf@j!*A@lzyyP_QxEWc#8U|X_zK|Ax8?3TW$ z9-k;v&C^O>r?7n52^6=i08ngaY>`+Bd^*hnxtb$lufG(>#}AE-O^FjuOzL46=Z|e< zDo1e3aAp{;;g%~XsdJe&sbX5wnmJvrL4w$Y5c~((T`6FD9Ifp9CA%pG)k>6})okT3HPFuzplU0d!4WwJT!f6)tYLtvojs6#WkBOEYr%vJD!ZB%42e6jhUL=qW_1n za}3TUTDNspY}>Z&tk||~+s2A*+jdrL+qP{dH+!EtxAs1@>)iXNtNL%x@9Wv`nBy5^ zf6TLqyQo}ayhsU4!{mio%SfD=S5oQVrNnPsek!XIc`hpmTz#+PcLwIqTPs=34^*g#+_C+%-lPrbf|7J}hR{>ek;viH&(McHm{<{@qK%sk=N(`_m{aUCX1fh+ooD z2WdXFvUFoR3jTva6;SmZ@F(S=xJCe|93&|a6Bf7>^C?PH567i(_ed?DuAg%oAvDNA zIqEb&6|I=z$|W2lduT%HT4AOcrmC)W$awLQe6jS_dvooE^PyULfj+#n$ma-(+`fc3 zC0NO@GE!mj(JGOJH&miey@4!udxpY(_N34!`6ct7ATakJaU7Xg@KlLvQF}B8>uo;H zFEYG(Qkq>rQz}A9pJ*a<^v0X2=1^+1vqPD%EYF3TZ(`d#y<#W$i+0rPOQpxfDmTHS>wEA(KlihN(T#KVZ5 zGxySb$!oh84|;*O!vxw4A!WQ=l3I;~HgZ#%G6o((l;Q8P1Xbz;!vV1Q0(oc} z(dw%ziRgk)$JiL?Cu^l1&=JH*`YUAS%gvG=4T-@P0RZ_WTuNyg%*$+=Z5mOt zIj2iL5ZY`}$@?Znc`PzvRN?`C@yq7FH+dYI4w&vhAJIYX8>#cB(Q%RRB7{m?Hw`FnuuJq20oo^H7~#gQ^%?y zovjG=42Ew*;TdwFgB9>EM;Zkwn)HUPBA;<$0HCqdrU1}CANPTwQ{6E|^gh`W{K6na z_ygsE(Fg1xq>Mb6|Ij-EvRd^-GJ+}@BT(Tnh*Be98Jc<-1_eapAGmL<(*S2TA#mMB z?N*`!am$1ZQzPga4A4i15)*H%`@}hWie9K=?J)00MN*payNX|n8t$Vi(LBqEwy9sn zxRx=m^aK|7;^iY4bEJ!_M+bnjPL@BYm{CZ81g9vvxdYP5wL)kox`E5!iLA4k2YK|Q zs{sfqWPhjA(PkGUD=_>T9E7`*H*7WZN0H@*_1JpHtMtA}xnVL$R}LIqvs_3S`7@t% zJ6%qqc0Kq8dT#1kKW$$n(#fW-d#w2SsD^hi4MDK`*T~zadTOzaQ}y_#MvAYzB+8RF z?Kz@T@z1euf8B**E%DVtjj|hF-nOgbw%c=n^9}_bNINytiH=nDP2R1A= znXJRDBV8~!WRW>(bMw>6%`0br;HdI}G&id4QjPgsZq)$0zqiR^YLH~$2~tBepy3iE z{Biu0F0{~S?$W*Z8O|>t^^ZMt(O(jLWqeE$65Bq{B|J0*8o5Qo$qMg3B391CAjz;nT5UZIILm(7Ua@sYGy|O zmtG5!0a7(g<&57KmH6->z0OS3b*$w^AuUK_bAsC^A8*1Gh4hdDMRsI((P`{MOS0J{ zc&CW_0?ltRPTp|Dt@WG^O~37py3&jlfrAjKj5#Cl?$S+|Gsdk*51!x5Svg+`Ue(Yj z0(lZfS(1pHaX;derUn4PgFu?)g9{(T4T3@RAE!`kE&--(<5s4elJjR=|{)vQGSU9(t@AMT>2}J^+B-Qed=d$%jz@G=Dye z_Oxe8JvdOE2a6}`Lw*3#=;$g&L3FedBNItnS%Ff$C*_Gf11D*?M`;p8yLN8en&E!; z$LB{rZ10`Pr!E>0-R|S7_KeU|-R7LFrG|UY$GR!K^XKgkTKAK~?SW7&`Faauo1dJT zI~*|9j+ct~K0Z`nO-hGqiVEFl#3VkjCbpn8CVu)op^EyTR2tG`!Ar+^R1iTaO2fJ2 zMn=;|#W(!rplSKO6OX+XpG+IId}79FE5_Rsj2?S#+q!&BgH(8=am9H3><=acS2@F zQ9XMA?G}3&&BA*CGFX!)7iNDL5XBo@4^wiWKj zhOd80NONdAUM4nu*FEq0b$u(lz5BIW_-ap=u3gw7`J4~HQ1foej#@l?@6HNS5ZGy# z?ANPx77o_R8ZPMC_!IZXLb)bw7~LEPAv(}OBK|X_3L>$O%bH7 zN-XZQ;sHaZA`3xRV#RupdUwNFzk}=$S~q_Y0ZVR{_Ev2!XN=BIJRyD}eO`}tOiv@+ z8-;d1KW!D9r$^U;x!A5Zd*%mgi4!x%1U<@5@!7q5tLiwr$h$Chtz-q@(X>(5_YBgL zW*hV9aQUT>(FWAFVN)1Hr2|&(I+7c|?C}cs6K6hHl=lvnb|4yNlZ%Aqwztxh)?kzSgF}m!D=;!vw}nu} z5|a)SJ3{WZhQF%noIWN~j)lLvbY!iAc-EPV2U^70OR|DQIHr2AkddKN+sXyzQ+4Y& zzZNTp|3s9ijHsjDCC}1cF-!${m^x7Z70gc(v$shYzC=vCu)-u`Hle>J1*CAhl~%;H zcQ1ByERIdSAWz#!?gv5JqMC%mdE0#v|7`tQ!u$HnXcw4$GqdV{)eW(6JX;mi%y#>F z>;1FdY;A4b-E9569c!sEiV;Lg#!SqFL0S-(tj%})N_*LQtJ9Kc{M_`ROq8!Z zff}FMC$(?3#OLPVsJ3!(V+~Zt6kr2jF&X|}<8(vB!@)&xS zcuch6BzIGBe0nQ68LGJaTnzOS&25Q9Ageu$II4B}BJ_11v+La9jTX_(Y4kk3; z=k0!D;rwg&kO@oo)8~@$8Frj?KwUlm2d8;t?p}t3BkhPBZ7X3 zizxCkaCL+*dra1N1?&YGZou(~!g?basjJH$xfOA|cJJ;-ZryvwU6%c(-InJbg3);J zZRTw>y+f(K7dpl#b`2=`hukXq(Z|iL@w<8Z5Heu$u;sN1V=J=s3`N~i$(SbvhnDtA zoq16H8!BIQuijJ!HOwkN;3wn=3jOIcX6oAGZ{FwT(QL;gP76%Z*A<@Zro)ohA@DZvx z6eSI`E}G+c*Ckkom%#X$^!GXOxqmo@scZdhD*IdSE)ZqB3>s`E25+B}!6TgT^dC}d zHgd!2Wg|N}Z<1_PTWkOPXRcRsw#nr=vt0>MD$X$G}pXFJEGb;o)9cKr$RK+@|5p-HN(OjlUyQ}#t#_roB zlI?2z!te(C9b^hC0DccvtIzjfy2i75BB_m0^=M2hjmpvZziz&|QB07p4T84l38J4* z&~JMDzzNhOYl?_TUb`nqPjYFd0xmCaCwo!k60PoI zVeb>He`x|#=mU7{dYA>+GoVUe!^W>vD@~zxnez>o}F~pH$ZqwJcXtRqsRK4Sv`ekH z_|mL*`TevovUq${s6M@@vOK*64jOo>xaq%lG*WbjW!yo9>aMo-Y|o2f7P$CotgKG$ zE73;ItMBQJul7?@F$?L&eElGayAw}TeO)fHE1R?kqV4D|jd(7ZF7zO<0(~=GC^o_U zHwbowvHEbkqwH<2l~pWkE&3bGi*vc^=}TrtHOY$-+i^#*(km7Gp2O)Y=mgse*O(ao z;gO(Kr7Xpx7#4v`fiMh)6F?|uJ9@NVGmI-7t${vK%TnUkA8;Cfpa%YvjK}mZGT#3t zoiZ`7{F`j|KS~6F&He<%QvQ{|eiAkG21rk(odcH_gX{PVkmfRv`~9~1wFj3`Y7-qb zn=OiGlSt#XWm$kNwLdAogVt)%kJy`(>_g%;p4UJPx#yD24IOnVs*;>3nnS?l&UQb^ zABE;-Fx#%U)7W-5*=7UO!e;5K2e9uxQ65fp(l1?;<$VsigD}<{1?hfyY(4X#>@|tn z`dels3L8bLIbny>5kzHZSE++LSdoGLOt%Yvu_$FbtN)ByX}B)5B6t9Tq9RUV>@ZQ% zG9QovNr)^T+B^jwCk$4M4dbLww?7yCwV54dekLocEk_@dmUYKMbGYb zpxFou;|EMP^eQzn8ZPw1fi{OW-{<~Y3)sR#P?Lby-Y8CymuVzaUn%amR=9dew4OL= z?)XO3Ub1C{S5gxDaKOwAqju&hTJK-TQF0l><0$~@h5!$s2FlbUV6gsM zyC03uV`n_HEz;HCx$A)Vp7b6Y;FO=e={-A8;fHFBA*>|wa&@1qA@>@hqM4!F^}to(dkjenkuTcZqxYyM*(g^eUe6G59njnW-^h3(5WYS}+d&Ktn|<`cs7OCW zg8c++QR4~~-G;e1#2v*_UzJ$6%@d5}zy~=LQR{=cxl8l`O5rTTmp%UB1yH~P^kO(c z#1|slPd&g=hYle^xNPCA-gfvYGw8KW>HC*L3!aJOhLY&Jy>?eM<9_@ei& ziaE~nxJBH{c$1&B?@1e8PsRhS_3M1*yEW#?A2(F35`Iekvb)^+cF}BF{<=Nx&;$5> zb8U`diu-{;pWdD8%{HfD)>l_&ks_RH>sN9bY~IDj`yoe<=joW|%L`T2Rq9QQ$d!py zfL{tNrv%vXYv24CEw)Nxlx92IaHJzIX7B&9)3p-pSHA!`f zW6gDRDJZ0sCE#tjb%yJc5JJnQjsFNVgicNiXii zOFp9T2GnynqDs3RE{;lHoO|Gj#)*JIhSe;%Nc7#%!+u*v*)%}joI4EtqiM|lvCFS@VE*0Q zsHaxXj=s+y0H*(z14IOV#`JB0o4Pmjnw#8tF@1`d{4hy4oJ@v-DI$^NHYloA} zKx!^5d|J18{;?BdTek3t7x`8VyR9mptR=qJ@@UIftPf9L#>NYqEvh#QJwN#Y@- zR)cI`N2|6a839T{F2DW|IejZkg@rimYWQG>w%5fYQn9I>WZ zIX}t;vHg``sAnG6(j-QC+e^syH&0bOZZ;YaFW6RoY<|x2T4TW^AOFn!`VOS=ch}+) zy;w42hh_9 z&5U$!A3Z<7XaoREF>ck_=$T9Y~x1KWBxQd zo7v!qn~WsjQlvb?X=MJ4McyDm(czVn2CkeYv<l{ubiY|(8YUb{WTJfr>m8>sidFR~5q*a>XOjnEZtUOPRb#}yNWZD8$_xow7eFld07jl!c;sl%1) zm|%xe2#}p|8R&NJHzamIxa{F|L5tpC9EHca6D2XaT!rZjl8C=+jIT6|lGXMF%6Op#tB#5p*5Vl3_X;O5t z#IVVCU`QsqL4;51U3oeSQ0bLm_RvslJ`w3^vh6g&o@kzSu`l{KVc<7V=>J!ZvZquD-8>C!dit?C%SI~MvoIo_FOIMG+oMlgL z&24JZ02a(ZXKe(LL+VT&UtMlc)S}y>LnO@*&S^fTb;N2Dl!HX6RflN1K;=@Dm)Fox zx2YR>s!ug(xwmOyDsKZBntm_9yati&6`**cHKVPnKowVGrd4$eJh2dopfXMnuLftS zw$^B=wy)CC*I7ljx$zJ(U`^w`vJ+G!;%c6)KRo@@<#H>#-1WS{_c4A_(fyvYZMxlY zED6W!vHU4ZYUpS>&1cE7m~;6)deZ%AmlwofpUL^qvn#LlZFj}^zP*9`X5YR?;gUK@ z0vmFBC!B>z=hvVJMAxVS^jN)v`uKB3{0k6<j#nSLWlQa(}{u|FnMw_)5s zL-*LKwrmn*JP8YCwS*n8inKT(>4Tgf)UQx@rxOR6zyS|ghnVZS3wq-Qs6+QS8Q3LF z{H!^`ar9g9>GQ%jz8C+X@`zCH( zRad8}UXJL3AOX*CA-~d&DKgDe-8Kv;H;Bw8psOuQSfE4&xH3-qfzb*XW^@?plZo=r z%-=XHhTv4*$Sf^=0W@{Zr~Zo~CR3fR2U*c(SldoRpt{=m<(T?;viJAyisi`^Tk|l3 z4w-zS?w)H{D4#_oN(<`=p}%=1ve~>m^mgf1 zV>*P7AD=NiOKq1L5I#TkiFP?@>-2DpR`LQ@djvxB|x-aQBH-u8G9(2M-6Iy*Ibk5f8PpU79 zwpGHKOrLe{JGxbbLN~S;G``$OIYphmpCzdX2KE3ow2D3b>ci3D( zKV1Yn6~c!@m+hAKcZAQVoLR2TEzhGA>``EYx_2^``?E%M*19Z@{C1^Yf`Mu}Wum;# z-$Q`Bf%rauA(uaiH);SI*GkxDT)5yNqir8Gxmf7*j=ES(#n_^yyRudFiS!fOl>ZhE zH7{HrJ|`r5#^LyA>lB5(Hh#VEVtsC^fJ;CL8uTyY^L|>j&F1}#vNhQr|8h%KbJ`=c zlriF?tjzl4_8|Bzhk%h%=Ma}15O|ERx`xk+MoEwZH7D1%Rj;G6qNI#y<#llS^8gk& zmrYtJET3@J_eIfsdM-WOmywaDf*s9>z^lTym5!Q$Dj(W632NIvUAn6}3c1UZz$)5U*yf8M{dw-m#!sr^SV$X!21dR?X4Xr>k6fx_X^*@QLozGXhj&(1Z-X)e#usrmg zS8RNqpY8pDF%Q_A_IG*xSYp#{Xh3t1%FxiW_)$AB}aoe-tl7!RO7c{g`>Fm3HiNz<Ks8 z^O>f??}2XI^ksTL;Lwg9XpXx2GJ_Xuo9K`AIGB--xOp{gsV1b^fmT2h=po58ftVa?PA& zx#11G)6Xf0NfKP*Zy{cYw27yRT$3-e8<70a1fY#lRm-R*k8*)4G6&heyE;on1!73$ zZ01f9LVW)IU1Y|1%{&-7@wLsd8nd^|l?;~*ih6Hfd4Xg-zP`MDYq1u8ZFwsE$ZHbd zMz4-cK{@^~p*?0J@Rpp0^ezAMAcXU^S4%ZjK#nG2pUl3h^5mY(GMN93;LSBQwj2I( zS4(#V`J({I&k6XjR>eD&`ahsGK&*l7S}}DUW+UnAO^%9MiW^ z`ZAqUOte7LqNx1~x@4~RKe3JMZ2vO3{cqzlp3B&Vit+?jBBZ}pF^f3_hP#LE-+MLTNa@Ln{Ce$ih%VfDjIbEtLZ

qjoTO$;gF`wJBRk{VN|XCo4;P=Z3fh7EkTrAHE|ncCW>%<0qR5 zw&+rvfy(mV2G?0St?q|J0?0!M@>vCDIXY4Zj7DX4>r6WLx?zxHrPK0Bj7WtAV^{>X=SMSDm!*a>G zrGLTK2#aYcKx&Yw$;Gs%PLCvI&IOnJuN4tpEkFJGYJx^9ndC8_W0(@umCwI^T?@xl z{io@e{a>E(e^18@j2!>3jsO-W=6@fLFS(%Xloy*UbGAQ^vmJe3H-a)V5`gK$UN^j; z@!JmY9A1Oq+sN+B0L7uf5y3_ooxNlvUSc%MmuD{)HZpG`OuIvuB0J*%3QHU4qg;sVA8hz0QO5m*m6`pCD1 z+s^WfZFp&{Qk&l*l4?l?ilu*gu55JmPx{@O#|tz8Rt}%A(@XL_eX5WTl&|0C*I8qS zsr7ZpY|;#fTx-Uj=aTDFhdxFZ#=Fv%u%0`aBl-_G%D@{+G-s&$1nd;2&(yy%0r=19 zm<0++VmI@MGPdqZU2K`huBI&~Y~;7kZ~G0#FZ?8vNc@*#)FvRX5Lh*ieN7-3_z;j< z^yJ@MXRU~=ebzUcFX&&~oECBu{%;V-RJm9xy2a?9pC{M9PTtGkD62xG{FGka;`@0C z-S82Pec-pTUIRbss32O6!MDR1OKr(IoZ-Cp$**s&W@R71L}kzaAneWAzF^ILi7*WF zn(jCP5`%38A43FMd+lI*fln78paBJ)*;pwP(L`jRvCwGI`|7mX+x!tW zMv;=U#=V37j75JjjOH41k!h?{hIAw-Q8Qb&E+-w(fe%&QI>)4V|!8!|tXhyY? z<$TKr0mKhRdPup*q5*rj)@r6Dvu_+HwEqu`)CcqjBi&e~BDk~<{lQ2<8_O7!G1ZYF zX7*}?HAM@W!nLrhBbwo&o@i8m+(xi#m$TWJ%xu(=_z`)tDK2kKYhX&!R_CNl3oi?n zXe<_2#aKj`3CdKiEkwY+l!-mgUw+Io4L9dAekT0;xxqh$>mgZ!1ZvSZRW%fd=i{{- z-`qiWj!IGH1*s{+^joOmr&#@waJGswEm4zkr9;LnPUI|Rw^^4O+YXV{$_otPr6gWg zaOCnS#3{!WpjD9?EKZd_b|b8)paN3Zp4L3U{QOz*7w#vHW6@u$@shNvu`q{<1q+RX zzBZRK0-%hTe|gDJ!6S$?N-?qWo?3@3K%wsJg*>r1t&E#?rD$|dXSpQ~TV2aESg10H zhGJjnCl!l!Wf1U+4wuo-C91>b#NLamF9cP$9{tvMfCkB>;{@Tcd3e;Q-*v$S7)lot z>uMm07~4rPPfzCN)<1AsMcNNS`ErAmjPfYsWRgP2H5}i}yAj075mY0Hq9!E_6)g|` zw$3pC8xI>VY7L5ny%<{2tFbsHt4GuOs0a%n{BodSO&n8yS&~vW@e*>1{#C@U!yy?B z&lf3QfVt+>R@}h(lfI%#e`tQ9yclDTWQO*twD=BWfvXt>O?Ng!kD3_?7@lV-Z)m~7 z@dGKUViDu>*5*_BB!r<6n}sTBQhrP;j0t$5gC7Xg z7b*w_{e!KH$(b+VXq3z!)piW~jY>HV5>;q#Z>&RG+&jh}d|`$O9fvbn6({H>7wbwL z%{>iYTwbMsGa;mP5F3dV`OBC*5zt(;7-!5J!DRxp^IHx)ce=*`wCAJ-olvi5!jK-2 zDkK$MDiUIh6*$4M&?Oc+B82JYRVe;bL=;ZNyO${Qtm0y1_Y>}13p+Y1T*f_CTaxvQi zLB}pFTpOi}B4E5uFh2+|2-Yh zsrE5zmNA^4b<2*^?k`v_a4y<2(JYx+RS*UK!8zR7CHqPKX*d!3afW+`?ZW%R=znB0%JeC?z-wzu&KMB;Tv@kMH3%b`Hh!!Akv-mzvy?J;tw$4=SN>nrc? zU2{WKLsJ5#3aGyO!2Tgi)tvLNfs^)S_4)k;oyR~12$sWe&cMk#TowT!5UB2U`u zC;W#;6+XqkZc-Mdu-w0&CU}36qePj4?q8v%h9Si9`(g655{CQjDHN@mp&3X9PoYx> zjTqdsEzrUOQH06Z75mEPLB#b@L{$%dD+os)1l$#V*wVbC6*#N+;xEo9%g_)w>cr^X zy?N=tl>m#?mNpi$YswRknt_D;IF%xaZ7CqzECdIW=0E7S(j-2=!gH0=jsTkK#E*-`~Ak74}hd`|=Xaz)4tqJOcgdZO|@ZLnt0H$K#QJGHr37%4* z>1GHo8iRLa3Wr0I_5^XCzwT|?$(w7S@J>5qp$cn8oSl_UE2(uB1#WOBgjs0vW> z<@R@{KqPVslgcaY=VjdY!Zu-%6bgktYt+Ux9yUjx7GBDLaxO9MoFGId#B$(oI}p8& zK~uzIO*MGtR2YH;(yyJOwgM+@eeN5)+hI9by2oJPSTi)>oIxBF`#8>i%JZ-Dt{!mu zt$}^0v3T?m_?MUmQD>O*0wWUhzBTvL1Ia&PHD5b<{S#ns{coraci8TO#0Bd~42TE_o$J@s?gQ9p`O!!s!60+FVNa8z^`Jv%_%a{NZuj`>uX zb3%77;oB3({fTRm_m1gGK>jM6Ave@yU|C0^AUYiSR*5UL>{`5N+=Bb8o--Jz|nC+$K-BKyJ zBV<2Ul44X1fn5wuG2cKB6C8~dS^&5Y>v4+ml2HgdTpZRox6SeX@;ZncYTLf2Uru0- zN8`;%F5;_zJ48E8xnr7DAy3gHbEEH?CqRZ&^CGltARz{xQ&VyAxWrfg4X<#f#1H%| zL^C6DD2{@X5|t?SII2fH8=OX+svW>kl-paJFT=cPk{j#=?fB4Qy5;3s#S(}7IV~mn zTpnfl(&Xw?rFl&tJRrV7{BnRZF20Or+TDIV&6N#~?e?+#e7O#0Pm@yM418lqP5C3C z#gkA>8aEY_x@%WjR*%(_{sB5Fhn+pBQkL$bLYz+W6r6A&7NiHE-^H|~Qv=qq?Kv($ zeaHt{Zr(N^ou)sRe3X6EjXj7s4s|Ea`JUR$0!yaj9^q|v-uzqDA2GrrL^w)Z>g(b2 zya}i6c)4n>xK96hgIwgpB<2OIjk z1vTA_a#>>TtwdCnzs3xfUe%lM=gZgUpBP`?^N*tY;|Y8dm-`zRm-}kr2%qA^9GMKZ z3RLHw1mG6D&a>cnIY`}o+=jq&^?9hQ2zZSH;(#R4x}cs{K*y+uMc z7z0N_GWfcv8+3pK*g!#;GdoCp zmv&-|bhpkH`NV6PWdjmb{zvqg`YZmCSVG}Aq(jsRIBe4N3~CZth8^C>h=TUd=ffGv zR$4`P-)?^spC4#alzg`wTRt8_zhvg)vzw&8k0z(Fab6QOpLRM(WT(1!M?8rXDXgX& z=#MxS)&-}LPdIY&s+W5ul~l_uq~^nXGESN*oFX_bLyQ+JOQmjtA4RwF`+Ppq^L{Jd zx7Wl})riWM!^EFXk*r+$*tIKqC37y4ajtSMx;ww+A)MU~PAjzP>f?@$m`Ip$-nETX zvuL(#bafiPw!*YKv#DIc6eTsGGes|=gvg{Fpz@6wS&^(>s zUIAF_4rwW&jEVI{^@X2vN;8Ksitw^yXLD-pn3RmdeT|Qj+l1fU?q8<{cnv8HvYABc z#Yx`L14fK*Nur1<*7eQe$}hy|PKdX@rqpEVyq%wkY2`kiqB(2zNs^}l8|t42myhsqWBUzM$XwhWSn(2`NO&R z^{C#k0bX8NM@-@F6?Th#CJ8+U)S;wRJQLKY&(iI3?#bp@lf`@gR(?Ir_--HLGrUW_ z;c2n{d&z(J(exQk3qM#$=m-AP`q)7O8y!8jwb8(iAa_AJqZCjPGtd&@7I)&{bi?&W z5ms>5Do_hb$QODFCpQ>eokwbr!1WN|`;yOYaEm=}I_YlUt@l1~wpraZ?u6g&%;v{X zmqU<1i|29iD?7!NWnJMpeR8tYFwm$qqek3LwPR2b-Wb(c@m9| zb@+S?flJy3gTpcSaCOe&@ijS^$Xr$WGi*0`Ik<4-pD%|9noFgcE3`k_Q4&Ark#Mn)=P$Tx_T zg>~)s3l+|F{bpnB?Tccr{F>DD|~>CJNT7-qI3EQ>emK^ zf*@-$)UNP~!QtBtV}=8@i-5Fy12{)YVls%GDr=r0)d&DmL<~yriP=RX z8E~pqsYnt?t22z>D+sCRSV$(~0G25jkS<>TGv>=g*o!F42jM`*j>-xwsBj2BLOV+A z{ZOYSC%74D@)js%X-J(Xz!u=i<=P7rApLX91z7EqZvA;i)#t76Iv(A{bF1M4E?)PX z=U10+@V6+c4;HUA{Qy}%=@&J$z2>QxA&4x4Ad-2THIm)9-uz-mYv;oQ5>;{kwiK@` zVq~}Q&YT{_6`^EXiXKG<_I|%=AFc@wkNf~+^K+_9FD~Tqm%+?+p5aPo?VnG??hFDv z`CZJ*?Z;akhdC>ICC@spL^cb<%O8w13=u7(z1n zxiSgZrow~Z3HgD63XPPIIRXx#ey_VAHO`@$_C9&I5pR*Y6?C#~75lC_dv;9rHPQ2J z9pR&d?^)x<FId$Cwa@b6YFHzEh?qZ_#4XIG|=on zNT(eC-(|S}!%3taKl+cD#E@(5;FwbaKxm^lc*H#Zy`RQSZvX?hvLXZOeQdY)^t2#} zCL_rl(=T;y*ovdJ*|EBt&FFlP;U9fE*t|pi*9D+zQD7=lSx`Gtw!w)MyoWuPENqC# zvtjIUWH8Al3r3*{iN!mhmGyfM-RYS9XUB9Y2I_34(I(EOpidK zHP-3n*raC7>-|e641F}VB8x#HeVUBll=^BwSg}iv9sDxsnc4VUb1kWHf#dew%$?BA7p<;*<85GGd z&LNip(R28`=%;0OX8bLXyW)n^q5%Pfb~f(i4#{GILJY>J>mm?$4-c4w zqZ2;U&j|wEf63qY3~bD7ki5K*j!q87`qq$cnVTBcwphamUsJja+mr>5TT@q4U4{Gr z;?Y*a@s?sTin+AmQ10^JimrgpfQeskKk&MQl)JPOK@vJB`PTZ@L<84!2hCvNXe@$k zGO?KhF@!HNbV3PvI$%*L1)`-X1%e|uJ6ZGEZorDV7luJtYx6+wUK{*y(0evCnHDhP z((WO+@>;yV0^KV?+JT+^h{Xv@a;3dHyn2a0RBgbJGd@;TY?x8P@TX8T!3JRMFAK|& zHtv;ps90N^w$$STapoSt_|(+kSoUGyB*LCx#jsy=Sa+BbnMBhF0zn=3@K>XrQlPP3 zBNYkYcC`v>s0qQ0AQ|`*a`4~?qP-7xbT>3qNWZ^Md-i~KUD2K#zO0Jw z(a4Eg6J2wvo3MA@{&Xmuk#y9e8vu&`%rONhmN}hU$8LVs?CAp-{V**H9CSUccfE)~ z-OMSe=k1$pUb7ruU)x~8N*9yP^?TxZmy=RFV7I_9iM=S*9%spUeoGH}1BA}h_7oPU zgL?-(wH#B>E%+o~drM~B^{~FZq7He}{Af|aGrPBuI2&2iRH?%{S@m%5m@1tNQoLom zWz)C|f?xDddXa|zw&lFMi~Ky}Sai}LWU!)S(n?3yfZtS(#n#v3%R-@})TUUOhw7ZQ zJMnmD67%u>Xx$?^h4Rh?X-Vv{X5E1yCmLV}3?K*xAX7D^CBos=4Vd4S2)rX~=Y?Lg zxMlj(o^|JxZS&dnb!wG@1D}gnt?lg+)N8#_I=e?*k*!-F(MAukzMnC=Kt2@cZ2r2K z7q*riwzk!A6Xp|q1P=kc{xdrL5c;<6*(*ypi>Po{glWOWyV z@%X4@>+)9C;^+Aedwx&1$&DSh(e?tphW^HZAEh$L?K>g_>s;^BN*V+C^j>OA35lW0 zhJC?U08e1CzM*&Rh?@^6iKqQ7tJS#^dLYKxu_wQRSu9@3u|x#pw*A?-G_2W-;-T}+ zN2I3(>5ciBqgiYx4#I#bIOM>$rtu%gWuR6&2uGWJ8Z8-jY9a+LbtZm4h10F^y(-z z`VCXDjjnk~OEa_tQYeOYbjIFMcnSJn(1-D%JY{<>l8CQ4tbYrNs8r%)Fi^0k%l3VP zb^3_Pws_k#*sKp4j|^@i6|6veYtiCsG&~umB0oDe{F=JBWL{gIAF2*zY zd_^36ENWrW6moD075k#dkUXE!0=;INFcz-J4c;X8yyR>1XOUO?AWd4~2yT{%*+cXl z(u&WP^vRIa50%`d2t@o#eAIQSvrctV$_?4dz#ry*tyRzJca+AO!Q7JDmLkv0mIIoE z+YZqT7VroY|G?w-kSEzJm;xPA{qnoT-^Y0Q60k<@P-C_B)S_Jvd3|DQ^{9$}eNP)! zOKm>(&Ng>sc_<1}bLonQgR205aBJUzkTO)-kdL-DmQ!;x%I@vzr*G&c6y?RT`tUKYedC!B6#T(T+UxT-e-6xal zHfWXepzf^km2+FyL((jv+V=R#{FFsV>}^9z^mwxtb4tS3C4UHqGYj4Vv7|F(Nxs;}Cti=lci zt1cMc>6Jej!=u|>v>M`L#XlJRP0-72#?XXOe-Lwu{qW8iFA6U-(vZMpO3RktLsYLk z-0+;%4zG{5H-TZAqqj_J2w3e2LiYa&ieZiC7%W80lQO?f zO_Ad8x9x9qigzDx+~AhfP|0gFzFK3z5}V)0$*j@a)4B9i zamiqPrqZQ&7q9N5?U=z}uI-eLY;la~c_wb%>3D|Mt4XsK9ycv2TEc0@`u3Q`+wCd@ zOm5Rb(A5?yUse`(&SvfDs&E(e@!@j$`{c57nr;paAIjoZ&Hec6UoCHAxMB$rMILzYvNh{!g6P#CT2KjQb#}!F#CV0NA%272a)ylY)qi1Gtrz51wg$q zBg&fB0?#8IQN)x*^t8wG94d@dV&J&%~Ql4qhCY^LBSoj_NYnW`QS|cYe*@Im9&p5m-XU;GyaIeg6i_vA6CV9$Sgh zl-$BcnGPTT>F?D#k~S{#I6C!;lXSBhJcdzc3$wi<_Mv)-k@ODJT+FMiN4JsMOS|2{ z69^}LLlTZ;QHO_Ri25jG(3QNQ)x2Hds14&51_P-NR9k?e_kXI%Ev2@*!{lw1bc_N4 zLKzgmEZFh(2Owbfw9_$g1VKvzj0~HQVeiUnl6$)}Xtpq~cs8o4E(p5gicNl|uyh*X zCd=W9jb__}9M#nAN~rfy9Sh;2z$*H(=b#$#jjLOyk9>H30Q^6FTxmEI3Kv!qMY78kjV)P*F$l#>XvW248~fOX$aH0_4THg*vR@@h8T(jA z_K_tLqFa_4``RFe?90d!xznHTxj*jn{XFN#Ip=xaKkqrudtTo*%AWG)g1)GPeKjGO zTp0rZJ3vcYECYn$=@KsuN)zQn$O3m#Fh-e%D|3#v$urWaS?qS&g#z9DT|C(QdfH;T z%j50RnD^y^oz5>Gzu>0Ij>cRlDO_R7y|?%{LT#@Bsw{1`f~BClw{Tb}R=elz_{M^#MP+?EA_AuK1w6&Hcg>Ogs7mccd2@S}N; zD~m3>Ar`OkgCck*iM*y0M4W6ArXqch(sQx;RlGU8V^zYyMaWaXkJ)T5(gAXBLd!Bw z#wDCFPb9Eh+h*Dg`q^PNBqRNJAF%^;+Xsn`Kam|(RnAY2eY^pJ(%RvHPL*XeEccQm z0){9~jv(R{%lm5(S7=_JPr142y)N6CbS-4Vvfo9_>dPo!r?iC@AHwww)F$#AOWAke zX<3TP5s9nT7Pv%TrBKps_w^9|FUD6&MMm0&IPMi+Hcv%bc5=!M=h&qjr|(BCTtA39 z?!IV{#SnY)8-4(-F~lP-X?3S*E&3@vn6KOoaD@CWFJCiv(=jgTtd!%o>*l4Tg+b^C zwY_5r>1*#QVv&)%GfX2Km!aoTa;3$dt*!6ZS;#s(xoST48>Q!(&})fuPh>^*1PCKMjZ#<&K%m zz+j)2Vx>M#gr2br-_X}dgziQM{>;dbA8gKNc&>z@^w@~5bFL-_A99Hg);Zs``#GXA zf54-f^DY-NGBVDaa38o>A+6Ml8JQVkn##$Q6@9bQ=9_JbF2Jvochkl?O0W|&oVVGP zx_9L^cKZw7&${>wH+viQz_oq=zct8aVqEJas_HU zV&xiDx5nse*S-`r!la!?8FO{Xc*5mF3*$GRG$0lN(q1APG!GNX%63`?i7RkQAeOK# zUfZw7_7VhmZFiUFtugiYF}z1@{USv={5+qbD)&PpAuPlrDw*u?$8R@HY3o_eNY(l+Vmmorsm^Zsxe(Az|@qer5yY z%yA>IW{>H(CC5i{>;ucC7BWN8qM2t(!K@;LpeY+?q39UJ8ooFV+V$ZW|-p`zVJG_{(eJTqASiWm^PeF?t;4)+i>^dg#r;%hOcz24VxbfmY)bC+(A5E}CEC_} z=u?&WUg@3H+t6Qx~3c_&H)tnz9rF>3s>u!j~v;3RXzk_8_Vx1<# z`;(%raX}X{oBNZf69;IGF>f1C2~&#+@B_V@$>1C+NU$6)av}x!i~IlllD?pQ)#e&O zgnxUL_kQ!oJM+!<**zvcN{t1_&%`m*_Q{1#*wNe^w&l*j$laOQ+3&ip)kekUX68Ct z8G*4HGgZ}{Evb853Wkzj&qs_;OO8ByBb>eL#nUw|AA9ckZ1xT>O3sGNTQ-v4y0GBc z3~d5dj>CBCTX27^Tb3e&TpJ+0qB+|E1PBR{qx>n68?SjSLd#VWII{hUXnV+htD@`t ze^SbSAIOjxyeB{n%;JnzSZokL2h7qPTAfuj_VvO7)YN_{Jz3HJ;hpwYo?ibWnd)jR zBQ!ez3ZMp12Y><2zv|rf3}Gcezk09||GwVkek>pejr%zy5=llH{F_dS48L{IBAShO zp&bMVC8#BN7{L0!I|?ARqcLg2q+9CR@eVzuE6{O`M;yxTXS(ez8@206HZRf6^Y~8( zLS`O@^J_hLL6kOmi|Q32GNE0(B~Sx-B(XAkQiT%kG@2!smXnzO{`7VE^ Date: Sun, 27 Feb 2022 09:40:54 -0500 Subject: [PATCH 328/432] Fix stack_frame_pointer during function call --- src/code_gen/ccil_mips_gen.py | 124 +++++++++++++--------------------- 1 file changed, 47 insertions(+), 77 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index ff363cbf7..901221d90 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -81,16 +81,14 @@ def visit(self, node: ccil_ast.CCILProgram): # TODO: other .data section static data inicializations like strings functions = [] - # functions.extend(self.visit(node.entry_func)) - functions.extend( - [self.visit(func) for func in node.code_section if func.id == "main"][0] - ) + + print(node.entry_func) + functions.extend(self.visit(node.entry_func)) for classx in node.types_section: functions.extend(self.visit(classx.init_operations)) for func in node.code_section: - if func.id != "main": - functions.extend(self.visit(func)) + functions.extend(self.visit(func)) return mips_ast.MIPSProgram( None, @@ -104,100 +102,64 @@ def visit(self, node: ccil_ast.FunctionNode): instructions = [] instructions.append(mips_ast.LabelDeclaration(node, node.id)) - frame_size = (len(node.locals)) * DOUBLE_WORD + 2 * DOUBLE_WORD + frame_size = len(node.locals) * DOUBLE_WORD stack_pointer = mips_ast.RegisterNode(node, SP) return_address = mips_ast.RegisterNode(node, RA) frame_pointer = mips_ast.RegisterNode(node, FP) - index = 0 - for param in reversed(node.locals): - self.set_relative_location( - param.id, - mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, -1 * index), frame_pointer - ), - ) - index += DOUBLE_WORD - index = DOUBLE_WORD - for local in node.params: + for index, local in enumerate(node.locals): self.set_relative_location( local.id, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, index), frame_pointer + node, + mips_ast.Constant( + node, -1 * (len(node.locals) + 2 - index) * DOUBLE_WORD + ), + frame_pointer, ), ) - index += DOUBLE_WORD - - instructions.append( - mips_ast.Subu( - node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) - ) - ) - instructions.append( - mips_ast.StoreWord( - node, - return_address, + for index, param in enumerate(node.params): + self.set_relative_location( + param.id, mips_ast.MemoryIndexNode( node, - mips_ast.Constant(node, frame_size - DOUBLE_WORD), - stack_pointer, + mips_ast.Constant( + node, ((len(node.params) - 1) - index) * DOUBLE_WORD + ), + frame_pointer, ), ) - ) + + instructions.extend(self.push_stack(node, return_address)) + instructions.extend(self.push_stack(node, frame_pointer)) instructions.append( - mips_ast.StoreWord( - node, - frame_pointer, - mips_ast.MemoryIndexNode( - node, - mips_ast.Constant(node, frame_size - 2 * DOUBLE_WORD), - stack_pointer, - ), + mips_ast.Addi( + node, frame_pointer, stack_pointer, mips_ast.Constant(node, 16) ) ) instructions.append( - mips_ast.Addu( + mips_ast.Addi( node, - frame_pointer, stack_pointer, - mips_ast.Constant(node, frame_size - DOUBLE_WORD), + stack_pointer, + mips_ast.Constant(node, -1 * frame_size), ) ) for op in node.operations: instructions.extend(self.visit(op)) - ret_location = self.get_relative_location(node.ret) ret_register = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.LoadWord(node, ret_register, ret_location)) instructions.append( - mips_ast.LoadWord( - node, - return_address, - mips_ast.MemoryIndexNode( - node, - mips_ast.Constant(node, frame_size - DOUBLE_WORD), - stack_pointer, - ), - ) - ) - instructions.append( - mips_ast.LoadWord( - node, - frame_pointer, - mips_ast.MemoryIndexNode( - node, - mips_ast.Constant(node, frame_size - 2 * DOUBLE_WORD), - stack_pointer, - ), - ) - ) - instructions.append( - mips_ast.Addu( + mips_ast.Addi( node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) ) ) + instructions.extend(self.pop_stack(node, frame_pointer)) + instructions.extend(self.pop_stack(node, return_address)) + if node.id == "main": instructions.append( mips_ast.LoadImmediate( @@ -250,7 +212,7 @@ def visit(self, node: ccil_ast.CallOpNode): node, stack_pointer, stack_pointer, - mips_ast.Constant(node, len(node.args) * WORD), + mips_ast.Constant(node, len(node.args) * DOUBLE_WORD), ) ) return instructions @@ -260,10 +222,18 @@ def visit(self, node: ccil_ast.VCallOpNode): instructions = [] obj_location = self.get_relative_location(node.args[0].value) - obj_type = mips_ast.RegisterNode(node, T0) - instructions.append(mips_ast.LoadWord(node, obj_type, obj_location)) + reg_obj = mips_ast.RegisterNode(node, T0) + instructions.append(mips_ast.LoadWord(node, reg_obj, obj_location)) - register_function = mips_ast.RegisterNode(node, T1) + obj_type = mips_ast.RegisterNode(node, T1) + instructions.append( + mips_ast.LoadWord( + node, + obj_type, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), reg_obj), + ) + ) + register_function = mips_ast.RegisterNode(node, T2) function_index = self.get_method_index(node.type, node.id) instructions.append( mips_ast.LoadWord( @@ -274,8 +244,7 @@ def visit(self, node: ccil_ast.VCallOpNode): ), ) ) - reg_arg = mips_ast.RegisterNode(node, T2) - instructions = [] + reg_arg = mips_ast.RegisterNode(node, T3) for arg in node.args: instructions.append( mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg.value)) @@ -839,7 +808,6 @@ def get_attr_index(self, typex: str, attr: str): def get_attr_count(self, typex: str): for _type in self.__types_table: if _type.id == typex: - print(_type.attributes) return len(_type.attributes) raise Exception("Type declaration not found") @@ -850,12 +818,14 @@ def get_init_function(self, typex: str): raise Exception("Type's function for inicialization not found") def get_method_index(self, typex: str, method: str) -> int: + for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: return index * WORD + DOUBLE_WORD - raise Exception("Method implementation not found") + + raise Exception(f"Method implementation not found:{typex} {method}") def get_class_method(self, typex: str, method: str) -> str: for _type in self.__types_table: @@ -863,7 +833,7 @@ def get_class_method(self, typex: str, method: str) -> str: for _method in _type.methods: if _method.id == method: return _method.function.id - raise Exception("Method implementation not found") + raise Exception(f"Method implementation not found") def get_relative_location(self, id: str): return self.__location[self.__current_function.id, id] From 7f7d3e579cae8bf5d42008174424cf3e7fa33485 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 10:28:56 -0500 Subject: [PATCH 329/432] Add strings to .data section --- src/asts/ccil_ast.py | 2 +- src/asts/mips_ast.py | 16 +++++++++++++--- src/code_gen/ccil_mips_gen.py | 30 ++++++++++++++++++++++++++---- src/code_gen/mips_gen.py | 7 ++++++- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 6e0904424..96e31b205 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -12,7 +12,7 @@ class CCILProgram: entry_func: FunctionNode types_section: List[Class] code_section: List[FunctionNode] - data_section: List[str] # no idea what will be this the node, + data_section: List[Data] def __str__(self, all=False) -> str: types_section = self.types_section diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index 3d2e25f0f..af32fc0a3 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -127,6 +127,7 @@ class MoveFromLo(InstructionNode): """ This node represents `mflo` instruction in MIPS """ + def __init__(self, node, register) -> None: super().__init__(node) self.register = register @@ -267,13 +268,13 @@ def __init__(self, node, left, right) -> None: super().__init__(node, left, right) -class LoadAddress(BinaryNode): +class LoadAddress(BinaryOpNode): """ This node represents `la` instruction in MIPS """ - def __init__(self, left, right): - super().__init__(left, right) + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) class StoreWord(BinaryOpNode): @@ -350,6 +351,15 @@ def __init__(self, node, list) -> None: super().__init__(node, list) +class AsciizDirective(AssemblerDirective): + """ + This node represents `.asciiz` assembler directive + """ + + def __init__(self, node, list) -> None: + super().__init__(node, list) + + class Syscall(InstructionNode): """ This node represents `syscall` instruction in MIPS diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 901221d90..b6aaafc90 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -63,6 +63,8 @@ def visit(self, node): @visitor.when(ccil_ast.CCILProgram) def visit(self, node: ccil_ast.CCILProgram): self.__types_table = node.types_section + + data = [] types_table = [] for classx in node.types_section: word_directive = [ @@ -77,11 +79,16 @@ def visit(self, node: ccil_ast.CCILProgram): mips_ast.WordDirective(node, word_directive), ) ) - - # TODO: other .data section static data inicializations like strings + data.extend(types_table) + for d in node.data_section: + data.append( + ( + mips_ast.LabelDeclaration(node, d.id), + mips_ast.AsciizDirective(node, [mips_ast.Label(node, d.value)]), + ) + ) functions = [] - print(node.entry_func) functions.extend(self.visit(node.entry_func)) @@ -93,7 +100,7 @@ def visit(self, node: ccil_ast.CCILProgram): return mips_ast.MIPSProgram( None, mips_ast.TextNode(node, functions), - mips_ast.DataNode(node, types_table), + mips_ast.DataNode(node, data), ) @visitor.when(ccil_ast.FunctionNode) @@ -709,6 +716,11 @@ def visit(self, node: ccil_ast.NegOpNode): @visitor.when(ccil_ast.LoadOpNode) def visit(self, node: ccil_ast.LoadOpNode): instructions = [] + instructions.append( + mips_ast.LoadAddress( + node, mips_ast.RegisterNode(node, V0), mips_ast.Label(node, node.target) + ) + ) return instructions @@ -797,6 +809,16 @@ def visit(self, node: ccil_ast.ReadIntNode): ) return instructions + @visitor.when(ccil_ast.Abort) + def visit(self, node: ccil_ast.Abort): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 10) + ) + ) + return instructions + def get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index dca6ce983..132cc67ad 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -2,6 +2,7 @@ Add, Addi, Addu, + AsciizDirective, BranchOnEqual, BranchOnNotEqual, Constant, @@ -50,7 +51,7 @@ def visit(self, node): @visitor.when(MIPSProgram) def visit(self, node: MIPSProgram) -> str: - global_main = "\t.globl entry" + global_main = "\t.globl main" text_section = "\t.text\n" + self.visit(node.text_section) data_section = "\t.data\n" + self.visit(node.data_section) return f"{global_main}\n{text_section}\n{data_section}" @@ -102,6 +103,10 @@ def visit(self, node: MemoryIndexNode) -> str: def visit(self, node: WordDirective) -> str: return ".word " + (" ".join(self.visit(i) for i in node.list)) + @visitor.when(AsciizDirective) + def visit(self, node: AsciizDirective) -> str: + return ".asciiz " + (" ".join(f'"{self.visit(i)}"' for i in node.list)) + @visitor.when(Move) def visit(self, node: Move) -> str: return f"\tmove {self.visit(node.left)}, {self.visit(node.right)}" From 3e15d2e929c6922428757b099474920411e8bb8f Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 11:20:30 -0500 Subject: [PATCH 330/432] Fix BranchOnEqual generation to mips code --- src/code_gen/mips_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 132cc67ad..c73a7281e 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -163,7 +163,7 @@ def visit(self, node: Div) -> str: def visit(self, node: BranchOnEqual) -> str: return f"\tbeq {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" - @visitor.when(BranchOnEqual) + @visitor.when(BranchOnNotEqual) def visit(self, node: BranchOnNotEqual) -> str: return f"\tbne {self.visit(node.left)}, {self.visit(node.middle)}, {self.visit(node.right)}" From 511278bb11a7067dfee04cd8a75c59800316900a Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 11:22:06 -0500 Subject: [PATCH 331/432] Small change in register notation --- src/code_gen/ccil_mips_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index b6aaafc90..a2ae3269d 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -736,13 +736,13 @@ def visit(self, node: ccil_ast.IfFalseNode): ) instructions.append( mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, 9), mips_ast.Constant(node, 0) + node, mips_ast.RegisterNode(node, T1), mips_ast.Constant(node, 0) ) ) instructions.append( mips_ast.BranchOnEqual( node, - mips_ast.RegisterNode(node, 9), + mips_ast.RegisterNode(node, T1), mips_ast.RegisterNode(node, T0), mips_ast.Label(node, node.target.id), ) From 761e57b4277daa1d176a1f6b353598cf1d9500a8 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 11:46:55 -0500 Subject: [PATCH 332/432] Add IdNode visitor --- src/code_gen/ccil_mips_gen.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index a2ae3269d..e3a788808 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -189,6 +189,18 @@ def visit(self, node: ccil_ast.StorageNode): ) return instructions + @visitor.when(ccil_ast.IdNode) + def visit(self, node: ccil_ast.IdNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, V0), + self.get_relative_location(node.value), + ) + ) + return instructions + @visitor.when(ccil_ast.IntNode) def visit(self, node: ccil_ast.IntNode): instructions = [] From 2b43117f58e2d65913da0599f1d2df0c750e0f78 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 12:09:19 -0500 Subject: [PATCH 333/432] Add test let_instantiate.cl --- src/debbuging/tests_ccil/let_instantiate.cl | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/debbuging/tests_ccil/let_instantiate.cl diff --git a/src/debbuging/tests_ccil/let_instantiate.cl b/src/debbuging/tests_ccil/let_instantiate.cl new file mode 100644 index 000000000..8a3241bd1 --- /dev/null +++ b/src/debbuging/tests_ccil/let_instantiate.cl @@ -0,0 +1,22 @@ + class Main inherits IO { + main() : Main { + let a : A <- new A, b : B, c : Int <- 12 in + { + b <- a.f(); + c <- b.f(1,2); + out_int(c); + } + }; + }; + +class A { + f() : B { + new B + }; +}; + +class B { + f(a : Int, b : Int) : Int { + a + b + }; +}; From c11dfc96d6627915421d117292944b6ff2dc6fbf Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 13:39:13 -0500 Subject: [PATCH 334/432] Add ply to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 9eb0cad1a..cba16ee2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest pytest-ordering +ply From 1203bcede0bf4e0f1b617b32c26a788f63348087 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 14:07:23 -0500 Subject: [PATCH 335/432] Swap SELF_TYPE type to current type in classes atributes --- src/asts/ccil_ast.py | 4 ++-- src/code_gen/ccil_gen.py | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 96e31b205..1914cc966 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -12,7 +12,7 @@ class CCILProgram: entry_func: FunctionNode types_section: List[Class] code_section: List[FunctionNode] - data_section: List[Data] + data_section: List[Data] def __str__(self, all=False) -> str: types_section = self.types_section @@ -28,7 +28,7 @@ def __str__(self, all=False) -> str: return f"TYPES:\n{types}\nDATA:\n{data}\nCODE:\n{code} " -@dataclass(frozen=True) +@dataclass(frozen=False) class Class: """ This item represent the .type section in ccil diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 8738c7acb..87ecf34dc 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -79,9 +79,11 @@ def visit(self, node: sem_ast.ProgramNode) -> None: self.program_types[classx.id] = classx self.program_codes += class_code + program_types = update_self_type_attr(self.program_types.values()) + return CCILProgram( self.define_entry_func(), - list(self.program_types.values()), + program_types, self.program_codes, self.data, ) @@ -1000,7 +1002,7 @@ def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") def get_inherited_features( - self, node: sem_ast.ClassDeclarationNode#, node_methods: List[Method] + self, node: sem_ast.ClassDeclarationNode # , node_methods: List[Method] ): # node_methods: Set[str] = {m.id for m in node_methods} @@ -1026,3 +1028,15 @@ def make_unique_func_id(method_name: str, class_name: str): def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: return list(map(lambda x: const(*x), dict.items())) + + +def update_self_type_attr(classes: List[Class]): + for classx in classes: + classx.attributes = list( + map( + lambda attr: attr + if attr.type != SELFTYPE + else Attribute(attr.id, classx.id), + classx.attributes + ) + ) From a7b24487d7709ef60fd74f9ae04036c484f2d043 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 14:38:03 -0500 Subject: [PATCH 336/432] Override methods keep same location but change unique ids --- src/code_gen/ccil_gen.py | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 87ecf34dc..5684506f3 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -93,7 +93,8 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.current_type = node.id self.add_data(f"class_{node.id}", node.id) - attributes, methods = self.get_inherited_features(node) + attributes: List[Attribute] = [] + methods: List[Method] = [] attr_nodes = [] func_nodes = [] @@ -118,7 +119,19 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: class_code.append(f) methods.append(Method(func.id, f)) - return (Class(node.id, attributes, methods, init_func), class_code) + methods, inherited_methods, inherited_attrs = self.get_inherited_features( + node, methods + ) + + return ( + Class( + node.id, + inherited_attrs + attributes, + inherited_methods + methods, + init_func, + ), + class_code, + ) @visitor.when(sem_ast.AttrDeclarationNode) def visit(self, node: sem_ast.AttrDeclarationNode) -> ATTR_VISITOR_RESULT: @@ -1002,18 +1015,36 @@ def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") def get_inherited_features( - self, node: sem_ast.ClassDeclarationNode # , node_methods: List[Method] + self, node: sem_ast.ClassDeclarationNode, defined_methods: List[Method] ): - # node_methods: Set[str] = {m.id for m in node_methods} + defined_methods: Dict[str, Method] = OrderedDict( + (m.id, m) for m in defined_methods + ) + new_defined_methods: List[Method] = [] inherited_attr: List[Attribute] = [] inherited_methods: List[Method] = [] + if node.parent is not None: parent_class: Class = self.program_types[node.parent] + inherited_attr = [a for a in parent_class.attributes] - inherited_methods = [m for m in parent_class.methods] - return inherited_attr, inherited_methods + for method in parent_class.methods: + try: + # Method override for an inherited method + override_method = defined_methods[method.id] + except KeyError: + pass + else: + method = Method(method.id, override_method.function) + del defined_methods[method.id] + + inherited_methods.append(method) + + new_defined_methods = list(defined_methods.values()) + + return new_defined_methods, inherited_attr, inherited_methods def find_function_id(self, class_name: str, method_name: str): for method in self.program_types[class_name].methods: @@ -1037,6 +1068,6 @@ def update_self_type_attr(classes: List[Class]): lambda attr: attr if attr.type != SELFTYPE else Attribute(attr.id, classx.id), - classx.attributes + classx.attributes, ) ) From 41072a1cc995014b71164cc689ca223222362ca4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 14:46:39 -0500 Subject: [PATCH 337/432] Fix naming bugs --- src/code_gen/ccil_gen.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5684506f3..91bc250d4 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -266,7 +266,7 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: else_label = LabelNode(label_id) if_false = IfFalseNode(extract_id(if_fval), else_label) - endif_label = LabelNode("endIf") + endif_label = LabelNode(f"endIf_{times}") goto_endif = GoToNode(endif_label) # Setting the final operation which will simbolize the return value of this expr @@ -385,13 +385,13 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: # Setting control flow labels loop_label_id = f"loop_{times}" - loop_label = LabelNode(node, loop_label_id) + loop_label = LabelNode(loop_label_id) end_loop_label_id = f"endLoop_{times}" - end_loop_label = LabelNode(node, end_loop_label_id) + end_loop_label = LabelNode(end_loop_label_id) # Setting control flow instructions ifFalse & GoTo - if_false = IfFalseNode(node, cond_fval, end_loop_label) - go_to = GoToNode(node, loop_label) + if_false = IfFalseNode(cond_fval, end_loop_label) + go_to = GoToNode(loop_label) fval = self.create_uninitialized_storage(f"loop_{times}_fv", VOID) # Loop Nodes have void return type, how to express it?? @@ -558,9 +558,9 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: error_ops = [] if node.expr.type.name not in {INT, STRING, BOOL}: expr_fval_is_void = self.create_equality( - "expr_is_void", extract_id(expr_fval), IntNode("0") + f"expr_is_void_{times}", extract_id(expr_fval), IntNode("0") ) - ok_label = LabelNode(f"expr_is_not_void") + ok_label = LabelNode(f"expr_is_not_void_{times}") if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) error_msg = self.add_data( "caller_void_err", From da78cf063925363155e38cb59ea726d6e9fc1f3f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 14:56:56 -0500 Subject: [PATCH 338/432] Fix naming issues + other bugs --- src/code_gen/ccil_gen.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 91bc250d4..5b04fe494 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -563,10 +563,12 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: ok_label = LabelNode(f"expr_is_not_void_{times}") if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) error_msg = self.add_data( - "caller_void_err", + f"caller_void_err_{times}", f"RuntimeError: expresion in {node.line}, {node.col} is void", ) - load_err = self.create_string_load_data("caller_void_err_var", error_msg.id) + load_err = self.create_string_load_data( + f"caller_void_err_var_{times}", error_msg.id + ) print_and_abort = self.notifiy_and_abort(load_err.id) error_ops = [ expr_fval_is_void, @@ -1043,8 +1045,7 @@ def get_inherited_features( inherited_methods.append(method) new_defined_methods = list(defined_methods.values()) - - return new_defined_methods, inherited_attr, inherited_methods + return new_defined_methods, inherited_methods, inherited_attr def find_function_id(self, class_name: str, method_name: str): for method in self.program_types[class_name].methods: @@ -1062,6 +1063,7 @@ def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: def update_self_type_attr(classes: List[Class]): + new_classes:List[Class] = [] for classx in classes: classx.attributes = list( map( @@ -1071,3 +1073,5 @@ def update_self_type_attr(classes: List[Class]): classx.attributes, ) ) + new_classes.append(classx) + return new_classes From 991f9c085e7e9041f3fd378795544cb6f819e877 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 15:13:32 -0500 Subject: [PATCH 339/432] Update simple_attr.cl test --- src/asts/mips_ast.py | 9 +++++++++ src/code_gen/mips_gen.py | 5 +++++ src/debbuging/tests_ccil/simple_attr.cl | 23 +++++++++++++++-------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index af32fc0a3..fcb1e4850 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -259,6 +259,15 @@ def __init__(self, node, left, right) -> None: super().__init__(node, left, right) +class LoadByte(BinaryOpNode): + """ + This node represents `lb` instruction in MIPS + """ + + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) + + class LoadWord(BinaryOpNode): """ This node represents `lw` instruction in MIPS diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index c73a7281e..8917b1df0 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -16,6 +16,7 @@ Less, LessOrEqual, LoadAddress, + LoadByte, LoadImmediate, LoadWord, MIPSProgram, @@ -190,3 +191,7 @@ def visit(self, node: Not) -> str: @visitor.when(MoveFromLo) def visit(self, node: MoveFromLo) -> str: return f"\tmflo {self.visit(node.register)}" + + @visitor.when(LoadByte) + def visit(self, node: LoadByte) -> str: + return f"\tlb {self.visit(node.left)} {self.visit(node.right)}" diff --git a/src/debbuging/tests_ccil/simple_attr.cl b/src/debbuging/tests_ccil/simple_attr.cl index a2caaf3f0..3455135b7 100644 --- a/src/debbuging/tests_ccil/simple_attr.cl +++ b/src/debbuging/tests_ccil/simple_attr.cl @@ -1,15 +1,22 @@ - class Main { - main() : Int - { - let a : A <- new A in a.f() - }; + class Main inherits IO { + a : Int; + main(): Main { + { + a <- 12; + out_int(a); + } + }; }; class A { - - f () : Int { - 12 + f() : Int { + 1 }; }; +class B inherits A{ + f() : Int { + 2 + }; +}; From 75febaf0a91eb180f5d3d04f9458e4259ebd3b31 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 15:25:23 -0500 Subject: [PATCH 340/432] Fix, using SELF_TYPE instead of current type when setting an attribute --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5b04fe494..644431a71 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -246,7 +246,7 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: if is_attr: # Assignation occurring to an attribute Go update the attribute - set_attr = SetAttrOpNode("self", ccil_id, extract_id(expr_fval), SELFTYPE) + set_attr = SetAttrOpNode("self", ccil_id, extract_id(expr_fval), self.current_type) return [*expr_ops, set_attr], expr_fval self.update_locals(expr_fval.id, ccil_id) From e698cd91be930d9a37333e8ffb57c1c4d06bfdec Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 15:41:17 -0500 Subject: [PATCH 341/432] Add attr.cl test --- src/debbuging/tests_ccil/attr.cl | 23 +++++++++++++++++++++++ src/debbuging/tests_ccil/len.cl | 5 +++++ 2 files changed, 28 insertions(+) create mode 100644 src/debbuging/tests_ccil/attr.cl create mode 100644 src/debbuging/tests_ccil/len.cl diff --git a/src/debbuging/tests_ccil/attr.cl b/src/debbuging/tests_ccil/attr.cl new file mode 100644 index 000000000..7c294d9f8 --- /dev/null +++ b/src/debbuging/tests_ccil/attr.cl @@ -0,0 +1,23 @@ + class Main inherits IO { + a : A; + main(): Main { + { + a <- new A; + out_int(a.f()); + } + }; +}; + +class A { + a : Int; + f() : Int { + 1 + }; +}; + +class B inherits A{ + f() : Int { + { a <- 12; a; } + }; +}; + diff --git a/src/debbuging/tests_ccil/len.cl b/src/debbuging/tests_ccil/len.cl new file mode 100644 index 000000000..c2cdcf255 --- /dev/null +++ b/src/debbuging/tests_ccil/len.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : Main { + out_int(("hola").length()) + }; +}; From b5635bfbbbd1e9827b861cfab8cacc0415888053 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 16:12:57 -0500 Subject: [PATCH 342/432] Add len builtin function --- src/code_gen/ccil_mips_gen.py | 62 ++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index e3a788808..45a73c5ad 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -11,7 +11,8 @@ class CCILToMIPSGenerator: def __init__(self) -> None: - self.__types_table: List[ccil_ast.Class] = [] # list or dict for classes??? + self.__id = 0 + self.__types_table: List[ccil_ast.Class] = [] self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode @@ -560,10 +561,7 @@ def visit(self, node: ccil_ast.DivOpNode): reg_ret = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.Div(node, reg_left, reg_right)) - instructions.append( - # mips_ast.Move(node, reg_ret, mips_ast.RegisterNode(node, "lo")) - mips_ast.MoveFromLo(node, reg_ret) - ) + instructions.append(mips_ast.MoveFromLo(node, reg_ret)) return instructions @visitor.when(ccil_ast.LessOpNode) @@ -831,6 +829,56 @@ def visit(self, node: ccil_ast.Abort): ) return instructions + @visitor.when(ccil_ast.LengthOpNode) + def visit(self, node: ccil_ast.LengthOpNode): + instructions = [] + count = mips_ast.RegisterNode(node, V0) + instructions.append( + mips_ast.LoadImmediate(node, count, mips_ast.Constant(node, 0)) + ) + string = mips_ast.RegisterNode(node, T1) + instructions.append( + mips_ast.LoadAddress(node, string, self.get_relative_location(node.target)) + ) + + loop = self.generate_unique_label() + instructions.append(mips_ast.LabelDeclaration(node, loop)) + + char = mips_ast.RegisterNode(node, T2) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string), + ) + ) + zero = mips_ast.RegisterNode(node, ZERO) + exit = self.generate_unique_label() + instructions.append( + mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node,exit)) + ) + instructions.append( + mips_ast.Addi(node, string, string, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, count, count, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + instructions.append(mips_ast.LabelDeclaration(node,exit)) + return instructions + + # @visitor.when(ccil_ast.EqualStrNode) + # def visit(self, node: ccil_ast.EqualStrNode): + # pass + + # @visitor.when(ccil_ast.ConcatOpNode) + # def visit(self, node: ccil_ast.ConcatOpNode): + # pass + + # @visitor.when(ccil_ast.SubstringOpNode) + # def visit(self, node: ccil_ast.SubstringOpNode): + # pass + def get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: @@ -874,3 +922,7 @@ def get_relative_location(self, id: str): def set_relative_location(self, id: str, memory: mips_ast.MemoryIndexNode): self.__location[self.__current_function.id, id] = memory + + def generate_unique_label(self): + self.__id += 1 + return f"label_{self.__id}" From bc16d78bf51e29261d6ed52f7c229b1caff53376 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 16:12:57 -0500 Subject: [PATCH 343/432] Add length builtin function --- src/code_gen/ccil_mips_gen.py | 62 ++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index e3a788808..45a73c5ad 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -11,7 +11,8 @@ class CCILToMIPSGenerator: def __init__(self) -> None: - self.__types_table: List[ccil_ast.Class] = [] # list or dict for classes??? + self.__id = 0 + self.__types_table: List[ccil_ast.Class] = [] self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode @@ -560,10 +561,7 @@ def visit(self, node: ccil_ast.DivOpNode): reg_ret = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.Div(node, reg_left, reg_right)) - instructions.append( - # mips_ast.Move(node, reg_ret, mips_ast.RegisterNode(node, "lo")) - mips_ast.MoveFromLo(node, reg_ret) - ) + instructions.append(mips_ast.MoveFromLo(node, reg_ret)) return instructions @visitor.when(ccil_ast.LessOpNode) @@ -831,6 +829,56 @@ def visit(self, node: ccil_ast.Abort): ) return instructions + @visitor.when(ccil_ast.LengthOpNode) + def visit(self, node: ccil_ast.LengthOpNode): + instructions = [] + count = mips_ast.RegisterNode(node, V0) + instructions.append( + mips_ast.LoadImmediate(node, count, mips_ast.Constant(node, 0)) + ) + string = mips_ast.RegisterNode(node, T1) + instructions.append( + mips_ast.LoadAddress(node, string, self.get_relative_location(node.target)) + ) + + loop = self.generate_unique_label() + instructions.append(mips_ast.LabelDeclaration(node, loop)) + + char = mips_ast.RegisterNode(node, T2) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string), + ) + ) + zero = mips_ast.RegisterNode(node, ZERO) + exit = self.generate_unique_label() + instructions.append( + mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node,exit)) + ) + instructions.append( + mips_ast.Addi(node, string, string, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, count, count, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + instructions.append(mips_ast.LabelDeclaration(node,exit)) + return instructions + + # @visitor.when(ccil_ast.EqualStrNode) + # def visit(self, node: ccil_ast.EqualStrNode): + # pass + + # @visitor.when(ccil_ast.ConcatOpNode) + # def visit(self, node: ccil_ast.ConcatOpNode): + # pass + + # @visitor.when(ccil_ast.SubstringOpNode) + # def visit(self, node: ccil_ast.SubstringOpNode): + # pass + def get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: @@ -874,3 +922,7 @@ def get_relative_location(self, id: str): def set_relative_location(self, id: str, memory: mips_ast.MemoryIndexNode): self.__location[self.__current_function.id, id] = memory + + def generate_unique_label(self): + self.__id += 1 + return f"label_{self.__id}" From 92266186d8ed8614f1f501f78c1912669a017094 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 16:37:02 -0500 Subject: [PATCH 344/432] Minor bug fix, inherited attributes were not being defined in scope --- src/semantics/inference/back_inferencer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 42ce2b005..98464121a 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -60,6 +60,8 @@ def visit(self, node: ProgramNode) -> Tuple[ProgramNode, bool]: def visit(self, node: ClassDeclarationNode, scope: Scope) -> ClassDeclarationNode: self.current_type = self.context.get_type(node.id, unpacked=True) scope.define_variable("self", TypeBag({SelfType()})) + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) new_features = [] for feature in node.features: From 3205aaf575b98ee4744d90b8ab4bb359aed1408a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 16:37:27 -0500 Subject: [PATCH 345/432] Bug fix with naming from inherited attributes --- src/asts/ccil_ast.py | 3 +++ src/code_gen/ccil_gen.py | 35 ++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 1914cc966..93a6fd5f3 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -60,7 +60,10 @@ def __str__(self) -> str: return f"{self.id} : {self.type}" +@dataclass(frozen=True) class Attribute(BaseVar): + cool_id: str + def __str__(self) -> str: return "attr " + super().__str__() diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 644431a71..08e7fe4c2 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -90,17 +90,18 @@ def visit(self, node: sem_ast.ProgramNode) -> None: @visitor.when(sem_ast.ClassDeclarationNode) def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: + self.reset_scope() self.current_type = node.id self.add_data(f"class_{node.id}", node.id) - attributes: List[Attribute] = [] + attributes: List[Attribute] = self.get_inherited_attributes(node) methods: List[Method] = [] attr_nodes = [] func_nodes = [] for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): - attributes.append(Attribute(ATTR + feature.id, feature.type.name)) + attributes.append(Attribute(ATTR + feature.id, feature.type.name, feature.id)) attr_nodes.append(feature) else: func_nodes.append(feature) @@ -108,10 +109,10 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: # Create init func using attributes and their expressions init_func = self.create_class_init_func(node, attr_nodes) - # Explore all functions self.reset_scope() + # Explore all functions self.ccil_cool_names.add_new_names( - *[(n.id, a.id) for (n, a) in zip(attr_nodes, attributes)] + *[(a.cool_id, a.id) for a in attributes] ) class_code: List[FunctionNode] = [] for func in func_nodes: @@ -119,14 +120,12 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: class_code.append(f) methods.append(Method(func.id, f)) - methods, inherited_methods, inherited_attrs = self.get_inherited_features( - node, methods - ) + methods, inherited_methods = self.get_inherited_methods(node, methods) return ( Class( node.id, - inherited_attrs + attributes, + attributes, inherited_methods + methods, init_func, ), @@ -246,7 +245,9 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: if is_attr: # Assignation occurring to an attribute Go update the attribute - set_attr = SetAttrOpNode("self", ccil_id, extract_id(expr_fval), self.current_type) + set_attr = SetAttrOpNode( + "self", ccil_id, extract_id(expr_fval), self.current_type + ) return [*expr_ops, set_attr], expr_fval self.update_locals(expr_fval.id, ccil_id) @@ -1016,7 +1017,14 @@ def reset_scope(self): def add_warning(self, msg: str): self.add_warning(f"Warning: {msg}") - def get_inherited_features( + def get_inherited_attributes(self, node: sem_ast.ClassDeclarationNode): + return ( + [a for a in self.program_types[node.parent].attributes] + if node.parent is not None + else [] + ) + + def get_inherited_methods( self, node: sem_ast.ClassDeclarationNode, defined_methods: List[Method] ): defined_methods: Dict[str, Method] = OrderedDict( @@ -1024,14 +1032,11 @@ def get_inherited_features( ) new_defined_methods: List[Method] = [] - inherited_attr: List[Attribute] = [] inherited_methods: List[Method] = [] if node.parent is not None: parent_class: Class = self.program_types[node.parent] - inherited_attr = [a for a in parent_class.attributes] - for method in parent_class.methods: try: # Method override for an inherited method @@ -1045,7 +1050,7 @@ def get_inherited_features( inherited_methods.append(method) new_defined_methods = list(defined_methods.values()) - return new_defined_methods, inherited_methods, inherited_attr + return new_defined_methods, inherited_methods def find_function_id(self, class_name: str, method_name: str): for method in self.program_types[class_name].methods: @@ -1063,7 +1068,7 @@ def to_vars(dict: Dict[str, str], const: BaseVar = BaseVar) -> List[BaseVar]: def update_self_type_attr(classes: List[Class]): - new_classes:List[Class] = [] + new_classes: List[Class] = [] for classx in classes: classx.attributes = list( map( From ec1fc44360482755a4172349ebf3a36a3b7afc4a Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 16:41:13 -0500 Subject: [PATCH 346/432] Update attr.cl test --- src/debbuging/tests_ccil/attr.cl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debbuging/tests_ccil/attr.cl b/src/debbuging/tests_ccil/attr.cl index 7c294d9f8..1b14cf58b 100644 --- a/src/debbuging/tests_ccil/attr.cl +++ b/src/debbuging/tests_ccil/attr.cl @@ -2,7 +2,7 @@ a : A; main(): Main { { - a <- new A; + a <- new B; out_int(a.f()); } }; From f3e38e3c32987b4a22268862a66448e940d58d48 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 16:41:43 -0500 Subject: [PATCH 347/432] Minor change to prevent redefinition of attributes on scope --- src/semantics/inference/back_inferencer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 98464121a..2deac476e 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -76,7 +76,7 @@ def visit(self, node, scope: Scope): if not node.expr: attr_node.inferenced_type = node.inferenced_type - scope.define_variable(node.id, node.inferenced_type) + scope.get_variable(node.id).type = node.inferenced_type return attr_node expr_node = self.visit(node.expr, scope) @@ -84,7 +84,6 @@ def visit(self, node, scope: Scope): decl_type = node.inferenced_type decl_type, changed = unify(decl_type, expr_type) - scope.define_variable(node.id, decl_type) self.changed |= changed attr_node.expr = expr_node From 6d54a923fc9409541b6a27c5ad3b67634159f583 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 17:34:27 -0500 Subject: [PATCH 348/432] All string types use calls instead of vcalls --- src/code_gen/ccil_gen.py | 56 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 08e7fe4c2..4c6be116a 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -101,7 +101,9 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: func_nodes = [] for feature in node.features: if isinstance(feature, sem_ast.AttrDeclarationNode): - attributes.append(Attribute(ATTR + feature.id, feature.type.name, feature.id)) + attributes.append( + Attribute(ATTR + feature.id, feature.type.name, feature.id) + ) attr_nodes.append(feature) else: func_nodes.append(feature) @@ -111,9 +113,7 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.reset_scope() # Explore all functions - self.ccil_cool_names.add_new_names( - *[(a.cool_id, a.id) for a in attributes] - ) + self.ccil_cool_names.add_new_names(*[(a.cool_id, a.id) for a in attributes]) class_code: List[FunctionNode] = [] for func in func_nodes: f = self.visit(func) @@ -555,29 +555,35 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: (expr_ops, expr_fval) = self.visit(node.expr) + if node.caller_type.name == STRING: + fval_id = f"call_str_{times}" + call = self.create_call( + fval_id, node.type.name, node.id, STRING, [extract_id(expr_fval), *args] + ) + return [*expr_ops, *args_ops, call], call + # Runtime error depending if expr is void or not error_ops = [] - if node.expr.type.name not in {INT, STRING, BOOL}: - expr_fval_is_void = self.create_equality( - f"expr_is_void_{times}", extract_id(expr_fval), IntNode("0") - ) - ok_label = LabelNode(f"expr_is_not_void_{times}") - if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) - error_msg = self.add_data( - f"caller_void_err_{times}", - f"RuntimeError: expresion in {node.line}, {node.col} is void", - ) - load_err = self.create_string_load_data( - f"caller_void_err_var_{times}", error_msg.id - ) - print_and_abort = self.notifiy_and_abort(load_err.id) - error_ops = [ - expr_fval_is_void, - if_is_not_void, - load_err, - *print_and_abort, - ok_label, - ] + expr_fval_is_void = self.create_equality( + f"expr_is_void_{times}", extract_id(expr_fval), IntNode("0") + ) + ok_label = LabelNode(f"expr_is_not_void_{times}") + if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) + error_msg = self.add_data( + f"caller_void_err_{times}", + f"RuntimeError: expresion in {node.line}, {node.col} is void", + ) + load_err = self.create_string_load_data( + f"caller_void_err_var_{times}", error_msg.id + ) + print_and_abort = self.notifiy_and_abort(load_err.id) + error_ops = [ + expr_fval_is_void, + if_is_not_void, + load_err, + *print_and_abort, + ok_label, + ] # @type.id(arg1, arg2, ..., argn) if node.at_type is not None: From 06dfd34f6c78d9824c03537890d3aa91adab34f9 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 21:41:21 -0500 Subject: [PATCH 349/432] Fix length function --- src/code_gen/ccil_mips_gen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 45a73c5ad..dbb9815f8 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -838,7 +838,7 @@ def visit(self, node: ccil_ast.LengthOpNode): ) string = mips_ast.RegisterNode(node, T1) instructions.append( - mips_ast.LoadAddress(node, string, self.get_relative_location(node.target)) + mips_ast.LoadWord(node, string, self.get_relative_location(node.target)) ) loop = self.generate_unique_label() @@ -855,7 +855,7 @@ def visit(self, node: ccil_ast.LengthOpNode): zero = mips_ast.RegisterNode(node, ZERO) exit = self.generate_unique_label() instructions.append( - mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node,exit)) + mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node, exit)) ) instructions.append( mips_ast.Addi(node, string, string, mips_ast.Constant(node, 1)) @@ -864,7 +864,7 @@ def visit(self, node: ccil_ast.LengthOpNode): mips_ast.Addi(node, count, count, mips_ast.Constant(node, 1)) ) instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) - instructions.append(mips_ast.LabelDeclaration(node,exit)) + instructions.append(mips_ast.LabelDeclaration(node, exit)) return instructions # @visitor.when(ccil_ast.EqualStrNode) From f44d9a193f0420d0e94e7a19f863aef79886a9cb Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 22:09:59 -0500 Subject: [PATCH 350/432] Fix string in lexer --- src/lexing/lexer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index dca17f790..6da45a751 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -147,7 +147,7 @@ def t_ONELINECOMMENT(self, t): # String rules def t_string(self, t): r'"' - self._string_value = '"' + self._string_value = '' t.lexer.col += 1 self._string_value += t.value self._string_line = t.lexer.lineno @@ -165,13 +165,14 @@ def t_string_end(self, t): t.value = self._string_value + t.value t.col = self._string_col t.line = self._string_line - for index, char in enumerate(t.value[1:-1]): + for index, char in enumerate(t.value): if char == "\0": null_col = t.col + index null_line = t.line self.errors.append( LexicographicError(null_line, null_col, "NULL CHARACTER") ) + t.value = t.value[1:-2] return t def t_string_space(self, t): From 164fe6726c2ef3d95b3f98ecbe35883624914b6c Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Sun, 27 Feb 2022 22:09:59 -0500 Subject: [PATCH 351/432] Fix string in lexer --- src/lexing/lexer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lexing/lexer.py b/src/lexing/lexer.py index dca17f790..898905d16 100644 --- a/src/lexing/lexer.py +++ b/src/lexing/lexer.py @@ -147,7 +147,7 @@ def t_ONELINECOMMENT(self, t): # String rules def t_string(self, t): r'"' - self._string_value = '"' + self._string_value = '' t.lexer.col += 1 self._string_value += t.value self._string_line = t.lexer.lineno @@ -165,13 +165,14 @@ def t_string_end(self, t): t.value = self._string_value + t.value t.col = self._string_col t.line = self._string_line - for index, char in enumerate(t.value[1:-1]): + for index, char in enumerate(t.value): if char == "\0": null_col = t.col + index null_line = t.line self.errors.append( LexicographicError(null_line, null_col, "NULL CHARACTER") ) + t.value = t.value[1:-1] return t def t_string_space(self, t): From dd5e512476f588a992b3eca8f811678684cee83e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Sun, 27 Feb 2022 18:42:49 -0500 Subject: [PATCH 352/432] Improve Case Of expressions Case Expression are now sorted in the background, where the more specific one always comes first. Add for each case branch the knwoledge of which types match with them. Other chages in Context and Types Inferencer to apply the previously said. --- src/asts/types_ast.py | 2 +- src/semantics/inference/types_inferencer.py | 31 +++++++++++++++++---- src/semantics/tools/context.py | 10 +++++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index 2a6548438..c9d8afd74 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -81,7 +81,7 @@ def __init__(self, case_expr, options, node): class CaseOptionNode(ExpressionNode): - def __init__(self, ret_expr, branch_type, node): + def __init__(self, ret_expr, branch_type, ancestor_types: List[str], node): Node.__init__(self, node) self.id = node.id self.decl_type = node.decl_type diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 1d4686622..9bd1a776f 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -1,4 +1,5 @@ -from typing import List +from typing import List, Tuple +from semantics.tools.context import Context from semantics.tools.errors import InternalError from semantics.tools.type import Type, join_list from utils import visitor @@ -44,8 +45,9 @@ class TypesInferencer: - def __init__(self) -> None: + def __init__(self, context: Context) -> None: self.errors = [] + self.context = context @visitor.on("node") def visit(self, node, scope): @@ -119,19 +121,38 @@ def visit(self, node: ConditionalNode, scope: Scope) -> types_ast.ConditionalNod def visit(self, node: CaseNode, scope: Scope) -> types_ast.CaseNode: expr = self.visit(node.case_expr, scope) - case_options = [] + case_options: List[CaseOptionNode] = [] for option in node.options: child_scope = scope.create_child() case_options.append(self.visit(option, child_scope)) - new_node = types_ast.CaseNode(expr, case_options, node) + # Order case options by specificity, most common go last + new_option_order: List[Tuple[int, CaseOptionNode]] = [] + for option1 in case_options: + specificity = 0 + for option2 in case_options: + specificity += ( + 1 if option2.branch_type.conforms_to(option1.branch_type) else 0 + ) + new_option_order.append((specificity, option1)) + + new_option_order: List[CaseOptionNode] = [ + opt for (_, opt) in sorted(new_option_order, key=lambda x: x[0]) + ] + + new_node = types_ast.CaseNode(expr, new_option_order, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node @visitor.when(CaseOptionNode) def visit(self, node: CaseOptionNode, scope: Scope) -> types_ast.CaseOptionNode: + ancestor_types: List[str] = self.context.get_successors(node.branch_type.name) + return types_ast.CaseOptionNode( - self.visit(node.expr, scope), node.branch_type, node + self.visit(node.expr, scope), + node.branch_type.heads[0], + ancestor_types, + node, ) @visitor.when(LoopNode) diff --git a/src/semantics/tools/context.py b/src/semantics/tools/context.py index b15a276de..4135bfdf9 100644 --- a/src/semantics/tools/context.py +++ b/src/semantics/tools/context.py @@ -1,6 +1,6 @@ from semantics.tools.errors import * from semantics.tools.type import TypeBag, Type, SelfType -from typing import Dict, Union +from typing import Dict, List, Union class Context: @@ -49,6 +49,13 @@ def dfs(root: str, results: list): dfs("Object", results) return results + def get_successors(self, type_name: str) -> List[str]: + successors: List[str] = [type_name] + for type in successors: + for succ in self.type_graph[type]: + successors.append(succ) + return successors + def __str__(self): return ( "{\n\t" @@ -58,4 +65,3 @@ def __str__(self): def __repr__(self): return str(self) - From 850e4c6b8aded56d1fde78cd0452bd0d3cb75edc Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 28 Feb 2022 08:39:20 -0500 Subject: [PATCH 353/432] Minor update, store succesor list on case option nodes --- src/asts/types_ast.py | 3 ++- src/semantics/inference/types_inferencer.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/asts/types_ast.py b/src/asts/types_ast.py index c9d8afd74..caaab04d1 100644 --- a/src/asts/types_ast.py +++ b/src/asts/types_ast.py @@ -81,11 +81,12 @@ def __init__(self, case_expr, options, node): class CaseOptionNode(ExpressionNode): - def __init__(self, ret_expr, branch_type, ancestor_types: List[str], node): + def __init__(self, ret_expr, branch_type, successors: List[str], node): Node.__init__(self, node) self.id = node.id self.decl_type = node.decl_type self.branch_type = branch_type + self.successors = successors self.expr = ret_expr diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 9bd1a776f..589fae26c 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -146,12 +146,12 @@ def visit(self, node: CaseNode, scope: Scope) -> types_ast.CaseNode: @visitor.when(CaseOptionNode) def visit(self, node: CaseOptionNode, scope: Scope) -> types_ast.CaseOptionNode: - ancestor_types: List[str] = self.context.get_successors(node.branch_type.name) + successors: List[str] = self.context.get_successors(node.branch_type.name) return types_ast.CaseOptionNode( self.visit(node.expr, scope), node.branch_type.heads[0], - ancestor_types, + successors, node, ) From 0f95741082dc5dfb0b0dfb8072378221b21d8feb Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 28 Feb 2022 09:04:33 -0500 Subject: [PATCH 354/432] Improve error handling during pattern matching --- src/code_gen/ccil_gen.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 4c6be116a..8bdd2d85c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -21,6 +21,7 @@ # See how typeof should work, a special kind of equality? # Define abort nodes with a text: # * Dispatch on a void class (Done) +# * Case expr is void # * No pattern match in case (Done) # * Division by zero (Done) # * Substring out of range (Done) @@ -300,6 +301,17 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Visiting case expression (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) + # Handling case expression is not void + + void_expr_error_ops = ( + self.throw_runtime_error( + f"case_{times}_void_expr_error", + f"RuntimeError: Case expression in {node.row}, {node.col} is void", + ) + if node.expr.type.name not in {STRING, INT, BOOL} + else [] + ) + # Storing the type of the resulting case expression type_of = self.create_type_of(f"case_{times}_typeOf", extract_id(case_expr_fv)) @@ -356,11 +368,10 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: self.locals[pre_fvalue_id] = node.type.name # Error handling when there is not pattern match - err_msg = self.add_data( - f"case_error_msg_{times}", + pattern_match_error_ops = self.throw_runtime_error( + f"case_{times}_pattern_match_fail", f"RuntimeError: Pattern match failure in {node.line}, {node.col}", ) - err_var = self.create_string_load_data(f"case_error_var_{times}", err_msg.id) # Merging all expression operations in correct order # and saving all to final value @@ -368,9 +379,10 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: fval = self.create_assignation(fval_id, node.type.name, pre_fvalue_id) operations = [ *case_expr_ops, + *void_expr_error_ops, type_of, *pattern_match_ops, - *self.notifiy_and_abort(err_var.id), + *pattern_match_error_ops, *branch_ops, final_label, fval, @@ -916,7 +928,7 @@ def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): self.add_local(idx, BOOL) return StorageNode(idx, EqualIntNode(left, right)) - def notifiy_and_abort(self, target: str): + def notifiy_and_abort(self, target: str) -> List[OperationNode]: print = PrintStrNode(target) abort = Abort() return [print, abort] @@ -1058,6 +1070,13 @@ def get_inherited_methods( new_defined_methods = list(defined_methods.values()) return new_defined_methods, inherited_methods + def throw_runtime_error(self, name: str, error_msg: str) -> List[OperationNode]: + data = self.add_data(name + "_msg", error_msg) + err_var = self.create_string_load_data(name + "_var", data.id) + abort_ops = self.notifiy_and_abort(err_var.id) + + return [err_var, *abort_ops] + def find_function_id(self, class_name: str, method_name: str): for method in self.program_types[class_name].methods: if method.id == method_name: From f3105944342d0502129738113dc2f2c7f2d01303 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 28 Feb 2022 10:40:33 -0500 Subject: [PATCH 355/432] Improve CIL case of translation Add functionality to evaluate branch type succesors. (e.g. Int now match with Object) Add built in classes name to .DATA Some refactoring --- src/asts/ccil_ast.py | 3 +- src/code_gen/ccil_gen.py | 80 +++++++++++++++++++++------------------ src/code_gen/constants.py | 1 + 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 93a6fd5f3..442dc5a19 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -426,8 +426,9 @@ def __init__(self) -> None: class CurrentTypeNameNode(ReturnOpNode): - def __init__(self) -> None: + def __init__(self, target: str) -> None: super().__init__() + self.target = target class IfNode(FlowControlNode): diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 8bdd2d85c..178c8ff8c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -75,6 +75,9 @@ def visit(self, node: sem_ast.ProgramNode) -> None: self.program_types = OrderedDict({OBJECT: obj, IO: io, STRING: str}) self.program_codes: List[FunctionNode] = builtin_methods + for builtin_name in [OBJECT, IO, STRING, INT, BOOL]: + self.add_data(f"{CLASS}{builtin_name}", builtin_name) + for type in node.declarations: classx, class_code = self.visit(type) self.program_types[classx.id] = classx @@ -93,7 +96,7 @@ def visit(self, node: sem_ast.ProgramNode) -> None: def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.reset_scope() self.current_type = node.id - self.add_data(f"class_{node.id}", node.id) + self.add_data(f"{CLASS}{node.id}", node.id) attributes: List[Attribute] = self.get_inherited_attributes(node) methods: List[Method] = [] @@ -302,60 +305,59 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) # Handling case expression is not void - void_expr_error_ops = ( self.throw_runtime_error( f"case_{times}_void_expr_error", f"RuntimeError: Case expression in {node.row}, {node.col} is void", ) - if node.expr.type.name not in {STRING, INT, BOOL} + if node.case_expr.type.name not in {STRING, INT, BOOL} else [] ) # Storing the type of the resulting case expression - type_of = self.create_type_of(f"case_{times}_typeOf", extract_id(case_expr_fv)) + expr_type = self.create_type_name(f"case_{times}_expr_type", case_expr_fv.id) # Final label where all branch must jump to - final_label_id = f"case_{times}_end" - final_label = LabelNode(final_label_id) - - # Inconditional jump to final label + final_label = LabelNode(f"case_{times}_end") final_goto = GoToNode(final_label) # All branch must end in a var named like this pre_fvalue_id = f"case_{times}_pre_fv" + # Holds strings for comparsion + type_name_holder = self.add_local(f"case_{times}_type_name_holder", STRING) + equality_holder = self.add_local(f"case_{times}_eq_holder", INT) + pattern_match_ops = self.init_default_values() branch_ops = [] for (i, option) in enumerate(node.options): # Initializing the branch var - branch_var_id = f"case_{times}_option_{i}" - branch_var = self.create_uninitialized_storage( - branch_var_id, option.branch_type.name - ) - - # Initializing var which holds the branch var type - branch_var_type_id = f"case_{times}_optionTypeOf_{i}" - branch_var_type_of = self.create_type_of( - branch_var_type_id, extract_id(branch_var) - ) - - # Initializng var which holds the comparison result between - # the case expression type of and branch var type of - select_branch_id = f"case_{times}_optionSelect_{i}" - select_branch = self.create_equality( - select_branch_id, - extract_id(type_of), - extract_id(branch_var_type_of), + branch_var = self.create_assignation( + f"case_{times}_option_{i}", option.branch_type.name, case_expr_fv.id ) # Label that means the start of this branch logic - branch_label_id = f"case_{times}_branch_{i}" - branch_label = LabelNode(branch_label_id) + branch_label = LabelNode(f"case_{times}_branch_{i}") + + # Compare expr type with node branch type and all of + # it's successors + branch_selection_ops = [] + for type_names in option.successors: + load_class_name = StorageNode( + type_name_holder.id, LoadOpNode(f"{CLASS}{type_names}") + ) + select_branch = StorageNode( + equality_holder.id, + EqualStrNode(extract_id(expr_type), extract_id(load_class_name)), + ) + # Conditional jump to the right branch label + if_op = IfNode(extract_id(select_branch), branch_label) + branch_selection_ops += [load_class_name, select_branch, if_op] - # Conditional jump to the right branch label - if_op = IfNode(extract_id(branch_var_type_of), branch_label) # Storing logic to jump to branch logic if this branch is selected - pattern_match_ops += [branch_var, branch_var_type_of, select_branch, if_op] + pattern_match_ops += [ + branch_var, + *branch_selection_ops, + ] # Translating the branch logic (expr_ops, expr_fval) = self.visit(option.expr) @@ -380,7 +382,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: operations = [ *case_expr_ops, *void_expr_error_ops, - type_of, + expr_type, *pattern_match_ops, *pattern_match_error_ops, *branch_ops, @@ -725,7 +727,7 @@ def define_built_ins(self): "abort", params, self.dump_locals(), [load, print, abort], "self" ) params = self.init_func_params(OBJECT) - get_name = self.create_current_type_name("get_name") + get_name = self.create_type_name("get_name", "self") type_name_func = FunctionNode( "type_name", params, self.dump_locals(), [get_name], get_name.id ) @@ -924,9 +926,12 @@ def create_type_of(self, idx: str, target: AtomOpNode): self.add_local(idx, ADDRESS) return StorageNode(idx, GetTypeOpNode(target)) - def create_equality(self, idx, left: AtomOpNode, right: AtomOpNode): + def create_equality( + self, idx, left: AtomOpNode, right: AtomOpNode, string: bool = False + ): self.add_local(idx, BOOL) - return StorageNode(idx, EqualIntNode(left, right)) + op = EqualStrNode(left, right) if string else EqualIntNode(left, right) + return StorageNode(idx, op) def notifiy_and_abort(self, target: str) -> List[OperationNode]: print = PrintStrNode(target) @@ -953,9 +958,9 @@ def create_read_int(self, idx: str): self.add_local(idx, INT) return StorageNode(idx, ReadIntNode()) - def create_current_type_name(self, idx: str): + def create_type_name(self, idx: str, target: str): self.add_local(idx, STRING) - return StorageNode(idx, CurrentTypeNameNode()) + return StorageNode(idx, CurrentTypeNameNode(target)) def create_length(self, idx: str, target: str): self.add_local(idx, INT) @@ -1017,6 +1022,7 @@ def add_local(self, idx: str, typex: str): if idx in self.locals: raise Exception(f"Trying to insert {idx} again as local") self.locals[idx] = typex + return Local(idx, typex) def reset_locals(self): """ diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index 2027ce702..1d25a5f1b 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -1,6 +1,7 @@ PARAM = "param_" LET = "let_" ATTR = "attr_" +CLASS = "class_" CASE_INIT = "init_case" CASE_END = "end_case" From 41143430edaaf070cd09887c6e3b2863c83a2b77 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Mon, 28 Feb 2022 10:47:06 -0500 Subject: [PATCH 356/432] Add new test --- src/debbuging/tests_ccil/case3.cl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/debbuging/tests_ccil/case3.cl diff --git a/src/debbuging/tests_ccil/case3.cl b/src/debbuging/tests_ccil/case3.cl new file mode 100644 index 000000000..614a999cd --- /dev/null +++ b/src/debbuging/tests_ccil/case3.cl @@ -0,0 +1,20 @@ +class Main inherits IO { + main(): Object + { + case 3 + 5 of + n : Object => 0; + n : Bool => 1; + n : Int => 2; + n : String => 3; + n : A => 4; + n : B => 5; + n : C => 6; + esac + }; +}; + +class A { }; + +class B inherits A { }; + +class C inherits B { }; From 7048590e7dc1e374210bb3610f8e83e83b8cc9e1 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 1 Mar 2022 10:05:45 -0500 Subject: [PATCH 357/432] Fix attributes inicialization during object allocation --- src/code_gen/ccil_mips_gen.py | 38 +++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index dbb9815f8..27c62ff69 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -292,7 +292,9 @@ def visit(self, node: ccil_ast.NewOpNode): # TODO: SELF_TYPE if node.type == "SELF_TYPE": return [] - size = self.get_attr_count(node.type) + WORD + + # Allocate memory for object instance + size = self.get_attr_count(node.type) * WORD + WORD instructions.append( mips_ast.LoadImmediate( node, @@ -323,6 +325,23 @@ def visit(self, node: ccil_ast.NewOpNode): ), ) ) + + # Initialize attibutes + init_function = mips_ast.RegisterNode(node, T2) + instructions.append( + mips_ast.LoadWord( + node, + init_function, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, T0) + ), + ) + ) + + instructions.extend(self.push_stack(node, mips_ast.RegisterNode(node, V0))) + instructions.append(mips_ast.JumpAndLink(node, init_function)) + instructions.extend(self.pop_stack(node, mips_ast.RegisterNode(node, V0))) + return instructions @visitor.when(ccil_ast.GetAttrOpNode) @@ -340,7 +359,7 @@ def visit(self, node: ccil_ast.GetAttrOpNode): mips_ast.RegisterNode(node, V0), mips_ast.MemoryIndexNode( node, - mips_ast.Constant(node, str(attr_offset)), + mips_ast.Constant(node, attr_offset), mips_ast.RegisterNode(node, T0), ), ) @@ -395,6 +414,18 @@ def visit(self, node: ccil_ast.SetAttrOpNode): self.get_relative_location(node.new_value.value), ) ) + # NOTE: Fix: instances should not be of type str + elif isinstance(node.new_value, str): + instructions.append( + mips_ast.LoadWord( + node, + reg_new_value, + self.get_relative_location(node.new_value), + ) + ) + else: + raise Exception(f"Invalid type of ccil node: {type(node.new_value)}") + instructions.append( mips_ast.StoreWord( node, @@ -884,7 +915,7 @@ def get_attr_index(self, typex: str, attr: str): if _type.id == typex: for index, _attr in enumerate(_type.attributes): if _attr.id == attr: - return index + WORD + return index * WORD + WORD raise Exception(f"Attribute {attr} not found in type {typex}") def get_attr_count(self, typex: str): @@ -900,7 +931,6 @@ def get_init_function(self, typex: str): raise Exception("Type's function for inicialization not found") def get_method_index(self, typex: str, method: str) -> int: - for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): From 1247d6c03c6eade3f9085dc2d85349e53881d77d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 1 Mar 2022 10:05:45 -0500 Subject: [PATCH 358/432] Fix attributes inicialization during object allocation --- src/code_gen/ccil_mips_gen.py | 38 +++++++++++++++++-- .../tests_ccil/attr_inicialization.cl | 9 +++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 src/debbuging/tests_ccil/attr_inicialization.cl diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index dbb9815f8..27c62ff69 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -292,7 +292,9 @@ def visit(self, node: ccil_ast.NewOpNode): # TODO: SELF_TYPE if node.type == "SELF_TYPE": return [] - size = self.get_attr_count(node.type) + WORD + + # Allocate memory for object instance + size = self.get_attr_count(node.type) * WORD + WORD instructions.append( mips_ast.LoadImmediate( node, @@ -323,6 +325,23 @@ def visit(self, node: ccil_ast.NewOpNode): ), ) ) + + # Initialize attibutes + init_function = mips_ast.RegisterNode(node, T2) + instructions.append( + mips_ast.LoadWord( + node, + init_function, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, T0) + ), + ) + ) + + instructions.extend(self.push_stack(node, mips_ast.RegisterNode(node, V0))) + instructions.append(mips_ast.JumpAndLink(node, init_function)) + instructions.extend(self.pop_stack(node, mips_ast.RegisterNode(node, V0))) + return instructions @visitor.when(ccil_ast.GetAttrOpNode) @@ -340,7 +359,7 @@ def visit(self, node: ccil_ast.GetAttrOpNode): mips_ast.RegisterNode(node, V0), mips_ast.MemoryIndexNode( node, - mips_ast.Constant(node, str(attr_offset)), + mips_ast.Constant(node, attr_offset), mips_ast.RegisterNode(node, T0), ), ) @@ -395,6 +414,18 @@ def visit(self, node: ccil_ast.SetAttrOpNode): self.get_relative_location(node.new_value.value), ) ) + # NOTE: Fix: instances should not be of type str + elif isinstance(node.new_value, str): + instructions.append( + mips_ast.LoadWord( + node, + reg_new_value, + self.get_relative_location(node.new_value), + ) + ) + else: + raise Exception(f"Invalid type of ccil node: {type(node.new_value)}") + instructions.append( mips_ast.StoreWord( node, @@ -884,7 +915,7 @@ def get_attr_index(self, typex: str, attr: str): if _type.id == typex: for index, _attr in enumerate(_type.attributes): if _attr.id == attr: - return index + WORD + return index * WORD + WORD raise Exception(f"Attribute {attr} not found in type {typex}") def get_attr_count(self, typex: str): @@ -900,7 +931,6 @@ def get_init_function(self, typex: str): raise Exception("Type's function for inicialization not found") def get_method_index(self, typex: str, method: str) -> int: - for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): diff --git a/src/debbuging/tests_ccil/attr_inicialization.cl b/src/debbuging/tests_ccil/attr_inicialization.cl new file mode 100644 index 000000000..4ce41c09a --- /dev/null +++ b/src/debbuging/tests_ccil/attr_inicialization.cl @@ -0,0 +1,9 @@ +class Main inherits IO { + a : Int <- 12; + b: Int <- 40; + main() : Main { + { + out_int(a + b); + } + }; +}; From 06c03efeb42f04ec29d6984a7cb832eaaa002daa Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 1 Mar 2022 11:23:57 -0500 Subject: [PATCH 359/432] Add cmp_string.cl test --- src/debbuging/tests_ccil/cmp_string.cl | 12 ++++++++++++ src/debbuging/tests_ccil/fib.cl | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/debbuging/tests_ccil/cmp_string.cl create mode 100644 src/debbuging/tests_ccil/fib.cl diff --git a/src/debbuging/tests_ccil/cmp_string.cl b/src/debbuging/tests_ccil/cmp_string.cl new file mode 100644 index 000000000..a72564d96 --- /dev/null +++ b/src/debbuging/tests_ccil/cmp_string.cl @@ -0,0 +1,12 @@ +class Main inherits IO { + a : Int; + b : String; + c : String; + main() : Int { + { + c <- "hola"; + b <- "hola" ; + if c=b then 1 else 0 fi; + } + }; +}; diff --git a/src/debbuging/tests_ccil/fib.cl b/src/debbuging/tests_ccil/fib.cl new file mode 100644 index 000000000..2fea92802 --- /dev/null +++ b/src/debbuging/tests_ccil/fib.cl @@ -0,0 +1,8 @@ +class Main inherits IO { + main(): Main { + out_int(fib(20)) + }; + fib(n : Int): Int { + if n <= 1 then 1 else fib(n-1) + fib(n-2) fi + }; +}; From c03e1d2866789125e6812e2756dbbcd0eda1e671 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:09:06 -0500 Subject: [PATCH 360/432] Delete unused constants --- src/code_gen/constants.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index 1d25a5f1b..15a94cc24 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -3,10 +3,6 @@ ATTR = "attr_" CLASS = "class_" -CASE_INIT = "init_case" -CASE_END = "end_case" -CASE_BRANCH = "case_branch" - # Registers ZERO = 0 AT = 1 From 3ffe8d88360c7a55a7057f81098a20e75512375b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:21:41 -0500 Subject: [PATCH 361/432] Delete unimplemented visit to EqualNode --- src/code_gen/ccil_gen.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 178c8ff8c..752d0f83c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -262,6 +262,8 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: times = self.times(node) + print(type(node.condition).__name__) + print(node.condition) (if_ops, if_fval) = self.visit(node.condition) (then_ops, then_fval) = self.visit(node.then_body) (else_ops, else_fval) = self.visit(node.else_body) @@ -505,9 +507,6 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: fval = self.create_storage(fval_id, node.type.name, op) return ([*left_ops, *right_ops, fval], fval) - @visitor.when(sem_ast.EqualsNode) - def visit(self, node: sem_ast.EqualsNode) -> VISITOR_RESULT: - pass @visitor.when(sem_ast.UnaryNode) def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: From e64a03c274d93e13479ed73e8c3f2d4e39cd87a2 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:32:03 -0500 Subject: [PATCH 362/432] Add source string to substr operator --- src/asts/ccil_ast.py | 7 ++++--- src/code_gen/ccil_gen.py | 5 +---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 442dc5a19..de50f59da 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -14,7 +14,7 @@ class CCILProgram: code_section: List[FunctionNode] data_section: List[Data] - def __str__(self, all=False) -> str: + def __str__(self, all=True) -> str: types_section = self.types_section code_section = self.code_section if not all: @@ -380,13 +380,14 @@ def __str__(self) -> str: class SubstringOpNode(ReturnOpNode): - def __init__(self, start: AtomOpNode, length: AtomOpNode) -> None: + def __init__(self, start: AtomOpNode, length: AtomOpNode, target: IdNode) -> None: super().__init__() self.start = start self.length = length + self.target = target def __str__(self) -> str: - return f"substr {self.start.value} {self.length.value}" + return f"substr {self.target.value} {self.start.value} {self.length.value}" class AtomOpNode(ReturnOpNode): diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 752d0f83c..65c94e66b 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -262,8 +262,6 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: times = self.times(node) - print(type(node.condition).__name__) - print(node.condition) (if_ops, if_fval) = self.visit(node.condition) (then_ops, then_fval) = self.visit(node.then_body) (else_ops, else_fval) = self.visit(node.else_body) @@ -507,7 +505,6 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: fval = self.create_storage(fval_id, node.type.name, op) return ([*left_ops, *right_ops, fval], fval) - @visitor.when(sem_ast.UnaryNode) def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: times = self.times(node) @@ -829,7 +826,7 @@ def define_built_ins(self): substr = self.create_storage( "substr_var", STRING, - SubstringOpNode(IdNode(start_index.id), IdNode(take.id)), + SubstringOpNode(IdNode(start_index.id), IdNode(take.id), IdNode("self")), ) goto_ok = GoToNode(ok_label) operations = [ From acb20ac64c7b23d0023e3e13c7fe6d86d7ba1059 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:38:46 -0500 Subject: [PATCH 363/432] Hot fix in case when adding an error string --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 65c94e66b..9eb0e44d6 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -308,7 +308,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: void_expr_error_ops = ( self.throw_runtime_error( f"case_{times}_void_expr_error", - f"RuntimeError: Case expression in {node.row}, {node.col} is void", + f"RuntimeError: Case expression in {node.line}, {node.col} is void", ) if node.case_expr.type.name not in {STRING, INT, BOOL} else [] From 5c0bdcc37382d22383f351053263d12afcd7549f Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:39:15 -0500 Subject: [PATCH 364/432] Add another case test --- src/debbuging/tests_ccil/case4.cl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/debbuging/tests_ccil/case4.cl diff --git a/src/debbuging/tests_ccil/case4.cl b/src/debbuging/tests_ccil/case4.cl new file mode 100644 index 000000000..f175f75d4 --- /dev/null +++ b/src/debbuging/tests_ccil/case4.cl @@ -0,0 +1,20 @@ +class Main inherits IO { + main(): Object + { + case new B of + n : Object => 0; + n : Bool => 1; + n : Int => 2; + n : String => 3; + n : A => 4; + n : B => 5; + n : C => 6; + esac + }; +}; + +class A { }; + +class B inherits A { }; + +class C inherits B { }; From f08a776e207286b4e7506f99ea610c82d418ab26 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:43:26 -0500 Subject: [PATCH 365/432] Add optimization when there is pattern mathcing with Object class --- src/code_gen/ccil_gen.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 9eb0e44d6..72d25dd2d 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -341,17 +341,20 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Compare expr type with node branch type and all of # it's successors branch_selection_ops = [] - for type_names in option.successors: - load_class_name = StorageNode( - type_name_holder.id, LoadOpNode(f"{CLASS}{type_names}") - ) - select_branch = StorageNode( - equality_holder.id, - EqualStrNode(extract_id(expr_type), extract_id(load_class_name)), - ) - # Conditional jump to the right branch label - if_op = IfNode(extract_id(select_branch), branch_label) - branch_selection_ops += [load_class_name, select_branch, if_op] + if option.successors[0] != OBJECT: + for type_names in option.successors: + load_class_name = StorageNode( + type_name_holder.id, LoadOpNode(f"{CLASS}{type_names}") + ) + select_branch = StorageNode( + equality_holder.id, + EqualStrNode(extract_id(expr_type), extract_id(load_class_name)), + ) + # Conditional jump to the right branch label + if_op = IfNode(extract_id(select_branch), branch_label) + branch_selection_ops += [load_class_name, select_branch, if_op] + else: + branch_selection_ops = [GoToNode(branch_label)] # Storing logic to jump to branch logic if this branch is selected pattern_match_ops += [ From 954861d3c1cc6ca63ac5a2a726dd857bc0446a66 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Tue, 1 Mar 2022 15:47:20 -0500 Subject: [PATCH 366/432] Add optimization to not pattern match with a class successor if this is already declared in case expresion --- src/code_gen/ccil_gen.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 72d25dd2d..124c5cfec 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -328,7 +328,9 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: equality_holder = self.add_local(f"case_{times}_eq_holder", INT) pattern_match_ops = self.init_default_values() + branch_ops = [] + visited_types = set() # To optimize and reduce redundant calling for (i, option) in enumerate(node.options): # Initializing the branch var branch_var = self.create_assignation( @@ -343,6 +345,10 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: branch_selection_ops = [] if option.successors[0] != OBJECT: for type_names in option.successors: + if type_names in visited_types: + continue + visited_types.add(type_names) + load_class_name = StorageNode( type_name_holder.id, LoadOpNode(f"{CLASS}{type_names}") ) From b171fe776b96087aeb0d71f5924023b475576bce Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 2 Mar 2022 00:55:29 -0500 Subject: [PATCH 367/432] Add concat string builtin --- src/asts/mips_ast.py | 6 + src/code_gen/ccil_mips_gen.py | 415 ++++++++++++++++++------- src/code_gen/mips_gen.py | 7 +- src/debbuging/tests_ccil/concat_str.cl | 5 + 4 files changed, 328 insertions(+), 105 deletions(-) create mode 100644 src/debbuging/tests_ccil/concat_str.cl diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index fcb1e4850..ca36997d7 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -267,6 +267,12 @@ class LoadByte(BinaryOpNode): def __init__(self, node, left, right) -> None: super().__init__(node, left, right) +class StoreByte(BinaryOpNode): + """ + This node represents `sb` instruction in MIPS + """ + def __init__(self, node, left, right) -> None: + super().__init__(node, left, right) class LoadWord(BinaryOpNode): """ diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 27c62ff69..1d6b1219d 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1,7 +1,9 @@ -from typing import Tuple, Union, Dict, List +from typing import Dict, List, Tuple + +from asts import ccil_ast, mips_ast from utils import visitor -from asts import mips_ast, ccil_ast from utils import visitor + from .constants import * WORD = 4 @@ -10,53 +12,16 @@ class CCILToMIPSGenerator: + """ + This class transform CCIL AST to MIPS AST using visitor pattern + """ + def __init__(self) -> None: self.__id = 0 self.__types_table: List[ccil_ast.Class] = [] self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode - def push_stack(self, node, register: mips_ast.RegisterNode): - stack_pointer = mips_ast.RegisterNode(node, SP) - instructions = [] - instructions.append( - mips_ast.Addi( - node, - stack_pointer, - stack_pointer, - mips_ast.Constant(node, -1 * DOUBLE_WORD), - ) - ) - instructions.append( - mips_ast.StoreWord( - node, - register, - mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, 0), stack_pointer - ), - ) - ) - return instructions - - def pop_stack(self, node, register: mips_ast.RegisterNode): - stack_pointer = mips_ast.RegisterNode(node, SP) - instructions = [] - instructions.append( - mips_ast.LoadWord( - node, - register, - mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, 0), stack_pointer - ), - ) - ) - instructions.append( - mips_ast.Addi( - node, stack_pointer, stack_pointer, mips_ast.Constant(node, DOUBLE_WORD) - ) - ) - return instructions - @visitor.on("node") def visit(self, node): pass @@ -116,7 +81,7 @@ def visit(self, node: ccil_ast.FunctionNode): frame_pointer = mips_ast.RegisterNode(node, FP) for index, local in enumerate(node.locals): - self.set_relative_location( + self._set_relative_location( local.id, mips_ast.MemoryIndexNode( node, @@ -127,7 +92,7 @@ def visit(self, node: ccil_ast.FunctionNode): ), ) for index, param in enumerate(node.params): - self.set_relative_location( + self._set_relative_location( param.id, mips_ast.MemoryIndexNode( node, @@ -138,8 +103,8 @@ def visit(self, node: ccil_ast.FunctionNode): ), ) - instructions.extend(self.push_stack(node, return_address)) - instructions.extend(self.push_stack(node, frame_pointer)) + instructions.extend(self._push_stack(node, return_address)) + instructions.extend(self._push_stack(node, frame_pointer)) instructions.append( mips_ast.Addi( node, frame_pointer, stack_pointer, mips_ast.Constant(node, 16) @@ -156,7 +121,7 @@ def visit(self, node: ccil_ast.FunctionNode): for op in node.operations: instructions.extend(self.visit(op)) - ret_location = self.get_relative_location(node.ret) + ret_location = self._get_relative_location(node.ret) ret_register = mips_ast.RegisterNode(node, V0) instructions.append(mips_ast.LoadWord(node, ret_register, ret_location)) @@ -165,8 +130,8 @@ def visit(self, node: ccil_ast.FunctionNode): node, stack_pointer, stack_pointer, mips_ast.Constant(node, frame_size) ) ) - instructions.extend(self.pop_stack(node, frame_pointer)) - instructions.extend(self.pop_stack(node, return_address)) + instructions.extend(self._pop_stack(node, frame_pointer)) + instructions.extend(self._pop_stack(node, return_address)) if node.id == "main": instructions.append( @@ -182,7 +147,7 @@ def visit(self, node: ccil_ast.FunctionNode): @visitor.when(ccil_ast.StorageNode) def visit(self, node: ccil_ast.StorageNode): - location_id = self.get_relative_location(node.id) + location_id = self._get_relative_location(node.id) instructions = [] instructions.extend(self.visit(node.operation)) instructions.append( @@ -197,7 +162,7 @@ def visit(self, node: ccil_ast.IdNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, V0), - self.get_relative_location(node.value), + self._get_relative_location(node.value), ) ) return instructions @@ -220,9 +185,9 @@ def visit(self, node: ccil_ast.CallOpNode): instructions = [] for arg in node.args: instructions.append( - mips_ast.LoadWord(node, reg, self.get_relative_location(arg.value)) + mips_ast.LoadWord(node, reg, self._get_relative_location(arg.value)) ) - instructions.extend(self.push_stack(node, reg)) + instructions.extend(self._push_stack(node, reg)) instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, node.id))) if len(node.args) > 0: @@ -241,7 +206,7 @@ def visit(self, node: ccil_ast.CallOpNode): def visit(self, node: ccil_ast.VCallOpNode): instructions = [] - obj_location = self.get_relative_location(node.args[0].value) + obj_location = self._get_relative_location(node.args[0].value) reg_obj = mips_ast.RegisterNode(node, T0) instructions.append(mips_ast.LoadWord(node, reg_obj, obj_location)) @@ -254,7 +219,7 @@ def visit(self, node: ccil_ast.VCallOpNode): ) ) register_function = mips_ast.RegisterNode(node, T2) - function_index = self.get_method_index(node.type, node.id) + function_index = self._get_method_index(node.type, node.id) instructions.append( mips_ast.LoadWord( node, @@ -267,9 +232,9 @@ def visit(self, node: ccil_ast.VCallOpNode): reg_arg = mips_ast.RegisterNode(node, T3) for arg in node.args: instructions.append( - mips_ast.LoadWord(node, reg_arg, self.get_relative_location(arg.value)) + mips_ast.LoadWord(node, reg_arg, self._get_relative_location(arg.value)) ) - instructions.extend(self.push_stack(node, reg_arg)) + instructions.extend(self._push_stack(node, reg_arg)) instructions.append(mips_ast.JumpAndLink(node, register_function)) if len(node.args) > 0: @@ -294,7 +259,7 @@ def visit(self, node: ccil_ast.NewOpNode): return [] # Allocate memory for object instance - size = self.get_attr_count(node.type) * WORD + WORD + size = self._get_attr_count(node.type) * WORD + WORD instructions.append( mips_ast.LoadImmediate( node, @@ -338,17 +303,17 @@ def visit(self, node: ccil_ast.NewOpNode): ) ) - instructions.extend(self.push_stack(node, mips_ast.RegisterNode(node, V0))) + instructions.extend(self._push_stack(node, mips_ast.RegisterNode(node, V0))) instructions.append(mips_ast.JumpAndLink(node, init_function)) - instructions.extend(self.pop_stack(node, mips_ast.RegisterNode(node, V0))) + instructions.extend(self._pop_stack(node, mips_ast.RegisterNode(node, V0))) return instructions @visitor.when(ccil_ast.GetAttrOpNode) def visit(self, node: ccil_ast.GetAttrOpNode): instructions = [] - attr_offset = self.get_attr_index(node.instance_type, node.attr) - location_object = self.get_relative_location(node.instance) + attr_offset = self._get_attr_index(node.instance_type, node.attr) + location_object = self._get_relative_location(node.instance) instructions.append( mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), location_object) @@ -374,7 +339,7 @@ def visit(self, node: ccil_ast.GetTypeOpNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, T0), - self.get_relative_location(node.atom.value), + self._get_relative_location(node.atom.value), ) ) instructions.append( @@ -392,8 +357,8 @@ def visit(self, node: ccil_ast.GetTypeOpNode): def visit(self, node: ccil_ast.SetAttrOpNode): instructions = [] - attr_offset = self.get_attr_index(node.instance_type, node.attr) - object_location = self.get_relative_location(node.instance) + attr_offset = self._get_attr_index(node.instance_type, node.attr) + object_location = self._get_relative_location(node.instance) instructions.append( mips_ast.LoadWord(node, mips_ast.RegisterNode(node, T0), object_location) @@ -411,7 +376,7 @@ def visit(self, node: ccil_ast.SetAttrOpNode): mips_ast.LoadWord( node, reg_new_value, - self.get_relative_location(node.new_value.value), + self._get_relative_location(node.new_value.value), ) ) # NOTE: Fix: instances should not be of type str @@ -420,7 +385,7 @@ def visit(self, node: ccil_ast.SetAttrOpNode): mips_ast.LoadWord( node, reg_new_value, - self.get_relative_location(node.new_value), + self._get_relative_location(node.new_value), ) ) else: @@ -447,7 +412,7 @@ def visit(self, node: ccil_ast.SumOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -461,7 +426,7 @@ def visit(self, node: ccil_ast.SumOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -486,7 +451,7 @@ def visit(self, node: ccil_ast.MinusOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -500,7 +465,7 @@ def visit(self, node: ccil_ast.MinusOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -525,7 +490,7 @@ def visit(self, node: ccil_ast.MultOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -539,7 +504,7 @@ def visit(self, node: ccil_ast.MultOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -564,7 +529,7 @@ def visit(self, node: ccil_ast.DivOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -578,7 +543,7 @@ def visit(self, node: ccil_ast.DivOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -603,7 +568,7 @@ def visit(self, node: ccil_ast.LessOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -617,7 +582,7 @@ def visit(self, node: ccil_ast.LessOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -642,7 +607,7 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -656,7 +621,7 @@ def visit(self, node: ccil_ast.LessOrEqualOpNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -681,7 +646,7 @@ def visit(self, node: ccil_ast.EqualIntNode): if isinstance(node.left, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_left, self.get_relative_location(node.left.value) + node, reg_left, self._get_relative_location(node.left.value) ) ) elif isinstance(node.left, ccil_ast.ConstantNode): @@ -695,7 +660,7 @@ def visit(self, node: ccil_ast.EqualIntNode): if isinstance(node.right, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg_right, self.get_relative_location(node.right.value) + node, reg_right, self._get_relative_location(node.right.value) ) ) elif isinstance(node.right, ccil_ast.ConstantNode): @@ -726,7 +691,7 @@ def visit(self, node: ccil_ast.NotOpNode): elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg, self.get_relative_location(node.atom.value) + node, reg, self._get_relative_location(node.atom.value) ) ) instructions.append(mips_ast.Not(node, reg, reg)) @@ -747,7 +712,7 @@ def visit(self, node: ccil_ast.NegOpNode): elif isinstance(node.atom, ccil_ast.IdNode): instructions.append( mips_ast.LoadWord( - node, reg, self.get_relative_location(node.atom.value) + node, reg, self._get_relative_location(node.atom.value) ) ) instructions.append(mips_ast.Xori(node, reg, reg, mips_ast.Constant(node, "1"))) @@ -772,7 +737,7 @@ def visit(self, node: ccil_ast.IfFalseNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, T0), - self.get_relative_location(node.eval_value.value), + self._get_relative_location(node.eval_value.value), ) ) instructions.append( @@ -809,7 +774,7 @@ def visit(self, node: ccil_ast.PrintIntNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, A0), - self.get_relative_location(node.id), + self._get_relative_location(node.id), ) ) @@ -828,7 +793,7 @@ def visit(self, node: ccil_ast.PrintStrNode): mips_ast.LoadWord( node, mips_ast.RegisterNode(node, A0), - self.get_relative_location(node.id), + self._get_relative_location(node.id), ) ) @@ -869,10 +834,10 @@ def visit(self, node: ccil_ast.LengthOpNode): ) string = mips_ast.RegisterNode(node, T1) instructions.append( - mips_ast.LoadWord(node, string, self.get_relative_location(node.target)) + mips_ast.LoadWord(node, string, self._get_relative_location(node.target)) ) - loop = self.generate_unique_label() + loop = self._generate_unique_label() instructions.append(mips_ast.LabelDeclaration(node, loop)) char = mips_ast.RegisterNode(node, T2) @@ -884,7 +849,7 @@ def visit(self, node: ccil_ast.LengthOpNode): ) ) zero = mips_ast.RegisterNode(node, ZERO) - exit = self.generate_unique_label() + exit = self._generate_unique_label() instructions.append( mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node, exit)) ) @@ -898,19 +863,220 @@ def visit(self, node: ccil_ast.LengthOpNode): instructions.append(mips_ast.LabelDeclaration(node, exit)) return instructions - # @visitor.when(ccil_ast.EqualStrNode) - # def visit(self, node: ccil_ast.EqualStrNode): - # pass + @visitor.when(ccil_ast.EqualStrNode) + def visit(self, node: ccil_ast.EqualStrNode): + instructions = [] + left_string = mips_ast.RegisterNode(node, T0) + right_string = mips_ast.RegisterNode(node, T1) - # @visitor.when(ccil_ast.ConcatOpNode) - # def visit(self, node: ccil_ast.ConcatOpNode): - # pass + instructions.append( + mips_ast.LoadWord( + node, left_string, self._get_relative_location(node.left.value) + ) + ) + instructions.append( + mips_ast.LoadWord( + node, right_string, self._get_relative_location(node.right.value) + ) + ) + left_char = mips_ast.RegisterNode(node, T2) + right_char = mips_ast.RegisterNode(node, T3) + loop = self._generate_unique_label() + instructions.append(mips_ast.LabelDeclaration(node, loop)) + instructions.append( + mips_ast.LoadByte( + node, + left_char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), left_string), + ) + ) + instructions.append( + mips_ast.LoadByte( + node, + right_char, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), right_string + ), + ) + ) + + equals_end = self._generate_unique_label() + not_equals_end = self._generate_unique_label() + + zero = mips_ast.RegisterNode(node, ZERO) + instructions.append( + mips_ast.BranchOnNotEqual( + node, left_char, right_char, mips_ast.Label(node, not_equals_end) + ) + ) + instructions.append( + mips_ast.BranchOnEqual( + node, left_char, zero, mips_ast.Label(node, equals_end) + ) + ) + + instructions.append( + mips_ast.Addi(node, left_string, left_string, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, right_string, right_string, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + + end = self._generate_unique_label() + result = mips_ast.RegisterNode(node, V0) + instructions.append(mips_ast.LabelDeclaration(node, equals_end)) + instructions.append( + mips_ast.LoadImmediate(node, result, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, end))) + instructions.append(mips_ast.LabelDeclaration(node, not_equals_end)) + instructions.append( + mips_ast.LoadImmediate(node, result, mips_ast.Constant(node, 0)) + ) + instructions.append(mips_ast.LabelDeclaration(node, end)) + return instructions + + @visitor.when(ccil_ast.ConcatOpNode) + def visit(self, node: ccil_ast.ConcatOpNode): + instructions = [] + string_a = mips_ast.RegisterNode(node, T0) + string_b = mips_ast.RegisterNode(node, T1) + + len_a = mips_ast.RegisterNode(node, T4) + len_b = mips_ast.RegisterNode(node, T3) + + instructions.append( + mips_ast.LoadWord( + node, string_a, self._get_relative_location(node.source) + ) + ) + instructions.extend(self._push_stack(node, string_a)) + instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, "length"))) + instructions.extend(self._pop_stack(node, string_a)) + instructions.append(mips_ast.Move(node, len_a, mips_ast.RegisterNode(node, V0))) + + instructions.append( + mips_ast.LoadWord( + node, string_b, self._get_relative_location(node.target) + ) + ) + instructions.extend(self._push_stack(node, string_b)) + instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, "length"))) + instructions.extend(self._pop_stack(node, string_b)) + + instructions.append(mips_ast.Move(node, len_b, mips_ast.RegisterNode(node, V0))) + + instructions.append( + mips_ast.Add(node, mips_ast.RegisterNode(node, A0), len_a, len_b) + ) + instructions.append( + mips_ast.Addi( + node, + mips_ast.RegisterNode(node, A0), + mips_ast.RegisterNode(node, A0), + mips_ast.Constant(node, 1), + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) + ) + ) + instructions.append(mips_ast.Syscall(node)) + + concat_string = mips_ast.RegisterNode(node, V0) + concat_char = mips_ast.RegisterNode(node, T6) + char = mips_ast.RegisterNode(node, T5) + instructions.append(mips_ast.Move(node, concat_char, concat_string)) + + loop_string_a = self._generate_unique_label() + end_loop_string_a = self._generate_unique_label() + instructions.append(mips_ast.LabelDeclaration(node, loop_string_a)) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string_a), + ) + ) + instructions.append( + mips_ast.BranchOnEqual( + node, + char, + mips_ast.RegisterNode(node, ZERO), + mips_ast.Label(node, end_loop_string_a), + ) + ) + instructions.append( + mips_ast.StoreByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), concat_char), + ) + ) + instructions.append( + mips_ast.Addi(node, string_a, string_a, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, concat_char, concat_char, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop_string_a))) + instructions.append(mips_ast.LabelDeclaration(node, end_loop_string_a)) + + loop_string_b = self._generate_unique_label() + end_loop_string_b = self._generate_unique_label() + instructions.append(mips_ast.LabelDeclaration(node, loop_string_b)) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string_b), + ) + ) + instructions.append( + mips_ast.BranchOnEqual( + node, + char, + mips_ast.RegisterNode(node, ZERO), + mips_ast.Label(node, end_loop_string_b), + ) + ) + instructions.append( + mips_ast.StoreByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), concat_char), + ) + ) + instructions.append( + mips_ast.Addi(node, string_b, string_b, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, concat_char, concat_char, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop_string_b))) + instructions.append(mips_ast.LabelDeclaration(node, end_loop_string_b)) + + instructions.append( + mips_ast.StoreByte( + node, + mips_ast.RegisterNode(node, ZERO), + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), concat_char), + ) + ) + + return instructions # @visitor.when(ccil_ast.SubstringOpNode) # def visit(self, node: ccil_ast.SubstringOpNode): + # instructions = [] + # substring = mips_ast.RegisterNode(node, V0) + # instructions.append() + # pass - def get_attr_index(self, typex: str, attr: str): + def _get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: for index, _attr in enumerate(_type.attributes): @@ -918,19 +1084,19 @@ def get_attr_index(self, typex: str, attr: str): return index * WORD + WORD raise Exception(f"Attribute {attr} not found in type {typex}") - def get_attr_count(self, typex: str): + def _get_attr_count(self, typex: str): for _type in self.__types_table: if _type.id == typex: return len(_type.attributes) raise Exception("Type declaration not found") - def get_init_function(self, typex: str): + def _get_init_function(self, typex: str): for _type in self.__types_table: if _type.id == typex: return _type.init_operations raise Exception("Type's function for inicialization not found") - def get_method_index(self, typex: str, method: str) -> int: + def _get_method_index(self, typex: str, method: str) -> int: for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): @@ -939,7 +1105,7 @@ def get_method_index(self, typex: str, method: str) -> int: raise Exception(f"Method implementation not found:{typex} {method}") - def get_class_method(self, typex: str, method: str) -> str: + def _get_class_method(self, typex: str, method: str) -> str: for _type in self.__types_table: if _type.id == typex: for _method in _type.methods: @@ -947,12 +1113,53 @@ def get_class_method(self, typex: str, method: str) -> str: return _method.function.id raise Exception(f"Method implementation not found") - def get_relative_location(self, id: str): + def _get_relative_location(self, id: str): return self.__location[self.__current_function.id, id] - def set_relative_location(self, id: str, memory: mips_ast.MemoryIndexNode): + def _set_relative_location(self, id: str, memory: mips_ast.MemoryIndexNode): self.__location[self.__current_function.id, id] = memory - def generate_unique_label(self): + def _generate_unique_label(self): self.__id += 1 return f"label_{self.__id}" + + def _push_stack(self, node, register: mips_ast.RegisterNode): + stack_pointer = mips_ast.RegisterNode(node, SP) + instructions = [] + instructions.append( + mips_ast.Addi( + node, + stack_pointer, + stack_pointer, + mips_ast.Constant(node, -1 * DOUBLE_WORD), + ) + ) + instructions.append( + mips_ast.StoreWord( + node, + register, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), stack_pointer + ), + ) + ) + return instructions + + def _pop_stack(self, node, register: mips_ast.RegisterNode): + stack_pointer = mips_ast.RegisterNode(node, SP) + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + register, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), stack_pointer + ), + ) + ) + instructions.append( + mips_ast.Addi( + node, stack_pointer, stack_pointer, mips_ast.Constant(node, DOUBLE_WORD) + ) + ) + return instructions diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index 8917b1df0..b41ed59da 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -26,6 +26,7 @@ Multiply, Not, RegisterNode, + StoreByte, StoreWord, Sub, Subu, @@ -194,4 +195,8 @@ def visit(self, node: MoveFromLo) -> str: @visitor.when(LoadByte) def visit(self, node: LoadByte) -> str: - return f"\tlb {self.visit(node.left)} {self.visit(node.right)}" + return f"\tlb {self.visit(node.left)}, {self.visit(node.right)}" + + @visitor.when(StoreByte) + def visit(self, node: StoreByte) -> str: + return f"\tsb {self.visit(node.left)}, {self.visit(node.right)}" diff --git a/src/debbuging/tests_ccil/concat_str.cl b/src/debbuging/tests_ccil/concat_str.cl new file mode 100644 index 000000000..f1c868d47 --- /dev/null +++ b/src/debbuging/tests_ccil/concat_str.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : Main { + out_string("hello".concat("world")) + }; +}; From fbb381d1c1f2c6bedf8419707e43bc280cbe3a80 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 2 Mar 2022 16:27:14 -0500 Subject: [PATCH 368/432] Add copy node and str representation for copy node and type name node --- src/asts/ccil_ast.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index de50f59da..6430551ce 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -427,9 +427,23 @@ def __init__(self) -> None: class CurrentTypeNameNode(ReturnOpNode): - def __init__(self, target: str) -> None: + def __init__(self, target: str, static_type: str) -> None: super().__init__() self.target = target + self.static_type = static_type + + def __str__(self) -> str: + return f"type_name {self.target}" + + +class ShallowCopyOpNode(OperationNode): + def __init__(self, dest: str, source: str) -> None: + super().__init__() + self.dest = dest + self.source = source + + def __str__(self) -> str: + return f"copy {self.dest} {self.source}" class IfNode(FlowControlNode): From baf7a213b5e1333c61f9ec20659a1806a7e61f40 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 2 Mar 2022 16:30:02 -0500 Subject: [PATCH 369/432] Improve copy method in builtin and add static type to current type name node --- src/code_gen/ccil_gen.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 124c5cfec..e125dbc81 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -315,7 +315,9 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: ) # Storing the type of the resulting case expression - expr_type = self.create_type_name(f"case_{times}_expr_type", case_expr_fv.id) + expr_type = self.create_type_name( + f"case_{times}_expr_type", case_expr_fv.id, node.case_expr.type.name + ) # Final label where all branch must jump to final_label = LabelNode(f"case_{times}_end") @@ -330,7 +332,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: pattern_match_ops = self.init_default_values() branch_ops = [] - visited_types = set() # To optimize and reduce redundant calling + visited_types = set() # To optimize and reduce redundant calling for (i, option) in enumerate(node.options): # Initializing the branch var branch_var = self.create_assignation( @@ -354,7 +356,9 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: ) select_branch = StorageNode( equality_holder.id, - EqualStrNode(extract_id(expr_type), extract_id(load_class_name)), + EqualStrNode( + extract_id(expr_type), extract_id(load_class_name) + ), ) # Conditional jump to the right branch label if_op = IfNode(extract_id(select_branch), branch_label) @@ -732,14 +736,19 @@ def define_built_ins(self): "abort", params, self.dump_locals(), [load, print, abort], "self" ) params = self.init_func_params(OBJECT) - get_name = self.create_type_name("get_name", "self") + get_name = self.create_type_name("get_name", "self", OBJECT) type_name_func = FunctionNode( "type_name", params, self.dump_locals(), [get_name], get_name.id ) params = self.init_func_params(OBJECT) - new_instance = self.create_new_type("copy", SELFTYPE) + new_instance = self.create_new_type("shallow_copy", SELFTYPE) + update_instance = ShallowCopyOpNode(new_instance.id, "self") copy_func = FunctionNode( - "copy", params, self.dump_locals(), [new_instance], new_instance.id + "copy", + params, + self.dump_locals(), + [new_instance, update_instance], + new_instance.id, ) object_class = Class( OBJECT, @@ -963,9 +972,9 @@ def create_read_int(self, idx: str): self.add_local(idx, INT) return StorageNode(idx, ReadIntNode()) - def create_type_name(self, idx: str, target: str): + def create_type_name(self, idx: str, target: str, static_type: str): self.add_local(idx, STRING) - return StorageNode(idx, CurrentTypeNameNode(target)) + return StorageNode(idx, CurrentTypeNameNode(target, static_type)) def create_length(self, idx: str, target: str): self.add_local(idx, INT) From c4980dcf0c1fcc5f4cd2ab841efb718cb6bc0468 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 00:40:58 -0500 Subject: [PATCH 370/432] Add more builtin function --- src/code_gen/ccil_mips_gen.py | 233 ++++++++++++++++++++-- src/debbuging/tests_ccil/get_type_name.cl | 9 + src/debbuging/tests_ccil/substring.cl | 5 + 3 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 src/debbuging/tests_ccil/get_type_name.cl create mode 100644 src/debbuging/tests_ccil/substring.cl diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 1d6b1219d..e9e855694 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -36,6 +36,8 @@ def visit(self, node: ccil_ast.CCILProgram): word_directive = [ mips_ast.Label(node, classx.id), mips_ast.Label(node, classx.init_operations.id), + mips_ast.Label(node, f"class_{classx.id}"), + mips_ast.Label(node, self._get_attr_count(classx.id)), ] for method in classx.methods: word_directive.append(mips_ast.Label(node, method.function.id)) @@ -947,9 +949,7 @@ def visit(self, node: ccil_ast.ConcatOpNode): len_b = mips_ast.RegisterNode(node, T3) instructions.append( - mips_ast.LoadWord( - node, string_a, self._get_relative_location(node.source) - ) + mips_ast.LoadWord(node, string_a, self._get_relative_location(node.source)) ) instructions.extend(self._push_stack(node, string_a)) instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, "length"))) @@ -957,9 +957,7 @@ def visit(self, node: ccil_ast.ConcatOpNode): instructions.append(mips_ast.Move(node, len_a, mips_ast.RegisterNode(node, V0))) instructions.append( - mips_ast.LoadWord( - node, string_b, self._get_relative_location(node.target) - ) + mips_ast.LoadWord(node, string_b, self._get_relative_location(node.target)) ) instructions.extend(self._push_stack(node, string_b)) instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, "length"))) @@ -1068,13 +1066,218 @@ def visit(self, node: ccil_ast.ConcatOpNode): return instructions - # @visitor.when(ccil_ast.SubstringOpNode) - # def visit(self, node: ccil_ast.SubstringOpNode): - # instructions = [] - # substring = mips_ast.RegisterNode(node, V0) - # instructions.append() + @visitor.when(ccil_ast.SubstringOpNode) + def visit(self, node: ccil_ast.SubstringOpNode): + instructions = [] + substring = mips_ast.RegisterNode(node, V0) + substring_length = mips_ast.RegisterNode(node, A0) + instructions.append( + mips_ast.LoadWord( + node, substring_length, self._get_relative_location(node.length.value) + ) + ) + instructions.append( + mips_ast.Addi( + node, substring_length, substring_length, mips_ast.Constant(node, 1) + ) + ) + instructions.append( + mips_ast.LoadImmediate(node, substring, mips_ast.Constant(node, 9)) + ) + instructions.append(mips_ast.Syscall(node)) + + char_string = mips_ast.RegisterNode(node, T0) + char_substring = mips_ast.RegisterNode(node, T1) + char = mips_ast.RegisterNode(node, T2) + start = mips_ast.RegisterNode(node, T3) + + loop = self._generate_unique_label() + end = self._generate_unique_label() + + instructions.append(mips_ast.Move(node, char_substring, substring)) + + instructions.append( + mips_ast.LoadWord( + node, char_string, self._get_relative_location(node.target.value) + ) + ) + + instructions.append( + mips_ast.LoadWord( + node, start, self._get_relative_location(node.start.value) + ) + ) + instructions.append(mips_ast.Add(node, char_string, char_string, start)) + instructions.append( + mips_ast.Addi( + node, substring_length, substring_length, mips_ast.Constant(node, -1) + ) + ) + instructions.append(mips_ast.LabelDeclaration(node, loop)) + + zero = mips_ast.RegisterNode(node, ZERO) + instructions.append( + mips_ast.BranchOnEqual( + node, substring_length, zero, mips_ast.Label(node, end) + ) + ) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), char_string), + ) + ) + instructions.append( + mips_ast.StoreByte( + node, + char, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), char_substring + ), + ) + ) + instructions.append( + mips_ast.Addi(node, char_string, char_string, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi( + node, char_substring, char_substring, mips_ast.Constant(node, 1) + ) + ) + instructions.append( + mips_ast.Addi( + node, substring_length, substring_length, mips_ast.Constant(node, -1) + ) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + instructions.append(mips_ast.LabelDeclaration(node, end)) + instructions.append( + mips_ast.StoreByte( + node, + zero, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), char_substring + ), + ) + ) + return instructions + + @visitor.when(ccil_ast.CurrentTypeNameNode) + def visit(self, node: ccil_ast.CurrentTypeNameNode): + instructions = [] + result = mips_ast.RegisterNode(node, V0) - # pass + object = mips_ast.RegisterNode(node, T0) + instructions.append( + mips_ast.LoadWord(node, object, self._get_relative_location(node.target)) + ) + object_type = mips_ast.RegisterNode(node, T1) + + instructions.append( + mips_ast.LoadWord( + node, + object_type, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), object), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + result, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, DOUBLE_WORD), object_type + ), + ) + ) + return instructions + + @visitor.when(ccil_ast.ShallowCopyOpNode) + def visit(self, node: ccil_ast.ShallowCopyOpNode): + instructions = [] + object = mips_ast.RegisterNode(node, T0) + object_type = mips_ast.RegisterNode(node, T1) + attr_total = mips_ast.RegisterNode(node, T2) + + instructions.append( + mips_ast.LoadWord(node, object, self._get_relative_location(node.source)) + ) + instructions.append( + mips_ast.LoadWord( + node, + object_type, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), object), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + attr_total, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, DOUBLE_WORD), object_type + ), + ) + ) + instructions.append( + mips_ast.Addi(node, attr_total, attr_total, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Move(node, mips_ast.RegisterNode(node, A0), attr_total) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) + ) + ) + instructions.append(mips_ast.Syscall(node)) + + object_copy = mips_ast.RegisterNode(node, T3) + section = mips_ast.RegisterNode(node, T4) + zero = mips_ast.RegisterNode(node, ZERO) + loop = self._generate_unique_label() + end = self._generate_unique_label() + + instructions.append( + mips_ast.Move(node, object_copy, mips_ast.RegisterNode(node, V0)) + ) + + instructions.append(mips_ast.LabelDeclaration(node, loop)) + instructions.append( + mips_ast.BranchOnEqual(node, attr_total, zero, mips_ast.Label(node, end)) + ) + instructions.append( + mips_ast.LoadWord( + node, + section, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), object), + ) + ) + instructions.append( + mips_ast.StoreWord( + node, + section, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), object_copy), + ) + ) + instructions.append( + mips_ast.Addi(node, object, object, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, object_copy, object_copy, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, attr_total, attr_total, mips_ast.Constant(node, -1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + + instructions.append(mips_ast.LabelDeclaration(node, end)) + + instructions.append( + mips_ast.StoreWord( + node, object_copy, self._get_relative_location(node.dest) + ) + ) + return instructions def _get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: @@ -1088,20 +1291,20 @@ def _get_attr_count(self, typex: str): for _type in self.__types_table: if _type.id == typex: return len(_type.attributes) - raise Exception("Type declaration not found") + raise Exception(f"Type declaration not found: {typex}") def _get_init_function(self, typex: str): for _type in self.__types_table: if _type.id == typex: return _type.init_operations - raise Exception("Type's function for inicialization not found") + raise Exception(f"Type's function for inicialization not found: {typex}") def _get_method_index(self, typex: str, method: str) -> int: for _type in self.__types_table: if _type.id == typex: for index, _method in enumerate(_type.methods): if _method.id == method: - return index * WORD + DOUBLE_WORD + return index * WORD + WORD + WORD + DOUBLE_WORD raise Exception(f"Method implementation not found:{typex} {method}") diff --git a/src/debbuging/tests_ccil/get_type_name.cl b/src/debbuging/tests_ccil/get_type_name.cl new file mode 100644 index 000000000..17692837a --- /dev/null +++ b/src/debbuging/tests_ccil/get_type_name.cl @@ -0,0 +1,9 @@ +class Main inherits IO { + main(): Main { + out_string((new A).type_name()) + }; +}; + +class A { + +}; diff --git a/src/debbuging/tests_ccil/substring.cl b/src/debbuging/tests_ccil/substring.cl new file mode 100644 index 000000000..7748f108a --- /dev/null +++ b/src/debbuging/tests_ccil/substring.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : Main { + out_string("Hello World".substr(0,5)) + }; +}; From b20fee447ed965ecd0f28b9ee49fb39922869d3e Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 11:02:43 -0500 Subject: [PATCH 371/432] Bug fix where selftype was not being swaped by current type --- src/semantics/inference/back_inferencer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 2deac476e..7ba4296ea 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -244,7 +244,7 @@ def visit(self, node: AssignNode, scope) -> AssignNode: @visitor.when(MethodCallNode) def visit(self, node: MethodCallNode, scope) -> MethodCallNode: - caller_type: Type = node.caller_type.heads[0] + caller_type: Type = node.caller_type.swap_self_type(self.current_type).heads[0] method: Method = caller_type.get_method(node.id) new_args = [] From 1d7b0b0d48bca9ac6cae4ceb78b5e0f62f7906fe Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 12:25:40 -0500 Subject: [PATCH 372/432] Fix ComplementNode visit in types_inferencer --- src/asts/mips_ast.py | 7 +++++++ src/code_gen/mips_gen.py | 5 +++++ src/semantics/inference/types_inferencer.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/asts/mips_ast.py b/src/asts/mips_ast.py index ca36997d7..3fc47c87c 100644 --- a/src/asts/mips_ast.py +++ b/src/asts/mips_ast.py @@ -374,6 +374,13 @@ class AsciizDirective(AssemblerDirective): def __init__(self, node, list) -> None: super().__init__(node, list) +class SpaceDirective(AssemblerDirective): + """ + This node represents `.space` assembler directive + """ + + def __init__(self, node, list) -> None: + super().__init__(node, list) class Syscall(InstructionNode): """ diff --git a/src/code_gen/mips_gen.py b/src/code_gen/mips_gen.py index b41ed59da..a6f439fbe 100644 --- a/src/code_gen/mips_gen.py +++ b/src/code_gen/mips_gen.py @@ -26,6 +26,7 @@ Multiply, Not, RegisterNode, + SpaceDirective, StoreByte, StoreWord, Sub, @@ -105,6 +106,10 @@ def visit(self, node: MemoryIndexNode) -> str: def visit(self, node: WordDirective) -> str: return ".word " + (" ".join(self.visit(i) for i in node.list)) + @visitor.when(SpaceDirective) + def visit(self, node: SpaceDirective) -> str: + return ".space " + (" ".join(self.visit(i) for i in node.list)) + @visitor.when(AsciizDirective) def visit(self, node: AsciizDirective) -> str: return ".asciiz " + (" ".join(f'"{self.visit(i)}"' for i in node.list)) diff --git a/src/semantics/inference/types_inferencer.py b/src/semantics/inference/types_inferencer.py index 589fae26c..cba9cce1a 100644 --- a/src/semantics/inference/types_inferencer.py +++ b/src/semantics/inference/types_inferencer.py @@ -228,7 +228,7 @@ def visit(self, node: NotNode, scope: Scope) -> types_ast.NotNode: @visitor.when(ComplementNode) def visit(self, node: ComplementNode, scope: Scope) -> types_ast.ComplementNode: - expr = self.visit(node.expr) + expr = self.visit(node.expr,scope) new_node = types_ast.ComplementNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node From 778cc3db903207b563c8a54161fb0784a5f04493 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 14:00:06 -0500 Subject: [PATCH 373/432] Builtin types are represented as the rest of the types --- src/code_gen/ccil_mips_gen.py | 637 +++++++++++++++++++++------------- 1 file changed, 400 insertions(+), 237 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index e9e855694..dbeb70dc5 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -21,6 +21,7 @@ def __init__(self) -> None: self.__types_table: List[ccil_ast.Class] = [] self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode + self.buffer_size = 20 @visitor.on("node") def visit(self, node): @@ -55,6 +56,27 @@ def visit(self, node: ccil_ast.CCILProgram): mips_ast.AsciizDirective(node, [mips_ast.Label(node, d.value)]), ) ) + for builtin_type in ("Int", "Bool"): + word_directive = [ + mips_ast.Label(node, builtin_type), + mips_ast.Label(node, builtin_type), + mips_ast.Label(node, f"class_{builtin_type}"), + mips_ast.Label(node, 1), + ] + data.append( + ( + mips_ast.LabelDeclaration(node, builtin_type), + mips_ast.WordDirective(node, word_directive), + ) + ) + data.append( + ( + mips_ast.LabelDeclaration(node, "buffer"), + mips_ast.SpaceDirective( + node, [mips_ast.Constant(node, self.buffer_size)] + ), + ) + ) functions = [] print(node.entry_func) @@ -172,11 +194,33 @@ def visit(self, node: ccil_ast.IdNode): @visitor.when(ccil_ast.IntNode) def visit(self, node: ccil_ast.IntNode): instructions = [] + + v0 = mips_ast.RegisterNode(node, V0) + a0 = mips_ast.RegisterNode(node, A0) + instructions.append( - mips_ast.LoadImmediate( + mips_ast.LoadImmediate(node, a0, mips_ast.Constant(node, 2 * WORD)) + ) + instructions.append( + mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 9)) + ) + instructions.append(mips_ast.Syscall(node)) + t0 = mips_ast.RegisterNode(node, T0) + instructions.append(mips_ast.LoadAddress(node, t0, mips_ast.Label(node, "Int"))) + instructions.append( + mips_ast.StoreWord( + node, t0, mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), v0) + ) + ) + + instructions.append( + mips_ast.LoadImmediate(node, t0, mips_ast.Constant(node, node.value)) + ) + instructions.append( + mips_ast.StoreWord( node, - mips_ast.RegisterNode(node, V0), - mips_ast.Constant(node, node.value), + t0, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), v0), ) ) return instructions @@ -409,39 +453,18 @@ def visit(self, node: ccil_ast.SetAttrOpNode): @visitor.when(ccil_ast.SumOpNode) def visit(self, node: ccil_ast.SumOpNode): instructions = [] + instructions.extend(self._get_operands_value(node)) - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.append( + mips_ast.Add( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") + ) - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Add(node, reg_ret, reg_left, reg_right)) + instructions.extend(self._set_new_int(node)) return instructions @@ -449,38 +472,16 @@ def visit(self, node: ccil_ast.SumOpNode): def visit(self, node: ccil_ast.MinusOpNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.Sub( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Sub(node, reg_ret, reg_left, reg_right)) + ) + instructions.extend(self._set_new_int(node)) return instructions @@ -488,38 +489,16 @@ def visit(self, node: ccil_ast.MinusOpNode): def visit(self, node: ccil_ast.MultOpNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.Multiply( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Multiply(node, reg_ret, reg_left, reg_right)) + ) + instructions.extend(self._set_new_int(node)) return instructions @@ -527,77 +506,30 @@ def visit(self, node: ccil_ast.MultOpNode): def visit(self, node: ccil_ast.DivOpNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.Div( + node, mips_ast.RegisterNode(node, T5), mips_ast.RegisterNode(node, T6) ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Div(node, reg_left, reg_right)) - instructions.append(mips_ast.MoveFromLo(node, reg_ret)) + ) + instructions.append(mips_ast.MoveFromLo(node, mips_ast.RegisterNode(node, T7))) + instructions.extend(self._set_new_int(node)) return instructions @visitor.when(ccil_ast.LessOpNode) def visit(self, node: ccil_ast.LessOpNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.Less( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Less(node, reg_ret, reg_left, reg_right)) + ) + instructions.extend(self._set_new_bool(node)) return instructions @@ -605,77 +537,32 @@ def visit(self, node: ccil_ast.LessOpNode): def visit(self, node: ccil_ast.LessOrEqualOpNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.LessOrEqual( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.LessOrEqual(node, reg_ret, reg_left, reg_right)) - + ) + instructions.extend(self._set_new_bool(node)) return instructions @visitor.when(ccil_ast.EqualIntNode) def visit(self, node: ccil_ast.EqualIntNode): instructions = [] - reg_left = mips_ast.RegisterNode(node, T3) - if isinstance(node.left, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_left, self._get_relative_location(node.left.value) - ) - ) - elif isinstance(node.left, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) - ) - ) - - reg_right = mips_ast.RegisterNode(node, T4) - if isinstance(node.right, ccil_ast.IdNode): - instructions.append( - mips_ast.LoadWord( - node, reg_right, self._get_relative_location(node.right.value) - ) - ) - elif isinstance(node.right, ccil_ast.ConstantNode): - instructions.append( - mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) - ) + instructions.extend(self._get_operands_value(node)) + instructions.append( + mips_ast.Equal( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), ) - else: - raise Exception("Invalid type of ccil node") - - reg_ret = mips_ast.RegisterNode(node, V0) - instructions.append(mips_ast.Equal(node, reg_ret, reg_left, reg_right)) + ) + instructions.extend(self._set_new_bool(node)) return instructions @@ -683,20 +570,31 @@ def visit(self, node: ccil_ast.EqualIntNode): def visit(self, node: ccil_ast.NotOpNode): instructions = [] - reg = mips_ast.RegisterNode(node, V0) + value = mips_ast.RegisterNode(node, T7) if isinstance(node.atom, ccil_ast.IntNode): instructions.append( mips_ast.LoadImmediate( - node, reg, mips_ast.Constant(node, node.atom.value) + node, value, mips_ast.Constant(node, node.atom.value) ) ) elif isinstance(node.atom, ccil_ast.IdNode): + object = mips_ast.RegisterNode(node, T0) + instructions.append( + mips_ast.LoadWord( + node, object, self._get_relative_location(node.atom.value) + ) + ) instructions.append( mips_ast.LoadWord( - node, reg, self._get_relative_location(node.atom.value) + node, + value, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), object + ), ) ) - instructions.append(mips_ast.Not(node, reg, reg)) + instructions.append(mips_ast.Not(node, value, value)) + instructions.extend(self._set_new_bool(node)) return instructions @@ -704,20 +602,33 @@ def visit(self, node: ccil_ast.NotOpNode): def visit(self, node: ccil_ast.NegOpNode): instructions = [] - reg = mips_ast.RegisterNode(node, V0) + value = mips_ast.RegisterNode(node, T7) if isinstance(node.atom, ccil_ast.IntNode): instructions.append( mips_ast.LoadImmediate( - node, reg, mips_ast.Constant(node, node.atom.value) + node, value, mips_ast.Constant(node, node.atom.value) ) ) elif isinstance(node.atom, ccil_ast.IdNode): + object = mips_ast.RegisterNode(node, T0) instructions.append( mips_ast.LoadWord( - node, reg, self._get_relative_location(node.atom.value) + node, object, self._get_relative_location(node.atom.value) ) ) - instructions.append(mips_ast.Xori(node, reg, reg, mips_ast.Constant(node, "1"))) + instructions.append( + mips_ast.LoadWord( + node, + value, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), object + ), + ) + ) + instructions.append( + mips_ast.Xori(node, value, value, mips_ast.Constant(node, "1")) + ) + instructions.extend(self._set_new_int(node)) return instructions @@ -726,9 +637,10 @@ def visit(self, node: ccil_ast.LoadOpNode): instructions = [] instructions.append( mips_ast.LoadAddress( - node, mips_ast.RegisterNode(node, V0), mips_ast.Label(node, node.target) + node, mips_ast.RegisterNode(node, T7), mips_ast.Label(node, node.target) ) ) + instructions.extend(self._set_new_string(node)) return instructions @@ -742,16 +654,21 @@ def visit(self, node: ccil_ast.IfFalseNode): self._get_relative_location(node.eval_value.value), ) ) + instructions.append( - mips_ast.LoadImmediate( - node, mips_ast.RegisterNode(node, T1), mips_ast.Constant(node, 0) + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T1), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, T0) + ), ) ) instructions.append( mips_ast.BranchOnEqual( node, mips_ast.RegisterNode(node, T1), - mips_ast.RegisterNode(node, T0), + mips_ast.RegisterNode(node, ZERO), mips_ast.Label(node, node.target.id), ) ) @@ -772,13 +689,21 @@ def visit(self, node: ccil_ast.LabelNode): @visitor.when(ccil_ast.PrintIntNode) def visit(self, node: ccil_ast.PrintIntNode): instructions = [] + a0 = mips_ast.RegisterNode(node, A0) instructions.append( mips_ast.LoadWord( node, - mips_ast.RegisterNode(node, A0), + a0, self._get_relative_location(node.id), ) ) + instructions.append( + mips_ast.LoadWord( + node, + a0, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), a0), + ) + ) instructions.append( mips_ast.LoadImmediate( @@ -791,13 +716,21 @@ def visit(self, node: ccil_ast.PrintIntNode): @visitor.when(ccil_ast.PrintStrNode) def visit(self, node: ccil_ast.PrintStrNode): instructions = [] + a0 = mips_ast.RegisterNode(node, A0) instructions.append( mips_ast.LoadWord( node, - mips_ast.RegisterNode(node, A0), + a0, self._get_relative_location(node.id), ) ) + instructions.append( + mips_ast.LoadWord( + node, + a0, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), a0), + ) + ) instructions.append( mips_ast.LoadImmediate( @@ -830,7 +763,7 @@ def visit(self, node: ccil_ast.Abort): @visitor.when(ccil_ast.LengthOpNode) def visit(self, node: ccil_ast.LengthOpNode): instructions = [] - count = mips_ast.RegisterNode(node, V0) + count = mips_ast.RegisterNode(node, T7) instructions.append( mips_ast.LoadImmediate(node, count, mips_ast.Constant(node, 0)) ) @@ -838,6 +771,13 @@ def visit(self, node: ccil_ast.LengthOpNode): instructions.append( mips_ast.LoadWord(node, string, self._get_relative_location(node.target)) ) + instructions.append( + mips_ast.LoadWord( + node, + string, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), string), + ) + ) loop = self._generate_unique_label() instructions.append(mips_ast.LabelDeclaration(node, loop)) @@ -863,6 +803,7 @@ def visit(self, node: ccil_ast.LengthOpNode): ) instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) instructions.append(mips_ast.LabelDeclaration(node, exit)) + instructions.extend(self._set_new_int(node)) return instructions @visitor.when(ccil_ast.EqualStrNode) @@ -876,11 +817,30 @@ def visit(self, node: ccil_ast.EqualStrNode): node, left_string, self._get_relative_location(node.left.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + left_string, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), left_string + ), + ) + ) instructions.append( mips_ast.LoadWord( node, right_string, self._get_relative_location(node.right.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + right_string, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), right_string + ), + ) + ) + left_char = mips_ast.RegisterNode(node, T2) right_char = mips_ast.RegisterNode(node, T3) loop = self._generate_unique_label() @@ -926,7 +886,7 @@ def visit(self, node: ccil_ast.EqualStrNode): instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) end = self._generate_unique_label() - result = mips_ast.RegisterNode(node, V0) + result = mips_ast.RegisterNode(node, T7) instructions.append(mips_ast.LabelDeclaration(node, equals_end)) instructions.append( mips_ast.LoadImmediate(node, result, mips_ast.Constant(node, 1)) @@ -937,6 +897,7 @@ def visit(self, node: ccil_ast.EqualStrNode): mips_ast.LoadImmediate(node, result, mips_ast.Constant(node, 0)) ) instructions.append(mips_ast.LabelDeclaration(node, end)) + instructions.extend(self._set_new_bool(node)) return instructions @visitor.when(ccil_ast.ConcatOpNode) @@ -965,6 +926,21 @@ def visit(self, node: ccil_ast.ConcatOpNode): instructions.append(mips_ast.Move(node, len_b, mips_ast.RegisterNode(node, V0))) + instructions.append( + mips_ast.LoadWord( + node, + len_b, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), len_b), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + len_a, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), len_a), + ) + ) + instructions.append( mips_ast.Add(node, mips_ast.RegisterNode(node, A0), len_a, len_b) ) @@ -988,6 +964,21 @@ def visit(self, node: ccil_ast.ConcatOpNode): char = mips_ast.RegisterNode(node, T5) instructions.append(mips_ast.Move(node, concat_char, concat_string)) + instructions.append( + mips_ast.LoadWord( + node, + string_b, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), string_b), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + string_a, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), string_a), + ) + ) + loop_string_a = self._generate_unique_label() end_loop_string_a = self._generate_unique_label() instructions.append(mips_ast.LabelDeclaration(node, loop_string_a)) @@ -1063,6 +1054,12 @@ def visit(self, node: ccil_ast.ConcatOpNode): mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), concat_char), ) ) + instructions.append( + mips_ast.Move( + node, mips_ast.RegisterNode(node, T7), mips_ast.RegisterNode(node, V0) + ) + ) + instructions.extend(self._set_new_string(node)) return instructions @@ -1076,6 +1073,15 @@ def visit(self, node: ccil_ast.SubstringOpNode): node, substring_length, self._get_relative_location(node.length.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + substring_length, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), substring_length + ), + ) + ) instructions.append( mips_ast.Addi( node, substring_length, substring_length, mips_ast.Constant(node, 1) @@ -1101,12 +1107,30 @@ def visit(self, node: ccil_ast.SubstringOpNode): node, char_string, self._get_relative_location(node.target.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + char_string, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), char_string + ), + ) + ) instructions.append( mips_ast.LoadWord( node, start, self._get_relative_location(node.start.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + start, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), start + ), + ) + ) instructions.append(mips_ast.Add(node, char_string, char_string, start)) instructions.append( mips_ast.Addi( @@ -1161,6 +1185,12 @@ def visit(self, node: ccil_ast.SubstringOpNode): ), ) ) + instructions.append( + mips_ast.Move( + node, mips_ast.RegisterNode(node, T7), mips_ast.RegisterNode(node, V0) + ) + ) + instructions.extend(self._set_new_string(node)) return instructions @visitor.when(ccil_ast.CurrentTypeNameNode) @@ -1279,6 +1309,11 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): ) return instructions + @visitor.when(ccil_ast.ReadStrNode) + def visit(self, node: ccil_ast.ReadStrNode): + instructions = [] + return instructions + def _get_attr_index(self, typex: str, attr: str): for _type in self.__types_table: if _type.id == typex: @@ -1366,3 +1401,131 @@ def _pop_stack(self, node, register: mips_ast.RegisterNode): ) ) return instructions + + def _get_operands_value(self, node): + + instructions = [] + + left_value = mips_ast.RegisterNode(node, T5) + reg_left = mips_ast.RegisterNode(node, T3) + if isinstance(node.left, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord( + node, reg_left, self._get_relative_location(node.left.value) + ) + ) + elif isinstance(node.left, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg_left, mips_ast.Constant(node, node.left.value) + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + left_value, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), reg_left), + ) + ) + + right_value = mips_ast.RegisterNode(node, T6) + reg_right = mips_ast.RegisterNode(node, T4) + if isinstance(node.right, ccil_ast.IdNode): + instructions.append( + mips_ast.LoadWord( + node, reg_right, self._get_relative_location(node.right.value) + ) + ) + elif isinstance(node.right, ccil_ast.ConstantNode): + instructions.append( + mips_ast.LoadImmediate( + node, reg_right, mips_ast.Constant(node, node.right.value) + ) + ) + else: + raise Exception("Invalid type of ccil node") + instructions.append( + mips_ast.LoadWord( + node, + right_value, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), reg_right + ), + ) + ) + return instructions + + def _set_new_int(self, node): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, A0), mips_ast.Constant(node, 2 * WORD) + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) + ) + ) + instructions.append(mips_ast.Syscall(node)) + + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, V0) + ), + ) + ) + return instructions + + def _set_new_bool(self, node): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, A0), mips_ast.Constant(node, 2 * WORD) + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) + ) + ) + instructions.append(mips_ast.Syscall(node)) + + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, V0) + ), + ) + ) + return instructions + + def _set_new_string(self, node): + instructions = [] + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, A0), mips_ast.Constant(node, 2 * WORD) + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) + ) + ) + instructions.append(mips_ast.Syscall(node)) + + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, V0) + ), + ) + ) + return instructions From 213d1915f63be2f3074a3f6301d67e64c017893c Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 14:48:13 -0500 Subject: [PATCH 374/432] Add bool type to ccil --- src/code_gen/ccil_gen.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index e125dbc81..5e57cb36e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -515,7 +515,7 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: f"Pattern match failure visiting binary expression with {type(node).__name__}" ) - fval = self.create_storage(fval_id, node.type.name, op) + fval = self.create_storage(fval_id, BOOL, op) return ([*left_ops, *right_ops, fval], fval) @visitor.when(sem_ast.UnaryNode) @@ -536,7 +536,7 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: f"Redundant isVoid expression in {node.line}, {node.col}." f" Type {node.expr.type.name} will always evaluate to false" ) - op = IntNode("0") + op = BoolNode("0") else: op = EqualIntNode(IdNode(fval_id), IntNode("0")) elif node_type == sem_ast.NotNode: @@ -684,7 +684,7 @@ def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: bool_id = f"bool_{times}" value = "0" if node.value == "false" else "1" - bool_node = self.create_int(bool_id, value) + bool_node = self.create_bool(bool_id, value) return [bool_node], bool_node def create_class_init_func( @@ -960,6 +960,10 @@ def create_int(self, idx: str, value: str): self.add_local(idx, INT) return StorageNode(idx, IntNode(value)) + def create_bool(self, idx: str, value: str): + self.add_local(idx, BOOL) + return StorageNode(idx, BoolNode(value)) + def create_int_to_str(self, idx: str, target: str): self.add_local(str, STRING) return StorageNode(idx, StrOpNode(target)) From 4743d4e0d76b41deb384028cca866b35b3e242c4 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 15:18:53 -0500 Subject: [PATCH 375/432] Add Bool node --- src/asts/ccil_ast.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index 6430551ce..e65324334 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -417,6 +417,11 @@ def __init__(self, value: str) -> None: super().__init__(value) +class BoolNode(ConstantNode): + def __init__(self, value: str) -> None: + super().__init__(value) + + class FlowControlNode(OperationNode): """ Base class for all flow control operations like If, Label, goto, etc... From 7990bd7dd67383e7e8b828e8a4bb4ed411d11795 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 16:10:17 -0500 Subject: [PATCH 376/432] Add Int and Bool builtins. Box Int, String and Bool primitive data types --- src/code_gen/ccil_gen.py | 57 ++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5e57cb36e..24ea6d647 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -71,8 +71,10 @@ def visit(self, node: sem_ast.ProgramNode) -> None: self.data = [DEFAULT_STR] self.reset_locals() - [obj, io, str], builtin_methods = self.define_built_ins() - self.program_types = OrderedDict({OBJECT: obj, IO: io, STRING: str}) + [obj, io, str, int, bool], builtin_methods = self.define_built_ins() + self.program_types = OrderedDict( + {OBJECT: obj, IO: io, STRING: str, INT: int, BOOL: bool} + ) self.program_codes: List[FunctionNode] = builtin_methods for builtin_name in [OBJECT, IO, STRING, INT, BOOL]: @@ -696,7 +698,7 @@ def create_class_init_func( self.reset_scope() init_params = self.init_func_params(node.id) - self.ccil_cool_names.add_new_name_pair("self", node.id) + # self.ccil_cool_names.add_new_name_pair("self", node.id) # First operation, initalizing parent attributes init_parent = self.create_call( @@ -720,7 +722,7 @@ def create_class_init_func( return FunctionNode( f"init_{node.id}", init_params, - to_vars(self.locals, Local), + self.dump_locals(), init_attr_ops, dummy_return.id, ) @@ -758,7 +760,7 @@ def define_built_ins(self): Method("type_name", type_name_func), Method("copy", copy_func), ], - self.define_empty_init_func(OBJECT), + self.define_builtin_init_func(OBJECT), ) # Defining IO class methods @@ -797,7 +799,7 @@ def define_built_ins(self): Method("in_string", in_string_func), Method("in_int", in_int_func), ], - self.define_empty_init_func(IO), + self.define_builtin_init_func(IO), ) # Defining substring class methods @@ -864,19 +866,30 @@ def define_built_ins(self): substr_func = FunctionNode( "substr", params, self.dump_locals(), operations, substr.id ) + attributes = [Attribute("value", STRING, "value")] string_class = Class( STRING, - [], + attributes, [ *object_class.methods, Method("length", lenght_func), Method("concat", concat_func), Method("substr", substr_func), ], - self.define_empty_init_func(STRING), + self.define_builtin_init_func(STRING, attributes), + ) + + attributes = [Attribute("value", INT, "value")] + int_class = Class( + INT, attributes, [], self.define_builtin_init_func(INT, attributes) + ) + + attributes = [Attribute("value", BOOL, "value")] + bool_class = Class( + BOOL, attributes, [], self.define_builtin_init_func(BOOL, attributes) ) - return [object_class, io_class, string_class], [ + return [object_class, io_class, string_class, int_class, bool_class], [ abort_func, type_name_func, copy_func, @@ -1006,16 +1019,38 @@ def define_entry_func(self): "main", [], self.dump_locals(), [program, execute], execute.id ) - def define_empty_init_func(self, class_name: str): + def define_builtin_init_func( + self, class_name: str, attributes: List[Attribute] = [] + ): + self.reset_locals() params = self.init_func_params(class_name) dummy_return = self.create_storage( f"init_type_{class_name}_ret", INT, IntNode(0) ) + + set_default_ops: List[OperationNode] = self.init_default_values() + string_default = int_default = False + for attr in attributes: + if attr.type == STRING: + value = IdNode(EMPTY) + string_default = True + else: + value = IdNode(ZERO) + int_default = True + set_default_ops.append(SetAttrOpNode("self", attr.id, value, class_name)) + + if not string_default: + set_default_ops.pop(1) + del self.locals[EMPTY] + if not int_default: + set_default_ops.pop(0) + del self.locals[ZERO] + return FunctionNode( f"init_{class_name}", params, self.dump_locals(), - [dummy_return], + [*set_default_ops, dummy_return], dummy_return.id, ) From 4d5c0cb2af6f47ce4746208a15ad88f793698cdf Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 16:10:44 -0500 Subject: [PATCH 377/432] Update CCIL Program string representation --- src/asts/ccil_ast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index e65324334..b213945dc 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -18,7 +18,7 @@ def __str__(self, all=True) -> str: types_section = self.types_section code_section = self.code_section if not all: - types_section = self.types_section[3:] + types_section = self.types_section[5:] code_section = self.code_section[10:] ident = "\t" @@ -39,7 +39,7 @@ class Class: methods: List[Method] init_operations: FunctionNode - def __str__(self, all=False) -> str: + def __str__(self, all=True) -> str: ident = "\t\t" attributes = "\n".join(ident + str(a) for a in self.attributes) methods = "\n".join(ident + str(m) for m in self.methods) From b7d461b3089d3ca13e1684dfe08c7e5a69b892c9 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 16:40:36 -0500 Subject: [PATCH 378/432] Add read_str builtin --- src/asts/parser_ast.py | 6 -- src/code_gen/ccil_mips_gen.py | 156 ++++++++++++++++++++++++++++++++-- 2 files changed, 151 insertions(+), 11 deletions(-) diff --git a/src/asts/parser_ast.py b/src/asts/parser_ast.py index 56bc3f740..7b1bb41e8 100644 --- a/src/asts/parser_ast.py +++ b/src/asts/parser_ast.py @@ -67,12 +67,6 @@ def __init__(self, idx, typex, expression=None): self.type = typex self.expr = expression -class ParamNode(ExpressionNode): - def __init__(self, idx, typex): - Node.__init__(self) - self.id = idx - self.type = typex - class AssignNode(ExpressionNode): def __init__(self, idx, expr): diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index dbeb70dc5..265f801c1 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -21,7 +21,7 @@ def __init__(self) -> None: self.__types_table: List[ccil_ast.Class] = [] self.__location: Location = {} self.__current_function: ccil_ast.FunctionNode - self.buffer_size = 20 + self.buffer_size = 1000 @visitor.on("node") def visit(self, node): @@ -748,6 +748,13 @@ def visit(self, node: ccil_ast.ReadIntNode): node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 5) ) ) + instructions.append(mips_ast.Syscall(node)) + instructions.append( + mips_ast.Move( + node, mips_ast.RegisterNode(node, T7), mips_ast.RegisterNode(node, V0) + ) + ) + instructions.extend(self._set_new_int(node)) return instructions @visitor.when(ccil_ast.Abort) @@ -1126,9 +1133,7 @@ def visit(self, node: ccil_ast.SubstringOpNode): mips_ast.LoadWord( node, start, - mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, WORD), start - ), + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), start), ) ) instructions.append(mips_ast.Add(node, char_string, char_string, start)) @@ -1196,7 +1201,7 @@ def visit(self, node: ccil_ast.SubstringOpNode): @visitor.when(ccil_ast.CurrentTypeNameNode) def visit(self, node: ccil_ast.CurrentTypeNameNode): instructions = [] - result = mips_ast.RegisterNode(node, V0) + result = mips_ast.RegisterNode(node, T7) object = mips_ast.RegisterNode(node, T0) instructions.append( @@ -1220,6 +1225,7 @@ def visit(self, node: ccil_ast.CurrentTypeNameNode): ), ) ) + instructions.extend(self._set_new_string(node)) return instructions @visitor.when(ccil_ast.ShallowCopyOpNode) @@ -1312,6 +1318,102 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): @visitor.when(ccil_ast.ReadStrNode) def visit(self, node: ccil_ast.ReadStrNode): instructions = [] + + a0 = mips_ast.RegisterNode(node, A0) + a1 = mips_ast.RegisterNode(node, A1) + v0 = mips_ast.RegisterNode(node, V0) + t7 = mips_ast.RegisterNode(node, T7) + instructions.append( + mips_ast.LoadAddress(node, a0, mips_ast.Label(node, "buffer")) + ) + instructions.append( + mips_ast.LoadImmediate(node, a1, mips_ast.Constant(node, self.buffer_size)) + ) + instructions.append( + mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 8)) + ) + instructions.append(mips_ast.Syscall(node)) + instructions.append( + mips_ast.LoadAddress(node, t7, mips_ast.Label(node, "buffer")) + ) + instructions.extend(self._set_new_string(node)) + + instructions.extend(self._push_stack(node, v0)) + instructions.append(mips_ast.JumpAndLink(node, mips_ast.Label(node, "length"))) + instructions.extend(self._pop_stack(node, a0)) + + instructions.append( + mips_ast.LoadWord( + node, + a0, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), v0), + ) + ) + # instructions.append(mips_ast.Addi(node, a0, a0, mips_ast.Constant(node, 1))) + instructions.append( + mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 9)) + ) + instructions.append(mips_ast.Syscall(node)) + + char = mips_ast.RegisterNode(node, T0) + string = mips_ast.RegisterNode(node, T1) + buffer_string = mips_ast.RegisterNode(node, T2) + buffer_char = mips_ast.RegisterNode(node, T3) + string_char = mips_ast.RegisterNode(node, T4) + zero = mips_ast.RegisterNode(node, ZERO) + instructions.append(mips_ast.Move(node, string, v0)) + instructions.append( + mips_ast.LoadAddress(node, buffer_string, mips_ast.Label(node, "buffer")) + ) + instructions.append(mips_ast.Move(node, buffer_char, buffer_string)) + instructions.append(mips_ast.Move(node, string_char, string)) + + loop = self._generate_unique_label() + end = self._generate_unique_label() + + instructions.append(mips_ast.LabelDeclaration(node, loop)) + instructions.append( + mips_ast.LoadByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), buffer_char), + ) + ) + instructions.append( + mips_ast.StoreByte( + node, + char, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string_char), + ) + ) + new_line = mips_ast.RegisterNode(node, T9) + instructions.append( + mips_ast.LoadImmediate(node, new_line, mips_ast.Constant(node, 10)) + ) + instructions.append( + mips_ast.BranchOnEqual(node, char, new_line, mips_ast.Label(node, end)) + ) + + instructions.append( + mips_ast.Addi(node, buffer_char, buffer_char, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Addi(node, string_char, string_char, mips_ast.Constant(node, 1)) + ) + instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) + instructions.append(mips_ast.LabelDeclaration(node, end)) + + instructions.append( + mips_ast.StoreByte( + node, + zero, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), string_char), + ) + ) + + instructions.append(mips_ast.Move(node, t7, string)) + instructions.extend(self._set_new_string(node)) + return instructions def _get_attr_index(self, typex: str, attr: str): @@ -1468,6 +1570,21 @@ def _set_new_int(self, node): ) ) instructions.append(mips_ast.Syscall(node)) + instructions.append( + mips_ast.LoadAddress( + node, mips_ast.RegisterNode(node, T8), mips_ast.Label(node, "Int") + ) + ) + + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T8), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), mips_ast.RegisterNode(node, V0) + ), + ) + ) instructions.append( mips_ast.StoreWord( @@ -1493,6 +1610,21 @@ def _set_new_bool(self, node): ) ) instructions.append(mips_ast.Syscall(node)) + instructions.append( + mips_ast.LoadAddress( + node, mips_ast.RegisterNode(node, T8), mips_ast.Label(node, "Bool") + ) + ) + + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T8), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), mips_ast.RegisterNode(node, V0) + ), + ) + ) instructions.append( mips_ast.StoreWord( @@ -1518,7 +1650,21 @@ def _set_new_string(self, node): ) ) instructions.append(mips_ast.Syscall(node)) + instructions.append( + mips_ast.LoadAddress( + node, mips_ast.RegisterNode(node, T8), mips_ast.Label(node, "String") + ) + ) + instructions.append( + mips_ast.StoreWord( + node, + mips_ast.RegisterNode(node, T8), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 0), mips_ast.RegisterNode(node, V0) + ), + ) + ) instructions.append( mips_ast.StoreWord( node, From b4a58791ef9a6c5b11c547964ac7c1c79a884f13 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 17:09:01 -0500 Subject: [PATCH 379/432] Add BoolNode to ccil_mips_gen visitor --- src/code_gen/ccil_mips_gen.py | 52 ++++++++++------------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 265f801c1..a9fa277c9 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -56,19 +56,6 @@ def visit(self, node: ccil_ast.CCILProgram): mips_ast.AsciizDirective(node, [mips_ast.Label(node, d.value)]), ) ) - for builtin_type in ("Int", "Bool"): - word_directive = [ - mips_ast.Label(node, builtin_type), - mips_ast.Label(node, builtin_type), - mips_ast.Label(node, f"class_{builtin_type}"), - mips_ast.Label(node, 1), - ] - data.append( - ( - mips_ast.LabelDeclaration(node, builtin_type), - mips_ast.WordDirective(node, word_directive), - ) - ) data.append( ( mips_ast.LabelDeclaration(node, "buffer"), @@ -191,38 +178,27 @@ def visit(self, node: ccil_ast.IdNode): ) return instructions - @visitor.when(ccil_ast.IntNode) - def visit(self, node: ccil_ast.IntNode): + @visitor.when(ccil_ast.BoolNode) + def visit(self, node: ccil_ast.BoolNode): instructions = [] - v0 = mips_ast.RegisterNode(node, V0) - a0 = mips_ast.RegisterNode(node, A0) - - instructions.append( - mips_ast.LoadImmediate(node, a0, mips_ast.Constant(node, 2 * WORD)) - ) - instructions.append( - mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 9)) - ) - instructions.append(mips_ast.Syscall(node)) - t0 = mips_ast.RegisterNode(node, T0) - instructions.append(mips_ast.LoadAddress(node, t0, mips_ast.Label(node, "Int"))) + t7 = mips_ast.RegisterNode(node, T7) instructions.append( - mips_ast.StoreWord( - node, t0, mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), v0) - ) + mips_ast.LoadImmediate(node, t7, mips_ast.Constant(node, node.value)) ) + instructions.extend(self._set_new_bool(node)) + return instructions + + @visitor.when(ccil_ast.IntNode) + def visit(self, node: ccil_ast.IntNode): + instructions = [] + + t7 = mips_ast.RegisterNode(node, T7) instructions.append( - mips_ast.LoadImmediate(node, t0, mips_ast.Constant(node, node.value)) - ) - instructions.append( - mips_ast.StoreWord( - node, - t0, - mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), v0), - ) + mips_ast.LoadImmediate(node, t7, mips_ast.Constant(node, node.value)) ) + instructions.extend(self._set_new_int(node)) return instructions @visitor.when(ccil_ast.CallOpNode) From 362ea43855226f44e24e94c1412dd819bb0ee8fd Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 17:38:40 -0500 Subject: [PATCH 380/432] Bug fix, storing equality result as Int instead of Bool --- src/code_gen/ccil_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 24ea6d647..44e4bf9fa 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -829,10 +829,10 @@ def define_built_ins(self): "max_take", INT, SumOpNode(IdNode(start_index.id), IdNode(take.id)) ) upper_bound = self.create_storage( - "upper_bound", INT, LessOpNode(extract_id(length), extract_id(max_take)) + "upper_bound", BOOL, LessOpNode(extract_id(length), extract_id(max_take)) ) lesser_bound = self.create_storage( - "lesser_bound", INT, LessOpNode(IdNode(start_index.id), IntNode("0")) + "lesser_bound", BOOL, LessOpNode(IdNode(start_index.id), IntNode("0")) ) error_label = LabelNode("substring_error") ok_label = LabelNode("substring_success") From 6edfa20907b2df740df720fa14407e9538775b36 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 17:48:24 -0500 Subject: [PATCH 381/432] Fix operands type in binary operations --- src/code_gen/ccil_mips_gen.py | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index a9fa277c9..04db21a07 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -741,6 +741,7 @@ def visit(self, node: ccil_ast.Abort): node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 10) ) ) + instructions.append(mips_ast.Syscall(node)) return instructions @visitor.when(ccil_ast.LengthOpNode) @@ -1492,19 +1493,19 @@ def _get_operands_value(self, node): node, reg_left, self._get_relative_location(node.left.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + left_value, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), reg_left), + ) + ) elif isinstance(node.left, ccil_ast.ConstantNode): instructions.append( mips_ast.LoadImmediate( - node, reg_left, mips_ast.Constant(node, node.left.value) + node, left_value, mips_ast.Constant(node, node.left.value) ) ) - instructions.append( - mips_ast.LoadWord( - node, - left_value, - mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), reg_left), - ) - ) right_value = mips_ast.RegisterNode(node, T6) reg_right = mips_ast.RegisterNode(node, T4) @@ -1514,23 +1515,23 @@ def _get_operands_value(self, node): node, reg_right, self._get_relative_location(node.right.value) ) ) + instructions.append( + mips_ast.LoadWord( + node, + right_value, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), reg_right + ), + ) + ) elif isinstance(node.right, ccil_ast.ConstantNode): instructions.append( mips_ast.LoadImmediate( - node, reg_right, mips_ast.Constant(node, node.right.value) + node, right_value, mips_ast.Constant(node, node.right.value) ) ) else: raise Exception("Invalid type of ccil node") - instructions.append( - mips_ast.LoadWord( - node, - right_value, - mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, WORD), reg_right - ), - ) - ) return instructions def _set_new_int(self, node): From e7b4a6d7cb9ed8b9a426c721bc6ce1039c1f8289 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 18:25:32 -0500 Subject: [PATCH 382/432] Fix shallow_copy builtin function --- src/code_gen/ccil_mips_gen.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 04db21a07..ea1594759 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1227,13 +1227,18 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): node, attr_total, mips_ast.MemoryIndexNode( - node, mips_ast.Constant(node, DOUBLE_WORD), object_type + node, mips_ast.Constant(node, 3 * WORD), object_type ), ) ) instructions.append( mips_ast.Addi(node, attr_total, attr_total, mips_ast.Constant(node, 1)) ) + instructions.append( + mips_ast.Multiply( + node, attr_total, attr_total, mips_ast.Constant(node, WORD) + ) + ) instructions.append( mips_ast.Move(node, mips_ast.RegisterNode(node, A0), attr_total) ) @@ -1273,13 +1278,15 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): ) ) instructions.append( - mips_ast.Addi(node, object, object, mips_ast.Constant(node, 1)) + mips_ast.Addi(node, object, object, mips_ast.Constant(node, WORD)) ) instructions.append( - mips_ast.Addi(node, object_copy, object_copy, mips_ast.Constant(node, 1)) + mips_ast.Addi(node, object_copy, object_copy, mips_ast.Constant(node, WORD)) ) instructions.append( - mips_ast.Addi(node, attr_total, attr_total, mips_ast.Constant(node, -1)) + mips_ast.Addi( + node, attr_total, attr_total, mips_ast.Constant(node, -1 * WORD) + ) ) instructions.append(mips_ast.Jump(node, mips_ast.Label(node, loop))) @@ -1287,7 +1294,7 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): instructions.append( mips_ast.StoreWord( - node, object_copy, self._get_relative_location(node.dest) + node, mips_ast.RegisterNode(node, V0), self._get_relative_location(node.dest) ) ) return instructions @@ -1497,7 +1504,9 @@ def _get_operands_value(self, node): mips_ast.LoadWord( node, left_value, - mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), reg_left), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), reg_left + ), ) ) elif isinstance(node.left, ccil_ast.ConstantNode): From 055c56de77904c691a77d814d92fee086f33f8cf Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 18:49:38 -0500 Subject: [PATCH 383/432] Add object methods to bool and int class --- src/code_gen/ccil_gen.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 44e4bf9fa..84a5c16a9 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -881,12 +881,18 @@ def define_built_ins(self): attributes = [Attribute("value", INT, "value")] int_class = Class( - INT, attributes, [], self.define_builtin_init_func(INT, attributes) + INT, + attributes, + object_class.methods, + self.define_builtin_init_func(INT, attributes), ) attributes = [Attribute("value", BOOL, "value")] bool_class = Class( - BOOL, attributes, [], self.define_builtin_init_func(BOOL, attributes) + BOOL, + attributes, + object_class.methods, + self.define_builtin_init_func(BOOL, attributes), ) return [object_class, io_class, string_class, int_class, bool_class], [ From 6ce885e397d9061dac39e5401b52f24bf6a7e5a9 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 18:52:40 -0500 Subject: [PATCH 384/432] Add selftype.cl test --- src/debbuging/tests_ccil/selftype.cl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/debbuging/tests_ccil/selftype.cl diff --git a/src/debbuging/tests_ccil/selftype.cl b/src/debbuging/tests_ccil/selftype.cl new file mode 100644 index 000000000..3beea0c2c --- /dev/null +++ b/src/debbuging/tests_ccil/selftype.cl @@ -0,0 +1,18 @@ +class Main inherits IO { + a : A ; + main(): Object + { + { + a <- (new B).f(); + out_string(a.type_name()); + + } + + }; +}; + +class A { f() : SELF_TYPE { new SELF_TYPE }; }; + +class B inherits A { }; + +class C inherits B { }; From 2e1834efe663afa37a7b4b41738dda0114e5fb47 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 19:00:01 -0500 Subject: [PATCH 385/432] Swap declared method selftype for current type, swap back when finnish --- src/semantics/inference/back_inferencer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 7ba4296ea..90f9d97ee 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -112,9 +112,10 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: new_body_node = self.visit(node.body, scope) body_type = new_body_node.inferenced_type.swap_self_type(self.current_type) new_node = MethodDeclarationNode(new_params, node.type, new_body_node, node) - decl_type = node.inferenced_type + decl_type = node.inferenced_type.clone().swap_self_type(self.current_type) body_type = new_body_node.inferenced_type new_node.inferenced_type, changed = unify(decl_type, body_type) + new_node.inferenced_type.swap_self_type(self.current_type, back=True) self.changed |= changed return new_node From 5b528f4baa85a757535c2b7a9ae48cd4986fff10 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 19:32:20 -0500 Subject: [PATCH 386/432] Fix bool transaltion value --- src/code_gen/ccil_gen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 84a5c16a9..65dff3def 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -683,8 +683,9 @@ def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: times = self.times(node) + print(node.value) bool_id = f"bool_{times}" - value = "0" if node.value == "false" else "1" + value = "1" if node.value else "0" bool_node = self.create_bool(bool_id, value) return [bool_node], bool_node From e95b44723155576bbcf0563299acb74be7a9fe75 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 19:53:21 -0500 Subject: [PATCH 387/432] Add IfNode visit in ccil_mips_gen --- src/code_gen/ccil_mips_gen.py | 39 ++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index ea1594759..f64fa7922 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -650,6 +650,41 @@ def visit(self, node: ccil_ast.IfFalseNode): ) return instructions + @visitor.when(ccil_ast.IfNode) + def visit(self, node: ccil_ast.IfFalseNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T0), + self._get_relative_location(node.eval_value.value), + ) + ) + + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T1), + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, WORD), mips_ast.RegisterNode(node, T0) + ), + ) + ) + instructions.append( + mips_ast.LoadImmediate( + node, mips_ast.RegisterNode(node, T2), mips_ast.Constant(node, 1) + ) + ) + instructions.append( + mips_ast.BranchOnEqual( + node, + mips_ast.RegisterNode(node, T1), + mips_ast.RegisterNode(node, T2), + mips_ast.Label(node, node.target.id), + ) + ) + return instructions + @visitor.when(ccil_ast.GoToNode) def visit(self, node: ccil_ast.GoToNode): instructions = [] @@ -1294,7 +1329,9 @@ def visit(self, node: ccil_ast.ShallowCopyOpNode): instructions.append( mips_ast.StoreWord( - node, mips_ast.RegisterNode(node, V0), self._get_relative_location(node.dest) + node, + mips_ast.RegisterNode(node, V0), + self._get_relative_location(node.dest), ) ) return instructions From db3628f5558db5849e54683873e40142088b461b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 19:56:52 -0500 Subject: [PATCH 388/432] Bug fix, case void error is now given only when object address is 0, instead of always --- src/code_gen/ccil_gen.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 65dff3def..534813750 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -307,14 +307,23 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: (case_expr_ops, case_expr_fv) = self.visit(node.case_expr) # Handling case expression is not void - void_expr_error_ops = ( - self.throw_runtime_error( + void_expr_error_ops: List[OperationNode] = [] + if node.case_expr.type.name not in {STRING, INT, BOOL}: + case_expr_is_void = self.create_equality( + f"case_{times}_is_void", IdNode(case_expr_fv.id), IntNode("0") + ) + is_not_void = LabelNode(f"case_{times}_expr_not_void") + case_expr_if_void = IfFalseNode(IdNode(case_expr_is_void.id), is_not_void) + runtime_error_ops = self.throw_runtime_error( f"case_{times}_void_expr_error", f"RuntimeError: Case expression in {node.line}, {node.col} is void", ) - if node.case_expr.type.name not in {STRING, INT, BOOL} - else [] - ) + void_expr_error_ops = [ + case_expr_is_void, + case_expr_if_void, + *runtime_error_ops, + is_not_void, + ] # Storing the type of the resulting case expression expr_type = self.create_type_name( From 1cef7f087dea25e45aa5397eef549105dd585a30 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 20:54:19 -0500 Subject: [PATCH 389/432] Swap back body type to self type --- src/semantics/inference/back_inferencer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/semantics/inference/back_inferencer.py b/src/semantics/inference/back_inferencer.py index 90f9d97ee..b3ec1af1b 100644 --- a/src/semantics/inference/back_inferencer.py +++ b/src/semantics/inference/back_inferencer.py @@ -116,6 +116,7 @@ def visit(self, node: MethodDeclarationNode, scope) -> MethodDeclarationNode: body_type = new_body_node.inferenced_type new_node.inferenced_type, changed = unify(decl_type, body_type) new_node.inferenced_type.swap_self_type(self.current_type, back=True) + body_type.swap_self_type(self.current_type, back=True) self.changed |= changed return new_node From f7812a9133400ad7c9c90d9c507f82298bc809a5 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Thu, 3 Mar 2022 21:00:52 -0500 Subject: [PATCH 390/432] Fix recursion when adding warning --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 534813750..177b66588 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -1108,7 +1108,7 @@ def reset_scope(self): self.ccil_cool_names = Scope() def add_warning(self, msg: str): - self.add_warning(f"Warning: {msg}") + self.warnings.append(f"Warning: {msg}") def get_inherited_attributes(self, node: sem_ast.ClassDeclarationNode): return ( From 573c258f7181d5c3d33718ca641e2232a28b3376 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 21:01:40 -0500 Subject: [PATCH 391/432] Fix new SELF_TYPE --- src/code_gen/ccil_mips_gen.py | 80 ++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index f64fa7922..42c7c4ce5 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -276,19 +276,51 @@ def visit(self, node: ccil_ast.VCallOpNode): def visit(self, node: ccil_ast.NewOpNode): instructions = [] - # TODO: SELF_TYPE if node.type == "SELF_TYPE": - return [] - - # Allocate memory for object instance - size = self._get_attr_count(node.type) * WORD + WORD - instructions.append( - mips_ast.LoadImmediate( - node, - mips_ast.RegisterNode(node, A0), - mips_ast.Constant(node, size), + object_location = self._get_relative_location( + self.__current_function.params[0].id ) - ) + object_type = mips_ast.RegisterNode(node, T1) + attr_count = mips_ast.RegisterNode(node, T3) + object = mips_ast.RegisterNode(node, T4) + instructions.append(mips_ast.LoadWord(node, object, object_location)) + instructions.append( + mips_ast.LoadWord( + node, + object_type, + mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, 0), object), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + attr_count, + mips_ast.MemoryIndexNode( + node, mips_ast.Constant(node, 3 * WORD), object_type + ), + ) + ) + instructions.append( + mips_ast.Addi(node, attr_count, attr_count, mips_ast.Constant(node, 1)) + ) + instructions.append( + mips_ast.Multiply( + node, attr_count, attr_count, mips_ast.Constant(node, WORD) + ) + ) + instructions.append( + mips_ast.Move(node, mips_ast.RegisterNode(node, A0), attr_count) + ) + else: + size = self._get_attr_count(node.type) * WORD + WORD + instructions.append( + mips_ast.LoadImmediate( + node, + mips_ast.RegisterNode(node, A0), + mips_ast.Constant(node, size), + ) + ) + instructions.append( mips_ast.LoadImmediate( node, mips_ast.RegisterNode(node, V0), mips_ast.Constant(node, 9) @@ -296,13 +328,23 @@ def visit(self, node: ccil_ast.NewOpNode): ) instructions.append(mips_ast.Syscall(node)) - instructions.append( - mips_ast.LoadWord( - node, - mips_ast.RegisterNode(node, T0), - mips_ast.Label(node, node.type), + if node.type == "SELF_TYPE": + instructions.append( + mips_ast.Move( + node, + mips_ast.RegisterNode(node, T0), + mips_ast.RegisterNode(node, T1), + ) ) - ) + else: + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T0), + mips_ast.Label(node, node.type), + ) + ) + instructions.append( mips_ast.StoreWord( node, @@ -542,7 +584,7 @@ def visit(self, node: ccil_ast.EqualIntNode): return instructions - @visitor.when(ccil_ast.NotOpNode) + @visitor.when(ccil_ast.NegOpNode) def visit(self, node: ccil_ast.NotOpNode): instructions = [] @@ -574,7 +616,7 @@ def visit(self, node: ccil_ast.NotOpNode): return instructions - @visitor.when(ccil_ast.NegOpNode) + @visitor.when(ccil_ast.NotOpNode) def visit(self, node: ccil_ast.NegOpNode): instructions = [] From 315f2e882f5aa3400c34c92f7899f2acb76f4e21 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 3 Mar 2022 21:10:59 -0500 Subject: [PATCH 392/432] Add code generation pipeline --- src/__main__.py | 24 +++++++++++++++++++++--- tests/codegen_test.py | 30 +++++++++++++++--------------- tests/lexer_test.py | 2 -- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 2374bbb3e..1fefdb775 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,3 +1,6 @@ +from code_gen.ccil_gen import CCILGenerator +from code_gen.ccil_mips_gen import CCILToMIPSGenerator +from code_gen.mips_gen import MIPSGenerator from debbuging.type_logger import TypeLogger import sys @@ -46,11 +49,12 @@ def run_pipeline(program_ast): change = True back = BackInferencer(context) + # import pdb; pdb.set_trace() back_ast, change = back.visit(hard_ast) while change: back_ast, change = back.visit(back_ast) - types = TypesInferencer() + types = TypesInferencer(context) types_ast = types.visit(back_ast) errors += types.errors @@ -70,7 +74,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests/Auto/call1.cl" + input_file = "debbuging/tests_ccil/simple.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) @@ -91,7 +95,21 @@ def main(): print(error) exit(1) - run_pipeline(ast) + type_ast = run_pipeline(ast) + ccil_gen = CCILGenerator() + ccil_ast = ccil_gen.visit(type_ast) + print(str(ccil_ast)) + + ccil_mips_gen = CCILToMIPSGenerator() + mips_ast = ccil_mips_gen.visit(ccil_ast) + + mips_gen = MIPSGenerator() + mips_code = mips_gen.visit(mips_ast) + + out_file = input_file.split(".")[0] + path_to_file =f"{out_file}.mips" + with open(path_to_file, "w") as f: + f.write(mips_code) main() diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 598d7da01..49db4080b 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -1,17 +1,17 @@ -# import pytest -# import os -# from utils import compare_outputs +import pytest +import os +from utils import compare_outputs -# tests_dir = __file__.rpartition('/')[0] + '/codegen/' -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests_dir = __file__.rpartition('/')[0] + '/codegen/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] -# # @pytest.mark.lexer -# # @pytest.mark.parser -# # @pytest.mark.semantic -# @pytest.mark.codegen -# @pytest.mark.ok -# @pytest.mark.run(order=4) -# @pytest.mark.parametrize("cool_file", tests) -# def test_codegen(compiler_path, cool_file): -# compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ -# tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file +# @pytest.mark.lexer +# @pytest.mark.parser +# @pytest.mark.semantic +@pytest.mark.codegen +@pytest.mark.ok +@pytest.mark.run(order=4) +@pytest.mark.parametrize("cool_file", tests) +def test_codegen(compiler_path, cool_file): + compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt') diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 7cc100b22..aec99e4b1 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -9,8 +9,6 @@ @pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - print(compiler_path) - print(cool_file) compare_errors( compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + "_error.txt" ) From 6b44c07434ea7262c4684aabfc55e89ea3d4f816 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 08:51:51 -0500 Subject: [PATCH 393/432] Add branch var to scope in case expression and bug fix in loop expression --- src/code_gen/ccil_gen.py | 20 ++++++++++---------- src/code_gen/constants.py | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 177b66588..5aadb9cb9 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -346,9 +346,6 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: visited_types = set() # To optimize and reduce redundant calling for (i, option) in enumerate(node.options): # Initializing the branch var - branch_var = self.create_assignation( - f"case_{times}_option_{i}", option.branch_type.name, case_expr_fv.id - ) # Label that means the start of this branch logic branch_label = LabelNode(f"case_{times}_branch_{i}") @@ -378,10 +375,13 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: branch_selection_ops = [GoToNode(branch_label)] # Storing logic to jump to branch logic if this branch is selected - pattern_match_ops += [ - branch_var, - *branch_selection_ops, - ] + pattern_match_ops += (branch_selection_ops,) + + branch_var = self.create_assignation( + f"case_{times}_option_{i}", option.branch_type.name, case_expr_fv.id + ) + self.ccil_cool_names = self.ccil_cool_names.create_child() + self.ccil_cool_names.add_new_name_pair(option.id, branch_var.id) # Translating the branch logic (expr_ops, expr_fval) = self.visit(option.expr) @@ -390,6 +390,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: expr_fval.id = pre_fvalue_id # Translating to ccil of branch logic branch_ops += [branch_label, *expr_ops, final_goto] + self.ccil_cool_names = self.ccil_cool_names.get_parent self.locals[pre_fvalue_id] = node.type.name @@ -429,13 +430,13 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: end_loop_label = LabelNode(end_loop_label_id) # Setting control flow instructions ifFalse & GoTo - if_false = IfFalseNode(cond_fval, end_loop_label) + if_false = IfFalseNode(extract_id(cond_fval), end_loop_label) go_to = GoToNode(loop_label) fval = self.create_uninitialized_storage(f"loop_{times}_fv", VOID) # Loop Nodes have void return type, how to express it?? return ( - [*cond_ops, loop_label, if_false, *body_ops, go_to, end_loop_label, fval], + [loop_label, *cond_ops, if_false, *body_ops, go_to, end_loop_label, fval], fval, ) @@ -692,7 +693,6 @@ def visit(self, node: sem_ast.IntNode) -> VISITOR_RESULT: def visit(self, node: sem_ast.BooleanNode) -> VISITOR_RESULT: times = self.times(node) - print(node.value) bool_id = f"bool_{times}" value = "1" if node.value else "0" diff --git a/src/code_gen/constants.py b/src/code_gen/constants.py index 15a94cc24..c9ac87b96 100644 --- a/src/code_gen/constants.py +++ b/src/code_gen/constants.py @@ -2,6 +2,7 @@ LET = "let_" ATTR = "attr_" CLASS = "class_" +CASE = "case_" # Registers ZERO = 0 From 78bea173b58bcc1452b8dc9148231ba8b4dcb1d0 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 09:13:16 -0500 Subject: [PATCH 394/432] Fix init function, attributes now see each other --- src/code_gen/ccil_gen.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 5aadb9cb9..764d3c2d2 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -115,11 +115,11 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: func_nodes.append(feature) # Create init func using attributes and their expressions + self.ccil_cool_names.add_new_names(*[(a.cool_id, a.id) for a in attributes]) init_func = self.create_class_init_func(node, attr_nodes) - self.reset_scope() + # self.reset_scope() # Explore all functions - self.ccil_cool_names.add_new_names(*[(a.cool_id, a.id) for a in attributes]) class_code: List[FunctionNode] = [] for func in func_nodes: f = self.visit(func) @@ -705,10 +705,10 @@ def create_class_init_func( attr_nodes: List[sem_ast.AttrDeclarationNode], ): self.reset_locals() - self.reset_scope() + self.ccil_cool_names = self.ccil_cool_names.create_child() + self.ccil_cool_names.add_new_name_pair("self", "self") init_params = self.init_func_params(node.id) - # self.ccil_cool_names.add_new_name_pair("self", node.id) # First operation, initalizing parent attributes init_parent = self.create_call( @@ -728,6 +728,7 @@ def create_class_init_func( dummy_return = self.create_storage(f"init_type_{node.id}_ret", INT, IntNode(0)) init_attr_ops.append(dummy_return) + self.ccil_cool_names = self.ccil_cool_names.get_parent # return init function return FunctionNode( f"init_{node.id}", From 96ea9f51207095b92c1fcd5ec7162b45128b2cdf Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 09:15:49 -0500 Subject: [PATCH 395/432] Bug fix in case expression --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 764d3c2d2..6cbdf6bf5 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -375,7 +375,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: branch_selection_ops = [GoToNode(branch_label)] # Storing logic to jump to branch logic if this branch is selected - pattern_match_ops += (branch_selection_ops,) + pattern_match_ops += branch_selection_ops branch_var = self.create_assignation( f"case_{times}_option_{i}", option.branch_type.name, case_expr_fv.id From 1d4a9c90034a6d2c2556fa60a86e0a3faa0cd2c8 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 10:23:46 -0500 Subject: [PATCH 396/432] Bug fix, altering fval name affected previous assignation --- src/code_gen/ccil_gen.py | 43 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 6cbdf6bf5..6fbe8ee6c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -118,7 +118,8 @@ def visit(self, node: sem_ast.ClassDeclarationNode) -> CLASS_VISITOR_RESULT: self.ccil_cool_names.add_new_names(*[(a.cool_id, a.id) for a in attributes]) init_func = self.create_class_init_func(node, attr_nodes) - # self.reset_scope() + self.reset_scope() + self.ccil_cool_names.add_new_names(*[(a.cool_id, a.id) for a in attributes]) # Explore all functions class_code: List[FunctionNode] = [] for func in func_nodes: @@ -249,12 +250,19 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: ccil_id, is_attr = self.ccil_cool_names.get_value_position(node.id) + print(is_attr, node.id, ccil_id) if is_attr: # Assignation occurring to an attribute Go update the attribute set_attr = SetAttrOpNode( "self", ccil_id, extract_id(expr_fval), self.current_type ) - return [*expr_ops, set_attr], expr_fval + attr_val = self.create_assignation( + f"local_attr_{node.id}_{self.times(node, node.id)}", + node.type.name, + expr_fval.id, + reuse=False, + ) + return [*expr_ops, set_attr, attr_val], attr_val self.update_locals(expr_fval.id, ccil_id) expr_fval.id = ccil_id @@ -565,6 +573,8 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: @visitor.when(sem_ast.MethodCallNode) def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: + call_id = f"call_{self.times(node, extra='call')}" + vcall_id = f"vcall_{self.times(node, extra='vcall')}" times = self.times(node) # Translate all call arguments to ccil @@ -578,9 +588,8 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # id(arg1, arg2, ..., argn) if node.expr is None: - fval_id = f"vcall_{times}" call = self.create_vcall( - fval_id, + vcall_id, node.type.name, node.id, node.caller_type.name, @@ -591,9 +600,8 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: (expr_ops, expr_fval) = self.visit(node.expr) if node.caller_type.name == STRING: - fval_id = f"call_str_{times}" call = self.create_call( - fval_id, node.type.name, node.id, STRING, [extract_id(expr_fval), *args] + call_id, node.type.name, node.id, STRING, [extract_id(expr_fval), *args] ) return [*expr_ops, *args_ops, call], call @@ -622,9 +630,8 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # @type.id(arg1, arg2, ..., argn) if node.at_type is not None: - fval_id = f"call_{times}" call = self.create_call( - fval_id, + call_id, node.type.name, make_unique_func_id(node.id, node.caller_type.name), node.caller_type.name, @@ -633,9 +640,8 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: return [*expr_ops, *error_ops, *args_ops, call], call # .id(arg1, arg2, ..., argn) - fval_id = f"vcall_{times}" call = self.create_vcall( - fval_id, + vcall_id, node.type.name, node.id, node.caller_type.name, @@ -922,8 +928,10 @@ def define_built_ins(self): def init_func_params(self, typex: str): return [Parameter("self", typex)] - def create_assignation(self, idx: str, type_idx: str, target: str): - self.add_local(idx, type_idx) + def create_assignation(self, idx: str, type_idx: str, target: str, reuse=False): + self.add_local(idx, type_idx) if not reuse else self.soft_add_local( + idx, type_idx + ) return StorageNode(idx, IdNode(target)) def create_uninitialized_storage(self, idx: str, type_idx: str): @@ -1090,10 +1098,19 @@ def update_locals(self, old_id: str, new_id: str): def add_local(self, idx: str, typex: str): if idx in self.locals: - raise Exception(f"Trying to insert {idx} again as local") + raise KeyError(f"Trying to insert {idx} again as local") self.locals[idx] = typex return Local(idx, typex) + def soft_add_local(self, idx: str, typex: str): + try: + print(f"Addin {idx}") + return self.add_local(idx, typex) + except KeyError: + pass + print(f"Skipin {idx}") + return Local(idx, typex) + def reset_locals(self): """ Apply at the beginning of every method to reset local vars From 06097d58a792b5768444da2c4af0b646b6c0c17a Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 12:38:59 -0500 Subject: [PATCH 397/432] Add IsVoid and EqAddr nodes to ast --- src/asts/ccil_ast.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index b213945dc..ea356ba93 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -318,6 +318,10 @@ class EqualStrNode(ComparisonOpNode): pass +class EqualAddrNode(ComparisonOpNode): + pass + + class LessOrEqualOpNode(ComparisonOpNode): pass @@ -349,6 +353,21 @@ def __str__(self) -> str: return f"neg {self.atom.value}" +class IsVoidOpNode(UnaryOpNode): + def __str__(self) -> str: + return f"isvoid {self.atom.value}" + + +class CurrentTypeNameNode(ReturnOpNode): + def __init__(self, target: str, static_type: str) -> None: + super().__init__() + self.target = target + self.static_type = static_type + + def __str__(self) -> str: + return f"type_name {self.target}" + + class ChainOpNode(ReturnOpNode): def __init__(self, target: str) -> None: super().__init__() @@ -431,16 +450,6 @@ def __init__(self) -> None: super().__init__() -class CurrentTypeNameNode(ReturnOpNode): - def __init__(self, target: str, static_type: str) -> None: - super().__init__() - self.target = target - self.static_type = static_type - - def __str__(self) -> str: - return f"type_name {self.target}" - - class ShallowCopyOpNode(OperationNode): def __init__(self, dest: str, source: str) -> None: super().__init__() From 64ed301f21b0dd3d808dd495b74dc55194f64306 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 12:41:35 -0500 Subject: [PATCH 398/432] Change equal node it splits depending on static type between str, int and address comparisons, isvoid node is now used --- src/code_gen/ccil_gen.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 6fbe8ee6c..4ac04cfec 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -250,7 +250,6 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: ccil_id, is_attr = self.ccil_cool_names.get_value_position(node.id) - print(is_attr, node.id, ccil_id) if is_attr: # Assignation occurring to an attribute Go update the attribute set_attr = SetAttrOpNode( @@ -260,7 +259,6 @@ def visit(self, node: sem_ast.AssignNode) -> VISITOR_RESULT: f"local_attr_{node.id}_{self.times(node, node.id)}", node.type.name, expr_fval.id, - reuse=False, ) return [*expr_ops, set_attr, attr_val], attr_val @@ -518,12 +516,17 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: node_type = type(node) # Boolean Binary Nodes if node_type == sem_ast.EqualsNode: - op = ( - EqualIntNode(left_id, right_id) - if node.left.type.name != STRING - else EqualStrNode(left_id, right_id) - ) - fval_id = f"eq_{times}" + if node.left.type.name == STRING: + fval_id = f"eq_str_{times}" + op = EqualStrNode(left_id, right_id) + if node.left.type.name in {INT, BOOL}: + fval_id = ( + f"eq_{'int' if node.left.type.name == INT else 'bool'}_{times}" + ) + op = EqualIntNode(left_id, right_id) + else: + fval_id = f"eq_addr_{times}" + op = EqualAddrNode(left_id, right_id) elif node_type == sem_ast.LessNode: op = LessOpNode(left_id, right_id) fval_id = f"le_{times}" @@ -558,7 +561,7 @@ def visit(self, node: sem_ast.UnaryNode) -> VISITOR_RESULT: ) op = BoolNode("0") else: - op = EqualIntNode(IdNode(fval_id), IntNode("0")) + op = IsVoidOpNode(expr_id) elif node_type == sem_ast.NotNode: fval_id = f"not_{times}" op = NotOpNode(expr_id) @@ -1103,13 +1106,9 @@ def add_local(self, idx: str, typex: str): return Local(idx, typex) def soft_add_local(self, idx: str, typex: str): - try: - print(f"Addin {idx}") - return self.add_local(idx, typex) - except KeyError: - pass - print(f"Skipin {idx}") - return Local(idx, typex) + if not idx in self.locals: + self.locals[idx] = typex + return Local(idx, self.locals[idx]) def reset_locals(self): """ From 8f36d4519ac5ad805a711e709b2c1bb24760480d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 4 Mar 2022 12:57:19 -0500 Subject: [PATCH 399/432] Add EqualAddrNode to ccil_mips_gen visitor --- src/code_gen/ccil_mips_gen.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 42c7c4ce5..3738467ec 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -584,6 +584,36 @@ def visit(self, node: ccil_ast.EqualIntNode): return instructions + @visitor.when(ccil_ast.EqualAddrNode) + def visit(self, node: ccil_ast.EqualAddrNode): + instructions = [] + + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T5), + self._get_relative_location(node.left.value), + ) + ) + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T6), + self._get_relative_location(node.right.value), + ) + ) + instructions.append( + mips_ast.Equal( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, T6), + ) + ) + instructions.extend(self._set_new_bool(node)) + + return instructions + @visitor.when(ccil_ast.NegOpNode) def visit(self, node: ccil_ast.NotOpNode): instructions = [] From 5797518a18415a97f05b67968fb6541dfaf23ad8 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 4 Mar 2022 13:02:24 -0500 Subject: [PATCH 400/432] Add isvoid to ccil_mips_gen visitor --- src/code_gen/ccil_mips_gen.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 3738467ec..6faffabe4 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -614,6 +614,30 @@ def visit(self, node: ccil_ast.EqualAddrNode): return instructions + @visitor.when(ccil_ast.IsVoidOpNode) + def visit(self, node: ccil_ast.IsVoidOpNode): + instructions = [] + instructions.append( + mips_ast.LoadWord( + node, + mips_ast.RegisterNode(node, T5), + self._get_relative_location(node.atom.value), + ) + ) + + instructions.append( + mips_ast.Equal( + node, + mips_ast.RegisterNode(node, T7), + mips_ast.RegisterNode(node, T5), + mips_ast.RegisterNode(node, ZERO), + ) + ) + instructions.extend(self._set_new_bool(node)) + + return instructions + + @visitor.when(ccil_ast.NegOpNode) def visit(self, node: ccil_ast.NotOpNode): instructions = [] From eccbecd5e14e240037416d8ee998df98b3242244 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 13:22:11 -0500 Subject: [PATCH 401/432] Remove attribute and renamed --- src/asts/ccil_ast.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index ea356ba93..af87b16a7 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -358,11 +358,10 @@ def __str__(self) -> str: return f"isvoid {self.atom.value}" -class CurrentTypeNameNode(ReturnOpNode): - def __init__(self, target: str, static_type: str) -> None: +class TypeNameOpNode(ReturnOpNode): + def __init__(self, target: str) -> None: super().__init__() self.target = target - self.static_type = static_type def __str__(self) -> str: return f"type_name {self.target}" From f5f02d52bc43b545eb4bec55a97e5c98c98ed54c Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 13:22:30 -0500 Subject: [PATCH 402/432] Change abort fucntion message --- src/code_gen/ccil_gen.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 4ac04cfec..0199266a0 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -332,9 +332,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: ] # Storing the type of the resulting case expression - expr_type = self.create_type_name( - f"case_{times}_expr_type", case_expr_fv.id, node.case_expr.type.name - ) + expr_type = self.create_type_name(f"case_{times}_expr_type", case_expr_fv.id) # Final label where all branch must jump to final_label = LabelNode(f"case_{times}_end") @@ -751,14 +749,22 @@ def define_built_ins(self): # Defining Object class methods self.reset_scope() params = self.init_func_params(OBJECT) - abort_msg = self.add_data("abort_msg", "RuntimeError: Execution aborted") - load = self.create_string_load_data("abort_temp", abort_msg.id) - [print, abort] = self.notifiy_and_abort(load.id) + abort_msg = self.add_data("abort_msg", "Abort called from class ") + part1 = self.create_string_load_data("abort_var1", abort_msg.id) + part2 = self.create_type_name("abort_var2", "self") + abort_local_msg = self.create_storage( + "abort_local_msg", STRING, ConcatOpNode(part1.id, part2.id) + ) + [print, abort] = self.notifiy_and_abort(abort_local_msg.id) abort_func = FunctionNode( - "abort", params, self.dump_locals(), [load, print, abort], "self" + "abort", + params, + self.dump_locals(), + [part1, part2, abort_local_msg, print, abort], + "self", ) params = self.init_func_params(OBJECT) - get_name = self.create_type_name("get_name", "self", OBJECT) + get_name = self.create_type_name("get_name", "self") type_name_func = FunctionNode( "type_name", params, self.dump_locals(), [get_name], get_name.id ) @@ -1017,9 +1023,9 @@ def create_read_int(self, idx: str): self.add_local(idx, INT) return StorageNode(idx, ReadIntNode()) - def create_type_name(self, idx: str, target: str, static_type: str): + def create_type_name(self, idx: str, target: str): self.add_local(idx, STRING) - return StorageNode(idx, CurrentTypeNameNode(target, static_type)) + return StorageNode(idx, TypeNameOpNode(target)) def create_length(self, idx: str, target: str): self.add_local(idx, INT) From 9ac13fa5d4caff5d070c53e6905d1d9366320bcf Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 4 Mar 2022 13:27:29 -0500 Subject: [PATCH 403/432] Rename CurrentTypeName to TypeName in ccils_mips_gen visitor --- src/code_gen/ccil_mips_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index 6faffabe4..bfbd004ec 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -1306,8 +1306,8 @@ def visit(self, node: ccil_ast.SubstringOpNode): instructions.extend(self._set_new_string(node)) return instructions - @visitor.when(ccil_ast.CurrentTypeNameNode) - def visit(self, node: ccil_ast.CurrentTypeNameNode): + @visitor.when(ccil_ast.TypeNameOpNode) + def visit(self, node: ccil_ast.TypeNameOpNode): instructions = [] result = mips_ast.RegisterNode(node, T7) From 8de31d9fd721eebff9eb5a997da93de9dfe22c31 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 13:48:39 -0500 Subject: [PATCH 404/432] Fix isvoid checks on different nodes, and minor bug fix in while expr --- src/code_gen/ccil_gen.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 0199266a0..f174c84da 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -315,8 +315,8 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: # Handling case expression is not void void_expr_error_ops: List[OperationNode] = [] if node.case_expr.type.name not in {STRING, INT, BOOL}: - case_expr_is_void = self.create_equality( - f"case_{times}_is_void", IdNode(case_expr_fv.id), IntNode("0") + case_expr_is_void = self.create_isvoid( + f"case_{times}_is_void", IdNode(case_expr_fv.id) ) is_not_void = LabelNode(f"case_{times}_expr_not_void") case_expr_if_void = IfFalseNode(IdNode(case_expr_is_void.id), is_not_void) @@ -437,7 +437,7 @@ def visit(self, node: sem_ast.LoopNode) -> VISITOR_RESULT: if_false = IfFalseNode(extract_id(cond_fval), end_loop_label) go_to = GoToNode(loop_label) - fval = self.create_uninitialized_storage(f"loop_{times}_fv", VOID) + fval = self.create_uninitialized_storage(f"loop_{times}_fv", OBJECT) # Loop Nodes have void return type, how to express it?? return ( [loop_label, *cond_ops, if_false, *body_ops, go_to, end_loop_label, fval], @@ -608,8 +608,8 @@ def visit(self, node: sem_ast.MethodCallNode) -> VISITOR_RESULT: # Runtime error depending if expr is void or not error_ops = [] - expr_fval_is_void = self.create_equality( - f"expr_is_void_{times}", extract_id(expr_fval), IntNode("0") + expr_fval_is_void = self.create_isvoid( + f"expr_is_void_{times}", extract_id(expr_fval) ) ok_label = LabelNode(f"expr_is_not_void_{times}") if_is_not_void = IfFalseNode(extract_id(expr_fval_is_void), ok_label) @@ -945,6 +945,7 @@ def create_assignation(self, idx: str, type_idx: str, target: str, reuse=False): def create_uninitialized_storage(self, idx: str, type_idx: str): self.add_local(idx, type_idx) + self.init_default_values() return StorageNode(idx, ZERO if type_idx != STRING else EMPTY) def create_storage(self, idx: str, type_idx: str, op: ReturnOpNode): @@ -994,6 +995,10 @@ def create_equality( op = EqualStrNode(left, right) if string else EqualIntNode(left, right) return StorageNode(idx, op) + def create_isvoid(self, idx: str, atom: IdNode): + self.add_local(idx, BOOL) + return StorageNode(idx, IsVoidOpNode(atom)) + def notifiy_and_abort(self, target: str) -> List[OperationNode]: print = PrintStrNode(target) abort = Abort() From 88aeef5d8954a198eefa025717aa1df1bab05270 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 14:18:59 -0500 Subject: [PATCH 405/432] Bug fix --- src/code_gen/ccil_gen.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index f174c84da..54d1ccd90 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -284,9 +284,12 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: # Setting the final operation which will simbolize the return value of this expr pre_fvalue_id = f"if_{times}_pre_fv" - self.update_locals(then_fval.id, pre_fvalue_id) - self.update_locals(else_fval.id, pre_fvalue_id) - then_fval.id = else_fval.id = pre_fvalue_id + pre_fvalue_then = self.create_assignation( + pre_fvalue_id, node.type.name, then_fval.id + ) + pre_fvalue_else = self.create_assignation( + pre_fvalue_id, node.type.name, else_fval.id, reuse=True + ) fvalue_id = f"if_{times}_fv" fvalue = self.create_assignation(fvalue_id, node.type.name, pre_fvalue_id) @@ -296,9 +299,11 @@ def visit(self, node: sem_ast.ConditionalNode) -> VISITOR_RESULT: *if_ops, if_false, *then_ops, + pre_fvalue_then, goto_endif, else_label, *else_ops, + pre_fvalue_else, endif_label, fvalue, ], From 5cbd832121066a5b911b2d32892f2b755c6074f7 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 14:24:43 -0500 Subject: [PATCH 406/432] Add line end to abort function message --- src/code_gen/ccil_gen.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 54d1ccd90..238d0fd35 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -14,6 +14,7 @@ ATTR_VISITOR_RESULT = List[OperationNode] DEFAULT_STR = Data("default_str", "") +END_LINE = Data("line_end", r"\n") ZERO = "zero" EMPTY = "empty" @@ -68,7 +69,7 @@ def visit(self, node): @visitor.when(sem_ast.ProgramNode) def visit(self, node: sem_ast.ProgramNode) -> None: - self.data = [DEFAULT_STR] + self.data = [DEFAULT_STR, END_LINE] self.reset_locals() [obj, io, str, int, bool], builtin_methods = self.define_built_ins() @@ -757,15 +758,19 @@ def define_built_ins(self): abort_msg = self.add_data("abort_msg", "Abort called from class ") part1 = self.create_string_load_data("abort_var1", abort_msg.id) part2 = self.create_type_name("abort_var2", "self") - abort_local_msg = self.create_storage( - "abort_local_msg", STRING, ConcatOpNode(part1.id, part2.id) + abort_local_msg1 = self.create_storage( + "abort_local_msg1", STRING, ConcatOpNode(part1.id, part2.id) ) - [print, abort] = self.notifiy_and_abort(abort_local_msg.id) + line_end = self.create_string_load_data("line_end", END_LINE.id) + abort_local_msg2 = self.create_storage( + "abort_local_msg2", STRING, ConcatOpNode(abort_local_msg1.id, line_end.id) + ) + [print, abort] = self.notifiy_and_abort(abort_local_msg2.id) abort_func = FunctionNode( "abort", params, self.dump_locals(), - [part1, part2, abort_local_msg, print, abort], + [part1, part2, line_end, abort_local_msg1, abort_local_msg2, print, abort], "self", ) params = self.init_func_params(OBJECT) From 32af83ad0b74146ab3ab30d92c4613fa05006fe3 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 14:41:26 -0500 Subject: [PATCH 407/432] Workflow error, change if for else if --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 238d0fd35..610711e4c 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -523,7 +523,7 @@ def visit(self, node: sem_ast.ComparerNode) -> VISITOR_RESULT: if node.left.type.name == STRING: fval_id = f"eq_str_{times}" op = EqualStrNode(left_id, right_id) - if node.left.type.name in {INT, BOOL}: + elif node.left.type.name in {INT, BOOL}: fval_id = ( f"eq_{'int' if node.left.type.name == INT else 'bool'}_{times}" ) From 236c301db3fd5aac00b649ff071c873999d1c5a6 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 15:01:11 -0500 Subject: [PATCH 408/432] Add operation that bound case expression to case var --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 610711e4c..429388f0f 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -399,7 +399,7 @@ def visit(self, node: sem_ast.CaseNode) -> VISITOR_RESULT: self.update_locals(expr_fval.id, pre_fvalue_id) expr_fval.id = pre_fvalue_id # Translating to ccil of branch logic - branch_ops += [branch_label, *expr_ops, final_goto] + branch_ops += [branch_label, branch_var, *expr_ops, final_goto] self.ccil_cool_names = self.ccil_cool_names.get_parent self.locals[pre_fvalue_id] = node.type.name From a1ba1821beab4d3abceadb373433f5996f27a0fa Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 16:03:50 -0500 Subject: [PATCH 409/432] Add string representation for all binary operators --- src/asts/ccil_ast.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/asts/ccil_ast.py b/src/asts/ccil_ast.py index af87b16a7..3a614dbdc 100644 --- a/src/asts/ccil_ast.py +++ b/src/asts/ccil_ast.py @@ -291,19 +291,23 @@ class ArithmeticOpNode(BinaryOpNode): class SumOpNode(ArithmeticOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} + {self.right.value}" class MinusOpNode(ArithmeticOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} - {self.right.value}" class MultOpNode(ArithmeticOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} * {self.right.value}" class DivOpNode(ArithmeticOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} / {self.right.value}" class ComparisonOpNode(BinaryOpNode): @@ -311,23 +315,28 @@ class ComparisonOpNode(BinaryOpNode): class EqualIntNode(ComparisonOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} =(Int) {self.right.value}" class EqualStrNode(ComparisonOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} =(Str) {self.right.value}" class EqualAddrNode(ComparisonOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} =(Addr) {self.right.value}" class LessOrEqualOpNode(ComparisonOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} <= {self.right.value}" class LessOpNode(ComparisonOpNode): - pass + def __str__(self) -> str: + return f"{self.left.value} < {self.right.value}" class UnaryOpNode(ReturnOpNode): From 66afa731f09e7690f997cbbc9fa789e5cf3890bd Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Fri, 4 Mar 2022 16:07:56 -0500 Subject: [PATCH 410/432] Bug fix. Checking left operand instead of right operando for zero divission --- src/code_gen/ccil_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_gen/ccil_gen.py b/src/code_gen/ccil_gen.py index 429388f0f..c0da1633e 100644 --- a/src/code_gen/ccil_gen.py +++ b/src/code_gen/ccil_gen.py @@ -480,7 +480,7 @@ def visit(self, node: sem_ast.ArithmeticNode) -> VISITOR_RESULT: # Generating divison by zero runtime error ok_label = LabelNode(f"ok_div_{times}") right_id_is_zero = self.create_equality( - f"check_right_zero_{times}", left_id, IntNode("0") + f"check_right_zero_{times}", right_id, IntNode("0") ) if_id_is_not_zero = IfFalseNode(extract_id(right_id_is_zero), ok_label) error_msg = self.add_data( From da095112ec4454d3fb6b91a5b913200ae9e50025 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Fri, 4 Mar 2022 17:15:04 -0500 Subject: [PATCH 411/432] Fix error on input reading --- src/code_gen/ccil_mips_gen.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index bfbd004ec..e77770bf5 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -637,7 +637,6 @@ def visit(self, node: ccil_ast.IsVoidOpNode): return instructions - @visitor.when(ccil_ast.NegOpNode) def visit(self, node: ccil_ast.NotOpNode): instructions = [] @@ -1466,18 +1465,22 @@ def visit(self, node: ccil_ast.ReadStrNode): mips_ast.MemoryIndexNode(node, mips_ast.Constant(node, WORD), v0), ) ) - # instructions.append(mips_ast.Addi(node, a0, a0, mips_ast.Constant(node, 1))) - instructions.append( - mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 9)) - ) - instructions.append(mips_ast.Syscall(node)) + instructions.append(mips_ast.Addi(node, a0, a0, mips_ast.Constant(node, 1))) + loop = self._generate_unique_label() + end = self._generate_unique_label() + zero = mips_ast.RegisterNode(node, ZERO) char = mips_ast.RegisterNode(node, T0) string = mips_ast.RegisterNode(node, T1) buffer_string = mips_ast.RegisterNode(node, T2) buffer_char = mips_ast.RegisterNode(node, T3) string_char = mips_ast.RegisterNode(node, T4) - zero = mips_ast.RegisterNode(node, ZERO) + + instructions.append( + mips_ast.LoadImmediate(node, v0, mips_ast.Constant(node, 9)) + ) + instructions.append(mips_ast.Syscall(node)) + instructions.append(mips_ast.Move(node, string, v0)) instructions.append( mips_ast.LoadAddress(node, buffer_string, mips_ast.Label(node, "buffer")) @@ -1485,9 +1488,6 @@ def visit(self, node: ccil_ast.ReadStrNode): instructions.append(mips_ast.Move(node, buffer_char, buffer_string)) instructions.append(mips_ast.Move(node, string_char, string)) - loop = self._generate_unique_label() - end = self._generate_unique_label() - instructions.append(mips_ast.LabelDeclaration(node, loop)) instructions.append( mips_ast.LoadByte( @@ -1510,6 +1510,9 @@ def visit(self, node: ccil_ast.ReadStrNode): instructions.append( mips_ast.BranchOnEqual(node, char, new_line, mips_ast.Label(node, end)) ) + instructions.append( + mips_ast.BranchOnEqual(node, char, zero, mips_ast.Label(node, end)) + ) instructions.append( mips_ast.Addi(node, buffer_char, buffer_char, mips_ast.Constant(node, 1)) From b22643d7f25950d70b6841ae46cca1cbfaf0a9c0 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 8 Mar 2022 10:50:17 -0500 Subject: [PATCH 412/432] Fix ~ operator --- src/code_gen/ccil_mips_gen.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/code_gen/ccil_mips_gen.py b/src/code_gen/ccil_mips_gen.py index e77770bf5..06190753f 100644 --- a/src/code_gen/ccil_mips_gen.py +++ b/src/code_gen/ccil_mips_gen.py @@ -665,12 +665,15 @@ def visit(self, node: ccil_ast.NotOpNode): ) ) instructions.append(mips_ast.Not(node, value, value)) - instructions.extend(self._set_new_bool(node)) + instructions.append( + mips_ast.Addi(node, value, value, mips_ast.Constant(node, 1)) + ) + instructions.extend(self._set_new_int(node)) return instructions @visitor.when(ccil_ast.NotOpNode) - def visit(self, node: ccil_ast.NegOpNode): + def visit(self, node: ccil_ast.NotOpNode): instructions = [] value = mips_ast.RegisterNode(node, T7) @@ -699,7 +702,7 @@ def visit(self, node: ccil_ast.NegOpNode): instructions.append( mips_ast.Xori(node, value, value, mips_ast.Constant(node, "1")) ) - instructions.extend(self._set_new_int(node)) + instructions.extend(self._set_new_bool(node)) return instructions From bcbc1eeac57625e04c5abba68b786cbbae2f847f Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Tue, 8 Mar 2022 10:51:00 -0500 Subject: [PATCH 413/432] Configure main pipeline --- src/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/__main__.py b/src/__main__.py index 1fefdb775..ea4854273 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -108,6 +108,7 @@ def main(): out_file = input_file.split(".")[0] path_to_file =f"{out_file}.mips" + # path_to_file = "output.asm" with open(path_to_file, "w") as f: f.write(mips_code) From 546464273cab5b97b22a9f667e5b5d9dd0a7a837 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:32:16 -0500 Subject: [PATCH 414/432] Update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index baba1dc00..dd6b6c05c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ # Created by https://www.gitignore.io/api/visualstudiocode,linux,latex,python # Edit at https://www.gitignore.io/?templates=visualstudiocode,linux,latex,python +# +*.mips +pyrightconfig.json ### LaTeX ### ## Core latex/pdflatex auxiliary files: From 726d4d3f52f81b85caef801a6b423acf33478a21 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:32:32 -0500 Subject: [PATCH 415/432] Minor change --- src/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index ea4854273..5cf19604c 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -74,7 +74,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests_ccil/simple.cl" + input_file = "debbuging/tests_ccil/life.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) @@ -107,7 +107,7 @@ def main(): mips_code = mips_gen.visit(mips_ast) out_file = input_file.split(".")[0] - path_to_file =f"{out_file}.mips" + path_to_file = f"{out_file}.mips" # path_to_file = "output.asm" with open(path_to_file, "w") as f: f.write(mips_code) From 8c3b4e05488ba74789e28eab09cab90974c2e59b Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:32:50 -0500 Subject: [PATCH 416/432] Add many tests --- src/debbuging/tests_ccil/abort1.cl | 5 +++++ src/debbuging/tests_ccil/bool.cl | 6 ++++++ src/debbuging/tests_ccil/case5.cl | 25 +++++++++++++++++++++++++ src/debbuging/tests_ccil/case6.cl | 20 ++++++++++++++++++++ src/debbuging/tests_ccil/div1.cl | 5 +++++ src/debbuging/tests_ccil/fib1.cl | 29 +++++++++++++++++++++++++++++ src/debbuging/tests_ccil/self1.cl | 8 ++++++++ 7 files changed, 98 insertions(+) create mode 100644 src/debbuging/tests_ccil/abort1.cl create mode 100644 src/debbuging/tests_ccil/bool.cl create mode 100644 src/debbuging/tests_ccil/case5.cl create mode 100644 src/debbuging/tests_ccil/case6.cl create mode 100644 src/debbuging/tests_ccil/div1.cl create mode 100644 src/debbuging/tests_ccil/fib1.cl create mode 100644 src/debbuging/tests_ccil/self1.cl diff --git a/src/debbuging/tests_ccil/abort1.cl b/src/debbuging/tests_ccil/abort1.cl new file mode 100644 index 000000000..d68f076e4 --- /dev/null +++ b/src/debbuging/tests_ccil/abort1.cl @@ -0,0 +1,5 @@ + class Main { + main(): Object { + abort() + }; +}; diff --git a/src/debbuging/tests_ccil/bool.cl b/src/debbuging/tests_ccil/bool.cl new file mode 100644 index 000000000..ff555157a --- /dev/null +++ b/src/debbuging/tests_ccil/bool.cl @@ -0,0 +1,6 @@ + + class Main { + main(): Bool { + false + }; +}; diff --git a/src/debbuging/tests_ccil/case5.cl b/src/debbuging/tests_ccil/case5.cl new file mode 100644 index 000000000..13fe9992a --- /dev/null +++ b/src/debbuging/tests_ccil/case5.cl @@ -0,0 +1,25 @@ + class Main inherits IO { + a : Int; + b : A; + main(): Object + { { + b <- new B; + a <- ( + case b of + n : Bool => 1; + n : Int => 2; + n : Object => 5; + n : String => 3; + n : A => 7; + esac); + out_int(a); +} + + }; +}; + +class A { }; + +class B inherits A { }; + +class C inherits B { }; diff --git a/src/debbuging/tests_ccil/case6.cl b/src/debbuging/tests_ccil/case6.cl new file mode 100644 index 000000000..f9379e24b --- /dev/null +++ b/src/debbuging/tests_ccil/case6.cl @@ -0,0 +1,20 @@ + class Main inherits IO { + a : A = new A; + main(): Object + { { + b <- new B; + a <- ( + case b of + n : C => n.f(); + n : B => n.f(); + esac); + out_int(a); +} + + }; +}; + +class A { f():Int { 3 }; + +class B inherits A { f():Int {4 }; + diff --git a/src/debbuging/tests_ccil/div1.cl b/src/debbuging/tests_ccil/div1.cl new file mode 100644 index 000000000..2ee8acfd3 --- /dev/null +++ b/src/debbuging/tests_ccil/div1.cl @@ -0,0 +1,5 @@ + class Main { + main(): Int { + 3/2 + }; +}; diff --git a/src/debbuging/tests_ccil/fib1.cl b/src/debbuging/tests_ccil/fib1.cl new file mode 100644 index 000000000..08ceaede8 --- /dev/null +++ b/src/debbuging/tests_ccil/fib1.cl @@ -0,0 +1,29 @@ +class Main inherits IO { + -- the class has features. Only methods in this case. + main(): Object { + { + out_string("Enter n to find nth fibonacci number!\n"); + out_int(fib(in_int())); + out_string("\n"); + } + }; + + fib(i : Int) : Int { -- list of formals. And the return type of the method. + let a : Int <- 1, + b : Int <- 0, + c : Int <- 0 + in + { + while (not (i = 0)) loop -- expressions are nested. + { + c <- a + b; + i <- i - 1; + b <- a; + a <- c; + } + pool; + c; + } + }; + +}; diff --git a/src/debbuging/tests_ccil/self1.cl b/src/debbuging/tests_ccil/self1.cl new file mode 100644 index 000000000..d3106273e --- /dev/null +++ b/src/debbuging/tests_ccil/self1.cl @@ -0,0 +1,8 @@ + class Main { + main(): String { + self.f() + }; + f(): String { + "Hola mundo" + }; +}; From bec4db179f769758d15bac595eeea7de3ae85421 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:38:51 -0500 Subject: [PATCH 417/432] Mayor project re-structuring (first draw) --- src/{ => compiler}/asts/__init__.py | 0 src/{ => compiler}/asts/ccil_ast.py | 0 src/{ => compiler}/asts/inferencer_ast.py | 0 src/{ => compiler}/asts/mips_ast.py | 0 src/{ => compiler}/asts/parser_ast.py | 0 src/{ => compiler}/asts/types_ast.py | 0 .../visitors/ast_print}/__init__.py | 0 .../visitors/ast_print}/type_logger.py | 0 .../visitors/code_gen}/__init__.py | 0 .../visitors}/code_gen/ccil_gen.py | 0 .../visitors}/code_gen/ccil_mips_gen.py | 0 .../visitors}/code_gen/constants.py | 0 .../visitors}/code_gen/mips_gen.py | 0 src/{ => compiler/visitors}/code_gen/tools.py | 0 .../visitors}/lexing/__init__.py | 0 src/{ => compiler/visitors}/lexing/errors.py | 0 src/{ => compiler/visitors}/lexing/lexer.py | 0 .../visitors}/parsing/__init__.py | 0 src/{ => compiler/visitors}/parsing/errors.py | 0 src/{ => compiler/visitors}/parsing/parser.py | 0 .../visitors}/parsing/parsetab.py | 0 .../visitors}/semantics/__init__.py | 0 .../visitors}/semantics/inference/__init__.py | 0 .../semantics/inference/back_inferencer.py | 0 .../semantics/inference/hard_inferencer.py | 0 .../semantics/inference/soft_inferencer.py | 0 .../semantics/inference/types_inferencer.py | 0 .../visitors}/semantics/tools/__init__.py | 0 .../visitors}/semantics/tools/context.py | 0 .../visitors}/semantics/tools/errors.py | 0 .../visitors}/semantics/tools/scope.py | 0 .../visitors}/semantics/tools/type.py | 0 .../visitors}/semantics/type_builder.py | 0 .../visitors}/semantics/type_collector.py | 0 src/{ => compiler/visitors}/utils/__init__.py | 0 .../visitors}/utils/deep_equals.py | 0 src/{ => compiler/visitors}/utils/visitor.py | 0 src/debbuging/tests/Misc/00HelloRodro.cl | 5 - src/debbuging/tests/Misc/01Simple.cl | 13 - src/debbuging/tests/Misc/02Simple.cl | 9 - src/debbuging/tests/Misc/03Simple.cl | 23 - src/debbuging/tests/Misc/04SallySilly.cl | 10 - src/debbuging/tests/Misc/05Ackerman.cl | 24 - src/debbuging/tests/Misc/06FooBarRaz.cl | 67 --- src/debbuging/tests/Misc/07MultipleClass.cl | 46 -- src/debbuging/tests/Misc/08Cellullar.cl | 93 ---- src/debbuging/tests/Misc/09GameOfLife.cl | 436 ---------------- src/debbuging/tests/Misc/10BiG.cl | 477 ------------------ src/debbuging/tests/Misc/11Sum.cl | 9 - src/test.cl | 13 - .../Auto => tests/inference}/ackerman.cl | 0 .../tests/Auto => tests/inference}/assign1.cl | 0 .../Auto => tests/inference}/attributes1.cl | 0 .../Auto => tests/inference}/attributes2.cl | 0 .../tests/Auto => tests/inference}/call1.cl | 0 .../tests/Auto => tests/inference}/case1.cl | 0 .../tests/Auto => tests/inference}/case2.cl | 0 .../tests/Auto => tests/inference}/equals1.cl | 0 .../Auto => tests/inference}/fibonacci.cl | 0 .../tests/Auto => tests/inference}/if1.cl | 0 .../tests/Auto => tests/inference}/many1.cl | 0 .../tests/Auto => tests/inference}/many2.cl | 0 .../tests/Auto => tests/inference}/mixed1.cl | 0 .../tests/Auto => tests/inference}/mixed2.cl | 0 .../tests/Auto => tests/inference}/mixed3.cl | 0 .../inference}/not_that_simple1.cl | 0 .../tests/Auto => tests/inference}/param1.cl | 0 .../tests/Auto => tests/inference}/param2.cl | 0 .../tests/Auto => tests/inference}/point1.cl | 0 .../tests/Auto => tests/inference}/point2.cl | 0 .../Auto => tests/inference}/recursive1.cl | 0 .../Auto => tests/inference}/selftype1.cl | 0 .../Auto => tests/inference}/selftype2.cl | 0 .../Auto => tests/inference}/selftype3.cl | 0 .../Auto => tests/inference}/selftype4.cl | 0 .../Auto => tests/inference}/selftype5.cl | 0 .../tests/Auto => tests/inference}/simple1.cl | 0 .../tests/Auto => tests/inference}/simple2.cl | 0 .../tests/Auto => tests/inference}/simple3.cl | 0 .../tests/Auto => tests/inference}/simple4.cl | 0 .../tests_ccil => tests/normal}/abort1.cl | 0 .../normal}/allocation_call.cl | 0 .../normal}/aritmetica1.cl | 0 .../normal}/aritmetica2.cl | 0 .../normal}/aritmetica3.cl | 0 .../tests_ccil => tests/normal}/atributos1.cl | 0 .../tests_ccil => tests/normal}/attr.cl | 0 .../normal}/attr_inicialization.cl | 0 .../tests_ccil => tests/normal}/bool.cl | 0 .../tests_ccil => tests/normal}/case1.cl | 0 .../tests_ccil => tests/normal}/case2.cl | 0 .../tests_ccil => tests/normal}/case3.cl | 0 .../tests_ccil => tests/normal}/case4.cl | 0 .../tests_ccil => tests/normal}/case5.cl | 0 .../tests_ccil => tests/normal}/case6.cl | 0 .../tests_ccil => tests/normal}/classess1.cl | 0 .../tests_ccil => tests/normal}/cmp_string.cl | 0 .../tests_ccil => tests/normal}/concat_str.cl | 0 .../tests_ccil => tests/normal}/div1.cl | 0 .../tests_ccil => tests/normal}/fib.cl | 0 .../tests_ccil => tests/normal}/fib1.cl | 0 .../normal}/function_call.cl | 0 .../normal}/get_type_name.cl | 0 .../tests_ccil => tests/normal}/if1.cl | 0 .../normal}/instantiate1.cl | 0 .../tests_ccil => tests/normal}/isvoid1.cl | 0 .../tests_ccil => tests/normal}/isvoid2.cl | 0 .../tests_ccil => tests/normal}/len.cl | 0 .../tests_ccil => tests/normal}/let1.cl | 0 .../tests_ccil => tests/normal}/let2.cl | 0 .../normal}/let_instantiate.cl | 0 .../tests_ccil => tests/normal}/print_int.cl | 0 .../tests_ccil => tests/normal}/self1.cl | 0 .../tests_ccil => tests/normal}/selftype.cl | 0 .../tests_ccil => tests/normal}/simple.cl | 0 .../normal}/simple_attr.cl | 0 .../tests_ccil => tests/normal}/substring.cl | 0 117 files changed, 1225 deletions(-) rename src/{ => compiler}/asts/__init__.py (100%) rename src/{ => compiler}/asts/ccil_ast.py (100%) rename src/{ => compiler}/asts/inferencer_ast.py (100%) rename src/{ => compiler}/asts/mips_ast.py (100%) rename src/{ => compiler}/asts/parser_ast.py (100%) rename src/{ => compiler}/asts/types_ast.py (100%) rename src/{code_gen => compiler/visitors/ast_print}/__init__.py (100%) rename src/{debbuging => compiler/visitors/ast_print}/type_logger.py (100%) rename src/{debbuging => compiler/visitors/code_gen}/__init__.py (100%) rename src/{ => compiler/visitors}/code_gen/ccil_gen.py (100%) rename src/{ => compiler/visitors}/code_gen/ccil_mips_gen.py (100%) rename src/{ => compiler/visitors}/code_gen/constants.py (100%) rename src/{ => compiler/visitors}/code_gen/mips_gen.py (100%) rename src/{ => compiler/visitors}/code_gen/tools.py (100%) rename src/{ => compiler/visitors}/lexing/__init__.py (100%) rename src/{ => compiler/visitors}/lexing/errors.py (100%) rename src/{ => compiler/visitors}/lexing/lexer.py (100%) rename src/{ => compiler/visitors}/parsing/__init__.py (100%) rename src/{ => compiler/visitors}/parsing/errors.py (100%) rename src/{ => compiler/visitors}/parsing/parser.py (100%) rename src/{ => compiler/visitors}/parsing/parsetab.py (100%) rename src/{ => compiler/visitors}/semantics/__init__.py (100%) rename src/{ => compiler/visitors}/semantics/inference/__init__.py (100%) rename src/{ => compiler/visitors}/semantics/inference/back_inferencer.py (100%) rename src/{ => compiler/visitors}/semantics/inference/hard_inferencer.py (100%) rename src/{ => compiler/visitors}/semantics/inference/soft_inferencer.py (100%) rename src/{ => compiler/visitors}/semantics/inference/types_inferencer.py (100%) rename src/{ => compiler/visitors}/semantics/tools/__init__.py (100%) rename src/{ => compiler/visitors}/semantics/tools/context.py (100%) rename src/{ => compiler/visitors}/semantics/tools/errors.py (100%) rename src/{ => compiler/visitors}/semantics/tools/scope.py (100%) rename src/{ => compiler/visitors}/semantics/tools/type.py (100%) rename src/{ => compiler/visitors}/semantics/type_builder.py (100%) rename src/{ => compiler/visitors}/semantics/type_collector.py (100%) rename src/{ => compiler/visitors}/utils/__init__.py (100%) rename src/{ => compiler/visitors}/utils/deep_equals.py (100%) rename src/{ => compiler/visitors}/utils/visitor.py (100%) delete mode 100644 src/debbuging/tests/Misc/00HelloRodro.cl delete mode 100644 src/debbuging/tests/Misc/01Simple.cl delete mode 100644 src/debbuging/tests/Misc/02Simple.cl delete mode 100644 src/debbuging/tests/Misc/03Simple.cl delete mode 100644 src/debbuging/tests/Misc/04SallySilly.cl delete mode 100644 src/debbuging/tests/Misc/05Ackerman.cl delete mode 100644 src/debbuging/tests/Misc/06FooBarRaz.cl delete mode 100644 src/debbuging/tests/Misc/07MultipleClass.cl delete mode 100644 src/debbuging/tests/Misc/08Cellullar.cl delete mode 100644 src/debbuging/tests/Misc/09GameOfLife.cl delete mode 100644 src/debbuging/tests/Misc/10BiG.cl delete mode 100644 src/debbuging/tests/Misc/11Sum.cl delete mode 100644 src/test.cl rename src/{debbuging/tests/Auto => tests/inference}/ackerman.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/assign1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/attributes1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/attributes2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/call1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/case1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/case2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/equals1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/fibonacci.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/if1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/many1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/many2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/mixed1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/mixed2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/mixed3.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/not_that_simple1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/param1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/param2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/point1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/point2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/recursive1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/selftype1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/selftype2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/selftype3.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/selftype4.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/selftype5.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/simple1.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/simple2.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/simple3.cl (100%) rename src/{debbuging/tests/Auto => tests/inference}/simple4.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/abort1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/allocation_call.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/aritmetica1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/aritmetica2.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/aritmetica3.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/atributos1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/attr.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/attr_inicialization.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/bool.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case2.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case3.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case4.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case5.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/case6.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/classess1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/cmp_string.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/concat_str.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/div1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/fib.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/fib1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/function_call.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/get_type_name.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/if1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/instantiate1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/isvoid1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/isvoid2.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/len.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/let1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/let2.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/let_instantiate.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/print_int.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/self1.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/selftype.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/simple.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/simple_attr.cl (100%) rename src/{debbuging/tests_ccil => tests/normal}/substring.cl (100%) diff --git a/src/asts/__init__.py b/src/compiler/asts/__init__.py similarity index 100% rename from src/asts/__init__.py rename to src/compiler/asts/__init__.py diff --git a/src/asts/ccil_ast.py b/src/compiler/asts/ccil_ast.py similarity index 100% rename from src/asts/ccil_ast.py rename to src/compiler/asts/ccil_ast.py diff --git a/src/asts/inferencer_ast.py b/src/compiler/asts/inferencer_ast.py similarity index 100% rename from src/asts/inferencer_ast.py rename to src/compiler/asts/inferencer_ast.py diff --git a/src/asts/mips_ast.py b/src/compiler/asts/mips_ast.py similarity index 100% rename from src/asts/mips_ast.py rename to src/compiler/asts/mips_ast.py diff --git a/src/asts/parser_ast.py b/src/compiler/asts/parser_ast.py similarity index 100% rename from src/asts/parser_ast.py rename to src/compiler/asts/parser_ast.py diff --git a/src/asts/types_ast.py b/src/compiler/asts/types_ast.py similarity index 100% rename from src/asts/types_ast.py rename to src/compiler/asts/types_ast.py diff --git a/src/code_gen/__init__.py b/src/compiler/visitors/ast_print/__init__.py similarity index 100% rename from src/code_gen/__init__.py rename to src/compiler/visitors/ast_print/__init__.py diff --git a/src/debbuging/type_logger.py b/src/compiler/visitors/ast_print/type_logger.py similarity index 100% rename from src/debbuging/type_logger.py rename to src/compiler/visitors/ast_print/type_logger.py diff --git a/src/debbuging/__init__.py b/src/compiler/visitors/code_gen/__init__.py similarity index 100% rename from src/debbuging/__init__.py rename to src/compiler/visitors/code_gen/__init__.py diff --git a/src/code_gen/ccil_gen.py b/src/compiler/visitors/code_gen/ccil_gen.py similarity index 100% rename from src/code_gen/ccil_gen.py rename to src/compiler/visitors/code_gen/ccil_gen.py diff --git a/src/code_gen/ccil_mips_gen.py b/src/compiler/visitors/code_gen/ccil_mips_gen.py similarity index 100% rename from src/code_gen/ccil_mips_gen.py rename to src/compiler/visitors/code_gen/ccil_mips_gen.py diff --git a/src/code_gen/constants.py b/src/compiler/visitors/code_gen/constants.py similarity index 100% rename from src/code_gen/constants.py rename to src/compiler/visitors/code_gen/constants.py diff --git a/src/code_gen/mips_gen.py b/src/compiler/visitors/code_gen/mips_gen.py similarity index 100% rename from src/code_gen/mips_gen.py rename to src/compiler/visitors/code_gen/mips_gen.py diff --git a/src/code_gen/tools.py b/src/compiler/visitors/code_gen/tools.py similarity index 100% rename from src/code_gen/tools.py rename to src/compiler/visitors/code_gen/tools.py diff --git a/src/lexing/__init__.py b/src/compiler/visitors/lexing/__init__.py similarity index 100% rename from src/lexing/__init__.py rename to src/compiler/visitors/lexing/__init__.py diff --git a/src/lexing/errors.py b/src/compiler/visitors/lexing/errors.py similarity index 100% rename from src/lexing/errors.py rename to src/compiler/visitors/lexing/errors.py diff --git a/src/lexing/lexer.py b/src/compiler/visitors/lexing/lexer.py similarity index 100% rename from src/lexing/lexer.py rename to src/compiler/visitors/lexing/lexer.py diff --git a/src/parsing/__init__.py b/src/compiler/visitors/parsing/__init__.py similarity index 100% rename from src/parsing/__init__.py rename to src/compiler/visitors/parsing/__init__.py diff --git a/src/parsing/errors.py b/src/compiler/visitors/parsing/errors.py similarity index 100% rename from src/parsing/errors.py rename to src/compiler/visitors/parsing/errors.py diff --git a/src/parsing/parser.py b/src/compiler/visitors/parsing/parser.py similarity index 100% rename from src/parsing/parser.py rename to src/compiler/visitors/parsing/parser.py diff --git a/src/parsing/parsetab.py b/src/compiler/visitors/parsing/parsetab.py similarity index 100% rename from src/parsing/parsetab.py rename to src/compiler/visitors/parsing/parsetab.py diff --git a/src/semantics/__init__.py b/src/compiler/visitors/semantics/__init__.py similarity index 100% rename from src/semantics/__init__.py rename to src/compiler/visitors/semantics/__init__.py diff --git a/src/semantics/inference/__init__.py b/src/compiler/visitors/semantics/inference/__init__.py similarity index 100% rename from src/semantics/inference/__init__.py rename to src/compiler/visitors/semantics/inference/__init__.py diff --git a/src/semantics/inference/back_inferencer.py b/src/compiler/visitors/semantics/inference/back_inferencer.py similarity index 100% rename from src/semantics/inference/back_inferencer.py rename to src/compiler/visitors/semantics/inference/back_inferencer.py diff --git a/src/semantics/inference/hard_inferencer.py b/src/compiler/visitors/semantics/inference/hard_inferencer.py similarity index 100% rename from src/semantics/inference/hard_inferencer.py rename to src/compiler/visitors/semantics/inference/hard_inferencer.py diff --git a/src/semantics/inference/soft_inferencer.py b/src/compiler/visitors/semantics/inference/soft_inferencer.py similarity index 100% rename from src/semantics/inference/soft_inferencer.py rename to src/compiler/visitors/semantics/inference/soft_inferencer.py diff --git a/src/semantics/inference/types_inferencer.py b/src/compiler/visitors/semantics/inference/types_inferencer.py similarity index 100% rename from src/semantics/inference/types_inferencer.py rename to src/compiler/visitors/semantics/inference/types_inferencer.py diff --git a/src/semantics/tools/__init__.py b/src/compiler/visitors/semantics/tools/__init__.py similarity index 100% rename from src/semantics/tools/__init__.py rename to src/compiler/visitors/semantics/tools/__init__.py diff --git a/src/semantics/tools/context.py b/src/compiler/visitors/semantics/tools/context.py similarity index 100% rename from src/semantics/tools/context.py rename to src/compiler/visitors/semantics/tools/context.py diff --git a/src/semantics/tools/errors.py b/src/compiler/visitors/semantics/tools/errors.py similarity index 100% rename from src/semantics/tools/errors.py rename to src/compiler/visitors/semantics/tools/errors.py diff --git a/src/semantics/tools/scope.py b/src/compiler/visitors/semantics/tools/scope.py similarity index 100% rename from src/semantics/tools/scope.py rename to src/compiler/visitors/semantics/tools/scope.py diff --git a/src/semantics/tools/type.py b/src/compiler/visitors/semantics/tools/type.py similarity index 100% rename from src/semantics/tools/type.py rename to src/compiler/visitors/semantics/tools/type.py diff --git a/src/semantics/type_builder.py b/src/compiler/visitors/semantics/type_builder.py similarity index 100% rename from src/semantics/type_builder.py rename to src/compiler/visitors/semantics/type_builder.py diff --git a/src/semantics/type_collector.py b/src/compiler/visitors/semantics/type_collector.py similarity index 100% rename from src/semantics/type_collector.py rename to src/compiler/visitors/semantics/type_collector.py diff --git a/src/utils/__init__.py b/src/compiler/visitors/utils/__init__.py similarity index 100% rename from src/utils/__init__.py rename to src/compiler/visitors/utils/__init__.py diff --git a/src/utils/deep_equals.py b/src/compiler/visitors/utils/deep_equals.py similarity index 100% rename from src/utils/deep_equals.py rename to src/compiler/visitors/utils/deep_equals.py diff --git a/src/utils/visitor.py b/src/compiler/visitors/utils/visitor.py similarity index 100% rename from src/utils/visitor.py rename to src/compiler/visitors/utils/visitor.py diff --git a/src/debbuging/tests/Misc/00HelloRodro.cl b/src/debbuging/tests/Misc/00HelloRodro.cl deleted file mode 100644 index 08352cbc8..000000000 --- a/src/debbuging/tests/Misc/00HelloRodro.cl +++ /dev/null @@ -1,5 +0,0 @@ -class Main inherits IO { - main(): SELF_TYPE { - out_string("Hello, Rodro.\n") - }; -}; diff --git a/src/debbuging/tests/Misc/01Simple.cl b/src/debbuging/tests/Misc/01Simple.cl deleted file mode 100644 index 9046024dc..000000000 --- a/src/debbuging/tests/Misc/01Simple.cl +++ /dev/null @@ -1,13 +0,0 @@ -class Main{ - a: A; - - main(): A { - a <- new A - }; -}; - -class A { - method(): Int{ - 1 - }; -}; diff --git a/src/debbuging/tests/Misc/02Simple.cl b/src/debbuging/tests/Misc/02Simple.cl deleted file mode 100644 index eea0900fb..000000000 --- a/src/debbuging/tests/Misc/02Simple.cl +++ /dev/null @@ -1,9 +0,0 @@ - -class Main{ - a: A; - main(b:Int): A { - b <- 3 - }; -}; - -class A{}; diff --git a/src/debbuging/tests/Misc/03Simple.cl b/src/debbuging/tests/Misc/03Simple.cl deleted file mode 100644 index 978e266e2..000000000 --- a/src/debbuging/tests/Misc/03Simple.cl +++ /dev/null @@ -1,23 +0,0 @@ - -class Main{ - a: A; - main(): A { - 1 - }; -}; - -class A { - oper(a : Int, b : Int): Int{ - a + b - }; -}; -class B inherits A { - oper(a : Int, b : Int, c : Int) : Int{ - a * b * c - }; -}; -class C inherits A { - oper(a : Int, b : String) : Bool{ - a + b - }; -}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/04SallySilly.cl b/src/debbuging/tests/Misc/04SallySilly.cl deleted file mode 100644 index f4afdca9a..000000000 --- a/src/debbuging/tests/Misc/04SallySilly.cl +++ /dev/null @@ -1,10 +0,0 @@ -class Silly -{ - capy() : SELF_TYPE { self }; -}; -class Sally inherits Silly { }; - -class Main { - x : Sally <- (new Sally).capy(); - main() : Sally { x }; -}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/05Ackerman.cl b/src/debbuging/tests/Misc/05Ackerman.cl deleted file mode 100644 index 0ca3e1c7f..000000000 --- a/src/debbuging/tests/Misc/05Ackerman.cl +++ /dev/null @@ -1,24 +0,0 @@ -class Main inherits IO{ - a : Ackermann ; - main(): SELF_TYPE {{ - a <- new Ackermann; - out_int(a.ackermann(1,3)); - } - }; -}; - -class Fact { - fact(n : Int): Int{ - if (n=0) then 1 else n*fact(n-1) fi - }; -}; - -class Ackermann { - ackermann(m:Int, n: Int): Int{ - if (m = 0 ) then n+1 else - if ( n = 0) then ackermann(m-1, 1) else - ackermann(m-1, ackermann(m, n-1)) - fi - fi - }; -}; \ No newline at end of file diff --git a/src/debbuging/tests/Misc/06FooBarRaz.cl b/src/debbuging/tests/Misc/06FooBarRaz.cl deleted file mode 100644 index ec38a7766..000000000 --- a/src/debbuging/tests/Misc/06FooBarRaz.cl +++ /dev/null @@ -1,67 +0,0 @@ -(* hairy . . .*) - -class Foo inherits Bazz { - a : Razz <- case self of - n : Razz => (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - b : Int <- a.doh() + g.doh() + doh() + printh(); - - doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; - -}; - -class Bar inherits Razz { - - c : Int <- doh(); - - d : Object <- printh(); -}; - - -class Razz inherits Foo { - - e : Bar <- case self of - n : Razz => (new Bar); - n : Bar => n; - esac; - - f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); - -}; - -class Bazz inherits IO { - - h : Int <- 1; - - g : Foo <- case self of - n : Bazz => (new Foo); - n : Razz => (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - i : Object <- printh(); - - printh() : Int { { out_int(h); 0; } }; - - doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; -}; - -(* scary . . . *) -class Main { - a : Bazz <- new Bazz; - b : Foo <- new Foo; - c : Razz <- new Razz; - d : Bar <- new Bar; - - main(): String { "do nothing" }; - -}; - - - - - diff --git a/src/debbuging/tests/Misc/07MultipleClass.cl b/src/debbuging/tests/Misc/07MultipleClass.cl deleted file mode 100644 index 52464394a..000000000 --- a/src/debbuging/tests/Misc/07MultipleClass.cl +++ /dev/null @@ -1,46 +0,0 @@ -class Main -{ - h:AUTO_TYPE <- new H; - a:AUTO_TYPE <- new A; - main(): Int - { - { - 3; - } - }; -}; - -class H -{ - a:Int; -}; - -class Z inherits H -{ - x:Int; -}; - -class A inherits F -{ - b:Int; -}; - -class B inherits A -{ - c:Int; -}; - -class C inherits B -{ - e:Int; -}; - -class D inherits C -{ - f:Int; -}; - -class F inherits D -{ - g:Int; -}; diff --git a/src/debbuging/tests/Misc/08Cellullar.cl b/src/debbuging/tests/Misc/08Cellullar.cl deleted file mode 100644 index a43e3fa4a..000000000 --- a/src/debbuging/tests/Misc/08Cellullar.cl +++ /dev/null @@ -1,93 +0,0 @@ -class CellularAutomaton inherits IO { - population_map : String; - - init(map : String) : SELF_TYPE { - { - population_map <- map; - self; - } - }; - - print() : SELF_TYPE { - { - out_string(population_map.concat("\n")); - self; - } - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - population_map.substr(position, 1) - }; - - cell_left_neighbor(position : Int) : String { - if position = 0 then - cell(num_cells() - 1) - else - cell(position - 1) - fi - }; - - cell_right_neighbor(position : Int) : String { - if position = num_cells() - 1 then - cell(0) - else - cell(position + 1) - fi - }; - - (* a cell will live if exactly 1 of itself and it's immediate - neighbors are alive *) - cell_at_next_evolution(position : Int) : String { - if ((if cell(position) = "X" then 1 else 0 fi) - + (if cell_left_neighbor(position) = "X" then 1 else 0 fi) - + (if cell_right_neighbor(position) = "X" then 1 else 0 fi) - = 1) - then - "X" - else - "." - fi - }; - - evolve() : SELF_TYPE { - (let position : Int in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; -}; - -class Main { - cells : CellularAutomaton; - - main() : SELF_TYPE { - { - cells <- (new CellularAutomaton).init(" X "); - cells.print(); - (let countdown : Int <- 20 in - while 0 < countdown loop - { - cells.evolve(); - cells.print(); - countdown <- countdown - 1; - } - pool - ); - self; - } - }; -}; diff --git a/src/debbuging/tests/Misc/09GameOfLife.cl b/src/debbuging/tests/Misc/09GameOfLife.cl deleted file mode 100644 index 25facd526..000000000 --- a/src/debbuging/tests/Misc/09GameOfLife.cl +++ /dev/null @@ -1,436 +0,0 @@ -(* The Game of Life - Tendo Kayiira, Summer '95 - With code taken from /private/cool/class/examples/cells.cl - - This introduction was taken off the internet. It gives a brief - description of the Game Of Life. It also gives the rules by which - this particular game follows. - - Introduction - - John Conway's Game of Life is a mathematical amusement, but it - is also much more: an insight into how a system of simple - cellualar automata can create complex, odd, and often aesthetically - pleasing patterns. It is played on a cartesian grid of cells - which are either 'on' or 'off' The game gets it's name from the - similarity between the behaviour of these cells and the behaviour - of living organisms. - - The Rules - - The playfield is a cartesian grid of arbitrary size. Each cell in - this grid can be in an 'on' state or an 'off' state. On each 'turn' - (called a generation,) the state of each cell changes simultaneously - depending on it's state and the state of all cells adjacent to it. - - For 'on' cells, - If the cell has 0 or 1 neighbours which are 'on', the cell turns - 'off'. ('dies of loneliness') - If the cell has 2 or 3 neighbours which are 'on', the cell stays - 'on'. (nothing happens to that cell) - If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', - the cell turns 'off'. ('dies of overcrowding') - - For 'off' cells, - If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which - are 'on', the cell stays 'off'. (nothing happens to that cell) - If the cell has 3 neighbours which are 'on', the cell turns - 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) - - Repeat for as many generations as desired. - - *) - - -class Board inherits IO { - - rows : Int; - columns : Int; - board_size : Int; - - size_of_board(initial : String) : Int { - initial.length() - }; - - board_init(start : String) : SELF_TYPE { - (let size :Int <- size_of_board(start) in - { - if size = 15 then - { - rows <- 3; - columns <- 5; - board_size <- size; - } - else if size = 16 then - { - rows <- 4; - columns <- 4; - board_size <- size; - } - else if size = 20 then - { - rows <- 4; - columns <- 5; - board_size <- size; - } - else if size = 21 then - { - rows <- 3; - columns <- 7; - board_size <- size; - } - else if size = 25 then - { - rows <- 5; - columns <- 5; - board_size <- size; - } - else if size = 28 then - { - rows <- 7; - columns <- 4; - board_size <- size; - } - else - { - rows <- 5; - columns <- 5; - board_size <- size; - } - fi fi fi fi fi fi; - self; - } - ) - }; - -}; - - - -class CellularAutomaton inherits Board { - population_map : String; - - init(map : String) : SELF_TYPE { - { - population_map <- map; - board_init(map); - self; - } - }; - - - - - print() : SELF_TYPE { - - (let i : Int <- 0 in - (let num : Int <- board_size in - { - out_string("\n"); - while i < num loop - { - out_string(population_map.substr(i,columns)); - out_string("\n"); - i <- i + columns; - } - pool; - out_string("\n"); - self; - } - ) ) - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - if board_size - 1 < position then - " " - else - population_map.substr(position, 1) - fi - }; - - north(position : Int): String { - if (position - columns) < 0 then - " " - else - cell(position - columns) - fi - }; - - south(position : Int): String { - if board_size < (position + columns) then - " " - else - cell(position + columns) - fi - }; - - east(position : Int): String { - if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - cell(position + 1) - fi - }; - - west(position : Int): String { - if position = 0 then - " " - else - if ((position / columns) * columns) = position then - " " - else - cell(position - 1) - fi fi - }; - - northwest(position : Int): String { - if (position - columns) < 0 then - " " - else if ((position / columns) * columns) = position then - " " - else - north(position - 1) - fi fi - }; - - northeast(position : Int): String { - if (position - columns) < 0 then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - north(position + 1) - fi fi - }; - - southeast(position : Int): String { - if board_size < (position + columns) then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - south(position + 1) - fi fi - }; - - southwest(position : Int): String { - if board_size < (position + columns) then - " " - else if ((position / columns) * columns) = position then - " " - else - south(position - 1) - fi fi - }; - - neighbors(position: Int): Int { - { - (if north(position) = "X" then 1 else 0 fi) - + (if south(position) = "X" then 1 else 0 fi) - + (if east(position) = "X" then 1 else 0 fi) - + (if west(position) = "X" then 1 else 0 fi) - + (if northeast(position) = "X" then 1 else 0 fi) - + (if northwest(position) = "X" then 1 else 0 fi) - + (if southeast(position) = "X" then 1 else 0 fi) - + (if southwest(position) = "X" then 1 else 0 fi); - } - }; - - -(* A cell will live if 2 or 3 of it's neighbors are alive. It dies - otherwise. A cell is born if only 3 of it's neighbors are alive. *) - - cell_at_next_evolution(position : Int) : String { - - if neighbors(position) = 3 then - "X" - else - if neighbors(position) = 2 then - if cell(position) = "X" then - "X" - else - "-" - fi - else - "-" - fi fi - }; - - - evolve() : SELF_TYPE { - (let position : Int <- 0 in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; - -(* This is where the background pattern is detremined by the user. More - patterns can be added as long as whoever adds keeps the board either - 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) - option(): String { - { - (let num : Int in - { - out_string("\nPlease chose a number:\n"); - out_string("\t1: A cross\n"); - out_string("\t2: A slash from the upper left to lower right\n"); - out_string("\t3: A slash from the upper right to lower left\n"); - out_string("\t4: An X\n"); - out_string("\t5: A greater than sign \n"); - out_string("\t6: A less than sign\n"); - out_string("\t7: Two greater than signs\n"); - out_string("\t8: Two less than signs\n"); - out_string("\t9: A 'V'\n"); - out_string("\t10: An inverse 'V'\n"); - out_string("\t11: Numbers 9 and 10 combined\n"); - out_string("\t12: A full grid\n"); - out_string("\t13: A 'T'\n"); - out_string("\t14: A plus '+'\n"); - out_string("\t15: A 'W'\n"); - out_string("\t16: An 'M'\n"); - out_string("\t17: An 'E'\n"); - out_string("\t18: A '3'\n"); - out_string("\t19: An 'O'\n"); - out_string("\t20: An '8'\n"); - out_string("\t21: An 'S'\n"); - out_string("Your choice => "); - num <- in_int(); - out_string("\n"); - if num = 1 then - " XX XXXX XXXX XX " - else if num = 2 then - " X X X X X " - else if num = 3 then - "X X X X X" - else if num = 4 then - "X X X X X X X X X" - else if num = 5 then - "X X X X X " - else if num = 6 then - " X X X X X" - else if num = 7 then - "X X X XX X " - else if num = 8 then - " X XX X X X " - else if num = 9 then - "X X X X X " - else if num = 10 then - " X X X X X" - else if num = 11 then - "X X X X X X X X" - else if num = 12 then - "XXXXXXXXXXXXXXXXXXXXXXXXX" - else if num = 13 then - "XXXXX X X X X " - else if num = 14 then - " X X XXXXX X X " - else if num = 15 then - "X X X X X X X " - else if num = 16 then - " X X X X X X X" - else if num = 17 then - "XXXXX X XXXXX X XXXX" - else if num = 18 then - "XXX X X X X XXXX " - else if num = 19 then - " XX X XX X XX " - else if num = 20 then - " XX X XX X XX X XX X XX " - else if num = 21 then - " XXXX X XX X XXXX " - else - " " - fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; - } - ); - } - }; - - - - - prompt() : Bool { - { - (let ans : String in - { - out_string("Would you like to continue with the next generation? \n"); - out_string("Please use lowercase y or n for your answer [y]: "); - ans <- in_string(); - out_string("\n"); - if ans = "n" then - false - else - true - fi; - } - ); - } - }; - - - prompt2() : Bool { - (let ans : String in - { - out_string("\n\n"); - out_string("Would you like to choose a background pattern? \n"); - out_string("Please use lowercase y or n for your answer [n]: "); - ans <- in_string(); - if ans = "y" then - true - else - false - fi; - } - ) - }; - - -}; - -class Main inherits CellularAutomaton { - cells : CellularAutomaton; - - main() : SELF_TYPE { - { - (let continue : Bool in - (let choice : String in - { - out_string("Welcome to the Game of Life.\n"); - out_string("There are many initial states to choose from. \n"); - while prompt2() loop - { - continue <- true; - choice <- option(); - cells <- (new CellularAutomaton).init(choice); - cells.print(); - while continue loop - if prompt() then - { - cells.evolve(); - cells.print(); - } - else - continue <- false - fi - pool; - } - pool; - self; - } ) ); } - }; -}; - diff --git a/src/debbuging/tests/Misc/10BiG.cl b/src/debbuging/tests/Misc/10BiG.cl deleted file mode 100644 index 775589cce..000000000 --- a/src/debbuging/tests/Misc/10BiG.cl +++ /dev/null @@ -1,477 +0,0 @@ -(* A program for - - 1. Representing lambda terms - 2. Interpreting lambda terms - 3. Compiling lambda calculus programs to Cool - - The lambda calculus is described by the following grammar: - - e ::= x a variable - | \x.e a function with argument x - | e1@e2 apply function e1 to argument e2 - - Jeff Foster (jfoster@cs.berkeley.edu) - March 24, 2000 -*) - -(* - * A list of variables. We use this to do de Bruijn numbering - * - *) -class VarList inherits IO { - isNil() : Bool { true }; - head() : Variable { { abort(); new Variable; } }; - tail() : VarList { { abort(); new VarList; } }; - add(x : Variable) : VarList { (new VarListNE).init(x, self) }; - print() : SELF_TYPE { out_string("\n") }; -}; - -class VarListNE inherits VarList { - x : Variable; - rest : VarList; - isNil() : Bool { false }; - head() : Variable { x }; - tail() : VarList { rest }; - init(y : Variable, r : VarList) : VarListNE { { x <- y; rest <- r; self; } }; - print() : SELF_TYPE { { x.print_self(); out_string(" "); - rest.print(); self; } }; -}; - -(* - * A list of closures we need to build. We need to number (well, name) - * the closures uniquely. - *) -class LambdaList { - isNil() : Bool { true }; - headE() : VarList { { abort(); new VarList; } }; - headC() : Lambda { { abort(); new Lambda; } }; - headN() : Int { { abort(); 0; } }; - tail() : LambdaList { { abort(); new LambdaList; } }; - add(e : VarList, x : Lambda, n : Int) : LambdaList { - (new LambdaListNE).init(e, x, n, self) - }; -}; - -class LambdaListNE inherits LambdaList { - lam : Lambda; - num : Int; - env : VarList; - rest : LambdaList; - isNil() : Bool { false }; - headE() : VarList { env }; - headC() : Lambda { lam }; - headN() : Int { num }; - tail() : LambdaList { rest }; - init(e : VarList, l : Lambda, n : Int, r : LambdaList) : LambdaListNE { - { - env <- e; - lam <- l; - num <- n; - rest <- r; - self; - } - }; -}; - -class LambdaListRef { - nextNum : Int <- 0; - l : LambdaList; - isNil() : Bool { l.isNil() }; - headE() : VarList { l.headE() }; - headC() : Lambda { l.headC() }; - headN() : Int { l.headN() }; - reset() : SELF_TYPE { - { - nextNum <- 0; - l <- new LambdaList; - self; - } - }; - add(env : VarList, c : Lambda) : Int { - { - l <- l.add(env, c, nextNum); - nextNum <- nextNum + 1; - nextNum - 1; - } - }; - removeHead() : SELF_TYPE { - { - l <- l.tail(); - self; - } - }; -}; - -(* - * Lambda expressions - * - *) - --- A pure virtual class representing any expression -class Expr inherits IO { - - -- Print this lambda term - print_self() : SELF_TYPE { - { - out_string("\nError: Expr is pure virtual; can't print self\n"); - abort(); - self; - } - }; - - -- Do one step of (outermost) beta reduction to this term - beta() : Expr { - { - out_string("\nError: Expr is pure virtual; can't beta-reduce\n"); - abort(); - self; - } - }; - - -- Replace all occurrences of x by e - substitute(x : Variable, e : Expr) : Expr { - { - out_string("\nError: Expr is pure virtual; can't substitute\n"); - abort(); - self; - } - }; - - -- Generate Cool code to evaluate this expression - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("\nError: Expr is pure virtual; can't gen_code\n"); - abort(); - self; - } - }; -}; - -(* - * Variables - *) -class Variable inherits Expr { - name : String; - - init(n:String) : Variable { - { - name <- n; - self; - } - }; - - print_self() : SELF_TYPE { - out_string(name) - }; - - beta() : Expr { self }; - - substitute(x : Variable, e : Expr) : Expr { - if x = self then e else self fi - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - let cur_env : VarList <- env in - { while (if cur_env.isNil() then - false - else - not (cur_env.head() = self) - fi) loop - { out_string("get_parent()."); - cur_env <- cur_env.tail(); - } - pool; - if cur_env.isNil() then - { out_string("Error: free occurrence of "); - print_self(); - out_string("\n"); - abort(); - self; - } - else - out_string("get_x()") - fi; - } - }; -}; - -(* - * Functions - *) -class Lambda inherits Expr { - arg : Variable; - body : Expr; - - init(a:Variable, b:Expr) : Lambda { - { - arg <- a; - body <- b; - self; - } - }; - - print_self() : SELF_TYPE { - { - out_string("\\"); - arg.print_self(); - out_string("."); - body.print_self(); - self; - } - }; - - beta() : Expr { self }; - - apply(actual : Expr) : Expr { - body.substitute(arg, actual) - }; - - -- We allow variables to be reused - substitute(x : Variable, e : Expr) : Expr { - if x = arg then - self - else - let new_body : Expr <- body.substitute(x, e), - new_lam : Lambda <- new Lambda in - new_lam.init(arg, new_body) - fi - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("((new Closure"); - out_int(closures.add(env, self)); - out_string(").init("); - if env.isNil() then - out_string("new Closure))") - else - out_string("self))") fi; - self; - } - }; - - gen_closure_code(n : Int, env : VarList, - closures : LambdaListRef) : SELF_TYPE { - { - out_string("class Closure"); - out_int(n); - out_string(" inherits Closure {\n"); - out_string(" apply(y : EvalObject) : EvalObject {\n"); - out_string(" { out_string(\"Applying closure "); - out_int(n); - out_string("\\n\");\n"); - out_string(" x <- y;\n"); - body.gen_code(env.add(arg), closures); - out_string(";}};\n"); - out_string("};\n"); - } - }; -}; - -(* - * Applications - *) -class App inherits Expr { - fun : Expr; - arg : Expr; - - init(f : Expr, a : Expr) : App { - { - fun <- f; - arg <- a; - self; - } - }; - - print_self() : SELF_TYPE { - { - out_string("(("); - fun.print_self(); - out_string(")@("); - arg.print_self(); - out_string("))"); - self; - } - }; - - beta() : Expr { - case fun of - l : Lambda => l.apply(arg); -- Lazy evaluation - e : Expr => - let new_fun : Expr <- fun.beta(), - new_app : App <- new App in - new_app.init(new_fun, arg); - esac - }; - - substitute(x : Variable, e : Expr) : Expr { - let new_fun : Expr <- fun.substitute(x, e), - new_arg : Expr <- arg.substitute(x, e), - new_app : App <- new App in - new_app.init(new_fun, new_arg) - }; - - gen_code(env : VarList, closures : LambdaListRef) : SELF_TYPE { - { - out_string("(let x : EvalObject <- "); - fun.gen_code(env, closures); - out_string(",\n"); - out_string(" y : EvalObject <- "); - arg.gen_code(env, closures); - out_string(" in\n"); - out_string(" case x of\n"); - out_string(" c : Closure => c.apply(y);\n"); - out_string(" o : Object => { abort(); new EvalObject; };\n"); - out_string(" esac)"); - } - }; -}; - -(* - * Term: A class for building up terms - * - *) - -class Term inherits IO { - (* - * The basics - *) - var(x : String) : Variable { - let v : Variable <- new Variable in - v.init(x) - }; - - lam(x : Variable, e : Expr) : Lambda { - let l : Lambda <- new Lambda in - l.init(x, e) - }; - - app(e1 : Expr, e2 : Expr) : App { - let a : App <- new App in - a.init(e1, e2) - }; - - (* - * Some useful terms - *) - i() : Expr { - let x : Variable <- var("x") in - lam(x,x) - }; - - k() : Expr { - let x : Variable <- var("x"), - y : Variable <- var("y") in - lam(x,lam(y,x)) - }; - - s() : Expr { - let x : Variable <- var("x"), - y : Variable <- var("y"), - z : Variable <- var("z") in - lam(x,lam(y,lam(z,app(app(x,z),app(y,z))))) - }; - -}; - -(* - * - * The main method -- build up some lambda terms and try things out - * - *) - -class Main inherits Term { - -- Beta-reduce an expression, printing out the term at each step - beta_reduce(e : Expr) : Expr { - { - out_string("beta-reduce: "); - e.print_self(); - let done : Bool <- false, - new_expr : Expr in - { - while (not done) loop - { - new_expr <- e.beta(); - if (new_expr = e) then - done <- true - else - { - e <- new_expr; - out_string(" =>\n"); - e.print_self(); - } - fi; - } - pool; - out_string("\n"); - e; - }; - } - }; - - eval_class() : SELF_TYPE { - { - out_string("class EvalObject inherits IO {\n"); - out_string(" eval() : EvalObject { { abort(); self; } };\n"); - out_string("};\n"); - } - }; - - closure_class() : SELF_TYPE { - { - out_string("class Closure inherits EvalObject {\n"); - out_string(" parent : Closure;\n"); - out_string(" x : EvalObject;\n"); - out_string(" get_parent() : Closure { parent };\n"); - out_string(" get_x() : EvalObject { x };\n"); - out_string(" init(p : Closure) : Closure {{ parent <- p; self; }};\n"); - out_string(" apply(y : EvalObject) : EvalObject { { abort(); self; } };\n"); - out_string("};\n"); - } - }; - - gen_code(e : Expr) : SELF_TYPE { - let cl : LambdaListRef <- (new LambdaListRef).reset() in - { - out_string("Generating code for "); - e.print_self(); - out_string("\n------------------cut here------------------\n"); - out_string("(*Generated by lam.cl (Jeff Foster, March 2000)*)\n"); - eval_class(); - closure_class(); - out_string("class Main {\n"); - out_string(" main() : EvalObject {\n"); - e.gen_code(new VarList, cl); - out_string("\n};\n};\n"); - while (not (cl.isNil())) loop - let e : VarList <- cl.headE(), - c : Lambda <- cl.headC(), - n : Int <- cl.headN() in - { - cl.removeHead(); - c.gen_closure_code(n, e, cl); - } - pool; - out_string("\n------------------cut here------------------\n"); - } - }; - - main() : Int { - { - i().print_self(); - out_string("\n"); - k().print_self(); - out_string("\n"); - s().print_self(); - out_string("\n"); - beta_reduce(app(app(app(s(), k()), i()), i())); - beta_reduce(app(app(k(),i()),i())); - gen_code(app(i(), i())); - gen_code(app(app(app(s(), k()), i()), i())); - gen_code(app(app(app(app(app(app(app(app(i(), k()), s()), s()), - k()), s()), i()), k()), i())); - gen_code(app(app(i(), app(k(), s())), app(k(), app(s(), s())))); - 0; - } - }; -}; diff --git a/src/debbuging/tests/Misc/11Sum.cl b/src/debbuging/tests/Misc/11Sum.cl deleted file mode 100644 index 0d904f950..000000000 --- a/src/debbuging/tests/Misc/11Sum.cl +++ /dev/null @@ -1,9 +0,0 @@ -class Main inherits IO { - main(): Int { - { - 100 / 2 - 10 / 5; - 100 / 10 / 5 / 2; - } - }; -}; - diff --git a/src/test.cl b/src/test.cl deleted file mode 100644 index febe48b82..000000000 --- a/src/test.cl +++ /dev/null @@ -1,13 +0,0 @@ -class Main { - -- main () : AUTO_TYPE { method(1,2,3,4,5,6) }; - main(): Int {0}; - - method(a : AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d : AUTO_TYPE, e: AUTO_TYPE, f: AUTO_TYPE): AUTO_TYPE{{ - a <- e; - b <- a; - c <- b; - d <- c; - e <- f; - f + 12; - }}; -}; \ No newline at end of file diff --git a/src/debbuging/tests/Auto/ackerman.cl b/src/tests/inference/ackerman.cl similarity index 100% rename from src/debbuging/tests/Auto/ackerman.cl rename to src/tests/inference/ackerman.cl diff --git a/src/debbuging/tests/Auto/assign1.cl b/src/tests/inference/assign1.cl similarity index 100% rename from src/debbuging/tests/Auto/assign1.cl rename to src/tests/inference/assign1.cl diff --git a/src/debbuging/tests/Auto/attributes1.cl b/src/tests/inference/attributes1.cl similarity index 100% rename from src/debbuging/tests/Auto/attributes1.cl rename to src/tests/inference/attributes1.cl diff --git a/src/debbuging/tests/Auto/attributes2.cl b/src/tests/inference/attributes2.cl similarity index 100% rename from src/debbuging/tests/Auto/attributes2.cl rename to src/tests/inference/attributes2.cl diff --git a/src/debbuging/tests/Auto/call1.cl b/src/tests/inference/call1.cl similarity index 100% rename from src/debbuging/tests/Auto/call1.cl rename to src/tests/inference/call1.cl diff --git a/src/debbuging/tests/Auto/case1.cl b/src/tests/inference/case1.cl similarity index 100% rename from src/debbuging/tests/Auto/case1.cl rename to src/tests/inference/case1.cl diff --git a/src/debbuging/tests/Auto/case2.cl b/src/tests/inference/case2.cl similarity index 100% rename from src/debbuging/tests/Auto/case2.cl rename to src/tests/inference/case2.cl diff --git a/src/debbuging/tests/Auto/equals1.cl b/src/tests/inference/equals1.cl similarity index 100% rename from src/debbuging/tests/Auto/equals1.cl rename to src/tests/inference/equals1.cl diff --git a/src/debbuging/tests/Auto/fibonacci.cl b/src/tests/inference/fibonacci.cl similarity index 100% rename from src/debbuging/tests/Auto/fibonacci.cl rename to src/tests/inference/fibonacci.cl diff --git a/src/debbuging/tests/Auto/if1.cl b/src/tests/inference/if1.cl similarity index 100% rename from src/debbuging/tests/Auto/if1.cl rename to src/tests/inference/if1.cl diff --git a/src/debbuging/tests/Auto/many1.cl b/src/tests/inference/many1.cl similarity index 100% rename from src/debbuging/tests/Auto/many1.cl rename to src/tests/inference/many1.cl diff --git a/src/debbuging/tests/Auto/many2.cl b/src/tests/inference/many2.cl similarity index 100% rename from src/debbuging/tests/Auto/many2.cl rename to src/tests/inference/many2.cl diff --git a/src/debbuging/tests/Auto/mixed1.cl b/src/tests/inference/mixed1.cl similarity index 100% rename from src/debbuging/tests/Auto/mixed1.cl rename to src/tests/inference/mixed1.cl diff --git a/src/debbuging/tests/Auto/mixed2.cl b/src/tests/inference/mixed2.cl similarity index 100% rename from src/debbuging/tests/Auto/mixed2.cl rename to src/tests/inference/mixed2.cl diff --git a/src/debbuging/tests/Auto/mixed3.cl b/src/tests/inference/mixed3.cl similarity index 100% rename from src/debbuging/tests/Auto/mixed3.cl rename to src/tests/inference/mixed3.cl diff --git a/src/debbuging/tests/Auto/not_that_simple1.cl b/src/tests/inference/not_that_simple1.cl similarity index 100% rename from src/debbuging/tests/Auto/not_that_simple1.cl rename to src/tests/inference/not_that_simple1.cl diff --git a/src/debbuging/tests/Auto/param1.cl b/src/tests/inference/param1.cl similarity index 100% rename from src/debbuging/tests/Auto/param1.cl rename to src/tests/inference/param1.cl diff --git a/src/debbuging/tests/Auto/param2.cl b/src/tests/inference/param2.cl similarity index 100% rename from src/debbuging/tests/Auto/param2.cl rename to src/tests/inference/param2.cl diff --git a/src/debbuging/tests/Auto/point1.cl b/src/tests/inference/point1.cl similarity index 100% rename from src/debbuging/tests/Auto/point1.cl rename to src/tests/inference/point1.cl diff --git a/src/debbuging/tests/Auto/point2.cl b/src/tests/inference/point2.cl similarity index 100% rename from src/debbuging/tests/Auto/point2.cl rename to src/tests/inference/point2.cl diff --git a/src/debbuging/tests/Auto/recursive1.cl b/src/tests/inference/recursive1.cl similarity index 100% rename from src/debbuging/tests/Auto/recursive1.cl rename to src/tests/inference/recursive1.cl diff --git a/src/debbuging/tests/Auto/selftype1.cl b/src/tests/inference/selftype1.cl similarity index 100% rename from src/debbuging/tests/Auto/selftype1.cl rename to src/tests/inference/selftype1.cl diff --git a/src/debbuging/tests/Auto/selftype2.cl b/src/tests/inference/selftype2.cl similarity index 100% rename from src/debbuging/tests/Auto/selftype2.cl rename to src/tests/inference/selftype2.cl diff --git a/src/debbuging/tests/Auto/selftype3.cl b/src/tests/inference/selftype3.cl similarity index 100% rename from src/debbuging/tests/Auto/selftype3.cl rename to src/tests/inference/selftype3.cl diff --git a/src/debbuging/tests/Auto/selftype4.cl b/src/tests/inference/selftype4.cl similarity index 100% rename from src/debbuging/tests/Auto/selftype4.cl rename to src/tests/inference/selftype4.cl diff --git a/src/debbuging/tests/Auto/selftype5.cl b/src/tests/inference/selftype5.cl similarity index 100% rename from src/debbuging/tests/Auto/selftype5.cl rename to src/tests/inference/selftype5.cl diff --git a/src/debbuging/tests/Auto/simple1.cl b/src/tests/inference/simple1.cl similarity index 100% rename from src/debbuging/tests/Auto/simple1.cl rename to src/tests/inference/simple1.cl diff --git a/src/debbuging/tests/Auto/simple2.cl b/src/tests/inference/simple2.cl similarity index 100% rename from src/debbuging/tests/Auto/simple2.cl rename to src/tests/inference/simple2.cl diff --git a/src/debbuging/tests/Auto/simple3.cl b/src/tests/inference/simple3.cl similarity index 100% rename from src/debbuging/tests/Auto/simple3.cl rename to src/tests/inference/simple3.cl diff --git a/src/debbuging/tests/Auto/simple4.cl b/src/tests/inference/simple4.cl similarity index 100% rename from src/debbuging/tests/Auto/simple4.cl rename to src/tests/inference/simple4.cl diff --git a/src/debbuging/tests_ccil/abort1.cl b/src/tests/normal/abort1.cl similarity index 100% rename from src/debbuging/tests_ccil/abort1.cl rename to src/tests/normal/abort1.cl diff --git a/src/debbuging/tests_ccil/allocation_call.cl b/src/tests/normal/allocation_call.cl similarity index 100% rename from src/debbuging/tests_ccil/allocation_call.cl rename to src/tests/normal/allocation_call.cl diff --git a/src/debbuging/tests_ccil/aritmetica1.cl b/src/tests/normal/aritmetica1.cl similarity index 100% rename from src/debbuging/tests_ccil/aritmetica1.cl rename to src/tests/normal/aritmetica1.cl diff --git a/src/debbuging/tests_ccil/aritmetica2.cl b/src/tests/normal/aritmetica2.cl similarity index 100% rename from src/debbuging/tests_ccil/aritmetica2.cl rename to src/tests/normal/aritmetica2.cl diff --git a/src/debbuging/tests_ccil/aritmetica3.cl b/src/tests/normal/aritmetica3.cl similarity index 100% rename from src/debbuging/tests_ccil/aritmetica3.cl rename to src/tests/normal/aritmetica3.cl diff --git a/src/debbuging/tests_ccil/atributos1.cl b/src/tests/normal/atributos1.cl similarity index 100% rename from src/debbuging/tests_ccil/atributos1.cl rename to src/tests/normal/atributos1.cl diff --git a/src/debbuging/tests_ccil/attr.cl b/src/tests/normal/attr.cl similarity index 100% rename from src/debbuging/tests_ccil/attr.cl rename to src/tests/normal/attr.cl diff --git a/src/debbuging/tests_ccil/attr_inicialization.cl b/src/tests/normal/attr_inicialization.cl similarity index 100% rename from src/debbuging/tests_ccil/attr_inicialization.cl rename to src/tests/normal/attr_inicialization.cl diff --git a/src/debbuging/tests_ccil/bool.cl b/src/tests/normal/bool.cl similarity index 100% rename from src/debbuging/tests_ccil/bool.cl rename to src/tests/normal/bool.cl diff --git a/src/debbuging/tests_ccil/case1.cl b/src/tests/normal/case1.cl similarity index 100% rename from src/debbuging/tests_ccil/case1.cl rename to src/tests/normal/case1.cl diff --git a/src/debbuging/tests_ccil/case2.cl b/src/tests/normal/case2.cl similarity index 100% rename from src/debbuging/tests_ccil/case2.cl rename to src/tests/normal/case2.cl diff --git a/src/debbuging/tests_ccil/case3.cl b/src/tests/normal/case3.cl similarity index 100% rename from src/debbuging/tests_ccil/case3.cl rename to src/tests/normal/case3.cl diff --git a/src/debbuging/tests_ccil/case4.cl b/src/tests/normal/case4.cl similarity index 100% rename from src/debbuging/tests_ccil/case4.cl rename to src/tests/normal/case4.cl diff --git a/src/debbuging/tests_ccil/case5.cl b/src/tests/normal/case5.cl similarity index 100% rename from src/debbuging/tests_ccil/case5.cl rename to src/tests/normal/case5.cl diff --git a/src/debbuging/tests_ccil/case6.cl b/src/tests/normal/case6.cl similarity index 100% rename from src/debbuging/tests_ccil/case6.cl rename to src/tests/normal/case6.cl diff --git a/src/debbuging/tests_ccil/classess1.cl b/src/tests/normal/classess1.cl similarity index 100% rename from src/debbuging/tests_ccil/classess1.cl rename to src/tests/normal/classess1.cl diff --git a/src/debbuging/tests_ccil/cmp_string.cl b/src/tests/normal/cmp_string.cl similarity index 100% rename from src/debbuging/tests_ccil/cmp_string.cl rename to src/tests/normal/cmp_string.cl diff --git a/src/debbuging/tests_ccil/concat_str.cl b/src/tests/normal/concat_str.cl similarity index 100% rename from src/debbuging/tests_ccil/concat_str.cl rename to src/tests/normal/concat_str.cl diff --git a/src/debbuging/tests_ccil/div1.cl b/src/tests/normal/div1.cl similarity index 100% rename from src/debbuging/tests_ccil/div1.cl rename to src/tests/normal/div1.cl diff --git a/src/debbuging/tests_ccil/fib.cl b/src/tests/normal/fib.cl similarity index 100% rename from src/debbuging/tests_ccil/fib.cl rename to src/tests/normal/fib.cl diff --git a/src/debbuging/tests_ccil/fib1.cl b/src/tests/normal/fib1.cl similarity index 100% rename from src/debbuging/tests_ccil/fib1.cl rename to src/tests/normal/fib1.cl diff --git a/src/debbuging/tests_ccil/function_call.cl b/src/tests/normal/function_call.cl similarity index 100% rename from src/debbuging/tests_ccil/function_call.cl rename to src/tests/normal/function_call.cl diff --git a/src/debbuging/tests_ccil/get_type_name.cl b/src/tests/normal/get_type_name.cl similarity index 100% rename from src/debbuging/tests_ccil/get_type_name.cl rename to src/tests/normal/get_type_name.cl diff --git a/src/debbuging/tests_ccil/if1.cl b/src/tests/normal/if1.cl similarity index 100% rename from src/debbuging/tests_ccil/if1.cl rename to src/tests/normal/if1.cl diff --git a/src/debbuging/tests_ccil/instantiate1.cl b/src/tests/normal/instantiate1.cl similarity index 100% rename from src/debbuging/tests_ccil/instantiate1.cl rename to src/tests/normal/instantiate1.cl diff --git a/src/debbuging/tests_ccil/isvoid1.cl b/src/tests/normal/isvoid1.cl similarity index 100% rename from src/debbuging/tests_ccil/isvoid1.cl rename to src/tests/normal/isvoid1.cl diff --git a/src/debbuging/tests_ccil/isvoid2.cl b/src/tests/normal/isvoid2.cl similarity index 100% rename from src/debbuging/tests_ccil/isvoid2.cl rename to src/tests/normal/isvoid2.cl diff --git a/src/debbuging/tests_ccil/len.cl b/src/tests/normal/len.cl similarity index 100% rename from src/debbuging/tests_ccil/len.cl rename to src/tests/normal/len.cl diff --git a/src/debbuging/tests_ccil/let1.cl b/src/tests/normal/let1.cl similarity index 100% rename from src/debbuging/tests_ccil/let1.cl rename to src/tests/normal/let1.cl diff --git a/src/debbuging/tests_ccil/let2.cl b/src/tests/normal/let2.cl similarity index 100% rename from src/debbuging/tests_ccil/let2.cl rename to src/tests/normal/let2.cl diff --git a/src/debbuging/tests_ccil/let_instantiate.cl b/src/tests/normal/let_instantiate.cl similarity index 100% rename from src/debbuging/tests_ccil/let_instantiate.cl rename to src/tests/normal/let_instantiate.cl diff --git a/src/debbuging/tests_ccil/print_int.cl b/src/tests/normal/print_int.cl similarity index 100% rename from src/debbuging/tests_ccil/print_int.cl rename to src/tests/normal/print_int.cl diff --git a/src/debbuging/tests_ccil/self1.cl b/src/tests/normal/self1.cl similarity index 100% rename from src/debbuging/tests_ccil/self1.cl rename to src/tests/normal/self1.cl diff --git a/src/debbuging/tests_ccil/selftype.cl b/src/tests/normal/selftype.cl similarity index 100% rename from src/debbuging/tests_ccil/selftype.cl rename to src/tests/normal/selftype.cl diff --git a/src/debbuging/tests_ccil/simple.cl b/src/tests/normal/simple.cl similarity index 100% rename from src/debbuging/tests_ccil/simple.cl rename to src/tests/normal/simple.cl diff --git a/src/debbuging/tests_ccil/simple_attr.cl b/src/tests/normal/simple_attr.cl similarity index 100% rename from src/debbuging/tests_ccil/simple_attr.cl rename to src/tests/normal/simple_attr.cl diff --git a/src/debbuging/tests_ccil/substring.cl b/src/tests/normal/substring.cl similarity index 100% rename from src/debbuging/tests_ccil/substring.cl rename to src/tests/normal/substring.cl From 2e277ad32601d05dbb113ea08a6c969c386310d5 Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:40:16 -0500 Subject: [PATCH 418/432] Move __main__.py to compiler --- src/{ => compiler}/__main__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => compiler}/__main__.py (100%) diff --git a/src/__main__.py b/src/compiler/__main__.py similarity index 100% rename from src/__main__.py rename to src/compiler/__main__.py From e7ae7cbd0bbafd326f2d41547a0e2f1327a899fc Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:57:51 -0500 Subject: [PATCH 419/432] Minor execution changes --- src/coolc.sh | 2 +- src/makefile | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coolc.sh b/src/coolc.sh index 0bfe5ff13..12f913b13 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -10,4 +10,4 @@ echo "Copyright (c) 2021: Adrian, Rodrigo" # TODO: líneas a los valores corr # Llamar al compilador # echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -exec python3 __main__.py $INPUT_FILE \ No newline at end of file +exec python3 compiler/__main__.py $INPUT_FILE diff --git a/src/makefile b/src/makefile index 6f531b553..94ae8c701 100644 --- a/src/makefile +++ b/src/makefile @@ -3,6 +3,9 @@ main: # Compiling the compiler :) +sample: + python compiler/__main__.py + clean: rm -rf build/* rm -rf ../tests/*/*.mips From 7fd4ab8ad25e9c142b33bc8821a4ace5e9b1c4aa Mon Sep 17 00:00:00 2001 From: rodrigo-pino Date: Wed, 9 Mar 2022 08:58:14 -0500 Subject: [PATCH 420/432] Fix imports after re-structuring --- src/compiler/__main__.py | 18 +++++----- src/compiler/asts/ccil_ast.py | 2 +- .../visitors/ast_print/type_logger.py | 4 +-- src/compiler/visitors/code_gen/ccil_gen.py | 8 ++--- .../visitors/code_gen/ccil_mips_gen.py | 3 +- src/compiler/visitors/code_gen/mips_gen.py | 2 +- src/compiler/visitors/parsing/parser.py | 2 +- .../semantics/inference/back_inferencer.py | 36 +++++++++---------- .../semantics/inference/hard_inferencer.py | 8 ++--- .../semantics/inference/soft_inferencer.py | 8 ++--- .../semantics/inference/types_inferencer.py | 12 +++---- .../visitors/semantics/tools/__init__.py | 8 ++--- .../visitors/semantics/tools/context.py | 4 +-- .../visitors/semantics/tools/scope.py | 3 +- src/compiler/visitors/semantics/tools/type.py | 2 +- .../visitors/semantics/type_builder.py | 13 ++++--- .../visitors/semantics/type_collector.py | 6 ++-- 17 files changed, 68 insertions(+), 71 deletions(-) diff --git a/src/compiler/__main__.py b/src/compiler/__main__.py index 5cf19604c..c2bf1415c 100644 --- a/src/compiler/__main__.py +++ b/src/compiler/__main__.py @@ -1,13 +1,13 @@ -from code_gen.ccil_gen import CCILGenerator -from code_gen.ccil_mips_gen import CCILToMIPSGenerator -from code_gen.mips_gen import MIPSGenerator -from debbuging.type_logger import TypeLogger +from visitors.code_gen.ccil_gen import CCILGenerator +from visitors.code_gen.ccil_mips_gen import CCILToMIPSGenerator +from visitors.code_gen.mips_gen import MIPSGenerator +from visitors.ast_print.type_logger import TypeLogger import sys -from lexing import Lexer -from parsing import Parser -from semantics import TypeBuilder, TypeCollector -from semantics.inference import ( +from visitors.lexing import Lexer +from visitors.parsing import Parser +from visitors.semantics import TypeBuilder, TypeCollector +from visitors.semantics.inference import ( SoftInferencer, HardInferencer, BackInferencer, @@ -74,7 +74,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "debbuging/tests_ccil/life.cl" + input_file = "tests/normal/simple.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) diff --git a/src/compiler/asts/ccil_ast.py b/src/compiler/asts/ccil_ast.py index 3a614dbdc..8a697107b 100644 --- a/src/compiler/asts/ccil_ast.py +++ b/src/compiler/asts/ccil_ast.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from typing import Dict, List, Tuple -from semantics.tools.type import Type +from visitors.semantics.tools.type import Type @dataclass(frozen=True) diff --git a/src/compiler/visitors/ast_print/type_logger.py b/src/compiler/visitors/ast_print/type_logger.py index c6fead434..356b1ddff 100644 --- a/src/compiler/visitors/ast_print/type_logger.py +++ b/src/compiler/visitors/ast_print/type_logger.py @@ -1,4 +1,4 @@ -from utils import visitor +from visitors.utils import visitor from asts.inferencer_ast import ( AssignNode, AtomicNode, @@ -20,7 +20,7 @@ VarDeclarationNode, LoopNode, ) -from semantics.tools import Context, Scope +from visitors.semantics.tools import Context, Scope class TypeLogger(object): diff --git a/src/compiler/visitors/code_gen/ccil_gen.py b/src/compiler/visitors/code_gen/ccil_gen.py index c0da1633e..d280f5b1a 100644 --- a/src/compiler/visitors/code_gen/ccil_gen.py +++ b/src/compiler/visitors/code_gen/ccil_gen.py @@ -1,11 +1,11 @@ -from utils import visitor +from visitors.utils import visitor import asts.types_ast as sem_ast # Semantic generated ast from asts.ccil_ast import * # CCIL generated ast -from typing import OrderedDict, Set, Tuple, List, Dict -from code_gen.tools import * +from typing import OrderedDict, Tuple, List, Dict +from visitors.code_gen.tools import * from collections import OrderedDict -from code_gen.constants import * +from visitors.code_gen.constants import * # All operations that define an expression and where it is stored VISITOR_RESULT = Tuple[List[OperationNode], StorageNode] diff --git a/src/compiler/visitors/code_gen/ccil_mips_gen.py b/src/compiler/visitors/code_gen/ccil_mips_gen.py index 06190753f..558d86159 100644 --- a/src/compiler/visitors/code_gen/ccil_mips_gen.py +++ b/src/compiler/visitors/code_gen/ccil_mips_gen.py @@ -1,8 +1,7 @@ from typing import Dict, List, Tuple from asts import ccil_ast, mips_ast -from utils import visitor -from utils import visitor +from visitors.utils import visitor from .constants import * diff --git a/src/compiler/visitors/code_gen/mips_gen.py b/src/compiler/visitors/code_gen/mips_gen.py index a6f439fbe..d9cb38d6d 100644 --- a/src/compiler/visitors/code_gen/mips_gen.py +++ b/src/compiler/visitors/code_gen/mips_gen.py @@ -37,7 +37,7 @@ WordDirective, Xori, ) -from utils import visitor +from visitors.utils import visitor class MIPSGenerator: diff --git a/src/compiler/visitors/parsing/parser.py b/src/compiler/visitors/parsing/parser.py index fe53f6965..3a02cf79e 100644 --- a/src/compiler/visitors/parsing/parser.py +++ b/src/compiler/visitors/parsing/parser.py @@ -31,7 +31,7 @@ VariableNode, ParamNode, ) -from parsing.errors import SyntacticError +from visitors.parsing.errors import SyntacticError class Parser: diff --git a/src/compiler/visitors/semantics/inference/back_inferencer.py b/src/compiler/visitors/semantics/inference/back_inferencer.py index b3ec1af1b..eaf5fc7b5 100644 --- a/src/compiler/visitors/semantics/inference/back_inferencer.py +++ b/src/compiler/visitors/semantics/inference/back_inferencer.py @@ -1,37 +1,37 @@ from copy import copy, deepcopy -from semantics.tools.errors import SemanticError from typing import Tuple -from semantics.tools.type import Method, SelfType, Type -from semantics.tools import Context, Scope, TypeBag, join, join_list, unify -from utils import visitor from asts.inferencer_ast import ( - ParamNode, - ProgramNode, - ClassDeclarationNode, - MethodDeclarationNode, + AssignNode, + AttrDeclarationNode, AttrDeclarationNode, + BinaryNode, BlocksNode, - ConditionalNode, + BooleanNode, CaseNode, CaseOptionNode, - LoopNode, - LetNode, - VarDeclarationNode, - AssignNode, - MethodCallNode, - BinaryNode, - BooleanNode, ClassDeclarationNode, + ClassDeclarationNode, + ConditionalNode, InstantiateNode, IntNode, - ProgramNode, - AttrDeclarationNode, + LetNode, + LoopNode, + MethodCallNode, + MethodDeclarationNode, Node, + ParamNode, + ProgramNode, + ProgramNode, StringNode, UnaryNode, + VarDeclarationNode, VariableNode, ) +from visitors.semantics.tools import Context, Scope, TypeBag, join, join_list, unify +from visitors.semantics.tools.errors import SemanticError +from visitors.semantics.tools.type import Method, SelfType, Type +from visitors.utils import visitor class BackInferencer: diff --git a/src/compiler/visitors/semantics/inference/hard_inferencer.py b/src/compiler/visitors/semantics/inference/hard_inferencer.py index 0c1147ec3..99cf35a38 100644 --- a/src/compiler/visitors/semantics/inference/hard_inferencer.py +++ b/src/compiler/visitors/semantics/inference/hard_inferencer.py @@ -1,4 +1,3 @@ -from semantics.tools.errors import InternalError, AttributeError from asts.inferencer_ast import ( ArithmeticNode, AssignNode, @@ -33,12 +32,11 @@ VarDeclarationNode, VariableNode, ) -from semantics.tools.type import Type -from utils import visitor -from semantics.tools import ( +from visitors.semantics.tools import ( Context, Scope, SelfType, + Type, TypeBag, conforms, equal, @@ -46,6 +44,8 @@ join_list, smart_add, ) +from visitors.semantics.tools.errors import AttributeError, InternalError +from visitors.utils import visitor class HardInferencer: diff --git a/src/compiler/visitors/semantics/inference/soft_inferencer.py b/src/compiler/visitors/semantics/inference/soft_inferencer.py index cdf6494ba..e13f16b38 100644 --- a/src/compiler/visitors/semantics/inference/soft_inferencer.py +++ b/src/compiler/visitors/semantics/inference/soft_inferencer.py @@ -1,5 +1,6 @@ from inspect import currentframe from typing import Type + import asts.inferencer_ast as inf_ast from asts.parser_ast import ( ArithmeticNode, @@ -34,10 +35,7 @@ VarDeclarationNode, VariableNode, ) - -from utils import visitor -from semantics.tools.errors import SemanticError, AttributeError -from semantics.tools import ( +from visitors.semantics.tools import ( Context, Scope, SelfType, @@ -47,6 +45,8 @@ join_list, smart_add, ) +from visitors.semantics.tools.errors import AttributeError, SemanticError +from visitors.utils import visitor class SoftInferencer: diff --git a/src/compiler/visitors/semantics/inference/types_inferencer.py b/src/compiler/visitors/semantics/inference/types_inferencer.py index cba9cce1a..dc6ebad5a 100644 --- a/src/compiler/visitors/semantics/inference/types_inferencer.py +++ b/src/compiler/visitors/semantics/inference/types_inferencer.py @@ -1,10 +1,10 @@ from typing import List, Tuple -from semantics.tools.context import Context -from semantics.tools.errors import InternalError -from semantics.tools.type import Type, join_list -from utils import visitor +from visitors.semantics.tools.context import Context +from visitors.semantics.tools.errors import InternalError +from visitors.semantics.tools.type import Type, join_list +from visitors.utils import visitor -from semantics.tools import TypeBag, Scope +from visitors.semantics.tools import TypeBag, Scope import asts.types_ast as types_ast from asts.inferencer_ast import ( BinaryNode, @@ -228,7 +228,7 @@ def visit(self, node: NotNode, scope: Scope) -> types_ast.NotNode: @visitor.when(ComplementNode) def visit(self, node: ComplementNode, scope: Scope) -> types_ast.ComplementNode: - expr = self.visit(node.expr,scope) + expr = self.visit(node.expr, scope) new_node = types_ast.ComplementNode(expr, node) new_node.type = self._reduce_to_type(node.inferenced_type, node) return new_node diff --git a/src/compiler/visitors/semantics/tools/__init__.py b/src/compiler/visitors/semantics/tools/__init__.py index afe3b3074..0509fd4ec 100644 --- a/src/compiler/visitors/semantics/tools/__init__.py +++ b/src/compiler/visitors/semantics/tools/__init__.py @@ -1,6 +1,6 @@ -from semantics.tools.context import Context -from semantics.tools.scope import Scope -from semantics.tools.type import ( +from visitors.semantics.tools.context import Context +from visitors.semantics.tools.scope import Scope +from visitors.semantics.tools.type import ( ErrorType, SelfType, TypeBag, @@ -11,5 +11,5 @@ smart_add, try_conform, Type, - unify + unify, ) diff --git a/src/compiler/visitors/semantics/tools/context.py b/src/compiler/visitors/semantics/tools/context.py index 4135bfdf9..089d8e6c6 100644 --- a/src/compiler/visitors/semantics/tools/context.py +++ b/src/compiler/visitors/semantics/tools/context.py @@ -1,5 +1,5 @@ -from semantics.tools.errors import * -from semantics.tools.type import TypeBag, Type, SelfType +from visitors.semantics.tools.errors import * +from visitors.semantics.tools.type import TypeBag, Type, SelfType from typing import Dict, List, Union diff --git a/src/compiler/visitors/semantics/tools/scope.py b/src/compiler/visitors/semantics/tools/scope.py index f1c4ab7db..01d286d72 100644 --- a/src/compiler/visitors/semantics/tools/scope.py +++ b/src/compiler/visitors/semantics/tools/scope.py @@ -1,5 +1,5 @@ from typing import Optional -from semantics.tools.type import TypeBag, ErrorType +from visitors.semantics.tools.type import TypeBag, ErrorType import itertools as itt @@ -89,4 +89,3 @@ def get_all_names(self, s: str = "", level: int = 0): for child in self.children: s = child.get_all_names(s, level + 1) return s - diff --git a/src/compiler/visitors/semantics/tools/type.py b/src/compiler/visitors/semantics/tools/type.py index f4d24301f..5d82509dd 100644 --- a/src/compiler/visitors/semantics/tools/type.py +++ b/src/compiler/visitors/semantics/tools/type.py @@ -1,4 +1,4 @@ -from semantics.tools.errors import * +from visitors.semantics.tools.errors import * from typing import List, Set, Tuple from collections import OrderedDict diff --git a/src/compiler/visitors/semantics/type_builder.py b/src/compiler/visitors/semantics/type_builder.py index 6a908f4e5..6e50bf08e 100644 --- a/src/compiler/visitors/semantics/type_builder.py +++ b/src/compiler/visitors/semantics/type_builder.py @@ -1,14 +1,13 @@ -from semantics.tools.type import Type -from utils import visitor from asts.parser_ast import ( - Node, - ProgramNode, + AttrDeclarationNode, ClassDeclarationNode, MethodDeclarationNode, - AttrDeclarationNode, + Node, + ProgramNode, ) -from semantics.tools.errors import SemanticError -from semantics.tools import TypeBag, Context +from visitors.utils import visitor +from visitors.semantics.tools import Context, TypeBag, Type +from visitors.semantics.tools.errors import SemanticError class TypeBuilder: diff --git a/src/compiler/visitors/semantics/type_collector.py b/src/compiler/visitors/semantics/type_collector.py index 3fc06d986..6e31ecdc8 100644 --- a/src/compiler/visitors/semantics/type_collector.py +++ b/src/compiler/visitors/semantics/type_collector.py @@ -1,8 +1,8 @@ from asts.parser_ast import ClassDeclarationNode, Node, ProgramNode -from semantics.tools.errors import SemanticError -from semantics.tools import Context, SelfType -from utils import visitor +from visitors.semantics.tools.errors import SemanticError +from visitors.semantics.tools import Context, SelfType +from visitors.utils import visitor class TypeCollector: From 4b6180ace13d0863cdceed2abb6b3d3040e38bbc Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 9 Mar 2022 16:36:16 -0500 Subject: [PATCH 421/432] Restructure project --- {src/docs => doc/report}/codegen.md | 0 {src/docs => doc/report}/lexing.md | 0 {src/docs => doc/report}/parsing.md | 0 .../report}/semantic and type inference.md | 0 src/compiler/__main__.py | 13 +++++-------- src/compiler/{visitors => }/lexing/__init__.py | 0 src/compiler/{visitors => }/lexing/errors.py | 0 src/compiler/{visitors => }/lexing/lexer.py | 0 .../{visitors => }/parsing/__init__.py | 0 src/compiler/{visitors => }/parsing/errors.py | 0 src/compiler/{visitors => }/parsing/parser.py | 2 +- .../{visitors => }/parsing/parsetab.py | 0 src/compiler/visitors/code_gen/ccil_gen.py | 18 ------------------ src/compiler/visitors/utils/__init__.py | 1 - src/compiler/visitors/utils/deep_equals.py | 14 -------------- src/coolc.sh | 2 +- 16 files changed, 7 insertions(+), 43 deletions(-) rename {src/docs => doc/report}/codegen.md (100%) rename {src/docs => doc/report}/lexing.md (100%) rename {src/docs => doc/report}/parsing.md (100%) rename {src/docs => doc/report}/semantic and type inference.md (100%) rename src/compiler/{visitors => }/lexing/__init__.py (100%) rename src/compiler/{visitors => }/lexing/errors.py (100%) rename src/compiler/{visitors => }/lexing/lexer.py (100%) rename src/compiler/{visitors => }/parsing/__init__.py (100%) rename src/compiler/{visitors => }/parsing/errors.py (100%) rename src/compiler/{visitors => }/parsing/parser.py (99%) rename src/compiler/{visitors => }/parsing/parsetab.py (100%) delete mode 100644 src/compiler/visitors/utils/deep_equals.py diff --git a/src/docs/codegen.md b/doc/report/codegen.md similarity index 100% rename from src/docs/codegen.md rename to doc/report/codegen.md diff --git a/src/docs/lexing.md b/doc/report/lexing.md similarity index 100% rename from src/docs/lexing.md rename to doc/report/lexing.md diff --git a/src/docs/parsing.md b/doc/report/parsing.md similarity index 100% rename from src/docs/parsing.md rename to doc/report/parsing.md diff --git a/src/docs/semantic and type inference.md b/doc/report/semantic and type inference.md similarity index 100% rename from src/docs/semantic and type inference.md rename to doc/report/semantic and type inference.md diff --git a/src/compiler/__main__.py b/src/compiler/__main__.py index c2bf1415c..fef8d5a88 100644 --- a/src/compiler/__main__.py +++ b/src/compiler/__main__.py @@ -4,8 +4,8 @@ from visitors.ast_print.type_logger import TypeLogger import sys -from visitors.lexing import Lexer -from visitors.parsing import Parser +from lexing import Lexer +from parsing import Parser from visitors.semantics import TypeBuilder, TypeCollector from visitors.semantics.inference import ( SoftInferencer, @@ -16,13 +16,12 @@ def format_errors(errors, s=""): - # errors.sort(key=lambda x: x[0]) for error in errors: s += error[1] + "\n" return s[:] -def run_pipeline(program_ast): +def semantics_pipeline(program_ast): collector = TypeCollector() collector.visit(program_ast) @@ -49,7 +48,6 @@ def run_pipeline(program_ast): change = True back = BackInferencer(context) - # import pdb; pdb.set_trace() back_ast, change = back.visit(hard_ast) while change: back_ast, change = back.visit(back_ast) @@ -74,7 +72,7 @@ def main(): if len(sys.argv) > 1: input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] else: - input_file = "tests/normal/simple.cl" + input_file = "../tests/normal/abort1.cl" # raise Exception("Incorrect number of arguments") program_file = open(input_file) @@ -95,10 +93,9 @@ def main(): print(error) exit(1) - type_ast = run_pipeline(ast) + type_ast = semantics_pipeline(ast) ccil_gen = CCILGenerator() ccil_ast = ccil_gen.visit(type_ast) - print(str(ccil_ast)) ccil_mips_gen = CCILToMIPSGenerator() mips_ast = ccil_mips_gen.visit(ccil_ast) diff --git a/src/compiler/visitors/lexing/__init__.py b/src/compiler/lexing/__init__.py similarity index 100% rename from src/compiler/visitors/lexing/__init__.py rename to src/compiler/lexing/__init__.py diff --git a/src/compiler/visitors/lexing/errors.py b/src/compiler/lexing/errors.py similarity index 100% rename from src/compiler/visitors/lexing/errors.py rename to src/compiler/lexing/errors.py diff --git a/src/compiler/visitors/lexing/lexer.py b/src/compiler/lexing/lexer.py similarity index 100% rename from src/compiler/visitors/lexing/lexer.py rename to src/compiler/lexing/lexer.py diff --git a/src/compiler/visitors/parsing/__init__.py b/src/compiler/parsing/__init__.py similarity index 100% rename from src/compiler/visitors/parsing/__init__.py rename to src/compiler/parsing/__init__.py diff --git a/src/compiler/visitors/parsing/errors.py b/src/compiler/parsing/errors.py similarity index 100% rename from src/compiler/visitors/parsing/errors.py rename to src/compiler/parsing/errors.py diff --git a/src/compiler/visitors/parsing/parser.py b/src/compiler/parsing/parser.py similarity index 99% rename from src/compiler/visitors/parsing/parser.py rename to src/compiler/parsing/parser.py index 3a02cf79e..755dd7415 100644 --- a/src/compiler/visitors/parsing/parser.py +++ b/src/compiler/parsing/parser.py @@ -31,7 +31,7 @@ VariableNode, ParamNode, ) -from visitors.parsing.errors import SyntacticError +from .errors import SyntacticError class Parser: diff --git a/src/compiler/visitors/parsing/parsetab.py b/src/compiler/parsing/parsetab.py similarity index 100% rename from src/compiler/visitors/parsing/parsetab.py rename to src/compiler/parsing/parsetab.py diff --git a/src/compiler/visitors/code_gen/ccil_gen.py b/src/compiler/visitors/code_gen/ccil_gen.py index d280f5b1a..fc0b4ac5c 100644 --- a/src/compiler/visitors/code_gen/ccil_gen.py +++ b/src/compiler/visitors/code_gen/ccil_gen.py @@ -18,24 +18,6 @@ ZERO = "zero" EMPTY = "empty" -# TODO: -# See how typeof should work, a special kind of equality? -# Define abort nodes with a text: -# * Dispatch on a void class (Done) -# * Case expr is void -# * No pattern match in case (Done) -# * Division by zero (Done) -# * Substring out of range (Done) -# * Heap Overflow (don't know yet how to handle this) - -# TEST: -# * Built in methods - - -# BOSS: -# Test there are no runtimes errors during generation -# Test that generation is correct - # CCIL stands for Cool Cows Intermediate Language ;) class CCILGenerator: diff --git a/src/compiler/visitors/utils/__init__.py b/src/compiler/visitors/utils/__init__.py index 77a87f5f4..b6af07e9a 100644 --- a/src/compiler/visitors/utils/__init__.py +++ b/src/compiler/visitors/utils/__init__.py @@ -1,2 +1 @@ from .visitor import * -from .deep_equals import * \ No newline at end of file diff --git a/src/compiler/visitors/utils/deep_equals.py b/src/compiler/visitors/utils/deep_equals.py deleted file mode 100644 index f0f40224e..000000000 --- a/src/compiler/visitors/utils/deep_equals.py +++ /dev/null @@ -1,14 +0,0 @@ -import json - -_all_ = ['deep_equals'] - -def generate_json_string(a): - json_dump = json.dumps(a) - return str(json_dump) - - -def deep_equals(a, b) -> bool: - return generate_json_string(a) == generate_json_string(b) - -# TODO: Implementar deep_equals para hacer varias pasadas -# del BackInferncer si no hay cambios en el ast que se devuelve \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index 12f913b13..416ed8158 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -10,4 +10,4 @@ echo "Copyright (c) 2021: Adrian, Rodrigo" # TODO: líneas a los valores corr # Llamar al compilador # echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -exec python3 compiler/__main__.py $INPUT_FILE +exec python3 compiler $INPUT_FILE From ecc1130a8383e8a32ed23e81e85d232999b22afe Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 9 Mar 2022 16:39:02 -0500 Subject: [PATCH 422/432] Add typer to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index cba16ee2f..6da230a91 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ pytest pytest-ordering ply +typer From 144ed8802fbbddc874eb9e8e55488bdded51897b Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 9 Mar 2022 17:58:09 -0500 Subject: [PATCH 423/432] Enhance CLI --- src/compiler/__main__.py | 76 +++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/compiler/__main__.py b/src/compiler/__main__.py index fef8d5a88..545aeab30 100644 --- a/src/compiler/__main__.py +++ b/src/compiler/__main__.py @@ -3,6 +3,7 @@ from visitors.code_gen.mips_gen import MIPSGenerator from visitors.ast_print.type_logger import TypeLogger import sys +import typer from lexing import Lexer from parsing import Parser @@ -21,7 +22,27 @@ def format_errors(errors, s=""): return s[:] -def semantics_pipeline(program_ast): +def lexing_pipeline(program): + lexer = Lexer() + tokens = list(lexer.tokenize(program)) + if lexer.errors: + for error in lexer.errors: + print(error) + exit(1) + return tokens + + +def parsing_pipeline(program): + parser = Parser(Lexer()) + ast = parser.parse(program) + if parser.errors: + for error in parser.errors: + print(error) + exit(1) + return ast + + +def semantics_pipeline(program_ast, cool_ast): collector = TypeCollector() collector.visit(program_ast) @@ -56,9 +77,10 @@ def semantics_pipeline(program_ast): types_ast = types.visit(back_ast) errors += types.errors - logger = TypeLogger(context) - log = logger.visit(back_ast, back_ast.scope) - print(log) + if cool_ast: + logger = TypeLogger(context) + log = logger.visit(back_ast, back_ast.scope) + print(log) if len(errors) > 0: s = format_errors(errors) @@ -68,46 +90,44 @@ def semantics_pipeline(program_ast): return types_ast -def main(): - if len(sys.argv) > 1: - input_file = sys.argv[1] # + " " + sys.argv[2] + " " + sys.argv[3] - else: - input_file = "../tests/normal/abort1.cl" - # raise Exception("Incorrect number of arguments") - +def main( + input_file: str, + ccil: bool = typer.Option( + False, + help="Create .ccil file corresponding to the ccil code generated during compilation ", + ), + cool_ast: bool = typer.Option(False, help="Prints program's COOL AST"), +): + """ + Welcome to CoolCows Compiler! + """ program_file = open(input_file) program = program_file.read() program_file.close() + out_file = input_file.split(".")[0] - lexer = Lexer() - tokens = list(lexer.tokenize(program)) - if lexer.errors: - for error in lexer.errors: - print(error) - exit(1) - - parser = Parser(Lexer()) - ast = parser.parse(program) - if parser.errors: - for error in parser.errors: - print(error) - exit(1) + tokens = lexing_pipeline(program) + ast = parsing_pipeline(program) + type_ast = semantics_pipeline(ast, cool_ast) - type_ast = semantics_pipeline(ast) ccil_gen = CCILGenerator() ccil_ast = ccil_gen.visit(type_ast) + if ccil: + path_to_file = f"{out_file}.ccil" + with open(path_to_file, "w") as f: + f.write(str(ccil_ast)) + ccil_mips_gen = CCILToMIPSGenerator() mips_ast = ccil_mips_gen.visit(ccil_ast) mips_gen = MIPSGenerator() mips_code = mips_gen.visit(mips_ast) - out_file = input_file.split(".")[0] path_to_file = f"{out_file}.mips" - # path_to_file = "output.asm" with open(path_to_file, "w") as f: f.write(mips_code) -main() +if __name__ == "__main__": + typer.run(main) From 823024af8798e3f86eb0c03376c1ab380507c4dc Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 9 Mar 2022 17:59:37 -0500 Subject: [PATCH 424/432] Remove unnecessary comments --- src/compiler/visitors/code_gen/ccil_mips_gen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/visitors/code_gen/ccil_mips_gen.py b/src/compiler/visitors/code_gen/ccil_mips_gen.py index 558d86159..2974ce7fb 100644 --- a/src/compiler/visitors/code_gen/ccil_mips_gen.py +++ b/src/compiler/visitors/code_gen/ccil_mips_gen.py @@ -65,7 +65,6 @@ def visit(self, node: ccil_ast.CCILProgram): ) functions = [] - print(node.entry_func) functions.extend(self.visit(node.entry_func)) for classx in node.types_section: From a3275ef6846106e82ceaf6ad723826e3b9ab0b09 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Wed, 9 Mar 2022 18:06:43 -0500 Subject: [PATCH 425/432] Remove .vscode --- .vscode/launch.json | 16 ---------------- .vscode/settings.json | 6 ------ 2 files changed, 22 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 63bc6be37..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Current File", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal", - // "args": ["/home/adrian/Desktop/4to/PrimerSemestre/ComplementosCompilacion/cool-compiler-2021/src/debbuging/tests/Auto/00Simple.cl"] - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7e34d83ae..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "python.linting.enabled": false, - "python.linting.flake8Enabled": false, - "python.linting.pydocstyleEnabled": false, - "python.linting.pylintEnabled": true, -} \ No newline at end of file From 1721766e635bbe81ef491020265f6544d6b1a71d Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 10 Mar 2022 13:52:39 -0500 Subject: [PATCH 426/432] Update report --- doc/report/codegen.md | 470 --------------- doc/report/img/class.png | Bin 0 -> 19974 bytes doc/report/img/object.png | Bin 0 -> 15724 bytes doc/report/img/pipeline.png | Bin 0 -> 63017 bytes doc/report/lexing.md | 2 - doc/report/parsing.md | 2 - doc/report/report.md | 682 ++++++++++++++++++++++ doc/report/semantic and type inference.md | 60 -- src/compiler/__main__.py | 4 +- 9 files changed, 684 insertions(+), 536 deletions(-) delete mode 100644 doc/report/codegen.md create mode 100644 doc/report/img/class.png create mode 100644 doc/report/img/object.png create mode 100644 doc/report/img/pipeline.png delete mode 100644 doc/report/lexing.md delete mode 100644 doc/report/parsing.md create mode 100644 doc/report/report.md delete mode 100644 doc/report/semantic and type inference.md diff --git a/doc/report/codegen.md b/doc/report/codegen.md deleted file mode 100644 index 540f07c93..000000000 --- a/doc/report/codegen.md +++ /dev/null @@ -1,470 +0,0 @@ -# Generación de Código Intermedio - -Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. - -El programa original se divide en tres secciones: - -* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. -* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. -* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. - -## Types - -Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. - -Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. - -En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. - -La función `init` se ejecuta siempre que se instancie una clase. - -## Data - -Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. - -## Code - -Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. - -Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: - -1. Produce las operaciones de todas sus sub-expresiones -2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. -3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna - -Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. - -Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. - -Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: - -+ División por cero -+ El despacho ocurre desde un tipo sin inicializar (`Void`) -+ El rango del substring no es válido -+ Ninguna rama de algún `case of` es igual al tipo de la expresión - -Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: - -```assembly -# COOL -let x:int = 3 - in (let x:int = 4 in x) + x -# CIL -local let_x_0 -local let_x_1 -... -``` - -### Transformaciones - -Ejemplos de traducción de Cool a CIL - -#### Declaración de Clase - - **Cool Input** - -```haskell -class C { - -- Initialized attributes - a1: <- ; - a2: <- ; - ... - am: <- ; - - -- Functions - f1() { } - f2() { } - ... - fn() { } - -} -``` - -**CCIL Output** - -```assembly -type C { - attribute a1; - ... - attribute am; - - method f1 : ; - ... - method fn : ; -} -``` - -#### Herencia de Clases - - **Cool Input** - -```haskell -class A { - a1: - f1():{...} -} - -class B inherits A { - b1: - g1():{...} -} -``` - -**CCIL Output** - -```assembly -type A { - attr a1; - method f1 : f_f1_A -} - -type B { - attr a1; - attr b1; - method f1: f_f1_A - method g1: f_g1_B -} -``` - -#### While Loop - -**Cool Input** - -```assembly -while () loop pool -``` - -**CCIL Output** - -```assembly -label while_init -x = -ifFalse x goto while_end - - - -goto while_init -label while_end -``` - -#### If Then Else - -**Cool Input** - -``` -if then else fi -``` - -**CCIL Output** - -```assembly - # Produce todas las operaciones de la expr de la cond. inicial -x = # Guarda ese valor -ifFalse x goto else_expr -# x = 1 - -f = # El resultado final de la expresion if -goto endif - -# x = 0 -label else_expr - -f = # El resultado final de la expresion if - -label endif -``` - -#### Let In - -**Cool Input** - -``` -let :, ... : in -``` - -**CCIL Output** - -```assembly -# Inicializa todas las variables let, tengan expresión o no - - -... - -# traduce la expresion en operacions - -f = # Almacena el resultado final de la expresion let -``` - -#### Case Of - -**Cool Input** - -``` -case of - : => - : => - ... - : => -esac -``` - -**CCIL Output** - -```assembly - - -... - - - -x = -t = typeof x - -# Analiznado rama 1 -t1 = typeof -b1 = t1 == t # Comparando tipos -if b1 goto branch1: # En caso de exito ve a la rama - -# Analizando rama 2 -t2 = typeof -b2 = t2 == t -if b2 goto branch2 - -... - -# Analizando rama n -tn = typeof -bn = tn == t -if bn goto brannch - - # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama - - -# Realizando logica the rama1 -label branch1 - -goto end_case - -# Realizando logica the rama2 -label branch2 - -goto end_case - -... - -# Realizando logica the raman -label branchn - -goto end_case - -label end_case -``` - -#### Despacho Estático - -**Cool Input** - -``` -(, , ..., ); -``` - -**CCIL Output** - -```assembly - - -... - -r = call n -``` - -#### Despacho Dinámico - -**Cool Input** - -``` -@.(, , ..., ); -``` - -**CCIL Output** - -```assembly - - -... - -t = allocate # It needs to give the same attributes that type one has -r = vcall t n -``` - -#### Declaración de un método - -**Cool Input** - -``` -(:, ..., :) : -{ - -} -``` - -**CCIL Output** - -```assembly -function { - param - param - ... - param - local - local - ... - local - - r = - return r -} -``` - -#### Expresión de Bloque - -**Cool Input** - -``` -{ - ; - ; - ... - ; -} -``` - -**CCIL Output** - -``` - - -... - - - - -... - -``` - -#### Expresiones Aritméticas - -**Cool Input** - -```c# -3 + 5 -``` - -**CCIL Output** - -``` -t = 3 + 5 -``` - ---- - -###### More than one - -**Cool Input** - -``` -3 + 5 + 7 -``` - -**CCIL Output** - -```assembly -# Naive -t1 = 5 + 7 -t2 = 3 + t1 -``` - ---- - -###### Using non commutative operations - -```python -3 - 5 - 7 -# -2 -7 -# -9 -``` - -```assembly -t = 3 - 5 -t = t - 7 -``` - ---- - -**Cool Input** - -``` -100 / 20 / 5 / 2 -``` - -**CCIL Output** - -``` -t = 100 / 20 -t = t / 5 -t = t / 2 -``` - - - -## Lenguaje CCIL - -Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. - -$$ -\begin{array}{rcl} -\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ -\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ -\text{Type} &\rarr& \text{FeatureList}\\ -\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ -&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ -\\ -\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ -\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ -\text{FuncCode} &\rarr& \text{id }\{\\ -&&\text{ParamList}\\ -&&\text{LocalList}\\ -&&\text{OperationList} \text{\}}\\ -\\ -\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ -\text{Operation} &\rarr& \text{id = ReturnOp}\\ -&|& \text{goto id}\\ -&|& \text{label id}\\ -&|& \text{return Atom}\\ -&|& \text{setattr id id Atom}\\ -&|& \text{if Atom goto id}\\ -&|& \text{ifFalse Atom goto id}\\ -&|& \text{arg id}\\ - -\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ -&|& \text{Atom - Atom}\\ -&|& \text{Atom * Atom}\\ -&|& \text{Atom / Atom}\\ -&|& \text{not Atom}\\ -&|& \text{neg Atom}\\ -&|& \text{call id}\\ -&|& \text{vcall typeId id}\\ -&|& \text{typeof id}\\ -&|& \text{getatrr id id}\\ -&|& \text{allocate typeId}\\ -&|& \text{Atom < Atom}\\ -&|& \text{Atom <= Atom}\\ -&|& \text{Atom = Atom}\\ -&|& \text{allocate typeId}\\ -&|& \text{getattr id id}\\ -&|& \text{Atom}\\ -\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ -\text{Constant} &\rarr& \text{ integer } | \text{ string } -\end{array} -$$ diff --git a/doc/report/img/class.png b/doc/report/img/class.png new file mode 100644 index 0000000000000000000000000000000000000000..e26e025e42db0976328e3440762a159d3c7ca7d8 GIT binary patch literal 19974 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 literal 0 HcmV?d00001 diff --git a/doc/report/img/object.png b/doc/report/img/object.png new file mode 100644 index 0000000000000000000000000000000000000000..51db37f369698fb198af7acc3141053240633d05 GIT binary patch literal 15724 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 UK)h8D@E1;6TtTc-^xLoh37eIVBATCTW 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%0AU1AWW&3WK91LhEQ{#-E#TdD)iE~^V> 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

k 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 +``` + +El compilador también cuenta con otras opciones a las cuales se pueden acceder si pasamos como parámetro `--help` + +```bash +❯ python3 compiler --help +Usage: compiler [OPTIONS] INPUT_FILE + + Welcome to CoolCows Compiler! + +Arguments: + INPUT_FILE [required] + +Options: + --ccil / --no-ccil Create .ccil file + corresponding to the ccil code + generated during compilation + [default: False] + + --cool-ast / --no-cool-ast Print COOL AST + [default: False] + + --install-completion Install completion for the current + shell. + + --show-completion Show completion for the current + shell, to copy it or customize the + installation. + + --help Show this message and exit. +``` + +# Arquitectura + +El compilador se diseño siguiendo una ariquitectura modular y funcional. Cada compoenente del mismo es totalmente sustituible sin afectar el funcionamiento de los demás. La imagen siguiente muestra el p*pipeline* del compilador, desde que recibe el programa de COOL hasta que genera la salida del programa correspondiente en MIPS. + +![pipeline](./img/pipeline.png) + +La distribución del código se puede apreciar a continuación: + +``` +├── asts +│   ├── ccil_ast.py +│   ├── inferencer_ast.py +│   ├── __init__.py +│   ├── mips_ast.py +│   ├── parser_ast.py +│   └── types_ast.py +├── lexing +│   ├── errors.py +│   ├── __init__.py +│   └── lexer.py +├── __main__.py +├── parsing +│   ├── errors.py +│   ├── __init__.py +│   ├── parser.py +│   └── parsetab.py +└── visitors + ├── ast_print + │   ├── __init__.py + │   └── type_logger.py + ├── code_gen + │   ├── ccil_gen.py + │   ├── ccil_mips_gen.py + │   ├── constants.py + │   ├── __init__.py + │   ├── mips_gen.py + │   └── tools.py + ├── semantics + │   ├── inference + │   ├── __init__.py + │   ├── tools + │   ├── type_builder.py + │   └── type_collector.py + └── utils + ├── __init__.py + └── visitor.py +``` +En `asts` se encuentran cada uno de los AST que se utilizan a lo largo del proyecto. En `lexing` y `parsing` están la implementación del parser y lexer utilizados. En la carpeta `visitors` se ubican las clases que utilizan el patrón de mismo nombre para cada etapa del compilador divididos en subcarpetas. + +# Lexing + +Para el proceso de *lexing* y *parsing* se usó la biblioteca de *Python* **PLY**. Esta es una implementación de las herramientas *lex* y *yacc* completamente escritas en *Python*. Para el caso particular de la tokenización, *lex* fue la herramienta utilizada. + +La implementación se encuetra en el módulo `lexer.py`. La misma cuenta con una clase `Lexer` donde se definen las expresiones regulares para cada uno de los tokens. En el caso de los *string* y comentarios multilínea se usaron dos estados distintos para cada una, debido a que estos enguajes no son regulares y era necesario usar algoritmos más potentes. + +# Parsing + +Como se menciona en la sección anterior, para el proceso de *parsing* se utilizó *ply.yacc*. Esta herramienta cuenta con la misma técnica de parsing LALR que el *yacc* original. + +La gramática utilizada se encuentra definida en `parser.py`. En este módulo se encuentra la clase `Parser`, la cual cual cuenta con un conjunto de métodos que representan cada una de las producciones de la gramática. Como se puede apreciar, en el caso de las operaciones aritméticas y de comparación las producciones son ambiguas, sin embargo *ply.yacc* permite desambiguar definiendo la precedencia y la asociatividad de los operadores como se muestra a continuación: + +```python +self.precedence = ( + ("right", "ASSIGN"), + ("right", "NOT"), + ("nonassoc", "LESSEQ", "<", "="), + ("left", "+", "-"), + ("left", "*", "/"), + ("right", "ISVOID"), + ("left", "~"), + ("left", "@"), + ("left", "."), +) +``` + +Esto permite usar una gramática ambigua y evita tener que definir más producciones para poder parsear. + +# Semántica e Inferencia + +Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. + +La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. + +En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: + +1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. + +2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. + +3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. + +Para tratar cada caso el inferenciador se divide en tres partes: + +1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. +2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. +3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) +4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. + +Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. + +El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. + +En este ejemplo no funcional donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. + +Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. + +```c# +class Main { + a : AUTO_TYPE; + method main():AUTO_TYPE { + { + a.f(); // Boom si no es el soft inferencer + a.g(); // Solucionado + } + } +} +class A { + method f():Int{ + 3 + 3 + } + metod g():String{ + "yisus" + } + +}; +class B { + method f():String{ + "3 + 3" + } +}; +``` + +## SELF_TYPE + +La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. + + +# Generación de Código Intermedio + +Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a MIPS. + +El programa original se divide en tres secciones: + +* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. +* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. +* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. + +## Types + +Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. + +Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. + +En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. + +La función `init` se ejecuta siempre que se instancie una clase. + +## Data + +Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. + +## Code + +Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. + +Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: + +1. Produce las operaciones de todas sus sub-expresiones +2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. +3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna + +Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. + +Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. + +Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: + ++ División entre cero ++ El despacho ocurre desde un tipo sin inicializar (`Void`) ++ El rango del substring no es válido ++ Ninguna rama de algún `case of` es igual al tipo de la expresión + +Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: + +```assembly +# COOL +let x:int = 3 + in (let x:int = 4 in x) + x +# CIL +local let_x_0 +local let_x_1 +... +``` + +### Transformaciones + +Ejemplos de traducción de Cool a CIL + +#### Declaración de Clase + + **Cool Input** + +```haskell +class C { + -- Initialized attributes + a1: <- ; + a2: <- ; + ... + am: <- ; + + -- Functions + f1() { } + f2() { } + ... + fn() { } + +} +``` + +**CCIL Output** + +```assembly +type C { + attribute a1; + ... + attribute am; + + method f1 : ; + ... + method fn : ; +} +``` + +#### Herencia de Clases + + **Cool Input** + +```haskell +class A { + a1: + f1():{...} +} + +class B inherits A { + b1: + g1():{...} +} +``` + +**CCIL Output** + +```assembly +type A { + attr a1; + method f1 : f_f1_A +} + +type B { + attr a1; + attr b1; + method f1: f_f1_A + method g1: f_g1_B +} +``` + +#### While Loop + +**Cool Input** + +```assembly +while () loop pool +``` + +**CCIL Output** + +```assembly +label while_init +x = +ifFalse x goto while_end + + + +goto while_init +label while_end +``` + +#### If Then Else + +**Cool Input** + +``` +if then else fi +``` + +**CCIL Output** + +```assembly + # Produce todas las operaciones de la expr de la cond. inicial +x = # Guarda ese valor +ifFalse x goto else_expr +# x = 1 + +f = # El resultado final de la expresion if +goto endif + +# x = 0 +label else_expr + +f = # El resultado final de la expresion if + +label endif +``` + +#### Let In + +**Cool Input** + +``` +let :, ... : in +``` + +**CCIL Output** + +```assembly +# Inicializa todas las variables let, tengan expresión o no + + +... + +# traduce la expresion en operacions + +f = # Almacena el resultado final de la expresion let +``` + +#### Case Of + +**Cool Input** + +``` +case of + : => + : => + ... + : => +esac +``` + +**CCIL Output** + +```assembly + + +... + + + +x = +t = typeof x + +# Analiznado rama 1 +t1 = typeof +b1 = t1 == t # Comparando tipos +if b1 goto branch1: # En caso de exito ve a la rama + +# Analizando rama 2 +t2 = typeof +b2 = t2 == t +if b2 goto branch2 + +... + +# Analizando rama n +tn = typeof +bn = tn == t +if bn goto brannch + + # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama + + +# Realizando logica the rama1 +label branch1 + +goto end_case + +# Realizando logica the rama2 +label branch2 + +goto end_case + +... + +# Realizando logica the raman +label branchn + +goto end_case + +label end_case +``` + +#### *Dispatch* Estático + +**Cool Input** + +``` +(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +r = call n +``` + +#### *Dispatch* Dinámico + +**Cool Input** + +``` +@.(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +t = allocate # It needs to give the same attributes that type one has +r = vcall t n +``` + +#### Declaración de un método + +**Cool Input** + +``` +(:, ..., :) : +{ + +} +``` + +**CCIL Output** + +```assembly +function { + param + param + ... + param + local + local + ... + local + + r = + return r +} +``` + +#### Expresión de Bloque + +**Cool Input** + +``` +{ + ; + ; + ... + ; +} +``` + +**CCIL Output** + +``` + + +... + + + + +... + +``` + +#### Expresiones Aritméticas + +**Cool Input** + +```c# +3 + 5 +``` + +**CCIL Output** + +``` +t = 3 + 5 +``` + +--- + +###### More than one + +**Cool Input** + +``` +3 + 5 + 7 +``` + +**CCIL Output** + +```assembly +# Naive +t1 = 5 + 7 +t2 = 3 + t1 +``` + +--- + +###### Using non commutative operations + +```python +3 - 5 - 7 +# -2 -7 +# -9 +``` + +```assembly +t = 3 - 5 +t = t - 7 +``` + +--- + +**Cool Input** + +``` +100 / 20 / 5 / 2 +``` + +**CCIL Output** + +``` +t = 100 / 20 +t = t / 5 +t = t / 2 +``` + + + +## Lenguaje CCIL + +Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. + +$$ +\begin{array}{rcl} +\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ +\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ +\text{Type} &\rarr& \text{FeatureList}\\ +\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ +&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ +\\ +\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ +\text{FuncCode} &\rarr& \text{id }\{\\ +&&\text{ParamList}\\ +&&\text{LocalList}\\ +&&\text{OperationList} \text{\}}\\ +\\ +\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ +\text{Operation} &\rarr& \text{id = ReturnOp}\\ +&|& \text{goto id}\\ +&|& \text{label id}\\ +&|& \text{return Atom}\\ +&|& \text{setattr id id Atom}\\ +&|& \text{if Atom goto id}\\ +&|& \text{ifFalse Atom goto id}\\ +&|& \text{arg id}\\ + +\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ +&|& \text{Atom - Atom}\\ +&|& \text{Atom * Atom}\\ +&|& \text{Atom / Atom}\\ +&|& \text{not Atom}\\ +&|& \text{neg Atom}\\ +&|& \text{call id}\\ +&|& \text{vcall typeId id}\\ +&|& \text{typeof id}\\ +&|& \text{getatrr id id}\\ +&|& \text{allocate typeId}\\ +&|& \text{Atom < Atom}\\ +&|& \text{Atom <= Atom}\\ +&|& \text{Atom = Atom}\\ +&|& \text{allocate typeId}\\ +&|& \text{getattr id id}\\ +&|& \text{Atom}\\ +\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ +\text{Constant} &\rarr& \text{ integer } | \text{ string } +\end{array} +$$ + +# Generación de código MIPS + +Una vez definido un lenguaje intermedio, se pasa a MIPS. En este punto del proceso de compilación se tuvieron que resolver dos problemas fundamentales: la semántica de tipos y el manejo de la memoria. + +## Representacion de los tipos + +En *MIPS* las instancias de clases se representan a través de información estática y dinámica. La parte estática se define en la sección *.data* y contiene la información que se comparte entre cada uno de los objetos del mismo tipo. + +![class](./img/class.png) + +La sección `type` contiene la dirección hacia esa sección de código. En `init` se encuentra la dirección de una función especial que inicializa una instancia cualquiera de la clase correspondiente. Esta función se genera en ccil. Luego, en la sección `name` se encuentra la dirección del *string* que corresponde al nombre del tipo. En `attr count` se encuentra un valor que representa la cantidad de atributos que tiene la clase. Después de esta porción de memoria se encuentran los métodos, es decir, la dirección de las funciones que implementan cada uno de los métodos en una clase. + +Es importante señalar que los métodos de las clases están declarados en el mismo orden. Si una clase `B` hereda de otra clase `A`, los métodos de `A` que `B` hereda están en la misma posición que en `A`. De este modo los llamados a métodos virtuales se pueden hacer conociendo solamente el tipo estático del objeto y el *offset* del método que se está invocando. + +En el caso de las instancias de los tipos, su representación en memoria es como se muestra a continuación: + +![object](./img/object.png) + +En la sección `type` se encuentra la dirección hacia la información estática del tipo que se mencionó anteriormente. Luego le siguen cada uno de los atributos. Estos, al igual que en el caso de los métodos, se encuentran en el mismo orden para todas las instancias de una clase y de sus subclases. De este modo la lectura y escritura de los atributo se reduce a saber su tipo estático y el *offset* del atributo. + +## Llamados a función + +Para los llamados a función en MIPS se tomó como convenio pasar primeramente los argumentos a través de la pila ( el primer argumento siempre es la instnacia del objeto que realiza el llamado ) para luego saltar al *label* donde se encuentra la definición de la función. A continuación se guardan en la pila el *return address* y el *frame pointer*. Una vez hecho esto se ajusta el nuevo valor del *frame pointer* y se reserva el espacio necesario para las variables locales en la pila. Cuando se realizan cada una de las opraciones correspondientes a la función invocada se sacan de la pila los valores anterioes del *return address* y *frame pointer*, y se libera el espacio correspondiente a las variables locales y los argumentos de la función. Los valores de retorno de las funciones se guardan siempre en el registro `v0`. + +Como se había mencionado anteriormente, cuando se instancia un nuevo objeto, sabiendo el tipo podemos llamar directamente a la función `init` correspondiente y reservar la cantidad de memoria necesaria. Sin embargo, en el caso del `SELF_TYPE`, no se puede proceder como en los demás casos, porque el tipo del objeto que se va a instanciar solo se conoce en tiempo de ejecución. Por tanto, para resolver este problema, lo que se hace es buscar el tipo dinámico del objeto donde se encuentra la invocación del método actual que ssiempre se encuentra en el primer argumento del llamado a una función en MIPS, y a través del cual se puede obtener el tipo del objeto (identificador realmente ) y así acceder a la información estática de dicho tipo, donde se puede saber la cantidad memoria necesaria a reservar según la cantidad de atributos y a la función `init` que le corresponde. + + +### Funciones Built-in + +Las funciones *built-in* se implementaron directamente en el AST de MIPS. diff --git a/doc/report/semantic and type inference.md b/doc/report/semantic and type inference.md deleted file mode 100644 index 687b7c72a..000000000 --- a/doc/report/semantic and type inference.md +++ /dev/null @@ -1,60 +0,0 @@ -# Semántica e Inferencia - -Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. - -La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. - -En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: - -1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. - -2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. - -3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. - -Para tratar cada caso el inferenciador se divide en tres partes: - -1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. -2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. -3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) -4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. - -Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. - -## Soft Inferencer - -El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. - -En este ejemplo no funcional (Lanza `RuntimeError` debido a que `a` es `Void`) donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. - -Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. - -```c# -class Main { - a : AUTO_TYPE; - method main():AUTO_TYPE { - { - a.f(); // Boom si no es el soft inferencer - a.g(); // Solucionado - } - } -} -class A { - method f():Int{ - 3 + 3 - } - metod g():String{ - "yisus" - } - -}; -class B { - method f():String{ - "3 + 3" - } -}; -``` - -## SELF_TYPE - -La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. diff --git a/src/compiler/__main__.py b/src/compiler/__main__.py index 545aeab30..b67c54322 100644 --- a/src/compiler/__main__.py +++ b/src/compiler/__main__.py @@ -94,9 +94,9 @@ def main( input_file: str, ccil: bool = typer.Option( False, - help="Create .ccil file corresponding to the ccil code generated during compilation ", + help="Create a .ccil file corresponding to the ccil code generated during compilation ", ), - cool_ast: bool = typer.Option(False, help="Prints program's COOL AST"), + cool_ast: bool = typer.Option(False, help="Print COOL AST"), ): """ Welcome to CoolCows Compiler! From 5ccff87f5bcf21ba7b655cb8b028a8a50d3973c5 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 10 Mar 2022 13:52:39 -0500 Subject: [PATCH 427/432] Update report --- doc/report/codegen.md | 470 --------------- doc/report/img/class.png | Bin 0 -> 19974 bytes doc/report/img/object.png | Bin 0 -> 15724 bytes doc/report/img/pipeline.png | Bin 0 -> 63017 bytes doc/report/lexing.md | 2 - doc/report/parsing.md | 2 - doc/report/report.md | 682 ++++++++++++++++++++++ doc/report/semantic and type inference.md | 60 -- src/compiler/__main__.py | 4 +- 9 files changed, 684 insertions(+), 536 deletions(-) delete mode 100644 doc/report/codegen.md create mode 100644 doc/report/img/class.png create mode 100644 doc/report/img/object.png create mode 100644 doc/report/img/pipeline.png delete mode 100644 doc/report/lexing.md delete mode 100644 doc/report/parsing.md create mode 100644 doc/report/report.md delete mode 100644 doc/report/semantic and type inference.md diff --git a/doc/report/codegen.md b/doc/report/codegen.md deleted file mode 100644 index 540f07c93..000000000 --- a/doc/report/codegen.md +++ /dev/null @@ -1,470 +0,0 @@ -# Generación de Código Intermedio - -Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a smips. - -El programa original se divide en tres secciones: - -* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. -* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. -* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. - -## Types - -Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. - -Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. - -En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. - -La función `init` se ejecuta siempre que se instancie una clase. - -## Data - -Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. - -## Code - -Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. - -Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: - -1. Produce las operaciones de todas sus sub-expresiones -2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. -3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna - -Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. - -Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. - -Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: - -+ División por cero -+ El despacho ocurre desde un tipo sin inicializar (`Void`) -+ El rango del substring no es válido -+ Ninguna rama de algún `case of` es igual al tipo de la expresión - -Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: - -```assembly -# COOL -let x:int = 3 - in (let x:int = 4 in x) + x -# CIL -local let_x_0 -local let_x_1 -... -``` - -### Transformaciones - -Ejemplos de traducción de Cool a CIL - -#### Declaración de Clase - - **Cool Input** - -```haskell -class C { - -- Initialized attributes - a1: <- ; - a2: <- ; - ... - am: <- ; - - -- Functions - f1() { } - f2() { } - ... - fn() { } - -} -``` - -**CCIL Output** - -```assembly -type C { - attribute a1; - ... - attribute am; - - method f1 : ; - ... - method fn : ; -} -``` - -#### Herencia de Clases - - **Cool Input** - -```haskell -class A { - a1: - f1():{...} -} - -class B inherits A { - b1: - g1():{...} -} -``` - -**CCIL Output** - -```assembly -type A { - attr a1; - method f1 : f_f1_A -} - -type B { - attr a1; - attr b1; - method f1: f_f1_A - method g1: f_g1_B -} -``` - -#### While Loop - -**Cool Input** - -```assembly -while () loop pool -``` - -**CCIL Output** - -```assembly -label while_init -x = -ifFalse x goto while_end - - - -goto while_init -label while_end -``` - -#### If Then Else - -**Cool Input** - -``` -if then else fi -``` - -**CCIL Output** - -```assembly - # Produce todas las operaciones de la expr de la cond. inicial -x = # Guarda ese valor -ifFalse x goto else_expr -# x = 1 - -f = # El resultado final de la expresion if -goto endif - -# x = 0 -label else_expr - -f = # El resultado final de la expresion if - -label endif -``` - -#### Let In - -**Cool Input** - -``` -let :, ... : in -``` - -**CCIL Output** - -```assembly -# Inicializa todas las variables let, tengan expresión o no - - -... - -# traduce la expresion en operacions - -f = # Almacena el resultado final de la expresion let -``` - -#### Case Of - -**Cool Input** - -``` -case of - : => - : => - ... - : => -esac -``` - -**CCIL Output** - -```assembly - - -... - - - -x = -t = typeof x - -# Analiznado rama 1 -t1 = typeof -b1 = t1 == t # Comparando tipos -if b1 goto branch1: # En caso de exito ve a la rama - -# Analizando rama 2 -t2 = typeof -b2 = t2 == t -if b2 goto branch2 - -... - -# Analizando rama n -tn = typeof -bn = tn == t -if bn goto brannch - - # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama - - -# Realizando logica the rama1 -label branch1 - -goto end_case - -# Realizando logica the rama2 -label branch2 - -goto end_case - -... - -# Realizando logica the raman -label branchn - -goto end_case - -label end_case -``` - -#### Despacho Estático - -**Cool Input** - -``` -(, , ..., ); -``` - -**CCIL Output** - -```assembly - - -... - -r = call n -``` - -#### Despacho Dinámico - -**Cool Input** - -``` -@.(, , ..., ); -``` - -**CCIL Output** - -```assembly - - -... - -t = allocate # It needs to give the same attributes that type one has -r = vcall t n -``` - -#### Declaración de un método - -**Cool Input** - -``` -(:, ..., :) : -{ - -} -``` - -**CCIL Output** - -```assembly -function { - param - param - ... - param - local - local - ... - local - - r = - return r -} -``` - -#### Expresión de Bloque - -**Cool Input** - -``` -{ - ; - ; - ... - ; -} -``` - -**CCIL Output** - -``` - - -... - - - - -... - -``` - -#### Expresiones Aritméticas - -**Cool Input** - -```c# -3 + 5 -``` - -**CCIL Output** - -``` -t = 3 + 5 -``` - ---- - -###### More than one - -**Cool Input** - -``` -3 + 5 + 7 -``` - -**CCIL Output** - -```assembly -# Naive -t1 = 5 + 7 -t2 = 3 + t1 -``` - ---- - -###### Using non commutative operations - -```python -3 - 5 - 7 -# -2 -7 -# -9 -``` - -```assembly -t = 3 - 5 -t = t - 7 -``` - ---- - -**Cool Input** - -``` -100 / 20 / 5 / 2 -``` - -**CCIL Output** - -``` -t = 100 / 20 -t = t / 5 -t = t / 2 -``` - - - -## Lenguaje CCIL - -Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. - -$$ -\begin{array}{rcl} -\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ -\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ -\text{Type} &\rarr& \text{FeatureList}\\ -\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ -&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ -\\ -\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ -\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ -\text{FuncCode} &\rarr& \text{id }\{\\ -&&\text{ParamList}\\ -&&\text{LocalList}\\ -&&\text{OperationList} \text{\}}\\ -\\ -\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ -\text{Operation} &\rarr& \text{id = ReturnOp}\\ -&|& \text{goto id}\\ -&|& \text{label id}\\ -&|& \text{return Atom}\\ -&|& \text{setattr id id Atom}\\ -&|& \text{if Atom goto id}\\ -&|& \text{ifFalse Atom goto id}\\ -&|& \text{arg id}\\ - -\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ -&|& \text{Atom - Atom}\\ -&|& \text{Atom * Atom}\\ -&|& \text{Atom / Atom}\\ -&|& \text{not Atom}\\ -&|& \text{neg Atom}\\ -&|& \text{call id}\\ -&|& \text{vcall typeId id}\\ -&|& \text{typeof id}\\ -&|& \text{getatrr id id}\\ -&|& \text{allocate typeId}\\ -&|& \text{Atom < Atom}\\ -&|& \text{Atom <= Atom}\\ -&|& \text{Atom = Atom}\\ -&|& \text{allocate typeId}\\ -&|& \text{getattr id id}\\ -&|& \text{Atom}\\ -\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ -\text{Constant} &\rarr& \text{ integer } | \text{ string } -\end{array} -$$ diff --git a/doc/report/img/class.png b/doc/report/img/class.png new file mode 100644 index 0000000000000000000000000000000000000000..e26e025e42db0976328e3440762a159d3c7ca7d8 GIT binary patch literal 19974 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 literal 0 HcmV?d00001 diff --git a/doc/report/img/object.png b/doc/report/img/object.png new file mode 100644 index 0000000000000000000000000000000000000000..51db37f369698fb198af7acc3141053240633d05 GIT binary patch literal 15724 zcmdtIWmFtN8!kv7gy0DY1c%^GaM$4OE&+mDaEB0rYjAgWcS*3pZEzUe2L^ZB=DVwB z&)&Ve_x{+kzj~&-s=MT^sz=^XB?U=z6nqpoI5>1^DKQl|ICx>;_vG6*aB#0wxdrUu z-~`yD#YEKH(~lsCdLQ=*kWNw{fs_nuXonirHRm>mI3Ef4#_OJ39U9G%`WFHtBlXQq zsOel$-%1_Uww-4Mw_Pd?R(zUYy*^*>fgO&ukB_vUAM&vsj|^C$T`5aSf~1<+Hx7mr z+L<=h59_oiO!>7VR2WOtD}FO=7Sgtk<&FGx$mi1%mi`Mb1COJGRsA#eCu00-hHQ#& zuP9%k(jfmI9+C3#=l$u($k2Za6^=L>hnc$Y%8_~9U0CLzVAJWbISYrj_&&CV?|I6A z+J3Bya!ewc^v1tSsYER@8%^C6<8Z;#ObYyZq0P+dx-(0`KU`H&RP)7p%S|yb7C!SNVmzg6B6BVSEjm>LV|wpIcMc&#ZTRuI*rymK zR7peraa6JltkOy>9d3%5$B{J8bqdNE#_Z{xd&GR?`Yj5?gjTuYG<&UU*1EbzqT701 zkIVZ6o;beDz_@#GGLm561_r%7wa+d|uIn^q)YhJsvab&TPf^wKx{}_CV|6#a!Z};n!>28Zfo>)@< z0Nuq(KA2V;$64UWdwnGsql=NhQ$5MSv^6sp9W{E3)wF)nQcv~1RLQKj#GL%!f6GL_ z#6U`A(RXq(G8^&tK^OzL2Z^qFOB0leu}DuFc~0mIPQ);>cs2Lg@Sr}wL*-22{Z9ODU7A_tcLmWeyB6* z393Z4Gp_&P3R_-KsAnrcT4 zi|J9&We=w7OfC(ptUpy6C$*KeS46KaQ}+!kI{L;~L|4mU2~y=zR;|@upvWG21yTGl z4S&yWSl~PPrzQ6M@fhdb=vx1B-2;!E#o_&yt9Yo_T{4csVKYlpTse;s{y(zL_5N}J z{27q@u-t$mNActA^&|Qxg+=PJWw&spj<7gsRC!r*)5{#FZ)Ihaf#1y1vFn74YGSCN z#{??fyFEngw->)qUVDll!gplD`x_|v3o{oBXMa*7{Xab(z! zgz9+g<MPIqd&|_ZCU}p%r9%>;>)@(&_Ic)Tn(9(h?RCGLwYgPN@2Duke zhny>g|NZ-SMO(rj6vJ%T`3d-OmpcS5)2y1wH7KNuLoDS#Ug>c9Na>OCFB&L(b#?Wx zHL9%a6SKhl~nXv5&M)T*+4 ztTk~Ct4;0K5_OJDC|YK4YBbZRnD)^qG%^QG859!v^9~^j-eoABae?7?G)>i`C2P+e zQ8QuprPsFd9+nyj*-sRkcW>(ov;_p4PtsF^P;hJu>hop&hoM%Xx#_Cb84AnJ7#3fkgnK@*p=isaVCf5%Z6W%AE#;eOOT z>@{x1A=AZ|PqYyg{LdU;mIs9ct+h>c z+rPfbdF{sAMW&mhTdCUB(+*Exru5uR+!jt+4sKH0ll9)#bC{;&yhrg;O_bCsmpu&p zuP(U%oAvnr;PFCrVIXP^M)!PtDZEA^Yl*bIKQw0Hpo4apoMEwYb=CQj9XE**)_F$U^@RMAd!qzVWK%q7>#;m8^I@4ZK&*C^k! z9%3cnuyXE=-+qsiU=D1$;o<@E+J)uc{{8aL{Z&X;Et5c(BK2&boZ6U=#OfvR`FlY?WuDA2JGKtur5g5{ZX= zH0_(|@_XJcWQa~QKUCCudbrIBKO<=S3!STK3#nAy#{2T^FY6?nNs@Fz@Dq6C4I&~> z$gc=(;)Vt-HR1}{BqsG72Kz(Dp?F#+Sv9Ig_jh^x!O7FR&$h*Bi-wMGsxewj5Wnoqqsl;Kk zN;tS;(HVEAUZzMeeXr`<7Wo$ZM-S1gv-l*5gr?HYr&@_e5edxsyxJZ0q+^n+rrg`> zRkd?@>S%)>KhDxuFKD9^jB&iR5;AhW&NhwIEAaU(21EDxjwsmPF%Or0RAXkOygCxn z4LYn3$9Y{6pM+v1GU~Q`@qMCy(d}BwvB{Hu{lZI_KtSCdIOsqIzStI9o8YVN2N5Joi2jM5j4i(K<$YyE-$1 zjyYTDbTG0&-|$*Kp8{sSDx`kgbsH-c>q}wM{d%QEBCxC?shy;+!^_~wozYHlSv~i^oD8T}Dt)C6`gBE5UzlW7*TIn+ zp9Lk9I|9Ay8{A(staor<0$#s{8zFu53XV-m_`mO#Fj=8y^~KW6-Hz?E!x%ZwB?1pK z{f7#yc&w5;|LvwZPr7QS{qA)(>D1d4m5tPJOgTtEs&8-Eez6DWkU43=Jxis1-9DN<>9F)EFvO;QEu`jFjK(msgL)KN#2&z z&Pa-(xVaX{SgsZz3ek`@H+%X?gV}$$vcTrTb$Kvj%>lev`rYfNozXPYG%owjtXM{< zdqjajhbOhzCGaVf3f-oa4}^p^<3L*%njK7%<^v{}4cZ4lytpRX^%j#cidllD1#*DrS?jSVWtKlA zWY4{TvhggT@#lk?GXD5@Esz-vfX~WxvW5N4@z~7J%!$HjmCsVX82w7JfQM?KQS$OG zhUo}(cwHM@9M|!sg{%i_7I`+y7>MU+;!eFrTi+!*tZHk?7MVMqXG4@iU zt!}W@OsRgz@j1|vh=n?HMd(NhTW}#zdAdY(_hSW@?b&4Rw)C_8aGGOqMNV5}y*|xIF~ncHEL8H<4TF z>)Ym4|8{gAhD~pPt)72r8F4m3M2T!@xSH6X43M%G!*ECIRc8HGXHwfD=XcAv+kK|B zQ6T{5W>*D85m}S+?yRl7izgmmR5}CVa9l>2#8a^%MyJ6l!;~l~NBPVFAZbjF(3ewF zMzGuj9s+dWwPZy(5H)io+&|V-R1<8^GAF1NGs|V$toK=NEtJo4>cWZ?GD<(-slZrH=BMKlijk)acX+&YH!n#6U(-!~%;kE`SA!k~d0Wj{*Vl~JVkluwjc+39 zu-#kA4U)VO#_g0)SX5A>*rcjf7CQ8k|*v44b{ZZ3PITR0)h*TfrxdSe9~6 zEOYJ0^7KLjN~!{|neXlhRo8xRhoG}TsZ<_Oa>B z`P$2H&0#w=Wx!I)jG+YP<2F@k@VukFWE?JZ7ZF3&v>zjI!8T97Gz&t1Q7 z{cf=AsH$}sbl|~Ve!keB!r3SIQSU7L4qO^Wl);2%x%&B=aG^e>#+xpEgVoJ0S_!HA z_6!+Xnu0tHhnmf#rmX<#*Qnb%rfUYtz8KHzuy5~Ax^zq56wzth=r3wEn0+${ZMOT^ z{<~?)Vt07%Ys*8IM-;5SrDn80yGS>D%kjYZIFGD<_N*<8n6l*~#kjhk+H*qsT)xo! zNP-8ecg8liwL$3<)+LSVQLOr-y>BAl81IiBTdBx$-=GNHWBqDh5ZQ8)&WT|o+En?; zk2R9fVhfk%-I@@LTS{+=apZ27HvH73s;*uG+v7x$vxfuZ?VsA%#93>Mdb#YWH2e9N zdN$GPiH)&Im9I*15FDlL4hZ6Wb185zh=hJ4TgkHgD;>ksVyD*K74QP{s>E`36_ULP>(8uI9x7O1+gVTjP(s2_^i;~r73f7v9h!10K z=<$4}6YBJaB3)~A)QxkVqV@Cge0i>~WAwJai;vAr#l=3N*<_r~Ky2V=qmEWyN!OC$ zGrWK_pSLH>*)+#5F`k8YGiJ_4HWY>-T!*Rtz>^mc+8I4@Netl==qA!Oy6vOR3Ilr) zAXi!CV%2_3{9%ZW-69h83KELklyv5(uKTRK-OkE9@=kl)Gq|~;4^~;SdDtjk#*GqA@-MZE&c$Vr0ml)Ae;$)KSB8Gy**D|OA(W3E zpH_bemH~L9HY<`_B=m37f?GIx7l`)qf^Bb9nEyA^vmhmBVrYLU2~^*K>=WH*wB z0;jJNg(Z4RI?__*_X4Srvi}x$VwwZA_PgW)* zsSBqM!Pl}fF7oa}v-l0~$W!L#Tqftc6fWFckG#%YBff#Y3+bPCch?@0xaGc{af4>M zo!smRdEU80bx@fkGcwe~`3yfF!*)aX#zWwAWucq05bNMmLFz1SoS9;Hzq`w=qanYRr!(1q?osF( zu1BnlT)GoCGCQp4JUe_2!lO*c6>I>?sM2%TT~O7EnaDRaEnLR_O}m$DA=+PF_Xl4j zao+3egx4>XqRi;%)r0-BbL#eYjBoevJelDpqRT~(b0nx61GT5_8PuN_Y_6=@5g}uBk|<_)w^Qe{cp&U7K99@*Sb5h@;PsO z=HC6|U|5I2#`qN;UMgf-`tw^EgL~H(usQE;5CDt$3HK9^f)wuC8|1fe$s+LZaAyC5 zZvBb0FsOeAC5>P#_4U=YZejQZ9E^ptZ&gZuYt}^}Tr|1p<+al_^uOGu8cyK&N(v=~ zTk~2tvNfoQ`uB0f_|qW(+WN$zUqES=kl&N|MG8<9z(hsmxrzX|Z#+3UiOBsi>wp_4 zk@sg{rNe8N#`6U_(g936a$rD;0C==?-1RKz2e4y(;5Blxi41t`rbF@4FV$ag7t-t3 z9|0uHBH;JL-*pHa>n&g}comwDjxVv`>|Box#f^wOpoikhtZ+1RhN4^p0= zpF34()oiE(cvp2Wmh!kZ>fgMe_e~6Bb+wBhz`aKkIbY?0;wbw*X%zKLrfsfAR(!q> zH$qxSCUOE^R}ZoP8VrjsH(^NxkaLstF$hg+rQO32c+W?`c&JNrLF<=r(MSY}VwNMY zP+9Guft@z$idX>gMK_b#=6K%>5rplV$c4H=wG@UiJ?& zlv_@OE}=9Soq*H+d}lNR0QhJuEG#(jUf&C3lR6;{)^q5&mE{4fZ*+B+<}pIlJhVZ^ z4CdpR72?Q=25l`ZwwTDsH6}!HEY8O(KKh;+O*az~LjYy4oU4Q=EK-@=zgk#YLaGCr zG+Sl3DxaohJyYt^_+RW9ZIG!2F)^`jy?L<3Q+IbaYiPF?$W$ucz0#mV=MMnz>wWHB zxkyMz+^itAQGFA1YQ;YypFmXEh^RPdw$sIv@0H0Ljqqmw1t6ulLT7C|t{#(FOw7D* z&nUz9Pqyu2EMamm(8PX&sOM~ZaKC9ttF#^{YbU9 zI-RV<10IB8Xr!8)eZIdww$IG;RgwTSuzMhQ8yb$gD6?%AYJCnNZP%qZj5>#2_gA)K z@p98+V@wn|;}+yC?x)5xqJby^k;mt+5Z*AfIqfRY($kmi#RJ$G4Ug5^#l_`P)*^6{ zX$atBI^*d)PW3t!iBxW_@zq$oqw-*6bo9}5B_YBD8Opq|Ow-}Sj+EuI*jOH?9i;TheQ9M=4s_YY5x_ha=$>J>Vdxj94mVyzaFxt|>r z-F@5`aWCT*UbLvM*u~;RQRNjCd5$|Hx16w(Ru^dI#~BW14{1wC>m~6W+l4djVDGgo zq|tUs-x)nFXIM6jMPV3xT5zK?G@QhIyb28Z==AQ;geg2Il90y{;}OrZb*5CkjkFZU z4fnFU(9nIE|uUkJLH(Z@nj&Ky^5yQUHvR$7@r%`H!j%KQne5m^V;ZA^5&f zK8-j(d{R!mv*aVA4!iI@FAdFrzpIdTzX_UiY1fbSZbh-ceE}j;-;*`}571`PZ41p# z6Ht_H!>7)v9AwqZ2-f{0?!9?b%Iqq`E;FgBBDInfIim8tZ@K_AQ&?{IsAGU8M|_6C zggtp2j4Ca3r&oqdU&J~IV0yr6rfKZ2l+6kP42gK1=UvzS`kNIpEXD5$Gf-v&3yA0& zQFzV8(UKb?_Vg#L7+Xvz(bE z)~N~jSm!H3Yjk`1KmA)IPNVlL^=AQSEPcgANavarOWRvLN@<2vcHA>wHsNF=SIHslDt=d#!{o|}$5wp=$P<7~>xC=z^6jX?{lsw<2sf30S56R6(( z!w$P6Q}b)5z5Tu9leyn;mL18TvUc`GaqW?#zJL_@I|s1fLlY~9f8ta+TUOa>RYZs7 zbNj*BBc&qk9XsG9Qu6*QM#ZxUZx%q02&*1ujz+GEQGOD&p%!|We*S}_ zHpN_gxN10Ij_P;myaH|<|G>3MSx|*xEuh`Gw>{9MfXT4xI{nnue0ZzJjR`Bg+Fq;7~+V7KpEEBm9<(r@sP!GB2DoysQbm#QsZ5UqP?eax>`hw~`` zIz!Cuv-MB$que~tv*$mYi$)`DIo}9CbSRQki@Zp%SsD`^bUt?aq>j_D-A?^_aAbq`IAL`l36CZt6<|q5kZr&`N{q6m@6XqH{Tc4jZIIMwl4)X6wY1TEeRsKmrAX122F6zzmK8mn|Ik* zOtzlvKV@ia>p)jMW>*Fgt=*pQXD1UbDU4@WzAxWVl1gVL+wrhp2d9TvHI-+&9LksQ zM)Go5A1#4rY%vJw@oGCwp`0wGXaOB9t4%Gt7p@k&-ZU2GAgTlEaFm6%k*@c6=L`K| zo6{X(gH@bLf z?6#*b2&*Ie+LHyyr?ssKpaX02wmON?5eLNUeWO|siu0XZ^42PE)+U|fEQE=S6{H+Z zBK*03wRXFz!=kRXyVICkpJqH*4S%d5h;movQ#{A)w&d#_R&eo_YjYQxB%U7gRFZSG zZH5%cYj!=8P-e|r>ghnlV)J&{DxZ;ekoUG?f{ZStK&Hd&6iMFTB1P;9V!Icsg5Gd#rV% zs`6Cov>VPPtRPEi*q!O8DQPDPqbGefPL-^h+PwB_6KN?|s(EHQZW<|Ao33Km+wOo< zUq^rt?VLkeZdV19zNA~H+8cu8&(@o-t(Tf+q==?Rt>*-Z`Gl(ze0k?eTFq1` zveZ84YGg~5a=XIm^q16$ZJZ1@ff%GsRT{Db(3Eyy|GrxCr=Vkhl=HX{tKUX0b zj9t)0RIY}&e1H7U?7gBbx1|VW2g4Bs>RZ^k+3n}?a=!z^&h=tDdD_#NR^Mqz9jMeI z7+FNOR@$+-bK{NB)a}z4tfGz>w`S9|jMh|7p*PXVN!LNTv5^GreI1kDJ)vI9VN0uV z*K%yyqLJ+jWoM>M8>uw*h*8&zaqKUxD>RPr6^`t{jJ7AM!ued|ggHdM-U&HUI=3?& z(>45LN+0Kc&s{dNHWQV>1uI(b;ddxX(h<>-#=qm`*8Hu-PC@#06hF{cA_5mAk?KZ^D06Yedm zH-#GNWW>?onOeQPto34-DdtZnn)naM^@CWxe_@R~Nf8clm%f?c}jCje0WF)z2F}yULuUn6a5pA^1Pbr^~8G|$oHn?(g?{5U`=Q!Pp z)~C7yvVxWeGzuj;4dG!vQ{1hOo!_JfrYhy)FpE5lYMum+31_H=6~_gxiBydpFL6+t z#4;WY6BeWD49s1fpWdCpe4{$rB%B$N$9EQKkG=A+G8#=6ii>ye&o$^$w#VLN*lM z_}*TEW^RrpmtKE_U_X>4C-C;D9T_=A#%@@7rhCCMbg$ zcJBem2oG4PS3o91_&@l-e7u^mp{2Wbz`b0#^aPoNG(+wbNZ_WJ^&(LIXOpLP$fxP8Iz4tC(tb@8 z;)V03Yj&ZMKVhsK-f8tzJ?u1&>pdQ;))MbdwK);W-e9U~W>X>xX1_~GdSzC;4aQ4e zjMvUi8U1jAjKHp<2p2!dvKk40jG>_mEM{w2e&EH}| zvNnWpAHKc}h>F77M1!Ty_C6KA%A9bM)#CTYCRBstSOiFadtZj=XM7wlZNGtPYn1$; zd1xfUH{<^=3}@7c1QV(c)(LCGE|0&iNZ?tG5jktc^l)b_2AA+FDNA#lw{sTMHn8Fk_%4c0j^Z1%(TWP=DP^!580g z7|6hYb_b%)kdc$yiUECthrDon)C{H)-6ohcFc?Plb`Z~Tz{*^@fXRj* z57Y|jt?s8A|H=^p;&r=xeYkjyh5f)qiX?nyBguI6j@lqZTFD|=yBD_(aQBGzLJV?5 z12ZuQxqp-d28yFW=SfX-^YSXpfON&X7jX&*t02`D$L-fiJLz_R6cJy> zSbVR+8zIN70iNxlgf@qR=@Q;t)$)LVEmRZ~$87S~fD}Y8d<-PI_<6smI>2mm$+1Vf zc*l7EB0X`YOU0t^aQpG&ZEj?}*EI}kkx?6ksZ#hg7-I<#DA*}f3+0S}0P4|cbG5}> zhv8Vt;ZL)t!e^5uRlDO^yG8UiT@a)_!2d)qCco$j#thGM(p(hII0YO_m&7qi z5ajJ#x%Q@ZxmJxNV2`$ksTx@Z2M2?2co$VWy*>PnzVHe>Ua$ITzDRw?xwj0P0b6N6 zJaAk6RoP5%Vfg0$;>9yX72LF08&_FGz0ZJ zy;~gr{X#@Y5l5C*p-V`tujI6upJ?#BJn#cOMsP}44YW2l>lLXQ1G*VcFP(x^W`86B ziQQywUnd}BFh8Hx0io)8I9suFM+@{EOWx=`3B_u$a-Nyr;~huOi$W3yG>G5%B3MBl zJhlUPzcOp=E(a2tZD8KKeoV-7OpuQowT0E|N%S@vJWW6r+4%lGPU^Gr{ne56>5_dH zV}6;eg(5}gu@nUsy8e!&BzmzbV`M-_{PZpmvXs!7GPhp}LVSFDtBQMG)8pX^k(0`c zKpvsS2%z;8({BFGpR7RL+k*h6>75FODG??vi9W<_f2x3P`faWqQiV>#;xI4O4W5e* zCLjgLWn^t)Jnt*xUi9qm?(WJ2hsh){`S2-b@>lJ}D8HzV_-w*~qMwUoeN}lg^_Vm# zqTwM~B3Wnqj_P+Txl!SFav)p_dscpaesT`u;>oW z6<303-|=Gcd0y=9{WP7dO5yA9ygDT3 zFpaEzevh;KlK>>lbd^nes+@EYp9WyXocaQi2JtBogVc%kH$;?=?ykTzP4%NsexZ?O z0z|I8a_zb&Nuu=PBwxq=yfkeNi-|R@0-1!$3EKnf>0*bK`I>{TbCP=B0mJ>_uRp>l z8c{ThlH|7ou$YgbMTYaiw51bJk$0lg=bmUf!~n<(us?YIeyDXRl95qz8aH*iM?;)3 zn=fS2Yii-FPLR=Arr&mDxhN6GN6aw|q(JC+9ao510Ru)_68288sFgtefJP#0(Kx4v)+*RPCyuFbJYkawyLEoyq}~5IZqGApNe+xA!XW)N&5w35Lt;Pr5Uuj zR=^XF5t;%lCH12 zmX^^MK#E4BcJJH4uNh7IG!z*d`FXFL=dVD=NUs0 z`xo#DtQ-eaFM17V(E?!#Gr3*(KTjuJB@{8UgDt=%e9Ao}T_4`RH`0B{`KbS@(`d7h zhStrV>O2QWHtiOw@jVoa5~dt|+$`z7S33&>VRW5?xy`-38-;tk zOZ%ynaet$b82Af!OwS%}5B44))J{cs` zJqxB`+{n-RoIj;XR0?29MZIGgeD=8*O6)d3qD)7z6BDc`wo%Dk^q@yf@@VhOcTs6y z4H?q%034u!S|B9aub;G)B;5|gq={HcRJn*7f=Xr z`bxFh!u@#>jq?oFF0|e*Li4eurITC$qBZ?KF=|;EWVFa#631Sln@%U~wO5?kSVdg% zwbdR2vPqMp%M16@a-!tR!8>_PUoaxt_3^5k!nj+G;v71uXlP>Qy$F}^!Apuo>)d;2 zvM`skoBjc&m?Y-jDf~34G0}&;AdD6;Epw}uKd*%9hAGj9pDlS~lfY5%3?3e~hSygU zyL*K2w&JR@SbA>wh&e=l$X91GbbI!V*Pzn@;v%vWek)Wj6Iuoeg& z?m0W}(3zLFVO4hY-AL{$v81&FFE=A8qP;g6)4{!f(*FCu)V&~Cq7ptZX6i~Yn}o~t z!d+Xh+(&?T)GOtPDry7p2iO{xBoBV1014_`zzO*Cd15nGaZ<>IA^h^6cfF5o`^#29we`5>Rp|e!u6Q|8p*#Cp@d36F; zaBHS6orJsvjdKCjcPvgE=K>;yvz-SbT$nG=Wf~;<+7B<0-N~F~P_W#2Iv0<=KbSD} z5RggYSKVx7OAqsTAn!df5Biv?u>YH z#%6AD8(*37GoeW0Tc|^h*~t&IWqbVQjUu-uWN$f_E42&Z>qd=s_kh9DOVt@$6jyyH z8((d=JM|)l7e;CzJ{*4=C-i$$WxL3kv};6C=_}+nj;Wh)&(>7Cw_Ls~D5+h&v66Fn z$(imssdOvbv({&h$w{K5=epk&T5@A9*rCG-t1%kQvq)pOEo(6-)8)NKe>x9fFn<`E z^}=VW8(*^9_Wz*U>Ox1c*)8AxMTG_Z*-Tyc+O=%uiK&bef<+Gm`3%2g-y)TP@nKwcjM)-s4-Si>QLVgFZ`wkAnr9>X z{VYCZGL|pYY5(v}HfOncfxfNEVxz?~TC?MpYw_t|n~cwF3o!|$z~2RrKA_)3F}^7H zs^ZtM#UUlaUya3i&b-DZdz<4<=+FFwIlQXkf~=jOX~wAv{h5s0@}3?N5?xK}z9-2F za@#WTu~z58{Q<06r$Qai)^E#j8-a%WoX6)Khx~Q0T#rrN%hH;S)1X9H3ir`IG6%_* zxgMvHz~sV(R@nR|80_$hxza0C48P6sqj_cGkPm(FIz9EiAF9Vqe2XkoB!gjY|1vm$ zu7#x5tESFTlJALy2&J8S%0q9o#b33qe%14)F4~JA_*e%FPf`ocb5Op9wS_17xel)S zIYv&gVki=R>bp^7fc*HGXv-@PJ2V8*sqv6}fU(S=!gG2y2z z06lt+_>7&tOnscDq4$=*{q(poi%l);BAwG|v8ks@oO)GmkFAd={E(md?R&4;nFq(u z#p>V1!!-s`&Y(vTTv^2^PPH3hQwlh*PJKbS?#?9}wQ#V*54!|SJu)avS0E2IKKvA_ zS<0VyGW1J@Vsw)e&C0=#bkfA_mFJB=w+@;xks@_iouxaN0+F%|xQyl(_w}PM>|!!@ zbJ3fV(de+9e>GxRjh^3|?98Yz<#D=L?Q5J*9tV5wrhY9NoW3^0Ip%&kbC&<}$KOkn z^OzY1U)s$57|uZN*14%H=lKYt)rq&is#dPNeHCt)!Qi#kUaJGzIRmAi1Ed%Mz424#*eyES(S_vz2LW+!!y{ufsJoWP`b`gCp!rz zlU^Ug^|siR5mnlvLxBgn?954^f!kh%KM$l|7fw+67>QwBE?r}hZ7AlI zKQCvpI`f)sogOoXLhER-^#>`zjCH(saf!fW^GKI175@Gd3)6~kEr@y(6Vl}NT<-t~ zeRF;pevT?dw8OPCr#$>eQSuc#&?^iQ12Iq9PKWrU*?0plYo&&gZH7+h@Ouv{U5{0_ zRAa2Rei25i!Dk);Gi~Zz^CmLg*%6fFM$`4g&bR}Y)uc_(SEn$fSzj+h4#$Uvody-2 za>KM4%q_*-+qxe72m%L#Nq&=IbWrBu{uKWThI>snMW;RrvrV1lS+)cMJ+s#qB)be9 zRMO>B{vJzkId*cqP}+3uRcyEIa}YHg94hF(40du=5%)2m#n z7nH|px~){u?rUsJ2I7lX5Ode-IojA}<)UKUjV$?l#r)t29iI1oJpIHq+*WV%#pb!H z5p{Lw5Y?AoP#YjtTd z)0L4GsI-4xrAMrAJ}}kx)%3VSV|i|Vy_Rffg@EgEwkhOdm)sYwL}ziC6Z~P5>m@;~ zXN+D4O?D+Iu-yf!Pseo6cVSRdbByW91v9@_?8>^)P7K9&ablOk zNoqe%qc<2>^cc@%&fppT9&M~GV7&4{ecQt!c!3>7|4~EV%EfzC@q~?pNo6z7siU5b zW2O`s`s=0v#nj)S)-tDXk^;-Zi(~(vdY`I6}|a? zb(1IL;lEJOJiRV*H3J-*QBVQxEaImJf|QG`N=lfE8DU$|V0w;l!R*rqW^cR2uG&Z1 zbC@3jP^!PT{S`&om+jfe6WWDXp*PI)E=yf}tpwB@25P|Lm`oP?7Zn#SdGYy`WuEg< UK)h8D@E1;6TtTc-^xLoh37eIVBATCTW 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%0AU1AWW&3WK91LhEQ{#-E#TdD)iE~^V> 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

k zqz)0j;#X^C!TA0&?z%{n0Mv?wA$_lXaEOHLZX+dkSy`cosHF!oQHU;`3m&?OY1*si z#?uxoo}k86(W2fzR?YHvx!;*Rt!e}*{aLhYWb;DU-E47WpIZd-rk1EzJq4>7?2SO_iTl3Yj5(KW z%kmzt!2}0AHV~-~AQxP9d0x)?KO?elTf?4VRsScx7AJWz`OSXTRAVkKR;rOp{~8AG zeTsV22&VjLx-MnjpV5t3HAO#57g1=AQEi#lYt|sHCj50ZO9-bs2S)k`%HZ-C1-=UHE-Lf^B6jo2gq(iQfc#8iIxoCDv^ z@;;=i1_mEr;%&0??Kg5yv|OtW*x!9dn>RS@EL4W{L9CIe9q@XZr{$wPJk|B~{!-6# zD&0JnaQ~6(QZcXLw?i>=SZa!hFdSZKB$3p(n5_6JAiRZ6%rgIrt((~lQ=kwKAn_ru z?6$!Rza0PEh@~TkGnWy8n^3En4+a+>B>ZVxzvats=LD1FVJDwD&9h{5*RIutiPefa zya?a94wFW=PBlFK4;|Z&#++_C(j}v6zyUsd6&*JrS$l|-AhkssXdY;$&}dsnbGRsj1KQns-4bh zZXJ!HA4q2V6yo*3qEJWwo5hjSp|~_D&0%VTTT|pQhqxYQwPs;EL7DCaJ71=!LN`9e9}3+^68X=S6s z{b^97`HfA&c5S@p6Jwg7*}2EFgU(-@17pU3#`c4?y7{$+w0p6-h24k;VHSCL8?&mZ z)xU=SPWqZvrQnQ*$V__wU(C?8uR8LMRR&2k8mI|>hC3b~2l||+_i1iYArzXvg~xLr zfPqnsWRiMIKerG%rgKoNgZf!hwjte)#;A^eS^sjC2GBuw&>(%Dj4At`J zG@Y>w$y;f1oApINq3`Laci^XxRxo5Og4)IBpe*noGpg6&wxffVK_CeB|?2FzRv`)i|mIe*M`)C+Je~_E4{l+!fMAAV|I;LpR zXNPE%>P%-}lH0FfMFf)xW5Z0;N$yCZEd=nOn)x76-< zm#_xj{Rg;g5F};5NFIU~RpyO`?~^ISw_d!9r+Ugd?|A$nHl*Fr^)8)+L(dEbk8#XD zW@PaZ!3I2CB|F_~mVy7D1QE|pt};y?7KUao4J$RFr{CjJ@AUJ3D)agNPw zPkBsHd0X-M3c$TGGsvsB#y|dpzHWN%J;)@*yy&KeKFnTOr~i;#b!@$ZL-U2oFk#u( zBnIZ?pL+T~DL;$}So0Nu+~fLH0+0thU?lGcgZUw)lAj9@kbg|yuMH{jAWEcm-r~KR zs8HoZL=<{E58`ZG82~B)rvCn2<=qTog9)|1CH~O&?7?lH{nEC)aCSwdufA(geL1$9 zY$r4R6|fC(Gt-?v`5yZw#(&P(+;H%SNKw2(v|sD)xt?Ry*v@v>;Uz?Xuy^T=4*;GL zSY7aYX@Nw2%bPwr-~v9o8kk8BBKNrvw@Z4Q8%Ty8@GZ1c1(4RxHY zp8@eZ6&QMQR7bGDe7gGd^<}hWMFni}lkJY=ha=N&vBzEW-rloZRYVBPHP97x zpu1^zA`x_a)qmB`k1=u-f3N+bmoG=VK(Rmvj<*8tyJ^p^_fS7dTQXZYSH~{ox+_Bn zhnl`oYEJ2s2oa${A1kY(gNgouU31-=u@;*<)}p~FSN^nR__1HK_4T596%@KJpG+O_ z5(t3nBOZz5hAwO?2_GfQ=vl0kJg zv9)a7l*+}uWG1z@>oFD3iR?r}!0V`^sMP=W=DKZkONp>jm3&UIx_LFLAq#~yo*s^$ z_zdZa+E)D{M2{^^+;z+^{q0~W$B2y4Io#4S#<$llPIz%Xc>=6`IZ1dn)_g5(?PO&I zBiN>c#qsy)&NE9WFFG7J^*r!cDy#ArH;JNxU84zs?=mZw@R&vW-tOL-v%E0$LSRmZ z`CfELG-DDqIy%B*Tvz>(U~FH>Q}SK!oP6%?E!Wqve`ELks&AI>+ml5+ql=H;i!wp5 z4W&%TDJv=IgAD1UoE9x=3oM`sVuX^RQ`XJEePY7D6-GC-x4{#z(|V2wd4s&Ft(_~w z?Iv4M#m8L!N|AEwv0&qV1X!Prd#O)7y!mw54;^>7hNf%tkBA7#Pbgi488Z8u0|L2~ zsR$%xKsc+%v4co6o*+gB3UG^oof_UA6}KLxLkC~{^Xq_q`*D}FX$riewzbXo z4?Z(-;U9c{e-}~~J+R`^mRI}T*S z>PA@I(!_HbmF*~pr)Vst^y80)*9}`JqZMH?9(TuUfU8}y@ekvjcLZB6AysyInAG*0 zvNgp+%~&PqLxT3X@)XS7#GJ9Y`r~cAblErzuh~8t;hbbn7oP)@ioCL&hPjURH(-dEY*Ez4FK0D`_KQ;&b@&WmXzYxS>1wN;N zT3?1OP@r7tst-gSo`nC8CPKeWb$LmrO)-+naoKi61i&8?+O>pGnB0<|^h`o1ya!Fv zAMKr^44qB(b{at-xjo;W&Z8Dl>`BISDc;QH&5OIwZ&&TYbS zRU4(c9OZ6zQ?k-YBYc)rAcbP=C`IkV*#y6`vIJ(&1->riei56Hlan(TdpK1tSzV19 zpf}gq@r8SEePkZPY;~wiZz%aN+c~c*a0^@ZXKLpR7Yb4psM9gO_$B|_Kf*v<<3Gj! zPuraF+nU-=&%9q|@G}iBX)%z9$qfkitZdDg1rGK={94oA;W!S}GSSuEmvkLvTw(gXZ z@1vZM2g%RJcxWMl*bELL=r!OMH@|u7nypHN9;4l@CL`U|0_ZV}qaUkuG}ea?P2A@( z`u5W;cQ-<)wOLHEd%q|Q-dR!_Z49_}f332WjLbPE;6!Xqmvijp?q|*j6249Yy(?AK z9quA*-37}De-Y&}08ZCKzv-y$k}>y(MKnU#r(a=TVr@rWToFo_3ZXxsM%lj7@>lWB zL7RLb_1wyy)^aQe64E-WXQjZ(sIzTyMfmrZcDW$AhS7~5X?>{4V=n?_@L;ulpO%jN zwa%6~V{gh7L$jrF-)Cjufra>=ASA6`BkL#Y44<3HC@GTC7z$;x zM2IlQ65pWkw0Z*OS7v7Sbgrnt1QQ3WfUm=*v~btAFVLt$8r5s| zE!#sqzNrUUwbw37={g)u#PgcS)*CUQ-3?*RuWEVgnLsKo%nzfV|5Ketb?jvRZv%^b zZiwNikiua6vg9hMH9-9)9F>Z<)G2!H-W(D+ zas^w-c0_4$b|Gxz+TS}tn!`vk$D7bh>5&gmFXxv0JC#-EdzwIW?dgwd_z0!hlGae4~#OvkmwgqT-;l+b5XF4icSO#vv zy&gAw-1im>m)+)sZpuZ#bPzei$lzEk(QBsKpqcX9tm+gQZh2xML~K+R>kw4L9-NqQKqgJ8;dx=NN>;Ix zbw4Ra9y2%U;`4Ws)rIcUfAZ%VH*k3CDD9~)ZWIj`H`0756~Sy!mDQ8kce>IiTtN?m zOyjsj_F4F|b2@q(IooQ;g&@d=8OL|A_{CxGk7x z=QMu&_kB3|(7&jXl4T5~rdi4O3PMN2eXVQ52qL24_>vQU=MItSRUjFV#+XZP8`i|$ zf98Sy*kEst8@q3>qo%r-5Rl()ME0@>rXW#%t-i`s<%(49Qv7wP$o$<>`{q&zIA6C@ z*P4K58L7`P84tP}GCzkqvwpGIGU)v|wq2tPK!RH?I9@3xZR5Q%;@VR8P`Bs|8l>s+ z6C-VAM7Sn6`i<$ll^sxl-$n9lJ;B0<>rOxn#;(nfhj548rL+RqH89Lh1@r!$NyDS5DGLh|i9yBIOYGlk<0lepmnM-@ts z;>=!8BW+oTOy++vNh}<@aJ_*F9hj^A{p|+LPYtSxGOK5DKHjzh+u@{-k`A+PuCiD1 z-%peDI*sVv=f46W@tvk6f;lU)DHB~K;haBbh@Y)T++I|;m@Enns z`1$!rSRK`M^V)H!g;wBua4p>M_c1|Dwm=advF0(%(0JH~O+43BD_ zn~agsDIqIwoaekv?2x6~+jV~BSBYReifqyr6VtGPi!oj1`}-q+Sp77cU~Q62Zbb4F zD_x^#Rf3|iL#TV55A?kSZ=BR>sK(LWNroJ!#;}*w7QY@a;p8k??7bysqhE2|kF8xV z(g6C;vRR@0qvXCa^x{iUy4}@4Z6Id0CG}-}kEWKcJOmO-z&Dbtn;Oy)Uqj5Le1KZ`@?TV5JSOUqxZ&)Y?;YUykOX)CCMF zQBG5}&x@H9{?cvv4rH{Nr+*Rz#81_uAya2MRSUX~8MohBOf~m}Bqc-ICOW#bv!3w$ z+F0YIlg+6RrpWL+2MPZk-u~tTPOj_Und`7B@t`|mDY3W~SaJO_i?Q3{wwhdXn~2!9 zF_rYiT3hyR=QENvoc`00S(&z>5)x68_DV%(8AY041(ft((cD6^va_{<0uJQCZ(gP$ zwrcEG-{4DuV)7D5iil(SGUBdp6Ask}+RTtmuh3rrEWv@htz1eh>e2gjdG-deDQX4k zP4unhut5`!`>+kU576nD=#K%B`7zHzA~iAxcWs>=pFG!w@=k*>%?=*kproL(=}&0U zD__qpd(oNxrEk=(S%XHwd#YxZ%oj(BcBH~F^?Q6%J3d}vc%a`(3s3-OQ6Zn@05e4E zWU;Q2$T6q6)9C*F`7c`EeIw@OR@f~aB#c--ONK{7MNv7f$tTwQL;}>^-64(6O{knS z@bq2cHsM*dnE}jU3;lLPU+sXtGT&ZKo=U4)!e{^)T!gg!^Y-II(BaWrLO+~G&|+H)NtddEOb?dnxfi!fK}6qe zI1joz&dkDz9l%sQWZdLw?A$;98s+p-=HNXmoZ7MiT(m@8Kc#HGUpxT76d=BSTMWn` zmnzElJAY`C|FbXM +``` + +El compilador también cuenta con otras opciones a las cuales se pueden acceder si pasamos como parámetro `--help` + +```bash +❯ python3 compiler --help +Usage: compiler [OPTIONS] INPUT_FILE + + Welcome to CoolCows Compiler! + +Arguments: + INPUT_FILE [required] + +Options: + --ccil / --no-ccil Create .ccil file + corresponding to the ccil code + generated during compilation + [default: False] + + --cool-ast / --no-cool-ast Print COOL AST + [default: False] + + --install-completion Install completion for the current + shell. + + --show-completion Show completion for the current + shell, to copy it or customize the + installation. + + --help Show this message and exit. +``` + +# Arquitectura + +El compilador se diseño siguiendo una ariquitectura modular y funcional. Cada compoenente del mismo es totalmente sustituible sin afectar el funcionamiento de los demás. La imagen siguiente muestra el p*pipeline* del compilador, desde que recibe el programa de COOL hasta que genera la salida del programa correspondiente en MIPS. + +![pipeline](./img/pipeline.png) + +La distribución del código se puede apreciar a continuación: + +``` +├── asts +│   ├── ccil_ast.py +│   ├── inferencer_ast.py +│   ├── __init__.py +│   ├── mips_ast.py +│   ├── parser_ast.py +│   └── types_ast.py +├── lexing +│   ├── errors.py +│   ├── __init__.py +│   └── lexer.py +├── __main__.py +├── parsing +│   ├── errors.py +│   ├── __init__.py +│   ├── parser.py +│   └── parsetab.py +└── visitors + ├── ast_print + │   ├── __init__.py + │   └── type_logger.py + ├── code_gen + │   ├── ccil_gen.py + │   ├── ccil_mips_gen.py + │   ├── constants.py + │   ├── __init__.py + │   ├── mips_gen.py + │   └── tools.py + ├── semantics + │   ├── inference + │   ├── __init__.py + │   ├── tools + │   ├── type_builder.py + │   └── type_collector.py + └── utils + ├── __init__.py + └── visitor.py +``` +En `asts` se encuentran cada uno de los AST que se utilizan a lo largo del proyecto. En `lexing` y `parsing` están la implementación del parser y lexer utilizados. En la carpeta `visitors` se ubican las clases que utilizan el patrón de mismo nombre para cada etapa del compilador divididos en subcarpetas. + +# Lexing + +Para el proceso de *lexing* y *parsing* se usó la biblioteca de *Python* **PLY**. Esta es una implementación de las herramientas *lex* y *yacc* completamente escritas en *Python*. Para el caso particular de la tokenización, *lex* fue la herramienta utilizada. + +La implementación se encuetra en el módulo `lexer.py`. La misma cuenta con una clase `Lexer` donde se definen las expresiones regulares para cada uno de los tokens. En el caso de los *string* y comentarios multilínea se usaron dos estados distintos para cada una, debido a que estos enguajes no son regulares y era necesario usar algoritmos más potentes. + +# Parsing + +Como se menciona en la sección anterior, para el proceso de *parsing* se utilizó *ply.yacc*. Esta herramienta cuenta con la misma técnica de parsing LALR que el *yacc* original. + +La gramática utilizada se encuentra definida en `parser.py`. En este módulo se encuentra la clase `Parser`, la cual cual cuenta con un conjunto de métodos que representan cada una de las producciones de la gramática. Como se puede apreciar, en el caso de las operaciones aritméticas y de comparación las producciones son ambiguas, sin embargo *ply.yacc* permite desambiguar definiendo la precedencia y la asociatividad de los operadores como se muestra a continuación: + +```python +self.precedence = ( + ("right", "ASSIGN"), + ("right", "NOT"), + ("nonassoc", "LESSEQ", "<", "="), + ("left", "+", "-"), + ("left", "*", "/"), + ("right", "ISVOID"), + ("left", "~"), + ("left", "@"), + ("left", "."), +) +``` + +Esto permite usar una gramática ambigua y evita tener que definir más producciones para poder parsear. + +# Semántica e Inferencia + +Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. + +La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. + +En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: + +1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. + +2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. + +3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. + +Para tratar cada caso el inferenciador se divide en tres partes: + +1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. +2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. +3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) +4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. + +Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. + +El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. + +En este ejemplo no funcional donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. + +Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. + +```c# +class Main { + a : AUTO_TYPE; + method main():AUTO_TYPE { + { + a.f(); // Boom si no es el soft inferencer + a.g(); // Solucionado + } + } +} +class A { + method f():Int{ + 3 + 3 + } + metod g():String{ + "yisus" + } + +}; +class B { + method f():String{ + "3 + 3" + } +}; +``` + +## SELF_TYPE + +La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. + + +# Generación de Código Intermedio + +Para producir código CIL se toma como principal el guía el capitulo 7 del libro de `Cool Compilers` por su simpleza y facilidad luego para traducirlo a MIPS. + +El programa original se divide en tres secciones: + +* En **types** se guarda la signatura de los tipos. Nombre de atributos y funciones. +* **data** almacena todos los `String` definidos en tiempo de compilación por el usarion así como `Strings` definidos durante la propia generación de código. +* En **code** se encuentra el equivalente en CIL de las funciones definidas en Cool. Cada función en vez de tener expresiones y sub-expresiones complejas tienen una secuencia de operaciones más sencillas que producen un resultado equivalente. + +## Types + +Contiene solo el nombre de la clase, los métodos y su identificador único para buscarlo cuando se necesite llamar a un método y los atributos de la misma. Los tipos también contienen dentro de ellos los atributos de las clases que heredan al igual que sus funciones. + +Para todas las clases se les genera una función `init` donde se inicializan los valores iniciales de todos sus atributos. Si el atributo no esta inicializado, se inicializa por defecto apuntando a la cadena vacía en caso de ser de tipo `String` o con valor 0 en otro caso. + +En caso de que el atributo se inicialice con una expresión, se transforma a operaciones en CIL y se le asigna el resultado final al atributo correspondiente. + +La función `init` se ejecuta siempre que se instancie una clase. + +## Data + +Se almacenan todos las cadenas definidos por el usuario en el programa Cool. Ademas se tiene también la cadena vacía a la cual apuntan las variables `String` sin inicializar. Durante la generación de código se almacena aquí además los mensajes de errores en ejecución. + +## Code + +Cada expresión de Cool tiene una representación en secuencia de operaciones en CIL. Se asegura siempre que dentro de esa secuencia haya una instrucción que guarde en una variable local el resultado final de dicha expresión. + +Las expresiones no siempre tienen la misma secuencia de instrucciones, pues necesitan muchas veces del valor de sus sub-expresiones. El workflow para producir una serie de operaciones para una expresión es: + +1. Produce las operaciones de todas sus sub-expresiones +2. Produce las operaciones propias, sustituyendo donde se necesite cierta sub-expresion por la variable local donde esta guardada su resultado final. +3. Organiza las operaciones, crea una variable local donde se almacene el valor final propio y retorna + +Existen ciertas expresiones que en CIL se pueden reducir hasta un punto y no mas, como la igualdad entre dos variables de tipo `String`, o como obtener un substring. + +Existen otras que no es necesario que lleguen a smips como el operador unario `isVoid`. Como en smips todo son enteros, se puede saber dado el tipo estático si tiene sentido calcularlo. Para una variable de tipo `Int`, `String` o `Bool`, `isVoid` siempre retorna falso, en cambio con los demás tipos se evalúa la dirección de memoria, si esta es 0 (Equivalente a `Void` en nuestra implementación) el resultado de la expresión es `true` o `1` sino es `false` o `0`. + +Durante la generación de código se genera también las excepciones que pueden ser lanzadas durante la ejecución: + ++ División entre cero ++ El despacho ocurre desde un tipo sin inicializar (`Void`) ++ El rango del substring no es válido ++ Ninguna rama de algún `case of` es igual al tipo de la expresión + +Es posible para el usuario definir variables con mismos nombres con distintos contextos, para tratar con esto se reutilizan una versión simplificada del `Scope` de la semántica, donde se almacenan según el contexto la variable definida por el usuario y su traducción a Cool. Gracias a esto, en el ejemplo siguiente se conoce siempre a que variable `x` se refiere el programa: + +```assembly +# COOL +let x:int = 3 + in (let x:int = 4 in x) + x +# CIL +local let_x_0 +local let_x_1 +... +``` + +### Transformaciones + +Ejemplos de traducción de Cool a CIL + +#### Declaración de Clase + + **Cool Input** + +```haskell +class C { + -- Initialized attributes + a1: <- ; + a2: <- ; + ... + am: <- ; + + -- Functions + f1() { } + f2() { } + ... + fn() { } + +} +``` + +**CCIL Output** + +```assembly +type C { + attribute a1; + ... + attribute am; + + method f1 : ; + ... + method fn : ; +} +``` + +#### Herencia de Clases + + **Cool Input** + +```haskell +class A { + a1: + f1():{...} +} + +class B inherits A { + b1: + g1():{...} +} +``` + +**CCIL Output** + +```assembly +type A { + attr a1; + method f1 : f_f1_A +} + +type B { + attr a1; + attr b1; + method f1: f_f1_A + method g1: f_g1_B +} +``` + +#### While Loop + +**Cool Input** + +```assembly +while () loop pool +``` + +**CCIL Output** + +```assembly +label while_init +x = +ifFalse x goto while_end + + + +goto while_init +label while_end +``` + +#### If Then Else + +**Cool Input** + +``` +if then else fi +``` + +**CCIL Output** + +```assembly + # Produce todas las operaciones de la expr de la cond. inicial +x = # Guarda ese valor +ifFalse x goto else_expr +# x = 1 + +f = # El resultado final de la expresion if +goto endif + +# x = 0 +label else_expr + +f = # El resultado final de la expresion if + +label endif +``` + +#### Let In + +**Cool Input** + +``` +let :, ... : in +``` + +**CCIL Output** + +```assembly +# Inicializa todas las variables let, tengan expresión o no + + +... + +# traduce la expresion en operacions + +f = # Almacena el resultado final de la expresion let +``` + +#### Case Of + +**Cool Input** + +``` +case of + : => + : => + ... + : => +esac +``` + +**CCIL Output** + +```assembly + + +... + + + +x = +t = typeof x + +# Analiznado rama 1 +t1 = typeof +b1 = t1 == t # Comparando tipos +if b1 goto branch1: # En caso de exito ve a la rama + +# Analizando rama 2 +t2 = typeof +b2 = t2 == t +if b2 goto branch2 + +... + +# Analizando rama n +tn = typeof +bn = tn == t +if bn goto brannch + + # Lanza una excepcion en ejcucion si no se ejecuta ninguna rama + + +# Realizando logica the rama1 +label branch1 + +goto end_case + +# Realizando logica the rama2 +label branch2 + +goto end_case + +... + +# Realizando logica the raman +label branchn + +goto end_case + +label end_case +``` + +#### *Dispatch* Estático + +**Cool Input** + +``` +(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +r = call n +``` + +#### *Dispatch* Dinámico + +**Cool Input** + +``` +@.(, , ..., ); +``` + +**CCIL Output** + +```assembly + + +... + +t = allocate # It needs to give the same attributes that type one has +r = vcall t n +``` + +#### Declaración de un método + +**Cool Input** + +``` +(:, ..., :) : +{ + +} +``` + +**CCIL Output** + +```assembly +function { + param + param + ... + param + local + local + ... + local + + r = + return r +} +``` + +#### Expresión de Bloque + +**Cool Input** + +``` +{ + ; + ; + ... + ; +} +``` + +**CCIL Output** + +``` + + +... + + + + +... + +``` + +#### Expresiones Aritméticas + +**Cool Input** + +```c# +3 + 5 +``` + +**CCIL Output** + +``` +t = 3 + 5 +``` + +--- + +###### More than one + +**Cool Input** + +``` +3 + 5 + 7 +``` + +**CCIL Output** + +```assembly +# Naive +t1 = 5 + 7 +t2 = 3 + t1 +``` + +--- + +###### Using non commutative operations + +```python +3 - 5 - 7 +# -2 -7 +# -9 +``` + +```assembly +t = 3 - 5 +t = t - 7 +``` + +--- + +**Cool Input** + +``` +100 / 20 / 5 / 2 +``` + +**CCIL Output** + +``` +t = 100 / 20 +t = t / 5 +t = t / 2 +``` + + + +## Lenguaje CCIL + +Definición del lenguaje CCIL. Tomamos como No Terminales sólo las palabras que empiecen con mayúsculas. El resto de palabras y símbolos se consideran como Terminales. + +$$ +\begin{array}{rcl} +\text{Program} &\rarr& \text{.type TypeList .code CodeList}\\ +\text{TypeList} &\rarr& \text{Type } | \text{ Type TypeList}\\ +\text{Type} &\rarr& \text{FeatureList}\\ +\text{FeatureList} &\rarr& \text{Attribute } | \text{ Function } | \text{ FeatureList } | \space\epsilon\\ +&|& \text{ Attribute; FeatureList } | \text{ Function; FeatureList}\\ +\\ +\text{CodeList} &\rarr& \text{ FuncCode CodeList }| \space\epsilon \\ +\text{AttrCode} &\rarr& \text{id }\{ \text{LocalList OperationList} \}\\ +\text{FuncCode} &\rarr& \text{id }\{\\ +&&\text{ParamList}\\ +&&\text{LocalList}\\ +&&\text{OperationList} \text{\}}\\ +\\ +\text{OperationList} &\rarr& \text{Operation; OperationList } | \space\epsilon \\ +\text{Operation} &\rarr& \text{id = ReturnOp}\\ +&|& \text{goto id}\\ +&|& \text{label id}\\ +&|& \text{return Atom}\\ +&|& \text{setattr id id Atom}\\ +&|& \text{if Atom goto id}\\ +&|& \text{ifFalse Atom goto id}\\ +&|& \text{arg id}\\ + +\text{ReturnOp} &\rarr& \text{Atom + Atom}\\ +&|& \text{Atom - Atom}\\ +&|& \text{Atom * Atom}\\ +&|& \text{Atom / Atom}\\ +&|& \text{not Atom}\\ +&|& \text{neg Atom}\\ +&|& \text{call id}\\ +&|& \text{vcall typeId id}\\ +&|& \text{typeof id}\\ +&|& \text{getatrr id id}\\ +&|& \text{allocate typeId}\\ +&|& \text{Atom < Atom}\\ +&|& \text{Atom <= Atom}\\ +&|& \text{Atom = Atom}\\ +&|& \text{allocate typeId}\\ +&|& \text{getattr id id}\\ +&|& \text{Atom}\\ +\text{Atom} &\rarr& \text{Constant } | \text{ id}\\ +\text{Constant} &\rarr& \text{ integer } | \text{ string } +\end{array} +$$ + +# Generación de código MIPS + +Una vez definido un lenguaje intermedio, se pasa a MIPS. En este punto del proceso de compilación se tuvieron que resolver dos problemas fundamentales: la semántica de tipos y el manejo de la memoria. + +## Representación de los tipos + +En *MIPS* las instancias de clases se representan a través de información estática y dinámica. La parte estática se define en la sección *.data* y contiene la información que se comparte entre cada uno de los objetos del mismo tipo. + +![class](./img/class.png) + +La sección `type` contiene la dirección hacia esa sección de código. En `init` se encuentra la dirección de una función especial que inicializa una instancia cualquiera de la clase correspondiente. Esta función se genera en ccil. Luego, en la sección `name` se encuentra la dirección del *string* que corresponde al nombre del tipo. En `attr count` se encuentra un valor que representa la cantidad de atributos que tiene la clase. Después de esta porción de memoria se encuentran los métodos, es decir, la dirección de las funciones que implementan cada uno de los métodos en una clase. + +Es importante señalar que los métodos de las clases están declarados en el mismo orden. Si una clase `B` hereda de otra clase `A`, los métodos de `A` que `B` hereda están en la misma posición que en `A`. De este modo los llamados a métodos virtuales se pueden hacer conociendo solamente el tipo estático del objeto y el *offset* del método que se está invocando. + +En el caso de las instancias de los tipos, su representación en memoria es como se muestra a continuación: + +![object](./img/object.png) + +En la sección `type` se encuentra la dirección hacia la información estática del tipo que se mencionó anteriormente. Luego le siguen cada uno de los atributos. Estos, al igual que en el caso de los métodos, se encuentran en el mismo orden para todas las instancias de una clase y de sus subclases. De este modo la lectura y escritura de los atributo se reduce a saber su tipo estático y el *offset* del atributo. + +## Llamados a función + +Para los llamados a función en MIPS se tomó como convenio pasar primeramente los argumentos a través de la pila ( el primer argumento siempre es la instnacia del objeto que realiza el llamado ) para luego saltar al *label* donde se encuentra la definición de la función. A continuación se guardan en la pila el *return address* y el *frame pointer*. Una vez hecho esto se ajusta el nuevo valor del *frame pointer* y se reserva el espacio necesario para las variables locales en la pila. Cuando se realizan cada una de las opraciones correspondientes a la función invocada se sacan de la pila los valores anterioes del *return address* y *frame pointer*, y se libera el espacio correspondiente a las variables locales y los argumentos de la función. Los valores de retorno de las funciones se guardan siempre en el registro `v0`. + +Como se había mencionado anteriormente, cuando se instancia un nuevo objeto, sabiendo el tipo podemos llamar directamente a la función `init` correspondiente y reservar la cantidad de memoria necesaria. Sin embargo, en el caso del `SELF_TYPE`, no se puede proceder como en los demás casos, porque el tipo del objeto que se va a instanciar solo se conoce en tiempo de ejecución. Por tanto, para resolver este problema, lo que se hace es buscar el tipo dinámico del objeto donde se encuentra la invocación del método actual que ssiempre se encuentra en el primer argumento del llamado a una función en MIPS, y a través del cual se puede obtener el tipo del objeto (identificador realmente ) y así acceder a la información estática de dicho tipo, donde se puede saber la cantidad memoria necesaria a reservar según la cantidad de atributos y a la función `init` que le corresponde. + + +### Funciones Built-in + +Las funciones *built-in* se implementaron directamente en el AST de MIPS. diff --git a/doc/report/semantic and type inference.md b/doc/report/semantic and type inference.md deleted file mode 100644 index 687b7c72a..000000000 --- a/doc/report/semantic and type inference.md +++ /dev/null @@ -1,60 +0,0 @@ -# Semántica e Inferencia - -Nuestro proyecto hace uso de `AUTO_TYPE` con la que incorpora inferencia de tipos al lenguage Cool. La inferencia se realiza varias en distintos vistores. En nuestra implementación debido a que le inferencia se apoya fuertemente sobre el reglas semánticas, el chequeo semántico se realiza a la par que la inferencia, y dividido de igual manera por los visitores. - -La idea principal para realizar la inferencia es considerar todo declaración como `AUTO_TYPE` no como un tipo específico sino como un conjunto de tipos, donde inicialmente ese conjunto esta compuesto por todos los tipos definidos en un programa Cool. Los tipos declarados específicamente como `Int` o `String` se consideran conjuntos con un solo elemento. - -En Cool muchas veces las expresiones se ven obligadas a conformarse a un tipo definido por el usuario. Deben corresponder con el tipo definido de una variable, argumento o retorno de una función. También debe obedecer las reglas semánticas, cuando están presente frente a una operación aritmética, o en una posición donde se espera que el resultado sea `Bool`. Para reducir los conjuntos de tipos en presencia de `AUTO_TYPE` realizamos lo siguiente: - -1. Cuando el tipo declarado de una variable esta bien definido (diferente de `AUTO_TYPE`) , se eliminan del conjunto de tipos inferidos de la expresión los elementos que no conforman a dicho tipo bien definido. - -2. Cuando el tipo declarado de una variable es `AUTO_TYPE`, esta se puede reducir analizando que valores debe tener para conformarse con los tipos de la expresión inferida. - -3. Cuando ambos tipos, tanto el definido como el inferido son `AUTO_TYPES` se busca que valores puede tener el segundo para conformarse al primero, y que valores el primero para que el segundo se conforme. - -Para tratar cada caso el inferenciador se divide en tres partes: - -1. **soft inferencer** que aplica la primera regla y tercera regla. Se le llama **soft** porque perdona y no realiza ningún tipo de chequeo semántico y permite cosas como que un conjunto tengo dentro de si dos tipos sin un ancestro común. -2. **hard inferencer ** aplica la primera y la tercera regla, y fuerza el chequeo semántico sobre todas las expresiones. No permite tipos sin ancestros comunes dentro de un mismo conjunto. -3. **back inferencer** aplica la segunda y tercera regla. Dada las expresiones trata de reducir los conjuntos de los tipos definidos como `AUTO_TYPE` (e.g. parámetros de una función, retorno de una función, o declaración de variables) -4. **types inferencer** reduce todos los conjuntos de tipos de cada nodo al mayor ancestro en todos los casos, excepto cuando se trata del valor de retorno de una función, en el que reduce al ancestro común más cercano de los tipos del conjunto. - -Cada inferenciador se ejecuta secuencialmente, una sola vez, exceptuando por el **back inferencer** que puede ejecutarse tantas veces como sea necesario. - -## Soft Inferencer - -El **soft inferencer** es permisivo pues como es el primero en leer el programa, puede que un conjunto de tipos inválidos en la línea 5 se vuelva válido más adelante en el código. - -En este ejemplo no funcional (Lanza `RuntimeError` debido a que `a` es `Void`) donde el tipo de `a` puede ser cualquiera, al leer `a.f()`, se reducen los tipos de a de {`Object`, `String`, `IO`, `Int`, `Bool`, `Main`, `A`, `B`} a tan solo {`A`, `B`}. No obstante `A` y `B` no tienen un ancestro común dentro del conjunto, luego `a` posee un tipo invalido. - -Luego cuando se lee `a.g()` el conjunto de tipos se reduce a solo {`A`}. - -```c# -class Main { - a : AUTO_TYPE; - method main():AUTO_TYPE { - { - a.f(); // Boom si no es el soft inferencer - a.g(); // Solucionado - } - } -} -class A { - method f():Int{ - 3 + 3 - } - metod g():String{ - "yisus" - } - -}; -class B { - method f():String{ - "3 + 3" - } -}; -``` - -## SELF_TYPE - -La combinación de `SELF_TYPE` con `AUTO_TYPE` trajo sus problemas, sobre todo porque funciona como un comodín que puede tener un tipo dependiendo de las circunstancia. Logramos una mejor integración entre estos fue posible intercambiando el `SELF_TYPE` por la clase donde se encuentra analizando en ese momento. diff --git a/src/compiler/__main__.py b/src/compiler/__main__.py index 545aeab30..b67c54322 100644 --- a/src/compiler/__main__.py +++ b/src/compiler/__main__.py @@ -94,9 +94,9 @@ def main( input_file: str, ccil: bool = typer.Option( False, - help="Create .ccil file corresponding to the ccil code generated during compilation ", + help="Create a .ccil file corresponding to the ccil code generated during compilation ", ), - cool_ast: bool = typer.Option(False, help="Prints program's COOL AST"), + cool_ast: bool = typer.Option(False, help="Print COOL AST"), ): """ Welcome to CoolCows Compiler! From 317adb5dc546c7072ac0f704348fa998007f1b48 Mon Sep 17 00:00:00 2001 From: adrian13579 Date: Thu, 10 Mar 2022 14:17:33 -0500 Subject: [PATCH 428/432] Add report.pdf --- doc/report/report.md | 8 +++++--- doc/report/report.pdf | Bin 0 -> 313465 bytes 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 doc/report/report.pdf diff --git a/doc/report/report.md b/doc/report/report.md index f21cda33e..389f98acc 100644 --- a/doc/report/report.md +++ b/doc/report/report.md @@ -660,7 +660,7 @@ En *MIPS* las instancias de clases se representan a través de información est ![class](./img/class.png) -La sección `type` contiene la dirección hacia esa sección de código. En `init` se encuentra la dirección de una función especial que inicializa una instancia cualquiera de la clase correspondiente. Esta función se genera en ccil. Luego, en la sección `name` se encuentra la dirección del *string* que corresponde al nombre del tipo. En `attr count` se encuentra un valor que representa la cantidad de atributos que tiene la clase. Después de esta porción de memoria se encuentran los métodos, es decir, la dirección de las funciones que implementan cada uno de los métodos en una clase. +La sección `type` contiene la dirección hacia esa sección de código. En `init` se encuentra la dirección de una función especial que inicializa una instancia cualquiera de la clase correspondiente. Esta función se genera en ccil. Luego, en la sección `name` se encuentra la dirección del *string* que corresponde al nombre del tipo. En `attr count` se encuentra un valor que representa la cantidad de atributos que tiene la clase. Después de esta porción de memoria se encuentran los métodos, es decir, las direcciones de las funciones que implementan cada uno de los métodos en una clase. Es importante señalar que los métodos de las clases están declarados en el mismo orden. Si una clase `B` hereda de otra clase `A`, los métodos de `A` que `B` hereda están en la misma posición que en `A`. De este modo los llamados a métodos virtuales se pueden hacer conociendo solamente el tipo estático del objeto y el *offset* del método que se está invocando. @@ -672,9 +672,11 @@ En la sección `type` se encuentra la dirección hacia la información estática ## Llamados a función -Para los llamados a función en MIPS se tomó como convenio pasar primeramente los argumentos a través de la pila ( el primer argumento siempre es la instnacia del objeto que realiza el llamado ) para luego saltar al *label* donde se encuentra la definición de la función. A continuación se guardan en la pila el *return address* y el *frame pointer*. Una vez hecho esto se ajusta el nuevo valor del *frame pointer* y se reserva el espacio necesario para las variables locales en la pila. Cuando se realizan cada una de las opraciones correspondientes a la función invocada se sacan de la pila los valores anterioes del *return address* y *frame pointer*, y se libera el espacio correspondiente a las variables locales y los argumentos de la función. Los valores de retorno de las funciones se guardan siempre en el registro `v0`. +Para los llamados a función en MIPS se tomó como convenio pasar primeramente los argumentos a través de la pila ( el primer argumento siempre es la instnacia del objeto que realiza el llamado ) para luego saltar al *label* donde se encuentra la definición de la función. A continuación se guardan en la pila el *return address* y el *frame pointer*. Una vez hecho esto se ajusta el nuevo valor del *frame pointer* y se reserva el espacio necesario para las variables locales en la pila. Cuando se realizan cada una de las opraciones correspondientes a la función invocada se sacan de la pila los valores anteriores del *return address* y *frame pointer*, y se libera el espacio correspondiente a las variables locales y los argumentos de la función. Los valores de retorno de las funciones se guardan siempre en el registro `v0`. -Como se había mencionado anteriormente, cuando se instancia un nuevo objeto, sabiendo el tipo podemos llamar directamente a la función `init` correspondiente y reservar la cantidad de memoria necesaria. Sin embargo, en el caso del `SELF_TYPE`, no se puede proceder como en los demás casos, porque el tipo del objeto que se va a instanciar solo se conoce en tiempo de ejecución. Por tanto, para resolver este problema, lo que se hace es buscar el tipo dinámico del objeto donde se encuentra la invocación del método actual que ssiempre se encuentra en el primer argumento del llamado a una función en MIPS, y a través del cual se puede obtener el tipo del objeto (identificador realmente ) y así acceder a la información estática de dicho tipo, donde se puede saber la cantidad memoria necesaria a reservar según la cantidad de atributos y a la función `init` que le corresponde. +## new SELF_TYPE + +Como se había mencionado anteriormente, cuando se instancia un nuevo objeto, sabiendo el tipo podemos llamar directamente a la función `init` correspondiente y reservar la cantidad de memoria necesaria. Sin embargo, en el caso del `SELF_TYPE`, no se puede proceder como en los demás casos, porque el tipo del objeto que se va a instanciar solo se conoce en tiempo de ejecución. Por tanto, para resolver este problema, lo que se hace es buscar el tipo dinámico del objeto donde se encuentra la invocación del método actual que porsiempre se encuentra en el primer argumento del llamado a una función en MIPS, y a través del cual se puede obtener el tipo del objeto (identificador realmente ) y así acceder a la información estática de dicho tipo, donde se puede saber la cantidad memoria necesaria a reservar según la cantidad de atributos y a la función `init` que le corresponde. ### Funciones Built-in diff --git a/doc/report/report.pdf b/doc/report/report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..016b975d4774a5103e637c1508fc0db1fae0fbc3 GIT binary patch literal 313465 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