From 4d0527cd7ced1d96720e3af56da29a19551944f7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 22 Dec 2019 18:17:06 +0000 Subject: [PATCH] Command line parsing of anon args. --- src/Makefile.in | 14 ++++++------ src/ast.mli | 22 +++++++++---------- src/eval.ml | 21 ++++++++++++++++++ src/eval.mli | 22 +++++++++++++++++++ src/main.ml | 67 +++++++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 src/eval.ml create mode 100644 src/eval.mli diff --git a/src/Makefile.in b/src/Makefile.in index 1b838b1..d3e21fc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -22,6 +22,7 @@ OBJECTS = \ parser.cmx \ lexer.cmx \ parse.cmx \ + eval.cmx \ main.cmx all: goals @@ -32,17 +33,18 @@ clean: rm -f parser.ml parser.mli lexer.ml parser.conflicts stamp-parser rm -f goals -goals: $(OBJECTS) - @OCAMLFIND@ opt $^ -o $@ - +OCAMLPACKAGES = -package str,unix OCAMLFLAGS = -g -safe-string -warn-error CDEFLMPSUVYZX+52-3 +goals: $(OBJECTS) + @OCAMLFIND@ opt $(OCAMLFLAGS) $(OCAMLPACKAGES) -linkpkg $^ -o $@ + %.cmi: %.mli - @OCAMLFIND@ c $(OCAMLFLAGS) -c $< -o $@ + @OCAMLFIND@ c $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ %.cmo: %.ml - @OCAMLFIND@ c $(OCAMLFLAGS) -c $< -o $@ + @OCAMLFIND@ c $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ %.cmx: %.ml - @OCAMLFIND@ opt $(OCAMLFLAGS) -c $< -o $@ + @OCAMLFIND@ opt $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@ parser.ml parser.mli: stamp-parser stamp-parser: parser.mly diff --git a/src/ast.mli b/src/ast.mli index 6179fb4..e2189cf 100644 --- a/src/ast.mli +++ b/src/ast.mli @@ -19,34 +19,34 @@ type file = stmt list and stmt = - (* let id = expr *) + (** let id = expr *) | Let of id * expr - (* goal id (params) = patterns : exprs = code *) + (** goal id (params) = patterns : exprs = code *) | Goal of id * id list * pattern list * expr list * code option and pattern = - (* match tactic such as file ("filename") *) + (** match tactic such as file ("filename") *) | PTactic of id * substs list - (* match named variable, which must be a string or list *) + (** match named variable, which must be a string or list *) | PVarSubst of id and expr = - (* goalname (params), tactic (params) etc. *) + (** goalname (params), tactic (params) etc. *) | ECall of id * expr list - (* variable *) + (** variable *) | EVar of id - (* string with %-substitutions *) + (** string with %-substitutions *) | EString of substs - (* list *) + (** list *) | EList of expr list and id = string and code = substs and substs = subst list and subst = - (* String literal part. *) + (** String literal part. *) | SString of string - (* %-substitution. *) + (** %-substitution. *) | SVar of id -(* This is used for incrementally building Ast.substs in the parser. *) +(** This is used for incrementally building Ast.substs in the parser. *) module Substs : sig type t val create : unit -> t diff --git a/src/eval.ml b/src/eval.ml new file mode 100644 index 0000000..1df1a17 --- /dev/null +++ b/src/eval.ml @@ -0,0 +1,21 @@ +(* Goalfile evaluation + * Copyright (C) 2019 Richard W.M. Jones + * Copyright (C) 2019 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +let evaluate file vars exprs = + () diff --git a/src/eval.mli b/src/eval.mli new file mode 100644 index 0000000..2e55981 --- /dev/null +++ b/src/eval.mli @@ -0,0 +1,22 @@ +(* Goalfile evaluation + * Copyright (C) 2019 Richard W.M. Jones + * Copyright (C) 2019 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +val evaluate : Ast.file -> (string, Ast.expr) Hashtbl.t -> Ast.expr list -> unit +(** This drives evaluation of the list of expressions (in parallel) + until they are complete or we reach an error. *) diff --git a/src/main.ml b/src/main.ml index be1baff..2685160 100644 --- a/src/main.ml +++ b/src/main.ml @@ -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=" to assign a value to a variable, or + * "" 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 () -- 1.8.3.1