Пример #1
0
    def tryNew(cls, lineNumber: int, indentation: int,
               line: str) -> Optional[ParsedLine]:
        """Teste si la ligne respecte le modèle variable = expression
        et crée l'item correspondant le cas échéant

        :param lineNumber: numéro de la ligne
        :type lineNumber: int
        :param indentation: indentation de la ligne
        :type indentation: int
        :param line: ligne à analyser
        :type line: str
        :return: noeud du type print ou None
        :rtype: Optional[ParsedLine_Print]
        :raises: ParseError si l'expression ou variable détectée n'ont pas la bonne forme
        """
        allGroup = re.search(cls.regex(), line)
        if allGroup is None:
            return None
        variableName = allGroup[1].strip()  # la variable
        expressionStr = allGroup[
            2]  # tout ce qu'il y a dans les ( ) de l'input
        if not ExpressionParser.strIsVariableName(variableName):
            raise ParseError(
                "La variable <{}> est incorrecte.".format(variableName),
                {"lineNumber": lineNumber})
        expr = ExpressionParser.buildExpression(expressionStr)
        if not isinstance(expr, ArithmeticExpressionNode):
            raise ParseError("L'expression <{}> est incorrecte.".format(expr),
                             {"lineNumber": lineNumber})
        return ParsedLine_Affectation(lineNumber, indentation,
                                      Variable.add(variableName), expr)
Пример #2
0
    def _parseCode(cls, lignesCode: List[str]) -> List[StructureNode]:
        """Parse du programme donné sous forme d'une liste de lignes

        :param lignesCode: lignes du programme
        :type filename: List[str]
        :return: liste de noeuds représentant le programme
        :rtype: List[StructureNode]
        """
        # on réinitialise le manager des variables
        Variable.resetVariableManager()

        listParsedLines: List[ParsedLine] = []
        for index, line in enumerate(lignesCode):
            objLine = cls._parseLine(line, index + 1)
            # Traitement ligne non vide
            if not objLine.empty:
                # Ajout des informations parsées dans le listing
                listParsedLines.append(objLine)

        indentationErrorLineNumber = cls._verifyIndent(listParsedLines)
        if indentationErrorLineNumber >= 0:
            raise ParseError("Erreur d'indentation.",
                             {"lineNumber": indentationErrorLineNumber})

        elseErrorLineNumber = cls._verifyElse(listParsedLines)
        if elseErrorLineNumber >= 0:
            raise ParseError(
                "elif ou else n'est pas correctement lié à un if.",
                {"lineNumber": elseErrorLineNumber})

        groupedList = cls._groupBlocs(listParsedLines)
        return cls._convertParsedLinesToStructurNodes(groupedList)
Пример #3
0
    def tryNew(cls, lineNumber: int, indentation: int,
               line: str) -> Optional[ParsedLine]:
        """Teste si la ligne respecte le modèle print
        et crée l'item correspondant le cas échéant

        :param lineNumber: numéro de la ligne
        :type lineNumber: int
        :param indentation: indentation de la ligne
        :type indentation: int
        :param line: ligne à analyser
        :type line: str
        :return: noeud du type print ou None
        :rtype: Optional[ParsedLine_Print]
        :raises: ParseError si la variable n'a pas la bonne forme
        """
        allGroup = re.search(cls.regex(), line)
        if allGroup is None:
            return None
        variableName = allGroup[1].strip()  # la variable

        if not ExpressionParser.strIsVariableName(variableName):
            raise ParseError(
                "La variable <{}> est incorrecte.".format(variableName),
                {"lineNumber": lineNumber})
        return ParsedLine_Input(lineNumber, indentation,
                                Variable.add(variableName))
Пример #4
0
    def tryNew(cls, lineNumber: int, indentation: int,
               line: str) -> Optional[ParsedLine]:
        """Teste si la ligne respecte le modèle print
        et crée l'item correspondant le cas échéant

        :param lineNumber: numéro de la ligne
        :type lineNumber: int
        :param indentation: indentation de la ligne
        :type indentation: int
        :param line: ligne à analyser
        :type line: str
        :return: noeud du type print ou None
        :rtype: Optional[ParsedLine_Print]
        :raises: ParseError si l'expression détectée n'est pas du bon type
        """

        allGroup = re.search(cls.regex(), line)
        if allGroup is None:
            return None
        firstGroup = allGroup[1]  # tout ce qui match dans les ( )
        expr = ExpressionParser.buildExpression(firstGroup)
        if not isinstance(expr, ArithmeticExpressionNode):
            raise ParseError("L'expression <{}> est incorrecte.".format(expr),
                             {"lineNumber": lineNumber})
        return ParsedLine_Print(lineNumber, indentation, expr)
Пример #5
0
    def tryNew(cls, lineNumber: int, indentation: int,
               line: str) -> Optional[ParsedLine]:
        """Teste si la ligne respecte le modèle [mot-clef] condition
        et crée l'item correspondant le cas échéant

        :param lineNumber: numéro de la ligne
        :type lineNumber: int
        :param indentation: indentation de la ligne
        :type indentation: int
        :param line: ligne à analyser
        :type line: str
        :return: noeud du type reconnu ou None
        :rtype: Union[ParsedLine_If, ParsedLine_Elif, ParsedLine_While, None]
        :raises: ParseError si l'expression trouvée n'a pas le bon type
        """

        allGroup = re.search(cls.regex(), line)

        if allGroup is None:
            return None

        firstGroup = allGroup[
            1]  # tout ce qui match après testStructureKeyword et avant les :
        condition = ExpressionParser.buildExpression(firstGroup)
        if not isinstance(condition,
                          (LogicExpressionNode, ComparaisonExpressionNode)):
            raise ParseError(
                "L'expression <{}> n'est pas une condition.".format(condition),
                {"lineNumber": lineNumber})
        node = cls(lineNumber, indentation, condition)
        return node
Пример #6
0
    def _parseLine(cls, originalLine: str, lineNumber: int) -> ParsedLine:
        """parse d'une ligne

        :param originalLine: ligne d'origine
        :type originalLine: str
        :param lineNumber: numéro de la ligne d'origine
        :type line Number: int
        :return: noeud de type LP
        :raises: ParseError si type de ligne pas reconnue
        """

        cleanLine = cls._suppCommentsAndEndSpaces(originalLine)
        emptyLine = (cleanLine == "")
        indentation = cls._countIndentation(originalLine)

        if emptyLine:
            return ParsedLine(lineNumber)

        classesToTry = (ParsedLine_If, ParsedLine_Elif, ParsedLine_While,
                        ParsedLine_Else, ParsedLine_Print, ParsedLine_Input,
                        ParsedLine_Affectation)
        # remarque : il faut tester input avant affectation car input() génère autrement une erreur
        # si interprété comme une expression
        for c in classesToTry:
            lineObject: Optional[ParsedLine] = c.tryNew(
                lineNumber, indentation, cleanLine)
            if not lineObject is None:
                return lineObject
        raise ParseError("Erreur de syntaxe : <{}>".format(cleanLine),
                         {"lineNumber": lineNumber})
Пример #7
0
    def _convertParsedLinesToStructurNodes(
            cls, listParsedLine: List[ParsedLine]) -> List['StructureNode']:
        """Convertit une liste de ParsedLine en liste de StructureNode

        :param listParsedLine: liste des objets à convertir
        :type parsedLine: List[ParsedLine]
        :return: liste sous forme de StructureNode
        :rtype: List[StructureNode]
        """

        reversedListParsedLines = listParsedLine[::-1]
        outList: List[StructureNode] = []
        pendingElse: Optional[ParsedLine_Else] = None
        newNode: StructureNode
        children: List[StructureNode]
        elseChildren: List[StructureNode]
        for line in reversedListParsedLines:
            if isinstance(line, ParsedLine_Else):
                pendingElse = line
                continue
            elif isinstance(
                    line,
                    ParsedLine_While):  # While avant If, Attention héritage !
                children = cls._convertParsedLinesToStructurNodes(
                    line.children)
                newNode = WhileNode(line.lineNumber, line.condition, children)
            elif isinstance(line, ParsedLine_If) and not (pendingElse is None):
                children = cls._convertParsedLinesToStructurNodes(
                    line.children)
                elseChildren = cls._convertParsedLinesToStructurNodes(
                    pendingElse.children)
                newNode = IfElseNode(line.lineNumber, line.condition, children,
                                     pendingElse.lineNumber, elseChildren)
            elif isinstance(line, ParsedLine_If):
                children = cls._convertParsedLinesToStructurNodes(
                    line.children)
                newNode = IfNode(line.lineNumber, line.condition, children)
            elif isinstance(line, ParsedLine_Print):
                newNode = TransfertNode(line.lineNumber, None, line.expression)
            elif isinstance(line, ParsedLine_Input):
                newNode = TransfertNode(line.lineNumber, line.variable, None)
            elif isinstance(line, ParsedLine_Affectation):
                newNode = TransfertNode(line.lineNumber, line.variable,
                                        line.expression)
            else:
                raise ParseError("Erreur imprévue.",
                                 {"lineNumber": line.lineNumber})
            outList.append(newNode)

        return outList[::-1]
Пример #8
0
 def parse(cls, **options) -> List[StructureNode]:
     """
     parse le contenu de l'entité fournie :
     options doit contenir l'un des attributs :
     - filename : nom de fichier contenant le code
     - code : chaîne de caractère contenant le code
     """
     if "filename" in options:
         filename = options["filename"]
         return cls._parseFile(filename)
     if "code" in options:
         code = options["code"]
         return cls._parseCode(code.split("\n"))
     raise ParseError("Il faut donner 'filename' ou 'code'")