Source file template_expr.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
open Dec_template
exception Invalid_expr of string
let rec eval ~context = function
| Expr.Var name ->
(match Hashtbl.find_opt context name with
| Some var ->
var
| None ->
raise
(Invalid_expr
(Printf.sprintf "The context variable is missing: %s" name)))
| Expr.Function fn ->
eval_fn fn ~context
| Expr.String s ->
s
and eval_fn ~context =
let eval = eval ~context in
let to_bool = to_bool ~context in
function
| Expr.If (e1, e2, e3) ->
let e1 = to_bool e1 in
if e1 then eval e2 else eval e3
| Expr.And (e1, e2) ->
let e1 = to_bool e1 in
let e2 = to_bool e2 in
(e1 && e2) |> Bool.to_string
| Expr.Or (e1, e2) ->
let e1 = to_bool e1 in
let e2 = to_bool e2 in
(e1 || e2) |> Bool.to_string
| Expr.Eq (e1, e2) ->
let e1 = eval e1 in
let e2 = eval e2 in
String.equal e1 e2 |> Bool.to_string
| Expr.Neq (e1, e2) ->
let e1 = eval e1 in
let e2 = eval e2 in
(not (String.equal e1 e2)) |> Bool.to_string
| Expr.Not e ->
let e = to_bool e in
(not e) |> Bool.to_string
| Expr.Slugify e ->
let e = eval e in
Helpers.slugify e
| Expr.Upper e ->
let e = eval e in
String.uppercase_ascii e
| Expr.Lower e ->
let e = eval e in
String.lowercase_ascii e
| Expr.Snake_case e ->
let e = eval e in
Helpers.snake_case e
| Expr.Camel_case e ->
let e = eval e in
Helpers.camel_case e
| Expr.Trim e ->
let e = eval e in
String.trim e
| Expr.First_char e ->
let e = eval e in
String.prefix e 1
| Expr.Last_char e ->
let e = eval e in
String.suffix e 1
| Expr.Run (cmd, args) ->
let cmd = eval cmd in
let args = List.fold_left (fun acc arg -> eval arg :: acc) [] args in
(match Spawn.exec cmd (List.rev args) with Ok () -> "false" | _ -> "true")
| Expr.Concat l ->
let l = List.fold_left (fun acc arg -> eval arg :: acc) [] l in
String.concat "" (List.rev l)
and to_bool ~context expr =
let e = eval expr ~context in
try bool_of_string e with
| Invalid_expr _ as e ->
raise e
| _ ->
raise (Invalid_expr "The expression cannot be evaluated to a boolean")
let to_result ~context f expr =
try f ~context expr |> Result.ok with
| Invalid_expr reason ->
Error (Spin_error.failed_to_generate reason)
| _ ->
Error
(Spin_error.failed_to_generate
"Failed to evaluate an expression for unknown reason")
let filter_map ~context ~condition f l =
let open Result.Syntax in
List.fold_right
(fun el acc ->
let* acc = acc in
match condition el with
| None ->
Result.ok (f el :: acc)
| Some expr ->
let+ result = to_result to_bool expr ~context in
if result then
f el :: acc
else
acc)
l
(Result.ok [])