def update_module_stack(cmd: str, module_stack: List[str]) -> None: stripped_cmd = serapi_instance.kill_comments(cmd).strip() module_start_match = re.match(r"Module (\w*)\b(?!.*:=)", stripped_cmd) module_end_match = re.match(r"End (\w*)\.", stripped_cmd) if module_start_match: module_stack.append(module_start_match.group(1)) elif module_end_match: if module_stack: if module_stack[-1] == module_end_match.group(1): started_module_name = module_stack.pop() else: eprint(f"Unrecognized End \"{cmd}\"")
def no_compound_or_bullets(in_data : TacticContext, tactic : str, next_in_data : TacticContext, arg_values : argparse.Namespace) -> bool: tactic = serapi_instance.kill_comments(tactic) return (not re.match("\s*[\{\}\+\-\*].*", tactic, flags=re.DOTALL) and not re.match(".*;.*", tactic, flags=re.DOTALL))
def norm(statement: str): return serapi_instance.kill_comments(toStr(statement)).strip()
def linearize_commands(args: argparse.Namespace, file_idx: int, commands_sequence: Iterable[str], coq: serapi_instance.SerapiInstance, filename: str, relative_filename: str, skip_nochange_tac: bool, known_failures: List[List[str]]): commands_iter = iter(commands_sequence) command = next(commands_iter, None) assert command, "Got an empty sequence!" while command: # Run up to the next proof while coq.count_fg_goals() == 0: coq.run_stmt(command) if coq.count_fg_goals() == 0: yield command command = next(commands_iter, None) if not command: return # Cancel the proof starting command so that we're right before the proof coq.cancel_last() # Pull the entire proof from the lifter into command_batch command_batch = [] while command and not serapi_instance.ending_proof(command): command_batch.append(command) command = next(commands_iter, None) # Get the QED on there too. if command: command_batch.append(command) # Now command_batch contains everything through the next # Qed/Defined. theorem_statement = serapi_instance.kill_comments(command_batch.pop(0)) theorem_name = theorem_statement.split(":")[0].strip() coq.run_stmt(theorem_statement) yield theorem_statement if [relative_filename, theorem_name] in known_failures: eprint("Skipping {}".format(theorem_name), guard=args.verbose >= 1) for command in command_batch: coq.run_stmt(command) yield command command = next(commands_iter, None) continue # This might not be super robust? match = re.fullmatch("\s*Proof with (.*)\.\s*", command_batch[0]) if match and match.group(1): with_tactic = match.group(1) else: with_tactic = "" orig = command_batch[:] command_batch = list(prelinear_desugar_tacs(command_batch)) try: try: batch_handled = list(handle_with(command_batch, with_tactic)) linearized_commands = list( linearize_proof(coq, theorem_name, batch_handled, args.verbose, skip_nochange_tac)) yield from linearized_commands except (BadResponse, CoqExn, LinearizerCouldNotLinearize, ParseError, TimeoutError, NoSuchGoalError) as e: if args.verbose: eprint("Aborting current proof linearization!") eprint("Proof of:\n{}\nin file {}".format( theorem_name, filename)) eprint() if args.hardfail: raise e coq.run_stmt("Abort.") coq.run_stmt(theorem_statement) for command in orig: if command: coq.run_stmt(command, timeout=360) yield command except CoqAnomaly: eprint( f"Anomaly! Raising with {[relative_filename, theorem_name]}", guard=args.verbose >= 1) raise CoqAnomaly([relative_filename, theorem_name]) command = next(commands_iter, None)
def lifted_vernac(command: str) -> Optional[Match[Any]]: return re.match("Ltac\s", serapi_instance.kill_comments(command).strip())
def linearize_proof(coq: serapi_instance.SerapiInstance, theorem_name: str, command_batch: List[str], verbose: int = 0, skip_nochange_tac: bool = False) -> Iterable[str]: pending_commands_stack: List[Union[str, List[str], None]] = [] while command_batch: while coq.count_fg_goals() == 0: indentation = " " * (len(pending_commands_stack)) if len(pending_commands_stack) == 0: while command_batch: command = command_batch.pop(0) if "Transparent" in command or \ serapi_instance.ending_proof(command): coq.run_stmt(command) yield command return coq.run_stmt("}") yield indentation + "}" if coq.count_fg_goals() > 0: coq.run_stmt("{") yield indentation + "{" pending_commands = pending_commands_stack[-1] if isinstance(pending_commands, list): next_cmd, *rest_cmd = pending_commands dotdotmatch = re.match("(.*)<\.\.>", next_cmd, flags=re.DOTALL) for cmd in rest_cmd: dotdotmatch = re.match("(.*)<\.\.>", cmd, flags=re.DOTALL) if dotdotmatch: continue assert serapi_instance.isValidCommand(cmd), \ f"\"{cmd}\" is not a valid command" if (not rest_cmd) and dotdotmatch: pending_commands_stack[-1] = [next_cmd] assert serapi_instance.isValidCommand(dotdotmatch.group(1)), \ f"\"{dotdotmatch.group(1)}\" is not a valid command" command_batch.insert(0, dotdotmatch.group(1)) else: assert serapi_instance.isValidCommand(next_cmd), \ f"\"{next_cmd}\" is not a valid command" command_batch.insert(0, next_cmd) pending_commands_stack[-1] = rest_cmd if rest_cmd else None pass elif pending_commands: assert serapi_instance.isValidCommand(pending_commands), \ f"\"{command}\" is not a valid command" command_batch.insert(0, pending_commands) else: popped = pending_commands_stack.pop() if isinstance(popped, list) and len(popped) > 0 and len( pending_commands_stack) > 1: if pending_commands_stack[-1] is None: pending_commands_stack[-1] = popped elif isinstance(pending_commands_stack[-1], list): if isinstance(popped, list) and "<..>" in popped[-1]: raise LinearizerCouldNotLinearize pending_commands_stack[ -1] = popped + pending_commands_stack[-1] command = command_batch.pop(0) assert serapi_instance.isValidCommand(command), \ f"command is \"{command}\", command_batch is {command_batch}" comment_before_command = "" command_proper = command while re.fullmatch("\s*\(\*.*", command_proper, flags=re.DOTALL): next_comment, command_proper = \ split_to_next_matching("\(\*", "\*\)", command_proper) command_proper = command_proper[1:] comment_before_command += next_comment if comment_before_command: yield comment_before_command if re.match("\s*[*+-]+\s*|\s*[{}]\s*", command): continue command = serapi_instance.kill_comments(command_proper) if verbose >= 2: eprint(f"Linearizing command \"{command}\"") goal_selector_match = re.fullmatch(r"\s*(\d+)\s*:\s*(.*)\.\s*", command) if goal_selector_match: goal_num = int(goal_selector_match.group(1)) rest = goal_selector_match.group(2) if goal_num < 2: raise LinearizerCouldNotLinearize if pending_commands_stack[-1] is None: completed_rest = rest + "." assert serapi_instance.isValidCommand(rest + "."),\ f"\"{completed_rest}\" is not a valid command in {command}" pending_commands_stack[-1] = ["idtac."] * (goal_num - 2) + [ completed_rest ] elif isinstance(pending_commands_stack[-1], str): pending_cmd = pending_commands_stack[-1] pending_commands_stack[-1] = [pending_cmd] * (goal_num - 2) + \ [rest + " ; " + pending_cmd] + [pending_cmd + "<..>"] else: assert isinstance(pending_commands_stack[-1], list) pending_cmd_lst = pending_commands_stack[-1] try: old_selected_cmd = pending_cmd_lst[goal_num - 2] except IndexError: raise LinearizerCouldNotLinearize match = re.match("(.*)\.$", old_selected_cmd, re.DOTALL) assert match, f"\"{old_selected_cmd}\" doesn't match!" cmd_before_period = unwrap(match).group(1) new_selected_cmd = f"{cmd_before_period} ; {rest}." pending_cmd_lst[goal_num - 2] = new_selected_cmd continue if split_by_char_outside_matching("\(", "\)", "\|\||&&", command): coq.run_stmt(command) yield command continue if re.match("\(", command.strip()): inside_parens, after_parens = split_to_next_matching( '\(', '\)', command) command = inside_parens.strip()[1:-1] + after_parens # Extend this to include "by \(" as an opener if you don't # desugar all the "by"s semi_match = split_by_char_outside_matching("try \(|\(|\{\|", "\)|\|\}", "\s*;\s*", command) if semi_match: base_command, rest = semi_match rest = rest.lstrip()[1:] coq.run_stmt(base_command + ".") indentation = " " * (len(pending_commands_stack) + 1) yield indentation + base_command.strip() + "." if re.match("\(", rest) and not \ split_by_char_outside_matching("\(", "\)", "\|\|", rest): inside_parens, after_parens = split_to_next_matching( '\(', '\)', rest) rest = inside_parens[1:-1] + after_parens bracket_match = re.match("\[", rest.strip()) if bracket_match: bracket_command, rest_after_bracket = \ split_to_next_matching('\[', '\]', rest) rest_after_bracket = rest_after_bracket.lstrip()[1:] clauses = multisplit_matching("\[", "\]", "(?<!\|)\|(?!\|)", bracket_command.strip()[1:-1]) commands_list = [ cmd.strip() if cmd.strip().strip(".") != "" else "idtac" + cmd.strip() for cmd in clauses ] assert commands_list, command dotdotpat = re.compile(r"(.*)\.\.($|\W)") ending_dotdot_match = dotdotpat.match(commands_list[-1]) if ending_dotdot_match: commands_list = commands_list[:-1] + \ ([ending_dotdot_match.group(1)] * (coq.count_fg_goals() - len(commands_list) + 1)) else: starting_dotdot_match = dotdotpat.match(commands_list[0]) if starting_dotdot_match: starting_tac = starting_dotdot_match.group(1) commands_list = [starting_tac] * (coq.count_fg_goals() - len(commands_list) + 1)\ + commands_list[1:] else: for idx, command_case in enumerate( commands_list[1:-1]): middle_dotdot_match = dotdotpat.match(command_case) if middle_dotdot_match: commands_list = \ commands_list[:idx] + \ [command_case] * (coq.count_fg_goals() - len(commands_list) + 1) + \ commands_list[idx+1:] break if rest_after_bracket.strip(): command_remainders = [ cmd + ";" + rest_after_bracket for cmd in commands_list ] else: command_remainders = [cmd + "." for cmd in commands_list] assert serapi_instance.isValidCommand(command_remainders[0]), \ f"\"{command_remainders[0]}\" is not a valid command" command_batch.insert(0, command_remainders[0]) if coq.count_fg_goals() > 1: for command in command_remainders[1:]: assert serapi_instance.isValidCommand(command), \ f"\"{command}\" is not a valid command" pending_commands_stack.append(command_remainders[1:]) coq.run_stmt("{") yield indentation + "{" else: if coq.count_fg_goals() > 0: assert serapi_instance.isValidCommand(rest), \ f"\"{rest}\" is not a valid command, from {command}" command_batch.insert(0, rest) if coq.count_fg_goals() > 1: assert serapi_instance.isValidCommand(rest), \ f"\"{rest}\" is not a valid command, from {command}" pending_commands_stack.append(rest) coq.run_stmt("{") yield indentation + "{" elif coq.count_fg_goals() > 0: coq.run_stmt(command) indentation = " " * (len(pending_commands_stack) + 1) if command.strip() != "Proof." else "" yield indentation + command.strip() if coq.count_fg_goals() > 1: pending_commands_stack.append(None) coq.run_stmt("{") yield indentation + "{" pass