parser.cmx \
lexer.cmx \
parse.cmx \
+ eval.cmx \
main.cmx
all: goals
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
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
--- /dev/null
+(* 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 =
+ ()
--- /dev/null
+(* 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. *)
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).
(* 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 ()