-(* Find the goal which matches the given tactic and run it.
- * cargs is a list of parameters (all constants).
- *)
-and run_tactic env loc tactic cargs =
- (* This is used to print the tactic in debug and error messages only. *)
- let debug_tactic =
- Ast.string_expr ()
- (Ast.ETacticCtor (loc, tactic,
- List.map (fun c -> Ast.EConstant (loc, c)) cargs)) in
- Cmdline.debug "%a: running tactic %s" Ast.string_loc loc debug_tactic;
-
- (* Find all goals in the environment. Returns a list of (name, goal). *)
- let goals =
- let env = Ast.Env.bindings env in
- filter_map
- (function
- | name, Ast.EGoalDefn (loc, goal) -> Some (name, goal)
- | _ -> None) env in
-
- (* Find all patterns. Returns a list of (pattern, name, goal). *)
- let patterns : (Ast.pattern * Ast.id * Ast.goal) list =
- List.flatten
- (List.map (fun (name, ((_, patterns, _, _) as goal)) ->
- List.map (fun pattern -> (pattern, name, goal)) patterns) goals) in
-
- (* Find any patterns (ie. tactics) which match the one we
- * are searching for. This returns a binding for the goal args,
- * so we end up with a list of (pattern, name, goal, args).
- *)
- let patterns : (Ast.pattern * Ast.id * Ast.goal * Ast.expr list) list =
- filter_map (
- fun (pattern, name, ((params, _, _, _) as goal)) ->
- match matching_pattern env loc tactic cargs pattern params with
- | None -> None
- | Some args -> Some (pattern, name, goal, args)
- ) patterns in
-
- match patterns with
- | [] ->
- (* There's no matching goal, but we don't need one if
- * the tactic doesn't need to be rebuilt.
- *)
- let targs = List.map (function Ast.CString s -> [Ast.SString s]) cargs in
- let p = Ast.PTactic (loc, tactic, targs) in
- if needs_rebuild env loc [] [] p then
- failwithf "%a: don't know how to build %s"
- Ast.string_loc loc debug_tactic
-
- | [_, name, goal, args] ->
- (* Single goal matches, run it. *)
- run_goal env loc name args goal []
-
- | goals ->
- (* Two or more goals match. Only one must have a CODE section,
- * and we combine the dependencies into a "supergoal".
- *)
- let with_code, without_code =
- List.partition (
- fun (_, _, (_, _, _, code), _) -> code <> None
- ) goals in
-
- let (_, name, goal, args), extra_deps =
- match with_code with
- | [g] ->
- let extra_deps =
- List.flatten (
- List.map (fun (_, _, (_, _, deps, _), _) -> deps) without_code
- ) in
- (g, extra_deps)
-
- | [] ->
- (* This is OK, it means we'll rebuild all dependencies
- * but there is no code to run. Pick the first goal
- * without code and the dependencies from the other goals.
- *)
- let g = List.hd without_code in
- let extra_deps =
- List.flatten (
- List.map (fun (_, _, (_, _, deps, _), _) -> deps)
- (List.tl without_code)
- ) in
- (g, extra_deps)
-
- | _ :: _ ->
- failwithf "%a: multiple goals found which match tactic %s, but more than one of these goals have {code} sections which is not allowed"
- Ast.string_loc loc debug_tactic in
-
- run_goal env loc name args goal extra_deps
-
-(* Test if pattern matches *tactic(cargs). If it does
- * then we return Some args where args is the arguments that must
- * be passed to the matching goal. The params parameter is
- * the names of the parameters of that goal.
- *)
-and matching_pattern env loc tactic cargs pattern params =
- match pattern with
- | Ast.PTactic (loc, ttactic, targs)
- when tactic <> ttactic ||
- List.length cargs <> List.length targs ->
- None (* Can't possibly match if tactic name or #args is different. *)
- | Ast.PTactic (loc, ttactic, targs) ->
- (* Do the args match with a possible params binding? *)
- try Some (matching_params env loc params targs cargs)
- with Not_found -> None
-
-(* Return a possible binding. For example the goal is:
- * goal compile (name) = "%name.o": "%name.c" {}
- * which means that params = ["name"] and targs = ["%name.o"].
- *
- * If we are called with cargs = ["file1.o"], we would
- * return ["file1"].
- *
- * On non-matching this raises Not_found.
- *)
-and matching_params env loc params targs cargs =
- (* This is going to record the resulting binding. *)
- let res = ref Ast.Env.empty in
- List.iter2 (matching_param env loc params res) targs cargs;