package liquid_parser

  1. Overview
  2. Docs

Source file for.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
112
113
114
115
116
117
open Base
open Liquid_syntax
open Tools
open Syntax
open Parser_tools

type for_type = ForLoop | TableRow

let parse_forlike for_type block_parser tokens =
  let kw, is_tablerow =
    if for_type = ForLoop then (Tokens.LexFor, false) else (TableRow, true)
  in
  let do_for lid lex_val tl ~params =
    let id = join lid in
    let value = lex_value_to_value lex_val in

    let ts = [ kw ] @ tl in
    let bounds = Bounds.find_bounds ts 0 in
    let chunks = bounds |> Bounds.bounds_to_chunks ts in
    let stop_point = Bounds.stop_point_from_bounds bounds in
    let rest = sub_list_suffix ts stop_point in

    match List.length chunks with
    | 1 ->
        let for_loop = For (id, value, params, block_parser tl, None) in
        Some (for_loop, rest)
    | 2 ->
        let bchunk = nth chunks 0 in
        let body_chunk = List.tl_exn bchunk in
        let else_chunk = List.tl_exn (nth chunks 1) in
        Debug.print_lex_tokens_with_index else_chunk;
        let for_loop =
          For
            ( id
            , value
            , params
            , block_parser body_chunk
            , Some (block_parser else_chunk) )
        in
        Some (for_loop, rest)
    | _ ->
        raise (Failure "A for loop can only have a body and an else statement")
  in

  match tokens with
  | st :: LexValue (LexId id) :: In :: LexValue lex_val :: EOS :: tl
    when st = kw ->
      do_for id lex_val tl ~params:for_params_default
  | st :: LexValue (LexId id) :: In :: LexValue lex_val :: tl when st = kw ->
      let params, rest = scan_until_eos tl in
      let param_folder found = function
        | LexValue (LexId [ "reversed" ]) :: ptl ->
            Next
              ( {
                  limit = found.limit
                ; offset = found.offset
                ; reved = true
                ; cols = found.cols
                ; is_tablerow
                }
              , ptl )
        | LexValue (LexId [ "offset" ])
          :: Colon
          :: LexValue (LexNumber n)
          :: ptl ->
            Next
              ( {
                  limit = found.limit
                ; offset = Float.to_int n
                ; reved = found.reved
                ; cols = found.cols
                ; is_tablerow
                }
              , ptl )
        | LexValue (LexId [ "limit" ]) :: Colon :: LexValue (LexNumber n) :: ptl
          ->
            Next
              ( {
                  limit = Float.to_int n
                ; offset = found.offset
                ; reved = found.reved
                ; cols = found.cols
                ; is_tablerow
                }
              , ptl )
        | LexValue (LexId [ "cols" ]) :: Colon :: LexValue (LexNumber n) :: ptl
          ->
            Next
              ( {
                  limit = found.limit
                ; offset = found.offset
                ; reved = found.reved
                ; cols = Float.to_int n
                ; is_tablerow
                }
              , ptl )
        | _ -> Stop found
      in

      let params = unfold for_params_default params param_folder in

      do_for id lex_val rest ~params
  | _ -> None

let parse_for = parse_forlike ForLoop
let parse_tablerow = parse_forlike TableRow

let parse_paginate block_parser = function
  | Tokens.Paginate
    :: LexValue (LexId id)
    :: By
    :: LexValue (LexNumber num)
    :: tl ->
      let body, rest = parse_single_body Tokens.Paginate tl in
      let page = Paginate (id, Float.to_int num, block_parser body) in
      Some (page, rest)
  | _ -> None