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
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
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
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)
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
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
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
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
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")
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
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
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
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