$`int:stop_line$, $`int:stop_bol$, $`int:stop_off$,
$`bool:ghost$) >>
+(* Convert 'expr option' to an expression that contains the option inside. *)
+let expr_of_option _loc = function
+ | None -> <:expr< None >>
+ | Some e -> <:expr< Some $e$ >>
+
(* "Lift" an expression, turning it from an expression into an OCaml
* abstract syntax tree in the output. This is pretty obscure.
* http://caml.inria.fr/pub/ml-archives/caml-list/2008/09/591f7c4a8df9295d675a5adcb6802748.en.html
let lift_expr = M.Expr.meta_expr
(* Handle a top level statement. *)
-let rec call_stmt name (_loc, stmt, sh) =
- let name = if name <> "" then name else unique_job_name () in
- let name = <:expr< $str:name$ >> in
+let rec call_stmt name cleanup (_loc, stmt, sh) =
+ let name =
+ match name with
+ | None -> let name = unique_job_name () in <:expr< $str:name$ >>
+ | Some name -> name in
+ let cleanup = expr_of_option _loc cleanup in
match stmt with
- | `When e -> when_stmt _loc name e sh
- | `Every p -> every_stmt _loc name p sh
+ | `When e -> when_stmt _loc name cleanup e sh
+ | `Every p -> every_stmt _loc name cleanup p sh
(* Handle a top level "when" statement.
* e -> when expression
* Returns a top level statement (str_item) which when executed just
* adds the statement to a global list.
*)
-and when_stmt _loc name e sh =
+and when_stmt _loc name cleanup e sh =
let loc = expr_of_loc _loc _loc in
let e = lift_expr _loc e in
<:str_item<
open Camlp4.PreCast
- Whenfile.add_when_job $loc$ $name$ $e$ $sh$
+ Whenfile.add_when_job $loc$ $name$ $cleanup$ $e$ $sh$
>>
(* Handle a top level "every" statement. *)
-and every_stmt _loc name period sh =
+and every_stmt _loc name cleanup period sh =
let loc = expr_of_loc _loc _loc in
<:str_item<
open Camlp4.PreCast
- Whenfile.add_every_job $loc$ $name$ $period$ $sh$
+ Whenfile.add_every_job $loc$ $name$ $cleanup$ $period$ $sh$
>>
let () =
(* Convert ">\>" to ">>" in code. *)
let sh = replace_str sh ">\\>" ">>" in
- <:expr< { Whenutils.sh_loc = $loc$;
+ <:expr< { Whenexpr.sh_loc = $loc$;
sh_script = $str:sh$ } >>
in
Quotation.add "sh" Quotation.DynAst.expr_tag sh_quotation_expander;
Stream.junk stream;
(match Stream.next stream with
| KEYWORD ("sec"|"secs"|"second"|"seconds"), _ ->
- <:expr< Whenutils.Every_seconds $`int:i$ >>
+ <:expr< Whenexpr.Every_seconds $`int:i$ >>
| KEYWORD ("min"|"mins"|"minute"|"minutes"), _ ->
let i = 60 * i in
- <:expr< Whenutils.Every_seconds $`int:i$ >>
+ <:expr< Whenexpr.Every_seconds $`int:i$ >>
| KEYWORD ("hour"|"hours"), _ ->
let i = 3600 * i in
- <:expr< Whenutils.Every_seconds $`int:i$ >>
+ <:expr< Whenexpr.Every_seconds $`int:i$ >>
| KEYWORD ("day"|"days"), _ ->
- <:expr< Whenutils.Every_days $`int:i$ >>
+ <:expr< Whenexpr.Every_days $`int:i$ >>
| KEYWORD ("week"|"weeks"), _ ->
let i = 7 * i in
- <:expr< Whenutils.Every_days $`int:i$ >>
+ <:expr< Whenexpr.Every_days $`int:i$ >>
| KEYWORD ("month"|"months"), _ ->
- <:expr< Whenutils.Every_months $`int:i$ >>
+ <:expr< Whenexpr.Every_months $`int:i$ >>
| KEYWORD ("year"|"years"), _ ->
- <:expr< Whenutils.Every_years $`int:i$ >>
+ <:expr< Whenexpr.Every_years $`int:i$ >>
| KEYWORD ("decade"|"decades"), _ ->
let i = 10 * i in
- <:expr< Whenutils.Every_years $`int:i$ >>
+ <:expr< Whenexpr.Every_years $`int:i$ >>
| KEYWORD ("century"|"centuries"|"centurys"), _ ->
let i = 100 * i in
- <:expr< Whenutils.Every_years $`int:i$ >>
+ <:expr< Whenexpr.Every_years $`int:i$ >>
| KEYWORD ("millenium"|"millenia"|"milleniums"), _ ->
let i = 1000 * i in
- <:expr< Whenutils.Every_years $`int:i$ >>
+ <:expr< Whenexpr.Every_years $`int:i$ >>
| (KEYWORD s | LIDENT s), _ ->
eprintf "period: failed to parse %d %s\n%!" i s;
raise Stream.Failure
)
| _ -> raise Stream.Failure
)
-
-(*
-(* This hand-written parser looks for "job <name>" before a statement. *)
-let optjob =
- Gram.Entry.of_parser "optjob"
- (fun stream ->
- let info, name =
- match Stream.npeek 2 stream with
- | [ LIDENT "job", info; STRING (_,name), _ ] ->
- Stream.junk stream;
- Stream.junk stream;
- info, name
- | (_, info) :: _ ->
- (* Job is unnamed so generate a unique internal name. *)
- info, unique_job_name ()
- | _ -> assert false in
- let _loc = Gram.token_location info in
- <:expr< $str:name$ >>
- )
-*)
;;
EXTEND Gram
(* A period expression (used in "every"). *)
periodexpr: [
[ ["sec"|"secs"|"second"|"seconds"] ->
- <:expr< Whenutils.Every_seconds 1 >> ]
+ <:expr< Whenexpr.Every_seconds 1 >> ]
| [ ["min"|"mins"|"minute"|"minutes"] ->
- <:expr< Whenutils.Every_seconds 60 >> ]
- | [ ["hour"|"hours"] -> <:expr< Whenutils.Every_seconds 3600 >> ]
- | [ ["day"|"days"] -> <:expr< Whenutils.Every_days 1 >> ]
- | [ ["week"|"weeks"] -> <:expr< Whenutils.Every_days 7 >> ]
- | [ ["month"|"months"] -> <:expr< Whenutils.Every_months 1 >> ]
- | [ ["year"|"years"] -> <:expr< Whenutils.Every_years 1 >> ]
- | [ ["decade"|"decades"] -> <:expr< Whenutils.Every_years 10 >> ]
+ <:expr< Whenexpr.Every_seconds 60 >> ]
+ | [ ["hour"|"hours"] -> <:expr< Whenexpr.Every_seconds 3600 >> ]
+ | [ ["day"|"days"] -> <:expr< Whenexpr.Every_days 1 >> ]
+ | [ ["week"|"weeks"] -> <:expr< Whenexpr.Every_days 7 >> ]
+ | [ ["month"|"months"] -> <:expr< Whenexpr.Every_months 1 >> ]
+ | [ ["year"|"years"] -> <:expr< Whenexpr.Every_years 1 >> ]
+ | [ ["decade"|"decades"] -> <:expr< Whenexpr.Every_years 10 >> ]
| [ ["century"|"centuries"|"centurys"] ->
- <:expr< Whenutils.Every_years 100 >> ]
+ <:expr< Whenexpr.Every_years 100 >> ]
| [ ["millenium"|"millenia"|"milleniums"] ->
- <:expr< Whenutils.Every_years 1000 >> ]
+ <:expr< Whenexpr.Every_years 1000 >> ]
| [ e = period_parser -> e ]
];
+ (* Cleanup function. *)
+ cleanup: [
+ [ "cleanup"; f = expr -> f ]
+ ];
+
(* Top level statements. *)
statement: [
[ "when"; e = expr; ":"; sh = expr ->
(* "str_item" is a top level statement in an OCaml program. *)
str_item: LEVEL "top" [
- [ s = statement -> call_stmt "" s ]
- | [ "job"; name = STRING; s = statement -> call_stmt name s ]
+ [ s = statement -> call_stmt None None s ]
+ | [ "job"; name = expr;
+ cleanup = OPT cleanup;
+ s = statement ->
+ call_stmt (Some name) cleanup s ]
];
END