Example #1
0
    def o_var_with_title(self, q_var, c_title):

        self.wiggle_room = True

        c_name, _, c_pat = c_title.partition("(")

        if q_var in self.backward.keys():
            q_to = self.backward[q_var]
            c_basics = get_all_basics(c_title)
            c_trans = MatchDictionary.transform(c_title, c_basics,
                                                self.forward)
            matched = self.i_single_push(q_to, c_trans)
            if not matched:
                return False
            for b in c_basics:
                if match_type(
                        b) == 'var' and self.forward[b] in self.inside.keys():
                    self.forward[b] = self.inside[self.forward[b]]
            return True
        else:
            c_basics = get_all_basics(c_title)
            c_trans = MatchDictionary.transform(c_title, c_basics,
                                                self.forward)
            self.backward[q_var] = c_trans
            return True
Example #2
0
    def o_pack_with_var(self, q_pack, c_var):

        q_name, _, q_pat = q_pack.partition("{")

        if q_name not in self.interpreter.packages:
            return False

        if c_var in self.forward.keys():
            c_to = self.forward[c_var]
            q_basics = get_all_basics(q_pack)
            q_trans = MatchDictionary.transform(q_pack, q_basics,
                                                self.backward)
            matched = self.i_single_push(c_to, q_trans)
            if not matched:
                return False
            self.forward[c_var] = smart_replace(self.forward[c_var],
                                                self.inside)
            for b in q_basics:
                if match_type(
                        b) == 'var' and self.backward[b] in self.inside.keys():
                    self.backward[b] = self.inside[self.backward[b]]
            return True

        else:
            q_basics = get_all_basics(q_pack)
            q_trans = MatchDictionary.transform(q_pack, q_basics,
                                                self.backward)
            self.forward[c_var] = q_trans
            return True
Example #3
0
    def insert_variables(self, variables: str, line):
        """
        Inserts variables to the domain predicate.

        :param variables: str
        :param line: int
        :return: bool
        """
        a, _, b = variables.partition("(")
        b = b[:-1]
        if a.isnumeric() and match_type(b) == "var":
            self.variables = [f"{b}{i}" for i in range(1, int(a) + 1)]
            print(self.variables)
            return True
        self.raw_vars = variables
        self.variables = splitWithoutParen(variables)
        if any(match_type(var) != "var" for var in self.variables):
            self.interpreter.raiseError(
                f"Error: Illegal variables of domain {self.name}, in line {line}"
            )
            return False
        return True
Example #4
0
    def transform(cls, component, basics, target):
        """
        A method that receives a datatype list, head or title, and transforms each variable into a new variable

        :param component: str
        :param basics: list
        :param target: str
        :return:
        """
        r_d = {}  # replacing dictionary for the variables
        for basic in basics:
            if match_type(basic) == 'var':
                if basic in target:
                    new_var = target[basic]
                else:
                    new_var = f"?@{cls.index}"
                    cls.index += 1
                    target[basic] = new_var
                r_d[basic] = new_var

        return smart_replace(component, r_d)
Example #5
0
    def o_pair_with_var(self, q_pair, c_var):
        if c_var in self.forward:
            c_to = self.forward[c_var]
            q_basics = get_all_basics(q_pair, "/")
            q_trans = MatchDictionary.transform(q_pair, q_basics,
                                                self.backward)
            matched = self.i_single_push(c_to, q_trans)
            if not matched:
                return False
            self.forward[c_var] = smart_replace(self.forward[c_var],
                                                self.inside)
            for b in q_basics:
                if match_type(
                        b) == "var" and self.backward[b] in self.inside.keys():
                    self.backward[b] = self.inside[self.backward[b]]
            return True

        else:
            q_basics = get_all_basics(q_pair, "/")
            q_trans = MatchDictionary.transform(q_pair, q_basics,
                                                self.backward)
            self.forward[c_var] = q_trans
            return True
Example #6
0
    def match(cls, interp, patternA: str, patternB: str):
        """
        Matches two patterns

        :param interp: Interpreter
        :param patternA: str
        :param patternB: str
        :return: (forward:dict, backward:dict, bool)
        """

        if patternB == "...":
            forward = {"...": f"[{patternA}]"}
            backward = functools.reduce(lambda a, b: a.update(b) or a, [{
                d: d
                for d in get_all_basics(comp) if match_type(d) == "var"
            } for comp in splitWithoutParen(patternA)], {})
            return forward, backward, False

        MD = MatchDictionary(interp)
        matched = MD.outside_push(patternA, patternB)
        if not matched:
            return False
        MD.o_update()
        return MD.forward, MD.backward, MD.wiggle_room
Example #7
0
    def o_var_with_pair(self, q_var, c_pair):

        self.wiggle_room = True

        if q_var in self.backward.keys():
            q_to = self.backward[q_var]
            c_basics = get_all_basics(c_pair, "/")
            c_trans = MatchDictionary.transform(c_pair, c_basics, self.forward)
            matched = self.i_single_push(q_to, c_trans)
            if not matched:
                return False
            self.backward[q_var] = smart_replace(self.backward[q_var],
                                                 self.inside)
            for b in c_basics:
                if match_type(
                        b) == "var" and self.forward[b] in self.inside.keys():
                    self.forward[b] = self.inside[self.forward[b]]
            return True

        else:
            c_basics = get_all_basics(c_pair, "/")
            c_trans = MatchDictionary.transform(c_pair, c_basics, self.forward)
            self.backward[q_var] = c_trans
            return True
Example #8
0
    def o_var_with_pack(self, q_var, c_pack):

        c_name, _, c_pat = c_pack.partition("{")

        if c_name not in self.interpreter.packages:
            return False

        if q_var in self.backward.keys():
            q_to = self.backward[q_var]
            c_basics = get_all_basics(c_pack)
            c_trans = MatchDictionary.transform(c_pack, c_basics, self.forward)
            matched = self.i_single_push(q_to, c_trans)
            if not matched:
                return False
            for b in c_basics:
                if match_type(
                        b) == 'var' and self.forward[b] in self.inside.keys():
                    self.forward[b] = self.inside[self.forward[b]]
            return True
        else:
            c_basics = get_all_basics(c_pack)
            c_trans = MatchDictionary.transform(c_pack, c_basics, self.forward)
            self.backward[q_var] = c_trans
            return True
Example #9
0
    def search(self, depth):
        """
        Search. Uses generators (yield statements) to generate solutions for this query.
        Given type "r" looks for predicates
        Given type "~" looks to see that a predicate doesn't have a solution
        Given type "&" looks for both gates of query, uses the first to 'feed' the second
        Given type "\\" looks for left side once only, and then right size
        Given type "|" yields from first gate, and from second gate
        Given type "$" yields from first gate, if none yielded, yields from second gate
        Given type "pi", represents Package{param}(variables), searched packages
        Given type "%", unfolds (if possible) and searches normally ('r')
        Given type "c" conditional.

        :param depth: a Counter object, maximum recursion depth
        :return: a generator object that can generate solutions for this query, dict[str, str]
        """

        if depth.count < 0:
            return

        if self.interpreter.console_trace_on:
            print(
                f"Searching for {self.__str__()}, with accumulated depth of {depth}, type {self.type}"
            )

        if self.interpreter.trace_on:
            self.interpreter.message(f"Searching for {self.__str__()}")
            yield "Print"

        # regular query
        if self.type == 'r':

            if not self.gateA:
                return

            if outString(self.gateA, ":"):
                data_name, _, second_part = self.gateA.partition(":")
                action, _, query_pat = second_part.partition("(")
                query_pat = query_pat[:-1]
                data_struct: AbstractDataStructure = self.interpreter.datasets.get(
                    data_name, None) or self.interpreter.datahashes.get(
                        data_name, None)
                if data_struct:
                    if action == "Insert":
                        yield from data_struct.insert(query_pat)
                    elif action == "Remove":
                        yield from data_struct.remove(query_pat)
                    elif action == "Lookup":
                        yield from data_struct.lookup(query_pat)
                    elif action == "Clear":
                        if query_pat == "":
                            yield from data_struct.clear()

                elif match_type(data_name) == "title":
                    t_name, _, t_pattern = data_name.partition("(")
                    start = ""
                    if f"{t_name}.metacall" in self.interpreter.predicates and action != "metacall":
                        start = f"{t_name}.metacall(" + data_name + "," + action + ",[" + query_pat + "])&"
                    class_prefix = f"{t_name}.{action}"
                    if class_prefix in self.interpreter.predicates:
                        class_string = start + f"{class_prefix}(" + data_name + (
                            query_pat and "," + query_pat) + ")"
                        print(class_string)
                        class_action = Query.create(self.interpreter,
                                                    class_string)
                        if class_action:
                            yield from class_action.search(depth)
                    else:
                        if f"{t_name}.call" in self.interpreter.predicates:
                            class_string = start + f"{t_name}.call(" + data_name + "," + action + ",[" + query_pat + "])"
                            yield from Query.create(self.interpreter,
                                                    class_string).search(depth)

                elif f"{data_name}.new" in self.interpreter.predicates:
                    for construct_dict in Query.create(
                            self.interpreter,
                            f"{data_name}.new(?construct)").search(depth):
                        construct = construct_dict.get("?construct", None)
                        if construct:
                            m = MatchDictionary.match(self.interpreter, action,
                                                      construct)
                            if m:
                                yield m[1]

                return

            query_name, _, query_pat = self.gateA.partition("(")
            query_pat = query_pat[:-1]

            for mac in self.interpreter.macros:
                if mac in query_pat:
                    flag = True
                    break
            else:
                flag = False

            if flag:
                query_pat = self.interpreter.macroSimplified(query_pat, depth)
                if query_pat is None:
                    return

            if query_name == "True":
                yield {}
                return

            if "{" in query_name:
                self.type = "pi"
                yield from self.search(depth)
                return

            # if predicate is variable
            if query_name[0] == "?":
                if query_pat == "":
                    return
                for predicate in self.interpreter.predicates.values():
                    sol_with_predicate = {query_name: predicate.name}
                    Q = Query.create(
                        self.interpreter,
                        smart_replace(self.__str__(), sol_with_predicate))
                    depth.sub(1)
                    for sol in Q.search(depth):
                        if type(sol) == str:
                            yield sol
                            continue
                        complete_sol = smartUpdate(sol_with_predicate, sol)
                        yield complete_sol
                return

            if query_name in self.interpreter.pythons:
                try:
                    yield from self.interpreter.pythons[query_name](query_pat)
                except Exception as e:
                    self.interpreter.raiseError(f"Python Error: {e}")
                return

            if query_name == "Time":
                parts = splitWithoutParen(query_pat)
                if len(parts) != 1:
                    return
                m = MatchDictionary.match(
                    self.interpreter, parts[0],
                    str((time.time() - Query.start).__round__(2)))
                if m:
                    yield m[1]
                return

            if query_name == "ClockInit":
                if query_pat != "":
                    return
                Query.start = time.time()
                yield {}
                return

            found = [False]
            for solution in BuiltIns.builtin(self.interpreter, query_name,
                                             query_pat, depth, found):
                yield solution
            if found[0]:
                return

            if query_name in self.interpreter.domains:
                domain = self.interpreter.domains[query_name]
                # print(f"Found the domain {domain.name}")
                for sol in domain.search(depth, query_pat):
                    # print(f"Found a solution {sol}")
                    m = MatchDictionary.match(
                        self.interpreter, query_pat,
                        smart_replace(domain.raw_vars, sol))
                    if m:
                        yield m[1]
                return

            query_name, _, query_pat = self.gateA.partition("(")
            query_pat = query_pat[:-1]

            predicate_match = self.interpreter.predicates.get(query_name, None)

            if predicate_match:
                for search, backward, forwards in predicate_match.match(
                        query_pat):
                    if search == 1:
                        yield backward
                    else:
                        next_q = Query.create(self.interpreter, search)
                        depth.sub(1)
                        for solution in next_q.search(depth):

                            if solution == "Request":
                                yield "Request"
                                continue
                            if solution == "Print":
                                yield "Print"
                                continue

                            solution_as_dict = {}
                            for key in backward.keys():

                                if backward[key] in solution.keys():
                                    solution_as_dict[key] = solution[
                                        backward[key]]
                                else:
                                    solution_as_dict[key] = processHead(
                                        smart_replace(backward[key], solution))

                            yield solution_as_dict

        # filter clause
        elif self.type == "~":

            if not self.gateA:
                return

            for sol in self.gateA.search(depth):
                if sol != "Print" and sol != "Request":
                    return

            yield {}

        # cut clause
        elif self.type == "\\":

            if not self.gateA or not self.gateB:
                return

            try:
                gen = self.gateA.search(depth)
                p_solution = next(gen)
                while p_solution in ["Print", "Request"]:
                    yield p_solution
                    p_solution = next(gen)

                updated_gate_B = self.gateB.add_new_info(p_solution)

                for solution in updated_gate_B.search(depth):

                    if solution == "Request":
                        yield "Request"
                        continue

                    if solution == "Print":
                        yield "Print"
                        continue

                    q_solution = p_solution.copy()
                    q_solution = smartUpdate(q_solution, solution)
                    yield q_solution

            except StopIteration:
                pass
            finally:
                return

        # and clause
        elif self.type == "&":

            if not self.gateA or not self.gateB:
                return

            for p_solution in self.gateA.search(depth):

                if p_solution == "Request":
                    yield "Request"
                    continue
                if p_solution == "Print":
                    yield "Print"
                    continue

                updated_gate_B = self.gateB.add_new_info(p_solution)

                for solution in updated_gate_B.search(depth):
                    if solution == "Request":
                        yield "Request"
                        continue
                    if solution == "Print":
                        yield "Print"
                        continue

                    q_solution = p_solution.copy()
                    q_solution = smartUpdate(q_solution, solution)
                    yield q_solution

        # or clause
        elif self.type == '|':

            if not self.gateA or not self.gateB:
                return

            yield from self.gateA.search(depth)
            yield from self.gateB.search(depth)

        # Lazy Or
        elif self.type == "$":
            if not self.gateA or not self.gateB:
                return

            first_solutions = self.gateA.search(depth)
            found_in_first = False
            for sol in first_solutions:
                if sol != "Print" or sol != "Request":
                    found_in_first = True
                yield sol

            if not found_in_first:
                yield from self.gateB.search(depth)

        # Package with input
        elif self.type == 'pi':

            if not self.gateA:
                return

            X = find_package_end(self.gateA)
            if not X:
                return

            p_pred, q_inp = X
            q_inp = q_inp[1:-1]
            p_name, _, p_inp = p_pred.partition("{")
            p_inp = p_inp[:-1]

            if p_name not in self.interpreter.packages:
                return

            flag_p = False
            flag_q = False

            for macro in self.interpreter.macros:
                if macro in p_inp:
                    flag_p = True
                if macro in q_inp:
                    flag_q = True
                if flag_p and flag_q:
                    break

            if flag_p:
                p_inp = self.interpreter.macroSimplified(p_inp, depth)
            if flag_q:
                q_inp = self.interpreter.macroSimplified(q_inp, depth)

            package_match = self.interpreter.packages[p_name]

            for search, backward in package_match.match(p_inp, q_inp):
                if search == 1:
                    yield backward
                    continue

                new_query = Query.create(self.interpreter, search)

                depth.sub(1)

                for solution in new_query.search(depth):
                    solution_as_dict = {}
                    for key in backward:
                        solution_as_dict[key] = smart_replace(
                            backward[key], solution)
                    yield solution_as_dict

        # Folding
        elif self.type == '%':

            if not self.gateA:
                return

            if outString(self.gateA, "){"):
                X = find_package_end(self.gateA)
                if not X:
                    return

                p_pred, q_inp = X
                q_inp = q_inp[1:-1]
                p_name, _, p_inp = p_pred.partition("{")
                p_inp = p_inp[:-1]

                if outString(p_inp, "%"):
                    p_inp = unfold(p_inp)
                if outString(q_inp, "%"):
                    q_inp = unfold(q_inp)

                if not p_inp or not q_inp:
                    return

                new_query = Query.create(self.interpreter,
                                         f"{p_name}{{{p_inp}}}({q_inp})")
                yield from new_query.search(depth)

            try:
                query_name, _, query_pat = self.gateA.partition("(")
                query_pat = query_pat[:-1]
            except ValueError:
                return

            query_pat = unfold(query_pat)
            if query_pat == False or query_pat is None:
                return
            new_query = Query.create(self.interpreter,
                                     f"{query_name}({query_pat})")
            print(new_query)
            if new_query:
                yield from new_query.search(depth)
            return

        # Conditional Statements
        elif self.type == 'c':
            for key, value in self.cond:
                if not key or not value:
                    continue
                try:
                    search = key.search(depth)
                    p_solution = next(search)
                    while p_solution in ["Print", "Request"]:
                        yield p_solution
                        p_solution = next(search)
                    for sol in value.add_new_info(p_solution).search(depth):
                        if sol in ["Print", "Request"]:
                            yield sol
                            continue
                        yield smartUpdate(p_solution, sol)
                    return
                except StopIteration:
                    continue

        # Dereference
        elif self.type == "!":

            if not self.gateA:
                return

            if outString(self.gateA, "){"):
                X = find_package_end(self.gateA)
                if not X:
                    return

                p_pred, q_inp = X
                q_inp = q_inp[1:-1]
                p_name, _, p_inp = p_pred.partition("{")
                p_inp = p_inp[:-1]

                if outString(p_inp, "%"):
                    p_inp = deref(self.interpreter, p_inp)
                if outString(q_inp, "%"):
                    q_inp = deref(self.interpreter, q_inp)

                if not p_inp or not q_inp:
                    return

                new_query = Query.create(self.interpreter,
                                         f"{p_name}{{{p_inp}}}({q_inp})")
                yield from new_query.search(depth)

            try:
                query_name, _, query_pat = self.gateA.partition("(")
                query_pat = query_pat[:-1]
            except ValueError:
                return

            query_pat = deref(self.interpreter, query_pat)
            if not query_pat:
                return
            new_query = Query.create(self.interpreter,
                                     f"{query_name}({query_pat})")
            if new_query:
                yield from new_query.search(depth)
            return

        # Setting Reference
        elif self.type == ':=':
            if self.gateA not in self.interpreter.references:
                self.interpreter.raiseError(
                    f"Error: Trying to change the value of non-existent reference, '{self.gateA}'"
                )
                return
            elif independent(self.gateB):
                self.interpreter.raiseError(
                    f"Error: trying to change the value of a reference to a value containing variables, '{self.gateB}'"
                )
                return
            self.gateB = deref(self.interpreter, self.gateB)
            if not self.gateB:
                return
            self.gateB = processHead(self.gateB)
            if not self.gateB:
                return
            self.interpreter.references[self.gateA] = self.gateB
            yield {}

        else:
            self.interpreter.raiseError(f"Error: Illegal Query")
Example #10
0
def builtin(interpreter, query_name, query_pat, depth, found):
    """
    Builtin predicates (many different libraries).

    :param interpreter: Interpreter
    :param query_name: str
    :param query_pat: str
    :param depth: Counter
    :param found: "pointer" bool
    :return: Generator
    """

    found[0] = True

    # checks for terminal match
    if query_name == "GuaranteeUnify":
        comps = splitWithoutParen(query_pat)
        if len(comps) != 2:
            return
        comp1, comp2 = comps
        m = MatchDictionary.match(interpreter, comp1, comp2)
        if m and not m[2]:
            yield {}
        return

    # Can be unified
    if query_name == "CanUnify":
        comps = splitWithoutParen(query_pat)
        if len(comps) != 2:
            return
        comp1, comp2 = comps
        m = MatchDictionary.match(interpreter, comp1, comp2)
        if m:
            yield {}
        return

    # Exact copy of a pattern
    if query_name == "ExactCopy":
        comps = splitWithoutParen(query_pat)
        if len(comps) != 2:
            return
        comp1, comp2 = comps
        bs = get_all_basics(comp1)
        copy = MatchDictionary.transform(comp1, bs, {})
        m = MatchDictionary.match(interpreter, comp2, copy)
        if m:
            print(m[1])
            yield m[1]
        return

    # Online Request
    if query_name == "Request":
        parts = splitWithoutParen(query_pat)
        if len(parts) != 2:
            return
        try:
            inLcl = url_opener(parts[0][1:-1])
            if inLcl is None:
                return
            m = MatchDictionary.match(interpreter, parts[1], inLcl)
            if m:
                yield m[1]
        except Exception as e:
            print(e)
        finally:
            return

    # Ref.new - Create reference
    if query_name == "Ref.new":
        comps = splitWithoutParen(query_pat)
        if len(comps) != 1:
            return
        comp1, = comps
        if match_type(comp1) != "var":
            return
        rand = hex(randint(10000, 10000000))
        while rand in interpreter.references:
            rand = hex(randint(100, 100000))
        interpreter.references[rand] = "nil"
        yield {comp1: rand}
        return

    # Ref.del - delete a reference
    if query_name == "Ref.del":
        comps = splitWithoutParen(query_pat)
        if len(comps) != 1:
            return
        comp1, = comps
        if comp1 not in interpreter.references:
            return
        del interpreter.references[comp1]
        yield {}
        return

    if query_name == "SecIns":
        print(">> ", end="")
        inspect = input()
        try:
            print(eval(inspect))
            yield {}
        except Exception as e:
            print(e)
        return

    # Break predicate
    if query_name == 'hBreak' and (interpreter.list_added
                                   or interpreter.types_added):
        parts = splitWithoutParen(query_pat)
        if len(parts) != 2 or "[" in parts[0] or "?" in parts[0]:
            return
        broken = list(parts[0])
        if len(broken) == 0:
            return
        inLcl = '['
        for broke in broken:
            inLcl += broke + ","
        inLcl = inLcl[:-1] + "]"
        m = MatchDictionary.match(interpreter, parts[1], inLcl)
        if m:
            yield m[1]
        return

    # domain generator
    if query_name == "Domain-Generator":
        parts = splitWithoutParen(query_pat)
        if len(parts) != 4 or any(
                match_type(part) != "list" for part in parts):
            return
        variables = splitWithoutParen(parts[0][1:-1])
        if any(match_type(pattern) != "var" for pattern in variables):
            return
        ranges = splitWithoutParen(parts[1][1:-1])
        if len(ranges) != len(variables):
            return
        constraints = splitWithoutParen(parts[2][1:-1])
        elims = splitWithoutParen(parts[3][1:-1])
        D = Domain(interpreter, "~~Anon")
        D.variables = variables
        D.raw_vars = parts[0][1:-1]
        for i, var in enumerate(variables):
            D.range_searches[var] = ranges[i]
        for const in constraints:
            D.insert_constraint(const, "", -1)
        for elim in elims:
            D.insert_elimination(elim, "", -1)
        yield from D.search(depth, parts[0][1:-1])

    # Input
    if query_name == "hInput" and interpreter.strings_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if parts[0][0] != "?":
            return
        yield "Request"
        inp = interpreter.received_input
        interpreter.received_input = False
        yield {parts[0]: '"' + inp + '"'}

    # isList predicate (checks if list)
    if query_name == 'isList' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if parts[0][0] == "[":
            yield {}
        return

    # isVar predicate (checks if variable)
    if query_name == 'isVar' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if '?' == parts[0][0]:
            yield {}
        return

    # Title predicate (checks if title)
    if query_name == 'isTitle' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        try:
            T_name, _, T_pat = parts[0].partition("(")
            if T_name in interpreter.titles:
                yield {}
        except IndexError:
            pass
        except ValueError:
            pass
        return

    # Integer predicate (checks if integer)
    if query_name == 'isInteger' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        try:
            a = int(parts[0])
            yield {}
        except IndexError:
            pass
        except ValueError:
            pass
        return

    # Floating predicate (checks if float)
    if query_name == 'isFloating' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        try:
            a = float(parts[0])
            yield {}
        except IndexError:
            pass
        except ValueError:
            pass
        return

    # Known Predicate (checks if variables in predicate)
    if query_name == 'isKnown' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if outString(parts[0], "?"):
            return
        yield {}

    # Predicate predicate (is it a predicate)
    if query_name == 'isPredicate' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if parts[0] in interpreter.predicates or \
                (parts[0] in ['Add', 'Sub', 'Mul', 'Div', 'Mod', 'Floor', 'Ceil', 'Power', 'Log', 'Sin', 'Cos', 'Tan',
                              'LT'] and interpreter.math_added) \
                or parts[0] == 'Print' or parts[0] == 'Predicate' or (parts[0] == 'Break' and interpreter.list_added):
            yield {}
        return

    # isPackage predicate (is it a package)
    if query_name == 'isPackage' and interpreter.types_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if parts[0] in interpreter.packages:
            yield {}
        return

    # Math Predicates
    if query_name in [
            'hAdd', 'hSub', 'hMul', 'hDiv', 'hMod', 'hFloor', 'hCeil',
            'hPower', 'hLog', 'hSin', 'hCos', 'hTan', 'hLT', 'hE'
    ] and interpreter.math_added:
        yield from MathHelper.Reader(query_name, query_pat)
        return

    # Print 'predicate'
    if query_name == 'Print':
        parts = splitWithoutParen(query_pat)
        printible = []
        for part in parts:
            printible.append(formatPrint(part))
        printed = joinPrint(printible)
        interpreter.message(printed)
        yield "Print"
        if len(query_pat) != 0 and query_pat[-1] == ",":
            interpreter.newline = True
        else:
            interpreter.newline = False
        yield {}

    # AllSolutions predicate
    if query_name == 'hAllSolutions' and interpreter.predicates_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 3:
            return
        if parts[0][0] == "?":
            return
        try:
            n = int(parts[1])
        except ValueError:
            return
        sols = []
        pattern = ",".join([f"?x{j}" for j in range(n)])
        q = f"{parts[0]}({pattern})"
        for sol in interpreter.mixed_query(q, 0, depth.count, True):
            sols.append(smart_replace(f"[{pattern}]", sol))
        final = "[" + ",".join(sols) + "]"
        m = MatchDictionary.match(interpreter, parts[2], final)
        if m:
            yield m[1]
        return

    # Save predicate
    if query_name == 'hSave' and interpreter.save_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return
        if outString(parts[0], "?"):
            return
        to_save = parts[0]
        interpreter.saved.insert(0, to_save)
        yield {}
        return

    # helper Load predicate
    if query_name == 'hLoad' and interpreter.save_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) == 1:
            if len(interpreter.saved) == 0:
                return
            else:
                to_load = interpreter.saved.popleft()
                t = MatchDictionary.match(interpreter, parts[0], to_load)
                if t:
                    yield t[1]
        return

    # Chars predicate
    if query_name == 'ToChars' and interpreter.strings_added:

        parts = splitWithoutParen(query_pat)
        if len(parts) != 2 or outString("[", parts[0]) or outString(
                parts[0], "?") or parts[0][0] != '"' or parts[0][-1] != '"':
            return
        broken = list(parts[0][1:-1])
        inLcl = '[' + ",".join(list(map(lambda c: f'"{c}"', broken))) + "]"
        m = MatchDictionary.match(interpreter, parts[1], inLcl)
        if m:
            yield m[1]
        return

    # Chars to String
    if query_name == 'ToString' and interpreter.strings_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 2 or outString(
                parts[0], "?") or "[" != parts[0][0] or "]" != parts[0][-1]:
            return

        broken = splitWithoutParen(parts[0][1:-1])
        inLcl = '"'
        for broke in broken:
            if broke[0] != '"' or broke[-1] != '"':
                return
            inLcl += broke[1:-1]
        inLcl += '"'
        m = MatchDictionary.match(interpreter, parts[1], inLcl)
        if m:
            yield m[1]
        return

    # open file
    if query_name == 'hOpen' and interpreter.filestream_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 3:
            return
        file_name, file_type, file_var = parts
        if match_type(file_var) != "var":
            return
        file_name = file_name[1:-1]
        print(file_name)
        if file_type not in ["r", "w", "a", "rp"]:
            if file_type == "rp":
                file_type = "r+"
            interpreter.raiseError(f"Error: Illegal file type '{file_type}'")
            return
        if ":" not in file_name:
            try:
                f = open(interpreter.filepath + "/" + file_name, file_type)
            except FileNotFoundError:
                interpreter.raiseError(f"Error: File not found, '{file_name}'")
                return
        else:
            try:
                f = open(file_name, file_type)
            except FileNotFoundError:
                interpreter.raiseError(f"Error: File not found, '{file_name}'")
                return
        file_hash = hashlib.md5(
            (random().as_integer_ratio()[0] +
             random().as_integer_ratio()[1]).__str__().encode()).hexdigest()
        interpreter.files[file_hash] = f
        yield {file_var: file_hash}
        return

    # read file
    if query_name == 'hRead' and interpreter.filestream_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 2:
            return
        file_name, char_to = parts
        if match_type(char_to) != 'var':
            return False
        if file_name not in interpreter.files:
            interpreter.raiseError(f"Error: File '{file_name}' not opened.")
            return
        file_read = interpreter.files[file_name]
        try:
            c = file_read.read(1)
        except UnsupportedOperation:
            interpreter.raiseError(f"Error: File '{file_name}' not readable.")
            return

        yield {char_to: '"' + c + '"'}
        return

    # write in file
    if query_name == 'hWrite' and interpreter.filestream_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 2:
            return
        file_name, write = parts
        if write[0] == '"':
            write = write[1:-1]
        if file_name not in interpreter.files:
            interpreter.raiseError(f"Error: File '{file_name}' not opened.")
            return

        try:
            interpreter.files[file_name].write(write)
        except UnsupportedOperation:
            interpreter.raiseError(f"Error: File '{file_name}' not writable.")
            return

        yield {}

    # close file
    if query_name == 'hClose' and interpreter.filestream_added:
        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return

        file_name = parts[0]
        if file_name in interpreter.files:
            interpreter.files[file_name].close()
            interpreter.files.pop(file_name)
            yield {}
            return
        else:
            interpreter.raiseError(f"Error: file '{file_name}' not found.")
            return

    # Tracing searching algorithm
    if query_name == "Trace" and interpreter.inspect_added:
        if query_pat == "On":
            interpreter.trace_on = True
        elif query_pat == "Off":
            interpreter.trace_on = False
        elif query_pat == "OnOn":
            interpreter.console_trace_on = True
        elif query_pat == "OffOff":
            interpreter.console_trace_on = False
        else:
            return
        yield {}
        return

    # Show Memory
    if query_name == "ShowMem" and interpreter.inspect_added:
        interpreter.message(
            f"{interpreter.memory}\n{interpreter.references}\n")
        yield "Print"
        yield {}
        return

    # Listing - list all cases of predicate
    if query_name == "Listing" and interpreter.inspect_added:
        p_name = query_pat

        if p_name == "ALL":
            for predicate in interpreter.predicates.values():
                interpreter.message(predicate.__str__())
            yield 'Print'
            yield {}
            return

        if p_name not in interpreter.predicates:
            return
        else:
            predicate_match = interpreter.predicates[p_name]
            interpreter.message(predicate_match.__str__())
            yield "Print"
            yield {}
            return

        return

    if interpreter.dynamic_added and query_name in {"AssertF", "AssertFE", "AssertN", "AssertNE", "AssertC", "AssertCE", "DeleteF",
                                                    "DeleteN", "DeleteC", "Create", "SwitchRecursive", "SwitchRandom", 'Clear', 'Delete'} \
            :

        parts = splitWithoutParen(query_pat)
        if len(parts) != 1:
            return

        if query_name == "Create":
            if re.fullmatch(r'[a-zA-Z_0-9\-\.]+',
                            query_pat) and query_pat not in Lexer.reserved:
                new_pred = Predicate(interpreter, query_pat, False, False)
                interpreter.predicates[new_pred.name] = new_pred
                yield {}
            return
        if query_name == "SwitchRecursive":
            if query_pat in interpreter.predicates:
                pred = interpreter.predicates[query_pat]
                pred.recursive = not pred.recursive
                yield {}
            return
        if query_name == "SwitchRandom":
            if query_pat in interpreter.predicates:
                pred = interpreter.predicates[query_pat]
                pred.random = not pred.random
                yield {}
            return
        if query_name == 'Delete':
            if query_pat in interpreter.predicates:
                del interpreter.predicates[query_pat]
                yield {}
            return

        predicate_changed, _, body = query_pat.partition("(")
        body = "(" + body
        body = remove_whitespace(body)

        if predicate_changed not in interpreter.predicates:
            return

        predicate_changed = interpreter.predicates[predicate_changed]

        if query_name == "AssertFE":
            basic = processParen(body)
            if basic:
                predicate_changed.addBasic(basic)
                yield {}
                return
            else:
                return
        if query_name == "AssertF":
            basic = processParen(body)
            if basic:
                predicate_changed.addBasic(basic, insert=True)
                yield {}
                return
            else:
                return

        if query_name == "AssertNE":
            basic = processParen(body)
            if basic:
                predicate_changed.addNot(basic)
                yield {}
                return
            else:
                return
        if query_name == "AssertN":
            basic = processParen(body)
            if basic:
                predicate_changed.addNot(basic, insert=True)
                yield {}
                return
            else:
                return

        if query_name == "AssertCE":
            to_match, _, then = body.partition(">")
            to_match, then = processParen(to_match), processParen(then)
            if not to_match or not then:
                return
            predicate_changed.addCase(to_match, then)
            yield {}
            return
        if query_name == "AssertC":
            to_match, _, then = body.partition(">")
            to_match, then = processParen(to_match), processParen(then)
            if not to_match or not then:
                return
            predicate_changed.addCase(to_match, then, insert=True)
            yield {}
            return

        if query_name == "DeleteF":
            body = processParen(body)
            if body in predicate_changed.basic:
                predicate_changed.basic.remove(body)
                yield {}
                return
            else:
                return
        if query_name == "DeleteN":
            body = processParen(body)
            if body in predicate_changed.nope:
                predicate_changed.nope.remove(body)
                yield {}
                return
            else:
                return
        if query_name == 'DeleteC':
            to_match, _, then = body.partition(">")
            to_match, then = processParen(to_match), processParen(then)
            if to_match in predicate_changed.cases:
                index = predicate_changed.cases.index(to_match)
                if then != predicate_changed.then[index]:
                    return
                predicate_changed.cases.remove(to_match)
                predicate_changed.then.remove(then)
                predicate_changed.count -= 1
                yield {}
                return
            else:
                return

        if query_name == 'Clear':
            predicate_changed.cases = []
            predicate_changed.then = []
            predicate_changed.count = 0
            predicate_changed.basic = []
            predicate_changed.nope = []
            yield {}
            return

        return

    found[0] = False
Example #11
0
    def i_single_push(self, compA, compB):

        if compB == "_":
            compB = f"?@{MatchDictionary.index}"
            MatchDictionary.index += 1
        if compA == "_":
            compA = f"?@{MatchDictionary.index}"

        typeA = match_type(compA)
        typeB = match_type(compB)

        if typeA in ['list', 'head']:
            compA = processHead(compA)
            typeA = match_type(compA)
        if typeB in ['list', 'head']:
            compB = processHead(compB)
            typeB = match_type(compB)

        if typeA == 'constant' and typeB == 'constant':
            return compA == compB

        matched = False
        # var with var & var with constant
        if typeA == 'var' and typeB == 'var':
            matched = self.i_var_with_var(compA, compB)
        if typeA == 'var' and typeB == 'constant':
            matched = self.i_const_with_var(compB, compA)
        if typeA == 'constant' and typeB == 'var':
            matched = self.i_const_with_var(compA, compB)

        # Lists with vars
        if typeA == 'list' and typeB == 'var':
            matched = self.i_var_with_list(compB, compA)
        if typeA == 'var' and typeB == 'list':
            matched = self.i_var_with_list(compA, compB)

        # Appended lists with vars
        if typeA == 'head' and typeB == 'var':
            matched = self.i_var_with_head(compB, compA)
        if typeA == 'var' and typeB == 'head':
            matched = self.i_var_with_head(compA, compB)

        # lists with lists, lists with appended lists.
        if typeA == 'list' and typeB == 'list':
            matched = self.i_list_with_list(compA, compB)
        if typeA == 'head' and typeB == 'head':
            matched = self.i_head_with_head(compA, compB)
        if typeA == 'list' and typeB == 'head':
            matched = self.i_list_with_head(compA, compB)
        if typeA == 'head' and typeB == 'list':
            matched = self.i_list_with_head(compB, compA)

        # titles match
        if typeA == 'title' and typeB == 'title':
            matched = self.i_title_with_title(compA, compB)
        if typeA == 'var' and typeB == 'title':
            matched = self.i_var_with_title(compA, compB)
        if typeA == 'title' and typeB == 'var':
            matched = self.i_var_with_title(compB, compA)

        # Package match
        if typeA == 'pack' and typeB == 'pack':
            matched = self.i_pack_with_pack(compA, compB)
        if typeA == 'var' and typeB == 'pack':
            matched = self.i_var_with_pack(compA, compB)
        if typeA == 'pack' and typeB == 'var':
            matched = self.i_var_with_pack(compB, compA)

        if typeA == 'pair' and typeB == 'pair':
            matched = self.i_pair_with_pair(compA, compB)
        if typeA == 'var' and typeB == 'pair':
            matched = self.i_var_with_pair(compA, compB)
        if typeA == 'pair' and typeB == 'var':
            matched = self.i_var_with_pair(compB, compA)

        if not matched:
            return False

        self.update()
        return True
Example #12
0
    def o_single_push(self, compA, compB):

        compA = processParen(compA)
        compB = processParen(compB)

        if compB == "_":
            compB = f"?@{MatchDictionary.index}"
            MatchDictionary.index += 1
        if compA == "_":
            compA = f"?@{MatchDictionary.index}"
            MatchDictionary.index += 1

        if not compA or not compB:
            return

        if any(map(lambda infx: infx in compA, self.interpreter.infixes)):
            compA = lookup(compA, self.interpreter.infixes)
        if any(map(lambda infx: infx in compB, self.interpreter.infixes)):
            compB = lookup(compB, self.interpreter.infixes)

        if not compA or not compB:
            return False

        typeA = match_type(compA)
        typeB = match_type(compB)

        # print(compA, typeA, compB, typeB)

        if typeA in ['list', 'head']:
            compA = processHead(compA)
            if not compA:
                return False
            typeA = match_type(compA)
        if typeB in ['list', 'head']:
            compB = processHead(compB)
            if not compB:
                return False
            typeB = match_type(compB)

        if typeA == 'constant' and typeB == 'constant':
            return compA == compB

        # var with var & var with constant
        if typeA == 'var' and typeB == 'var':
            return self.o_var_with_var(compA, compB)
        if typeA == 'var' and typeB == 'constant':
            return self.o_var_with_const(compA, compB)
        if typeA == 'constant' and typeB == 'var':
            return self.o_const_with_var(compA, compB)

        # Lists with vars
        if typeA == 'list' and typeB == 'var':
            return self.o_list_with_var(compA, compB)
        if typeA == 'var' and typeB == 'list':
            return self.o_var_with_list(compA, compB)

        # Appended lists with vars
        if typeA == 'head' and typeB == 'var':
            return self.o_head_with_var(compA, compB)
        if typeA == 'var' and typeB == 'head':
            return self.o_var_with_head(compA, compB)

        # lists with lists, lists with appended lists.
        if typeA == 'list' and typeB == 'list':
            return self.o_list_with_list(compA, compB)
        if typeA == 'head' and typeB == 'head':
            return self.o_head_with_head(compA, compB)
        if typeA == 'list' and typeB == 'head':
            return self.o_list_with_head(compA, compB)
        if typeA == 'head' and typeB == 'list':
            return self.o_head_with_list(compA, compB)

        # titles match
        if typeA == 'title' and typeB == 'title':
            return self.o_title_with_title(compA, compB)
        if typeA == 'var' and typeB == 'title':
            return self.o_var_with_title(compA, compB)
        if typeA == 'title' and typeB == 'var':
            return self.o_title_with_var(compA, compB)

        # Packages match
        if typeA == 'pack' and typeB == 'pack':
            return self.o_pack_with_pack(compA, compB)
        if typeA == 'pack' and typeB == 'var':
            return self.o_pack_with_var(compA, compB)
        if typeA == 'var' and typeB == 'pack':
            return self.o_var_with_pack(compA, compB)

        # Pair Match
        if typeA == "pair" and typeB == "pair":
            return self.o_pair_with_pair(compA, compB)
        if typeA == "pair" and typeB == "var":
            return self.o_pair_with_var(compA, compB)
        if typeA == "var" and typeB == "pair":
            return self.o_var_with_pair(compA, compB)

        return False
Example #13
0
    def update_range(self, depth, ranges, fixed, consts, elims, already):
        """
        Updated the ranges based on the constraints, eliminations and fixed variables.

        :param depth: Counter
        :param ranges: dict[str, set[str]]
        :param fixed: dict[str, str]
        :param consts: dict[str, set[str]]
        :param elims: dict[str, set[str]]
        :param already: set[str]
        :return: bool
        """

        if self.deleted:
            return

        for const in list(consts.keys()):
            possible_sols = {
            }  # dictionary between variables and their solutions
            new_set = set(
            )  # to be : a set of all variables that appear in this const, and do not have an evaluation yet

            # Updating the constraint dictionary
            for var in consts[const]:
                if var not in fixed:
                    possible_sols[var] = set()
                    new_set.add(var)

            consts[const] = new_set
            original_const = const
            const = smart_replace(const, fixed)

            if const in already:
                # already searched this constraint
                continue
            else:
                already.add(const)

            # checking for when conditions
            try:
                if self.when[original_const] != "":
                    sol_gen = self.interpreter.mixed_query(
                        smart_replace(self.when[original_const], fixed), 0,
                        depth, True)
                    while next(sol_gen) in ["Print", "Request"]:
                        pass
            except StopIteration:
                # for when
                continue

            if len(possible_sols) == 0:
                try:
                    sol_gen = self.interpreter.mixed_query(
                        const, 0, depth, True)
                    while next(sol_gen) in ["Print", "Request"]:
                        pass
                    del consts[original_const]
                    continue
                except StopIteration:
                    return False

            for sol in self.interpreter.mixed_query(const, 0, depth, True):

                if type(sol) != dict:
                    continue

                for var in possible_sols:
                    if var in sol:
                        possible_sols[var].add(sol[var])

            for var in possible_sols:
                if any(
                        match_type(possible_value) == "var"
                        for possible_value in possible_sols[var]):
                    continue
                ranges[var] = ranges[var].intersection(possible_sols[var])
                if len(ranges[var]) == 0:
                    # print(f"Exited due to {const}")
                    return False

        for elim in list(elims.keys()):
            impossible_sols = {}

            new_set = set()

            for var in elims[elim]:
                if var in fixed:
                    continue
                impossible_sols[var] = set()
                new_set.add(var)

            elims[elim] = new_set

            original_elim = elim
            elim = smart_replace(elim, fixed)

            if elim in already:
                continue
            else:
                already.add(elim)

            try:
                if self.when[original_elim] != "":
                    next(
                        self.interpreter.mixed_query(
                            smart_replace(self.when[original_elim], fixed), 0,
                            depth, True))
            except StopIteration:
                continue

            if len(impossible_sols) == 0:
                continue

            for sol in self.interpreter.mixed_query(elim, 0, depth, True):
                # print(f"Solution to {elim} is {sol}, with possible solutions {possible_sols}")
                for var in impossible_sols:
                    if var in sol:
                        impossible_sols[var].add(sol[var])

            for var in impossible_sols:
                ranges[var] = ranges[var].difference(impossible_sols[var])
                if len(ranges[var]) == 0:
                    return False

        return True