Source file keyword_lexer.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
open Base
open Liquid_syntax
open Syntax
open Tools

let is_operator = function
  | "==" | ">=" | ">" | "<=" | "<" | "!=" | "<>" -> true
  | _ -> false

let lex_keyword text =
  let keywords =
    [ ("elsif", ElseIf)
    ; ("else", Else)
    ; ("if", If)
    ; ("endif", EndIf)
    ; ("unless", Unless)
    ; ("endunless", EndUnless)
    ; ("case", Case)
    ; ("endcase", EndCase)
    ; ("raw", Raw)
    ; ("endraw", EndRaw)
    ; ("when", When)
    ; ("with", LexWith)

    ; ("form", LexForm)
    ; ("endform", LexEndForm)
    ; ("style", LexStyle)
    ; ("endstyle", LexEndStyle)

    ; ("for", LexFor)
    ; ("endfor", LexEndFor)
    ; ("capture", Capture)
    ; ("endcapture", EndCapture)

    ; ("break", LexBreak)
    ; ("continue", LexContinue)
    ; ("cycle", Cycle)
    ; ("tablerow", TableRow)
    ; ("endtablerow", EndTableRow)

    ; ("paginate", Paginate)
    ; ("endpaginate", EndPaginate)

    ; ("assign", Assign)
    ; ("increment", Increment)
    ; ("decrement", Decrement)

    ; ("include", LexInclude)
    ; ("layout", LexLayout)
    ; ("render", LexRender)
    ; ("section", LexSection)

    ; ("in", In)
    ; ("by", By)
    ; ("as", LexAs)

    ; ("==", Operator Eq)
    ; (">=", Operator Gte)
    ; (">", Operator Gt)
    ; ("<=", Operator Lte)
    ; ("<", Operator Lt)
    ; ("!=", Operator Ne)
    ; ("<>", Operator Ne)
    ; ("contains", Operator Contains)
    ; ("and", LexCombiner LexAnd)
    ; ("or", LexCombiner LexOr)

    ; (":", Colon)
    ; ("|", Pipe)
    ; ("=", Equals)
    ; (",", Comma)
    ; (" ", Space)
    ; ("\n", Newline)

    ; ("nil", LexValue LexNil)
    ; ("blank", LexValue LexBlank)
    ; ("none", LexNone)
  ] in

  if text = " " || text = "\n" then
    None
  else begin
    (* words need a space, newline or eos (example: aspen != Keyword(As) Id(Pen)) *)
    let finder (check_literal, _) =
      if String.length check_literal = 1 || is_operator check_literal then
        starts_with text check_literal
      else
        starts_with text (check_literal ^ " ") || starts_with text (check_literal ^ "\n") || text = check_literal ^ " "
    in

    let found_keyword = List.find keywords ~f:finder in
    match found_keyword with
    | Some (literal, token) ->
      let trimmed = remove_prefix text literal in
      Some (token, trimmed)
    | None -> None
  end

let block_token_of_string = function
  | "{%" -> StatementStart White
  | "%}" -> StatementEnd White
  | "{{" -> ExpressionStart White
  | "}}" -> ExpressionEnd White
  | "{%-" -> StatementStart Trim
  | "-%}" -> StatementEnd Trim
  | "{{-" -> ExpressionStart Trim
  | "-}}" -> ExpressionEnd Trim
  | other -> RawText other

let is_block_token_string t =
  match block_token_of_string t with
  | StatementStart _ | StatementEnd _ | ExpressionStart _ | ExpressionEnd _ -> true
  | _ -> false

let is_block_token_whitespace_string t =
  String.is_substring t ~substring:"-" && is_block_token_string t