Skip to content

Commit 0dd022c

Browse files
author
Armael
committed
Keep track of locations in the AST
1 parent a641057 commit 0dd022c

File tree

5 files changed

+119
-67
lines changed

5 files changed

+119
-67
lines changed

lib/mustache.ml

+41-36
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@
2222
open MoreLabels
2323
include Mustache_types
2424

25+
let dummy_loc = {
26+
loc_start = Lexing.dummy_pos;
27+
loc_end = Lexing.dummy_pos;
28+
}
29+
2530
module List = ListLabels
2631
module String = StringLabels
2732

2833
module Infix = struct
29-
let (^) y x = Concat [x; y]
34+
let (^) y x = Concat (dummy_loc, [x; y])
3035
end
3136

3237
module Json = struct
@@ -62,30 +67,30 @@ let escape_html s =
6267

6368
let rec pp fmt = function
6469

65-
| String s ->
70+
| String (_, s) ->
6671
Format.pp_print_string fmt s
6772

68-
| Escaped s ->
73+
| Escaped (_, s) ->
6974
Format.fprintf fmt "{{ %s }}" s
7075

71-
| Unescaped s ->
76+
| Unescaped (_, s) ->
7277
Format.fprintf fmt "{{& %s }}" s
7378

74-
| Inverted_section s ->
79+
| Inverted_section (_, s) ->
7580
Format.fprintf fmt "{{^%s}}%a{{/%s}}"
7681
s.name pp s.contents s.name
7782

78-
| Section s ->
83+
| Section (_, s) ->
7984
Format.fprintf fmt "{{#%s}}%a{{/%s}}"
8085
s.name pp s.contents s.name
8186

82-
| Partial s ->
87+
| Partial (_, s) ->
8388
Format.fprintf fmt "{{> %s }}" s
8489

85-
| Comment s ->
90+
| Comment (_, s) ->
8691
Format.fprintf fmt "{{! %s }}" s
8792

88-
| Concat s ->
93+
| Concat (_, s) ->
8994
List.iter (pp fmt) s
9095

9196
let to_formatter = pp
@@ -100,26 +105,26 @@ let to_string x =
100105
let rec fold ~string ~section ~escaped ~unescaped ~partial ~comment ~concat t =
101106
let go = fold ~string ~section ~escaped ~unescaped ~partial ~comment ~concat in
102107
match t with
103-
| String s -> string s
104-
| Escaped s -> escaped s
105-
| Unescaped s -> unescaped s
106-
| Comment s -> comment s
107-
| Section { name; contents } ->
108+
| String (_, s) -> string s
109+
| Escaped (_, s) -> escaped s
110+
| Unescaped (_, s) -> unescaped s
111+
| Comment (_, s) -> comment s
112+
| Section (_, { name; contents }) ->
108113
section ~inverted:false name (go contents)
109-
| Inverted_section { name; contents } ->
114+
| Inverted_section (_, { name; contents }) ->
110115
section ~inverted:true name (go contents)
111-
| Concat ms ->
116+
| Concat (_, ms) ->
112117
concat (List.map ms ~f:go)
113-
| Partial p -> partial p
118+
| Partial (_, p) -> partial p
114119

115-
let raw s = String s
116-
let escaped s = Escaped s
117-
let unescaped s = Unescaped s
118-
let section n c = Section { name = n ; contents = c }
119-
let inverted_section n c = Inverted_section { name = n ; contents = c }
120-
let partial s = Partial s
121-
let concat t = Concat t
122-
let comment s = Comment s
120+
let raw s = String (dummy_loc, s)
121+
let escaped s = Escaped (dummy_loc, s)
122+
let unescaped s = Unescaped (dummy_loc, s)
123+
let section n c = Section (dummy_loc, { name = n ; contents = c })
124+
let inverted_section n c = Inverted_section (dummy_loc, { name = n ; contents = c })
125+
let partial s = Partial (dummy_loc, s)
126+
let concat t = Concat (dummy_loc, t)
127+
let comment s = Comment (dummy_loc, s)
123128

124129
let rec expand_partials =
125130
let section ~inverted =
@@ -176,37 +181,37 @@ let render_fmt ?(strict=true) (fmt : Format.formatter) (m : t) (js : Json.t) =
176181

177182
let rec render' m (js : Json.value) = match m with
178183

179-
| String s ->
184+
| String (_, s) ->
180185
Format.pp_print_string fmt s
181186

182-
| Escaped "." ->
187+
| Escaped (_, ".") ->
183188
Format.pp_print_string fmt (escape_html (Lookup.scalar js))
184-
| Escaped key ->
189+
| Escaped (_, key) ->
185190
Format.pp_print_string fmt (escape_html (Lookup.str ~strict ~key js))
186191

187-
| Unescaped "." ->
192+
| Unescaped (_, ".") ->
188193
Format.pp_print_string fmt (Lookup.scalar js)
189-
| Unescaped key ->
194+
| Unescaped (_, key) ->
190195
Format.pp_print_string fmt (Lookup.str ~strict ~key js)
191196

192-
| Inverted_section s ->
197+
| Inverted_section (loc, s) ->
193198
if Lookup.inverted js s.name
194-
then render' (Section s) js
199+
then render' (Section (loc, s)) js
195200

196-
| Section s ->
201+
| Section (_, s) ->
197202
begin match Lookup.section ~strict js ~key:s.name with
198203
| `Bool false -> ()
199204
| `Bool true -> render' s.contents js
200205
| `A contexts -> List.iter (render' s.contents) contexts
201206
| context -> render' s.contents context
202207
end
203208

204-
| Partial _ ->
209+
| Partial (_, _) ->
205210
pp fmt m
206211

207-
| Comment c -> ()
212+
| Comment (_, c) -> ()
208213

209-
| Concat templates ->
214+
| Concat (_, templates) ->
210215
List.iter (fun x -> render' x js) templates
211216

212217
in render' m (Json.value js)

lib/mustache.mli

+23-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,29 @@ module Json : sig (** Compatible with Ezjsonm *)
2020
| `O of (string * value) list ]
2121
end
2222

23-
type t
23+
type loc = {
24+
loc_start: Lexing.position;
25+
loc_end: Lexing.position;
26+
}
27+
28+
type t =
29+
| String of loc * string
30+
| Escaped of loc * string
31+
| Section of loc * section
32+
| Unescaped of loc * string
33+
| Partial of loc * string
34+
| Inverted_section of loc * section
35+
| Concat of loc * t list
36+
| Comment of loc * string
37+
38+
and section = {
39+
name: string;
40+
contents: t;
41+
}
42+
43+
(** A value of type [loc], guaranteed to be different from any valid
44+
location. *)
45+
val dummy_loc : loc
2446

2547
(** Read *)
2648
val parse_lx : Lexing.lexbuf -> t

lib/mustache_lexer.mll

+27-12
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,42 @@
2323
open Lexing
2424
open Mustache_parser
2525
open Mustache_types
26+
27+
let with_space space f lexbuf =
28+
let start_p = lexbuf.Lexing.lex_start_p in
29+
let () = space lexbuf in
30+
let x = f lexbuf in
31+
space lexbuf;
32+
lexbuf.Lexing.lex_start_p <- start_p;
33+
x
2634
}
2735

28-
let space = [' ' '\t' '\n']*
36+
let blank = [' ' '\t']*
37+
let newline = ('\n' | "\r\n")
38+
let raw = [^ '{' '}' '\n']*
2939
let id = ['a'-'z' 'A'-'Z' '_' '/'] ['a'-'z' 'A'-'Z' '0'-'9' '_' '/']+
3040

31-
rule ident = parse
32-
| space '.' space { "." }
33-
| space (id as x) space { x }
41+
rule space = parse
42+
| blank newline { new_line lexbuf; space lexbuf }
43+
| blank { () }
44+
45+
and ident = parse
46+
| '.' { "." }
47+
| (id as x) { x }
3448
| _ { raise (Invalid_template "Invalid section") }
3549

3650
and mustache = parse
37-
| "{{{" { UNESCAPE_START (ident lexbuf) }
38-
| "{{&" { UNESCAPE_START_AMPERSAND (ident lexbuf) }
39-
| "{{#" { SECTION_START (ident lexbuf) }
40-
| "{{^" { SECTION_INVERT_START (ident lexbuf) }
41-
| "{{/" { SECTION_END (ident lexbuf) }
42-
| "{{>" { PARTIAL_START (ident lexbuf) }
51+
| "{{{" { UNESCAPE_START (with_space space ident lexbuf) }
52+
| "{{&" { UNESCAPE_START_AMPERSAND (with_space space ident lexbuf) }
53+
| "{{#" { SECTION_START (with_space space ident lexbuf) }
54+
| "{{^" { SECTION_INVERT_START (with_space space ident lexbuf) }
55+
| "{{/" { SECTION_END (with_space space ident lexbuf) }
56+
| "{{>" { PARTIAL_START (with_space space ident lexbuf) }
4357
| "{{!" { COMMENT_START }
44-
| "{{" { ESCAPE_START (ident lexbuf) }
58+
| "{{" { ESCAPE_START (with_space space ident lexbuf) }
4559
| "}}}" { UNESCAPE_END }
4660
| "}}" { END }
47-
| [^ '{' '}']* { RAW (lexeme lexbuf) }
61+
| raw newline { new_line lexbuf; RAW (lexeme lexbuf) }
62+
| raw { RAW (lexeme lexbuf) }
4863
| ['{' '}'] { RAW (lexeme lexbuf) }
4964
| eof { EOF }

lib/mustache_parser.mly

+14-10
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
let msg =
3030
Printf.sprintf "Mismatched section %s with %s" start_s end_s in
3131
raise (Invalid_template msg)
32+
33+
let loc () =
34+
{ loc_start = Parsing.symbol_start_pos ();
35+
loc_end = Parsing.symbol_end_pos () }
3236
%}
3337

3438
%token EOF
@@ -51,19 +55,19 @@
5155
%%
5256

5357
section:
54-
| SECTION_INVERT_START END mustache SECTION_END END { Inverted_section (parse_section $1 $4 $3) }
55-
| SECTION_START END mustache SECTION_END END { Section (parse_section $1 $4 $3) }
58+
| SECTION_INVERT_START END mustache SECTION_END END { Inverted_section (loc (), parse_section $1 $4 $3) }
59+
| SECTION_START END mustache SECTION_END END { Section (loc (), parse_section $1 $4 $3) }
5660

5761
mustache_element:
58-
| UNESCAPE_START UNESCAPE_END { Unescaped $1 }
59-
| UNESCAPE_START_AMPERSAND END { Unescaped $1 }
60-
| ESCAPE_START END { Escaped $1 }
61-
| PARTIAL_START END { Partial $1 }
62-
| COMMENT_START RAW END { Comment $2 }
62+
| UNESCAPE_START UNESCAPE_END { Unescaped (loc (), $1) }
63+
| UNESCAPE_START_AMPERSAND END { Unescaped (loc (), $1) }
64+
| ESCAPE_START END { Escaped (loc (), $1) }
65+
| PARTIAL_START END { Partial (loc (), $1) }
66+
| COMMENT_START RAW END { Comment (loc (), $2) }
6367
| section { $1 }
6468

6569
string:
66-
| RAW { String $1 }
70+
| RAW { String (loc (), $1) }
6771

6872
mustache_l:
6973
| mustache_element mustache_l { ($1 :: $2) }
@@ -75,8 +79,8 @@ mustache:
7579
| mustache_l {
7680
match $1 with
7781
| [x] -> x
78-
| x -> Concat x
82+
| x -> Concat (loc (), x)
7983
}
80-
| EOF { String "" }
84+
| EOF { String (loc (), "") }
8185

8286
%%

lib/mustache_types.ml

+14-8
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2020
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2121
IN THE SOFTWARE. }}}*)
22+
23+
type loc = {
24+
loc_start: Lexing.position;
25+
loc_end: Lexing.position;
26+
}
27+
2228
type t =
23-
| String of string
24-
| Escaped of string
25-
| Section of section
26-
| Unescaped of string
27-
| Partial of string
28-
| Inverted_section of section
29-
| Concat of t list
30-
| Comment of string
29+
| String of loc * string
30+
| Escaped of loc * string
31+
| Section of loc * section
32+
| Unescaped of loc * string
33+
| Partial of loc * string
34+
| Inverted_section of loc * section
35+
| Concat of loc * t list
36+
| Comment of loc * string
3137
and section = {
3238
name: string;
3339
contents: t;

0 commit comments

Comments
 (0)