Implement inequality operator (use: != or <>)
[whenjobs.git] / lib / whenexpr.ml
index f24e9ed..1301e5e 100644 (file)
@@ -41,12 +41,14 @@ type whenexpr =
   | Expr_eq of whenexpr * whenexpr
   | Expr_ge of whenexpr * whenexpr
   | Expr_gt of whenexpr * whenexpr
+  | Expr_ne of whenexpr * whenexpr
   | Expr_not of whenexpr
   | Expr_add of whenexpr * whenexpr
   | Expr_sub of whenexpr * whenexpr
   | Expr_mul of whenexpr * whenexpr
   | Expr_div of whenexpr * whenexpr
   | Expr_mod of whenexpr * whenexpr
+  | Expr_len of whenexpr
   | Expr_changes of string
   | Expr_increases of string
   | Expr_decreases of string
@@ -105,6 +107,31 @@ let rpc_of_variable = function
 
 type variables = variable StringMap.t
 
+type preinfo = {
+  pi_job_name : string;
+  pi_serial : Big_int.big_int;
+  pi_variables : (string * variable) list;
+  pi_running : preinfo_running_job list;
+}
+and preinfo_running_job = {
+  pirun_job_name : string;
+  pirun_serial : Big_int.big_int;
+  pirun_start_time : float;
+  pirun_pid : int;
+}
+
+type result = {
+  res_job_name : string;
+  res_serial : Big_int.big_int;
+  res_code : int;
+  res_tmpdir : string;
+  res_output : string;
+  res_start_time : float;
+}
+
+type pre = preinfo -> bool
+type post = result -> unit
+
 type job_cond =
   | When_job of whenexpr
   | Every_job of periodexpr
@@ -112,6 +139,8 @@ type job_cond =
 type job = {
   job_loc : Loc.t;
   job_name : string;
+  job_pre : pre option;
+  job_post : post option;
   job_cond : job_cond;
   job_script : shell_script;
 }
@@ -184,6 +213,9 @@ and expr_of_iexpr _loc = function
   | IExpr_app (">", exprs) ->
     two_params _loc ">" exprs (fun e1 e2 -> Expr_gt (e1, e2))
 
+  | IExpr_app (("!="|"<>"), exprs) ->
+    two_params _loc "<>" exprs (fun e1 e2 -> Expr_ne (e1, e2))
+
   | IExpr_app ("!", exprs) ->
     one_param _loc "!" exprs (fun e1 -> Expr_not e1)
 
@@ -202,6 +234,9 @@ and expr_of_iexpr _loc = function
   | IExpr_app ("mod", exprs) ->
     two_params _loc "+" exprs (fun e1 e2 -> Expr_mod (e1, e2))
 
+  | IExpr_app (("len"|"length"|"size"), exprs) ->
+    one_param _loc "len" exprs (fun e1 -> Expr_len e1)
+
   | IExpr_app (("change"|"changes"|"changed"), [IExpr_var v]) ->
     Expr_changes v
 
@@ -263,6 +298,8 @@ let rec string_of_whenexpr = function
     sprintf "%s >= %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
   | Expr_gt (e1, e2) ->
     sprintf "%s > %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
+  | Expr_ne (e1, e2) ->
+    sprintf "%s <> %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
   | Expr_not e -> sprintf "! %s" (string_of_whenexpr e)
   | Expr_add (e1, e2) ->
     sprintf "%s + %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
@@ -274,6 +311,7 @@ let rec string_of_whenexpr = function
     sprintf "%s / %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
   | Expr_mod (e1, e2) ->
     sprintf "%s mod %s" (string_of_whenexpr e1) (string_of_whenexpr e2)
+  | Expr_len e -> sprintf "len %s" (string_of_whenexpr e)
   | Expr_changes v -> sprintf "changes %s" v
   | Expr_increases v -> sprintf "increases %s" v
   | Expr_decreases v -> sprintf "decreases %s" v
@@ -304,13 +342,15 @@ let rec dependencies_of_whenexpr = function
   | Expr_eq (e1, e2)
   | Expr_ge (e1, e2)
   | Expr_gt (e1, e2)
+  | Expr_ne (e1, e2)
   | Expr_add (e1, e2)
   | Expr_sub (e1, e2)
   | Expr_mul (e1, e2)
   | Expr_div (e1, e2)
   | Expr_mod (e1, e2) ->
     dependencies_of_whenexpr e1 @ dependencies_of_whenexpr e2
-  | Expr_not e ->
+  | Expr_not e
+  | Expr_len e ->
     dependencies_of_whenexpr e
   | Expr_changes v
   | Expr_increases v
@@ -386,6 +426,14 @@ let rec eval_whenexpr variables prev_variables onload = function
     else
       T_bool false
 
+  | Expr_ne (e1, e2) ->
+    let e1 = eval_whenexpr variables prev_variables onload e1
+    and e2 = eval_whenexpr variables prev_variables onload e2 in
+    if compare_values e1 e2 <> 0 then
+      T_bool true
+    else
+      T_bool false
+
   | Expr_not e ->
     if not (eval_whenexpr_as_bool variables prev_variables onload e) then
       T_bool true
@@ -417,6 +465,11 @@ let rec eval_whenexpr variables prev_variables onload = function
     and e2 = eval_whenexpr variables prev_variables onload e2 in
     mod_values e1 e2
 
+  | Expr_len e ->
+    let e = eval_whenexpr variables prev_variables onload e in
+    let e = string_of_variable e in
+    T_int (big_int_of_int (String.length e))
+
   | Expr_changes v ->
     let prev_value, curr_value = get_prev_curr_value variables prev_variables v in
     if compare_values prev_value curr_value <> 0 then
@@ -605,3 +658,22 @@ let next_periodexpr =
     let t0 = Date.make 1970 1 1 in
     let t' = Date.add t0 (Date.Period.month months) in
     Date.to_unixfloat t'
+
+let check_valid_variable_name name =
+  (* Don't permit certain names. *)
+  if name = "JOBSERIAL" then
+    failwith "JOBSERIAL variable cannot be set";
+
+  let len = String.length name in
+  if len = 0 then
+    failwith "variable name is an empty string";
+  if name.[0] <> '_' && not (isalpha name.[0]) then
+    failwith "variable name must start with alphabetic character or underscore";
+
+  let rec loop i =
+    if i >= len then ()
+    else if name.[i] <> '_' && not (isalnum name.[i]) then
+      failwith "variable name contains non-alphanumeric non-underscore character"
+    else loop (i+1)
+  in
+  loop 1