Skip to content

Commit 1e9357d

Browse files
committed
WIP
1 parent b201e88 commit 1e9357d

File tree

5 files changed

+79
-23
lines changed

5 files changed

+79
-23
lines changed

compiler/bin-js_of_ocaml/compile.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f
5656
match source_map, sm with
5757
| No_sourcemap, _ | _, None -> ()
5858
| ((Inline | File _) as output), Some sm ->
59+
if Debug.find "invariant" () then Source_map.invariant sm;
5960
let urlData =
6061
match output with
6162
| No_sourcemap -> assert false

compiler/lib/source_map.ml

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,29 @@ module Mappings = struct
256256
; ori_col = !ori_col
257257
; ori_name = !ori_name
258258
}
259-
| _ -> invalid_arg "Source_map.mapping_of_string"
259+
| _ -> invalid_arg "Source_map.Mappings.decode_exn"
260260
in
261261
let acc = v :: acc in
262262
if last = stop then last + 1, acc else read_tokens line (last + 1) stop acc
263263
in
264264
(* The binary format encodes lines starting at zero, but
265265
[ori_line] and [gen_line] are 1 based. *)
266266
readline 1 0 []
267+
268+
let invariant ~names:_ ~sources:_ (Uninterpreted str) =
269+
(* We can't check much without decoding (which is expensive) *)
270+
(* Just do very simple checks *)
271+
if not
272+
(String.for_all str ~f:(function
273+
| ';' | ',' -> true
274+
| x -> Vlq64.in_alphabet x))
275+
then invalid_arg "Mappings.invariant"
267276
end
268277

278+
let version_is_valid = function
279+
| 3 -> true
280+
| _ -> false
281+
269282
let rewrite_path path =
270283
if Filename.is_relative path
271284
then path
@@ -463,7 +476,8 @@ module Standard = struct
463476

464477
let of_json (json : Yojson.Raw.t) =
465478
match json with
466-
| `Assoc (("version", `Intlit version) :: rest) when int_of_string version = 3 ->
479+
| `Assoc (("version", `Intlit version) :: rest)
480+
when version_is_valid (int_of_string version) ->
467481
let string name json = Option.map ~f:string_of_stringlit (stringlit name json) in
468482
let file = string "file" rest in
469483
let sourceroot = string "sourceRoot" rest in
@@ -491,7 +505,7 @@ module Standard = struct
491505
| None -> Mappings.empty
492506
| Some s -> Mappings.of_string_unsafe s
493507
in
494-
{ version = int_of_float (float_of_string version)
508+
{ version = int_of_string version
495509
; file
496510
; sourceroot
497511
; names
@@ -504,8 +518,21 @@ module Standard = struct
504518
let to_string m = Yojson.Raw.to_string (json m)
505519

506520
let to_file m file = Yojson.Raw.to_file file (json m)
521+
522+
let invariant
523+
{ version; file = _; sourceroot = _; names; sources_content; sources; mappings } =
524+
if not (version_is_valid version)
525+
then invalid_arg "Source_map.Standard.invariant: invalid version";
526+
match sources_content with
527+
| None -> ()
528+
| Some x ->
529+
if not (List.length sources = List.length x)
530+
then
531+
invalid_arg
532+
"Source_map.Standard.invariant: sources and sourcesContent must have the \
533+
same size";
534+
Mappings.invariant ~names ~sources mappings
507535
end
508-
(* IO *)
509536

510537
module Index = struct
511538
type section =
@@ -564,52 +591,70 @@ module Index = struct
564591
"line"
565592
fields
566593
~errmsg:
567-
"Source_map_io.Index.of_json: field 'line' absent or invalid from \
594+
"Source_map.Index.of_json: field 'line' absent or invalid from \
568595
section"
569596
in
570597
let gen_column =
571598
intlit
572599
"column"
573600
fields
574601
~errmsg:
575-
"Source_map_io.Index.of_json: field 'column' absent or invalid from \
602+
"Source_map.Index.of_json: field 'column' absent or invalid from \
576603
section"
577604
in
578605
{ Offset.gen_line; gen_column }
579-
| _ ->
580-
invalid_arg "Source_map_io.Index.of_json: 'offset' field of unexpected type"
606+
| _ -> invalid_arg "Source_map.Index.of_json: 'offset' field of unexpected type"
581607
in
582608
(match List.assoc "url" json with
583609
| _ ->
584610
invalid_arg
585-
"Source_map_io.Index.of_json: URLs in index maps are not currently \
586-
supported"
611+
"Source_map.Index.of_json: URLs in index maps are not currently supported"
587612
| exception Not_found -> ());
588613
let map =
589614
try Standard.of_json (List.assoc "map" json) with
590-
| Not_found -> invalid_arg "Source_map_io.Index.of_json: field 'map' absent"
615+
| Not_found -> invalid_arg "Source_map.Index.of_json: field 'map' absent"
591616
| Invalid_argument _ ->
592-
invalid_arg "Source_map_io.Index.of_json: invalid sub-map object"
617+
invalid_arg "Source_map.Index.of_json: invalid sub-map object"
593618
in
594619
{ offset; map }
595-
| _ -> invalid_arg "Source_map_io.Index.of_json: section of unexpected type"
620+
| _ -> invalid_arg "Source_map.Index.of_json: section of unexpected type"
596621

597622
let of_json = function
598-
| `Assoc fields -> (
623+
| `Assoc (("version", `Intlit version) :: fields)
624+
when version_is_valid (int_of_string version) -> (
599625
let string name json = Option.map ~f:string_of_stringlit (stringlit name json) in
600626
let file = string "file" fields in
601627
match List.assoc "sections" fields with
602628
| `List sections ->
603629
let sections = List.map ~f:section_of_json sections in
604-
{ version = 3; file; sections }
605-
| _ -> invalid_arg "Source_map_io.Index.of_json: `sections` is not an array"
630+
{ version = int_of_string version; file; sections }
631+
| _ -> invalid_arg "Source_map.Index.of_json: `sections` is not an array"
606632
| exception Not_found ->
607-
invalid_arg "Source_map_io.Index.of_json: no `sections` field")
608-
| _ -> invalid_arg "Source_map_io.of_json: map is not an object"
633+
invalid_arg "Source_map.Index.of_json: no `sections` field")
634+
| _ -> invalid_arg "Source_map.Index.of_json"
609635

610636
let to_string m = Yojson.Raw.to_string (json m)
611637

612638
let to_file m file = Yojson.Raw.to_file file (json m)
639+
640+
let invariant { version; file = _; sections } =
641+
if not (version_is_valid version)
642+
then invalid_arg "Source_map.Index.invariant: invalid version";
643+
let _ : int =
644+
List.fold_left
645+
sections
646+
~init:(-1)
647+
~f:(fun acc { offset = { gen_line; gen_column }; map } ->
648+
if gen_line < 0 || gen_column < 0
649+
then invalid_arg "Source_map.Index.invariant: invalid offset";
650+
if acc >= gen_line
651+
then
652+
invalid_arg
653+
"Source_map.Index.invariant: overlapping or unordered map in sections";
654+
Standard.invariant map;
655+
gen_line + Mappings.number_of_lines map.mappings)
656+
in
657+
()
613658
end
614659

615660
type t =
@@ -621,7 +666,7 @@ let of_json = function
621666
match List.assoc "sections" fields with
622667
| _ -> Index (Index.of_json json)
623668
| exception Not_found -> Standard (Standard.of_json json))
624-
| _ -> invalid_arg "Source_map_io.of_json: map is not an object"
669+
| _ -> invalid_arg "Source_map.of_json: map is not an object"
625670

626671
let of_string s = of_json (Yojson.Raw.from_string s)
627672

@@ -636,6 +681,10 @@ let to_file x f =
636681
| Standard m -> Standard.to_file m f
637682
| Index i -> Index.to_file i f
638683

684+
let invariant = function
685+
| Standard m -> Standard.invariant m
686+
| Index i -> Index.invariant i
687+
639688
type info =
640689
{ mappings : Mappings.decoded
641690
; sources : string list

compiler/lib/source_map.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ val of_string : string -> t
137137

138138
val of_file : string -> t
139139

140+
val invariant : t -> unit
141+
140142
type info =
141143
{ mappings : Mappings.decoded
142144
; sources : string list

compiler/lib/vlq64.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919

2020
open! Stdlib
2121

22-
let code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
22+
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
2323

2424
let code_rev =
2525
let a = Array.make 255 (-1) in
26-
for i = 0 to String.length code - 1 do
27-
a.(Char.code code.[i]) <- i
26+
for i = 0 to String.length alphabet - 1 do
27+
a.(Char.code alphabet.[i]) <- i
2828
done;
2929
a
3030

31+
let in_alphabet x = code_rev.(Char.code x) <> -1
32+
3133
let vlq_base_shift = 5
3234

3335
(* binary: 100000 *)
@@ -56,7 +58,7 @@ let fromVLQSigned v =
5658
(* assert (fromVLQSigned 3 = -1); *)
5759
(* assert (fromVLQSigned 5 = -2);; *)
5860

59-
let add_char buf x = Buffer.add_char buf code.[x]
61+
let add_char buf x = Buffer.add_char buf alphabet.[x]
6062

6163
let rec encode' buf x =
6264
let digit = x land vlq_base_mask in

compiler/lib/vlq64.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1818
*)
1919

20+
val in_alphabet : char -> bool
21+
2022
val encode_l : Buffer.t -> int list -> unit
2123

2224
val decode_l : string -> pos:int -> len:int -> int list

0 commit comments

Comments
 (0)