Command line parsing of anon args.
[goals.git] / src / main.ml
index be1baff..2685160 100644 (file)
@@ -21,11 +21,14 @@ open Printf
 
 open Utils
 
+(* See also "let id" in [lexer.mll]. *)
+let var_regexp = Str.regexp "\\([a-zA-Z_][a-zA-Z0-9_]*\\)=\\(.*\\)"
+
 let usage =
   "\
 goals: Build software.
 
- goals [-f Goalfile] ['var = value' ...] ['target' ...]
+ goals [-f Goalfile] ['var=value' ...] ['target' ...]
 
 For detailed help see goals(1).
 
@@ -52,28 +55,56 @@ let main () =
   (* Parse the input file. *)
   let file = Parse.parse_goalfile filename in
 
-  Ast.print_file stdout file;
-
-  (* Find the target(s) to execute first. *)
-  let initial_targets = ref [] in
-  (* XXX Parse command line anon args here. XXX *)
+  (* Parse the command line anon args.  Each parameter has the
+   * form "name=<expr>" to assign a value to a variable, or
+   * "<expr>" to indicate a target to build.
+   *)
+  let assignments = ref [] in
+  let targets = ref [] in
+  List.iter (
+    fun arg ->
+      if Str.string_match var_regexp arg 0 then ( (* assignment *)
+        let name = Str.matched_group 1 arg in
+        let expr = Parse.parse_cli_expr (Str.matched_group 2 arg) in
+        assignments := Ast.Let (name, expr) :: !assignments
+      )
+      else ( (* target *)
+        let expr = Parse.parse_cli_expr arg in
+        targets := expr :: !targets
+      )
+  ) !args;
 
-  (* If no initial target set on the command line, find
+  (* If no target was set on the command line, find
    * the first goal in the file.
    *)
-  List.iter (
-    function
-    | Ast.Goal (name, [], _, _, _) ->
-       if !initial_targets = [] then
-         initial_targets := Ast.ECall (name, []) :: !initial_targets
-    | Ast.Goal (name, _, _, _, _) ->
-       if !initial_targets = [] then
+  if !targets = [] then (
+    try
+      let first_goal =
+        List.find (function Ast.Goal _ -> true | _ -> false) file in
+      match first_goal with
+      | Ast.Goal (name, [], _, _, _) ->
+         targets := [Ast.ECall (name, [])]
+      | Ast.Goal (name, _, _, _, _) ->
          failwithf "%s: first target ā€˜%sā€™ has parameters and so cannot be used as the default target"
            filename name
-    | _ -> ()
-  ) file;
+      | _ -> assert false
+    with
+      (* Actually this is fine.  If there are no goals we'll do nothing. *)
+      Not_found -> ()
+  );
+
+  let targets = List.rev !targets in
+
+  (* Assignments are simply treated as statements added to the end of
+   * the file (so they override earlier assignments to the same variable,
+   * if any).
+   *)
+  let file = file @ List.rev !assignments in
+
+  (* We start with an empty symbol table. *)
+  let vars = Hashtbl.create 13 in
 
-  let initial_targets = List.rev !initial_targets in
-  ignore initial_targets
+  (* Evaluate the target expressions in turn. *)
+  Eval.evaluate file vars targets
 
 let () = main ()