def addCase(self, to_match, then): """ Add a translation case to package. :param to_match: str, the pattern needs matching :param then: str, what to search if the match was successful :return: None """ to_match = to_match.strip() if len(to_match) == 0: self.cases.append('') self.then.append(then) self.count += 1 return to_match = processParen(to_match) if not to_match: self.interpreter.raiseError( f"Error: Incomplete parentheses in package {self.name}") return then = processParen(then) if not then: self.interpreter.raiseError( f"Error: Incomplete parentheses in package {self.name}") return if len(to_match) == 0: self.cases.append('') self.then.append(then) self.count += 1 return self.cases.append(to_match) self.then.append(then) self.count += 1
def addCase(self, to_match, then, insert=False): """ Add a translation case to predicate. :param to_match: str, the pattern needs matching :param then: str, what to search if the match was successful :param insert: Boolean - add it at the end :return: None """ to_match = to_match.strip() if len(to_match) == 0: if insert: self.cases = [to_match] + self.cases self.then = [then] + self.then self.count += 1 return self.cases.append('') self.then.append(then) self.count += 1 return to_match = processParen(to_match) if not to_match: self.interpreter.raiseError( f"Error: Incomplete parentheses in predicate {self.name}") return then = processParen(then) if not then: self.interpreter.raiseError( f"Error: Incomplete parentheses in predicate {self.name}") return if len(to_match) == 0: if insert: self.cases = [to_match] + self.cases self.then = [then] + self.then self.count += 1 return self.cases.append('') self.then.append(then) self.count += 1 return if insert: self.cases = [to_match] + self.cases self.then = [then] + self.then self.count += 1 return self.cases.append(to_match) self.then.append(then) self.count += 1
def addNot(self, to_match, insert=False): """ Add a terminal case - stops looking if matched. not that useful but sometimes important. :param to_match: str, pattrn to match :param insert: boolean, add in the beginning :return: """ to_match = to_match.strip() if len(to_match) == 0: if insert: self.nope = [''] + self.nope return self.nope.append('') return to_match = processParen(to_match) if not to_match: self.interpreter.raiseError( f"Error: Incomplete parentheses in predicate {self.name}") if len(to_match) == 0: if insert: self.nope = [''] + self.nope return self.nope.append('') return if insert: self.nope = [to_match] + self.nope return self.nope.append(to_match)
def addBasic(self, to_match, insert=False): """ Adding a Fact to predicate. :param to_match: str, pattern to match :param insert: boolean, denoting whether to add in the beginning :return: None """ to_match = to_match.strip() if len(to_match) == 0: if insert: self.basic = [''] + self.basic return self.basic.append('') return to_match = processParen(to_match) if not to_match: self.interpreter.raiseError( f"Error: Incomplete parentheses in predicate {self.name}") if len(to_match) == 0: if insert: self.basic = [''] + self.basic return self.basic.append('') return if insert: self.basic = [to_match] + self.basic return self.basic.append(to_match)
def insert_range(self, variable, range_search, line): """ Inserts a variable range to the domain predicate. :param variable: str :param range_search: str :param line: int :return: bool """ if variable == "?all": for variable in self.variables: if variable in self.range_searches: continue self.range_searches[variable] = smart_replace( range_search, {"?all": variable}) return True if variable not in self.variables: self.interpreter.raiseError( f"Error: Variable {variable} not part of Domain {self.name}, in line {line}" ) return False range_search = processParen(range_search) if not range_search: self.interpreter.raiseError( f"Error: Illegal range search in Domain {self.name} of variable {variable}, in line {line}" ) return False if variable in self.range_searches: self.interpreter.raiseError( f"Error: In Domain {self.name}, variable {variable} already has a defined range, in line {line}" ) return False self.range_searches[variable] = range_search return True
def create(cls, interpreter, query): """ Main way of creating queries. Used class method and not __init__ because it calls itself recursively. While it is possible to use __init__ and call input recursively, this way is more aesthetically pleasing (in my opinion), because it allows the __init__ to behave as a private method behind the scenes. :param interpreter: Interpreter :param query: str :return: Query (None if illegal) """ X = Query(interpreter) query = processParen(query) if not query: interpreter.raiseError("Error: Incomplete Parentheses") return X.input(query) return X
def addNot(self, to_match): """ Adding a terminal case to package. :param to_match: str, pattern to match :return: None """ to_match = to_match.strip() if len(to_match) == 0: self.nope.append('') return to_match = processParen(to_match) if not to_match: self.interpreter.raiseError( f"Error: Incomplete parentheses in package {self.name}") if len(to_match) == 0: self.nope.append('') return self.nope.append(to_match)
def insert_elimination(self, elim, when, line): """ Inserts a constraint. :param elim: str :param when: str :param line: int :return: bool """ elim = processParen(elim) if not elim: self.interpreter.raiseError( f"Error: In Domain {self.name}, elimination {elim} illegal, in line {line}" ) return False self.eliminations[elim] = { var for var in self.variables if var_in_query(elim, var) } self.when[elim] = when return True
def insert_constraint(self, const, when, line): """ Inserts a constraint. :param const: str :param when: str :param line: int :return: bool """ const = processParen(const) if not const: self.interpreter.raiseError( f"Error: In Domain {self.name}, constraint {const} illegal, in line {line}" ) return False self.constraints[const] = { var for var in self.variables if var_in_query(const, var) } self.when[const] = when return True
def input(self, query: str): """ Main function that builds queries. Searches for logical gates (&, |, $, ~). Searches for package calls (G{...}(...)) :param query: str :return: None """ # looking for cuts searchForCuts = splitWithoutParen(query, "\\") if len(searchForCuts) != 1: self.gateA = Query.create(self.interpreter, searchForCuts[0]) self.gateB = Query.create(self.interpreter, "\\".join(searchForCuts[1:])) self.type = '\\' return # looking for ands searchForAnd = splitWithoutParen(query, "&") if len(searchForAnd) != 1: self.gateA = Query.create(self.interpreter, searchForAnd[0]) self.gateB = Query.create(self.interpreter, "&".join(searchForAnd[1:])) self.type = '&' return # looking for ors searchForOr = splitWithoutParen(query, "|") if len(searchForOr) != 1: self.gateA = Query.create(self.interpreter, searchForOr[0]) self.gateB = Query.create(self.interpreter, "|".join(searchForOr[1:])) self.type = '|' return # looking for Xor searchForXor = splitWithoutParen(query, "$") if len(searchForXor) != 1: # print(searchForXor) self.gateA = Query.create(self.interpreter, searchForXor[0]) self.gateB = Query.create(self.interpreter, "$".join(searchForXor[1:])) self.type = '$' return # looking for not searchForFilter = splitWithoutParen(query, "~") if len(searchForFilter) != 1: if len(searchForFilter) != 2 or searchForFilter[0] != '': self.interpreter.raiseError("Error: ~ must have 1 side!") return self.gateA = Query.create(self.interpreter, searchForFilter[1]) self.type = "~" return # conditional statements if query[:4] == "cond": processed = processParen(query[5:-1]) if not processed: self.interpreter.raiseError("Error: illegal cond statement") return self.type = "c" parts = splitWithoutParen(processed) for part in parts: trie = splitWithoutParen(part, ">") if len(trie) != 2: self.interpreter.raiseError(f"Error: {part} illegal cond") return cond, exe = trie cond = Query.create(self.interpreter, cond) exe = Query.create(self.interpreter, exe) self.cond.append((cond, exe)) return # Changing a reference searchForReferenceDefinition = outString(query, ":=") if searchForReferenceDefinition: parts = query.split(":=") if len(parts) != 2: self.interpreter.raiseError( f"Error: Illegal pattern for changing a reference, '{query}'" ) return self.gateA, self.gateB = parts self.type = ":=" return # Dereference if outString(query, "!") and len(splitWithoutParen(query, "!")) == 1: self.gateA = query self.type = "!" return # Folding if outString(query, "%") and len(splitWithoutParen( query, "%")) == 1 and not outString(query, ":"): self.gateA = query self.type = "%" return # case that package searchForPackage = outString(query, "}(") if searchForPackage: self.gateA = query self.type = 'pi' return # case that it is a simple clause self.gateA = query self.type = 'r' return
def match(self, pattern): """ Given a pattern, look through all cases and determine if there exists a match. if match is basic, return basic solution. if match is terminal, return False. if match is translational, return the new search that has to be done, and a way (the backward dictionary) to translate from solutions of the new search back to the parameters given in the pattern. This is the fundamental idea of back chaining, used to solved queries. :param pattern: str :return: Generator of (search, forward, backward), False """ pattern = processParen(pattern) if pattern is False or pattern is None: self.interpreter.raiseError("Error: Incomplete Parentheses") return # Looking for false facts for nope in self.nope: t = MatchDictionary.match(self.interpreter, pattern, nope) if t and not t[ 2]: # only in the case the patterns matched AND no wiggle room return if self.random: # print("RANDOM") while True: if len(self.basic) == 0 and self.count == 0: return ch = [] if len(self.basic) != 0: ch.append('basic') if self.count != 0: ch.append('translation') indices_name = random.choice(ch) if indices_name == 'basic': basic = random.choice(self.basic) t = MatchDictionary.match(self.interpreter, pattern, basic) if t: # print(f"Match basic: {t[0]},{t[1]}") yield 1, t[1], t[0] if self.recursive: return if indices_name == 'translation': i = random.randint(0, self.count - 1) t = MatchDictionary.match(self.interpreter, pattern, self.cases[i]) if t: # print(f"Matched with {self.cases[i]}: {t[0]},{t[1]}") then = self.then[i] then = smart_replace(then, t[0]) yield then, t[1], t[0] if self.recursive: return for basic in self.basic: t = MatchDictionary.match(self.interpreter, pattern, basic) if t: yield 1, t[1], t[0] if self.recursive: return for i in range(self.count): t = MatchDictionary.match(self.interpreter, pattern, self.cases[i]) if t: then = self.then[i] then = smart_replace(then, t[0]) yield then, t[1], t[0] if self.recursive: return
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 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