示例#1
0
    def get_loops(self):
        """Return the recursives loops in the rules definitions of the source AST. For example, a rule A which calls to
        a rule B provokes a recursive loop if that rule B calls the rule A."""
        def rulecalls_of(node):

            if type(node) is RuleDefinition:
                rulecalls = []
                for subnode in node.definition:
                    rulecalls += rulecalls_of(subnode)
                return rulecalls

            elif type(node) is Choices:
                rulecalls = []
                for option in node.options:
                    for subnode in option.definition:
                        rulecalls += rulecalls_of(subnode)
                return rulecalls

            elif type(node) is OptionalGroup:
                rulecalls = []
                for subnode in node.definition:
                    rulecalls += rulecalls_of(subnode)
                return rulecalls

            elif type(node) is RuleCall:
                return [node.whole_name]

            else:
                return []

        loops = {}

        rules = [r for r in self.code.ast if type(r) is RuleDefinition]
        for rule in rules:

            loops[rule.whole_name] = []
            calls = rulecalls_of(rule)

            for call in calls:

                subcalls = rulecalls_of(get_rule(self.code, call))
                calls_trace = subcalls.copy()
                while subcalls and rule.whole_name not in subcalls:

                    new_subcalls = []
                    for subcall in subcalls:
                        new_subcalls += rulecalls_of(
                            get_rule(self.code, subcall))
                    subcalls = [
                        c for c in new_subcalls.copy() if c not in calls_trace
                    ]
                    calls_trace += new_subcalls.copy()

                if rule.whole_name in subcalls:
                    loops[rule.whole_name].append(call)

        return loops
示例#2
0
    def _check_uniline_inspection(self, node):
        assert type(node) is UnilineInspection, "Error in the checker code."
        self._current_inspected_rule = get_rule(self.code, node.whole_name)
        if not get_rule(self.code, node.whole_name):
            raise KombuError(
                "{} : 'inspect {}' : Cannot define an inspection on a not-existing rule."
                .format(self.formatted_pos(node.pos), node.name))

        for node in [n for n in node.definition if type(n) in [NodeCall]]:
            self._check_node(node)
示例#3
0
    def _find_recursion_guards(self, node, base_rule=None):
        self._checker.code.ast = self._ast

        if type(node) is RuleDefinition:
            definition = get_rule(Code(self._ast), node.whole_name).definition
            guards = None
            i = 1
            while not guards == '{!ARR}' and not guards and i <= len(definition):
                guards = self._find_recursion_guards(definition[-i], base_rule=node.whole_name if not base_rule else base_rule)
                i += 1
            if guards != '{!ARR}':
                return guards
            else:
                return ""

        elif type(node) is Match:
            return escape_quotes(node.string)

        elif type(node) is RegexMatch:
            return 'REGEX~' + node.regex

        elif type(node) is Choices:
            guards = []
            for option in node.options:
                for subnode in option.definition:
                    option_guards = self._find_recursion_guards(subnode, base_rule=base_rule)
                    if type(option_guards) is list:
                        guards += option_guards
                    elif type(option_guards) is str and option_guards != '{!ARR}':
                        guards.append(option_guards)
            return guards

        elif type(node) is RuleCall:
            # If there is left recursives calls, it means this rule'll need recursions guards and cannot be used
            # To set recursions guards for the father rule.
            left_calls = self._checker.left_calls(get_rule(Code(self._ast), node.whole_name))
            if not common(left_calls, self._calls_loops[node.whole_name]) and base_rule not in self._calls_loops[node.whole_name]:
                # Use this recursions guards.
                return self._find_recursion_guards(get_rule(Code(self._ast), node.whole_name))
            else:
                return '{!ARR}'  # Already Recursive Rulecall.
示例#4
0
 def find_left_recursive_rule_call(rule):
     for node in rule.definition:
         if type(node) is Match:
             return None
         elif type(node) is Choices:
             for option in node.options:
                 for subnode in option.definition:
                     if type(subnode) is Match:
                         return None
         elif type(node) is RuleCall:
             if not [s for s in rule.definition if type(s) is Match]:
                 return get_rule(self.code, node.whole_name)
             return None
示例#5
0
    def _check_multiline_inspection(self, node):
        assert type(node) is MultilineInspection, "Error in the checker code."
        self._current_inspected_rule = get_rule(self.code, node.whole_name)
        if not self._current_inspected_rule:
            raise KombuError(
                "{} : 'inspect {}' : Cannot define an inspection on a not-existing rule."
                .format(self.formatted_pos(node.pos), node.name))

        inspection_definition = split(node.definition,
                                      NewLine(),
                                      include_at_beginning=True)[1:]
        base_indentation = len(inspection_definition[0][0].indentation.replace(
            '\t', ' ' * 16))
        for i, line in enumerate(inspection_definition):
            indentation = len(line[0].indentation.replace('\t', ' ' * 16))
            if indentation < base_indentation and len(line) > 1:
                raise KombuError("{} : This line is under-indented.".format(
                    self.formatted_pos(line[0].pos) + i + 1))
示例#6
0
 def _check_constant_declaration(self, node):
     assert type(node) is SetConstant, "Error in the Checker code."
     if node.constantname == 'axiom':
         self._check_option_value(node, True)
         found = get_rule(self.code, node.value)
         assert found, "{} : Axiom is defined by {}, but that rule doesn't exist.".format(
             self.formatted_pos(node.pos), node.value)
     elif node.constantname == 'libspath':
         self._check_option_value(node, True)
     elif node.constantname == 'name':
         self._check_option_value(node, True)
     elif node.constantname == 'keep_whitespaces':
         self._check_option_value(node, False)
     elif node.constantname == 'cut_end':
         self._check_option_value(node, False)
     elif node.constantname == 'get_time':
         self._check_option_value(node, False)
     elif node.constantname == 'show_ast':
         self._check_option_value(node, False)
     else:
         raise KombuError("{} : '{}' isn't an option name.".format(
             self.formatted_pos(node.pos), node.constantname))
示例#7
0
    def _find_node(self, condition, rule=None, expected=1):
        def search_in(node, condition):
            found = []
            if condition(node):
                found.append(node)

            if type(node) in [RuleDefinition, OptionalGroup, Option]:
                for subnode in node.definition:
                    result = search_in(subnode, condition)
                    if result:
                        found.extend(result)

            elif type(node) is Choices:
                for option in node.options:
                    result = search_in(option, condition)
                    if result:
                        found.extend(result)

            elif type(node) in [WarningTrigger, ErrorTrigger]:
                found.extend(search_in(node.link, condition))

            return found

        if rule:
            result = search_in(get_rule(self.code, rule), condition)
        else:
            result = []
            for rule in [
                    r for r in self.code.ast if type(r) is RuleDefinition
            ]:
                result.extend(search_in(rule, condition))

        if expected == 0:
            return result
        elif expected == 1:
            return result[0] if result else None
        else:
            return result[:expected] if len(result) >= expected else None
示例#8
0
    def import_rules_from_lib(self, lib_name, rules):

        to_parse, directory_path = self._open_lib_file(lib_name)

        from KomBuInterpreter.KomBuParser import KomBuParser
        from KomBuInterpreter.KomBuChecker import KomBuChecker

        imported_libs_parser = KomBuParser()
        imported_code = imported_libs_parser.parse(to_parse, directory_path,
                                                   lib_name + '.kb',
                                                   self.imports_cache)

        for rule_to_import in rules:
            if not get_rule(imported_code, lib_name + '__' + rule_to_import):
                raise NameError(
                    "File {} : 'with {} from {}' : Cannot import {} from file {}.kb"
                    .format(self.filename, ", ".join(rules), lib_name,
                            rule_to_import, lib_name))
            else:
                self.new_namespaces[rule_to_import] = lib_name

        self.imports_cache[lib_name] = imported_code
        self.imported_code.add(imported_code)
示例#9
0
    def import_(self, imports_list):
        for toimport in imports_list:
            if type(
                    toimport
            ) is Import and toimport.toimport not in self.imports_cache.keys():
                self.import_lib(toimport.toimport)
            elif type(toimport) is Import:

                cached_code = self.imports_cache.get(toimport.toimport)
                if cached_code:
                    for rule in [
                            r for r in cached_code.ast
                            if type(r) is RuleDefinition
                    ]:
                        self.new_namespaces[rule] = toimport.toimport

            elif type(
                    toimport
            ) is FromImport and toimport.from_file not in self.imports_cache.keys(
            ):
                self.import_rules_from_lib(toimport.from_file,
                                           toimport.toimport)

            elif type(toimport) is FromImport:
                for rule in toimport.toimport:
                    cached_code = self.imports_cache.get(toimport.from_file)
                    if cached_code and not get_rule(
                            cached_code, toimport.from_file + '__' + rule):
                        raise NameError(
                            "File {} : 'with {} from {}' : Cannot import {} from file {}.kb"
                            .format(self.filename,
                                    ", ".join(toimport.toimport),
                                    toimport.from_file, rule,
                                    toimport.from_file))
                    else:
                        self.new_namespaces[rule] = toimport.from_file