Source file syntax.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
110
111
open Base
include Tokens

module LiquidObject =
  struct
    type t = string
    let compare = String.compare
  end

module Object = Stdlib.Map.Make(LiquidObject)

let obj_as_list obj =
  Object.to_seq obj
  |> Stdlib.Seq.fold_left (fun acc curr -> acc @ [curr]) []


module VariableContext =
  struct
    type t = string
    let compare = String.compare
  end

module Ctx = Stdlib.Map.Make(VariableContext)

let idf id = String.split id ~on:'.'

type id = string list

type value =
  | Bool of bool
  | String of string
  | Number of float
  | Var of string list
  | List of value list
  | Date of Date.t
  | Object of liquid_object
  | Nil
and liquid_object = value Object.t

type variable_context = value Ctx.t

type expression =
  | Value of value
  | Func of string * expression list

type operator_equation = value * operator * value

type combiner = And | Or
type condition =
  | Combine of combiner * condition * condition
  | Equation of operator_equation
  | IsTruthy of value
  | Not of condition
  | Always of bool

type for_params =
  { limit : int
  ; offset : int
  ; reved : bool
  ; cols : int
  ; is_tablerow : bool
  }

type ast =
  | Capture of string * ast
  | Block of ast list
  | Test of condition * ast * (ast option)
  | For of string * value * for_params * ast * (ast option)
  | Cycle of string option * string list
  | Expression of expression
  | Assignment of string * expression
  | Text of string
  | Break
  | Continue
  | Layout of string option
  | Include of string
  | Section of string
  | Render of string * variable_context * ast option
  | Paginate of id * int * ast
  | Nothing

let list_of_range = function
  | LexRange (start, stop) -> Batteries.(--) start stop |> Batteries.List.of_enum
  | _ -> raise (Failure "This is not a range!")

let liq_list_of_range r = List (
  List.map (list_of_range r) ~f:(fun n -> Number (Int.to_float n))
)

let lex_value_to_value = function
  | LexId id -> Var id
  | LexBool b -> Bool b
  | LexString s -> String s
  | LexNumber n -> Number n
  | LexRange (st, sp) -> liq_list_of_range (LexRange (st, sp))
  | LexNil -> Nil
  | LexBlank -> String ""

let for_params_default =
  { limit = 50
  ; offset = 0
  ; reved = false
  ; cols = 10
  ; is_tablerow = false
  }

type liquid_filter = variable_context -> value list -> (value, string) Result.t
type liquid_filter_lookup = string -> liquid_filter option

let liquid_int i = Number (Int.to_float i)
let liquid_float i = Number i
let pack_object obj = Object obj