The unpac monorepo manager self-hosting as a monorepo using unpac

Best-effort parsing for future opam files

+92 -32
+4 -1
vendor/opam/opam-file-format/CHANGES
··· 1 1 2.1.3 [???] 2 2 * Fix module link order (broken by #37) [#41 @dra27] 3 - * opam-version: "2.1" must appear at most once and as the first non-comment item [#43 @dra27] 3 + * opam-version: "2.1" must appear at most once and as the first non-comment 4 + item. If opam-version is at the start and is greater than the library version, 5 + `OpamLexer.Error` and `Parsing.Parse_error` are no longer raised; instead the 6 + items parsed so far are returned. [#43 @dra27] 4 7 5 8 2.1.2 [07 Jan 2021] 6 9 * Some hash-consing for strings [#27 @AltGr]
+73 -31
vendor/opam/opam-file-format/src/opamBaseParser.mly
··· 26 26 27 27 let get_pos n = get_pos_full ~s:n n 28 28 29 + let parsed_so_far = ref [] 30 + 31 + let record_token t = 32 + parsed_so_far := t :: !parsed_so_far; t 33 + 34 + (* This must match up with the package's version; checked by the build system *) 35 + let version = (2, 1) 36 + 29 37 %} 30 38 31 39 %token <string> STRING IDENT ··· 61 69 %% 62 70 63 71 main: 64 - | items EOF { fun file_name -> 72 + | items EOF { parsed_so_far := []; fun file_name -> 65 73 { file_contents = $1; file_name } } 66 74 ; 67 75 ··· 72 80 73 81 item: 74 82 | IDENT COLON value { 83 + record_token 75 84 { pos = get_pos_full 3; 76 85 pelem = 77 86 Variable ({ pos = get_pos 1; pelem = $1 }, $3); 78 87 } 79 88 } 80 89 | IDENT LBRACE items RBRACE { 90 + record_token 81 91 { pos = get_pos_full 4; 82 92 pelem = 83 93 Section ({section_kind = { pos = get_pos 1; pelem = $1 }; ··· 88 98 } 89 99 } 90 100 | IDENT STRING LBRACE items RBRACE { 101 + record_token 91 102 { pos = get_pos_full 4; 92 103 pelem = 93 104 Section ({section_kind = { pos = get_pos 1; pelem = $1 }; ··· 145 156 try Scanf.sscanf s "%u.%u" (fun maj min -> (maj, min)) 146 157 with Scanf.Scan_failure _ -> (0, 0) 147 158 148 - let main t l f = 149 - let r = 150 - try 151 - let r = main t l f in 152 - Parsing.clear_parser (); 153 - r 159 + let with_clear_parser f x = 160 + try 161 + let r = f x in 162 + Parsing.clear_parser (); 163 + r 164 + with e -> 165 + Parsing.clear_parser (); 166 + raise e 167 + 168 + exception Nothing 169 + 170 + let main t l file_name = 171 + (* Always return a result from parsing/lexing, but note if an exception 172 + occurred. *) 173 + let parsing_exception = ref Nothing in 174 + let t l = 175 + try t l 154 176 with 155 - | e -> 156 - Parsing.clear_parser (); 157 - raise e in 158 - match r with 159 - | {file_contents = {pelem = Variable({pelem = "opam-version"; _}, {pelem = String ver; _}); _}::items; _} 160 - when nopatch ver >= (2, 1) -> 161 - let opam_version_variable = function 162 - | {pelem = Variable({pelem = "opam-version"; _}, _); _} -> true 163 - | _ -> false 164 - in 165 - (* For opam-version: 2.1 and later, there must be no other opam-version 166 - fields. *) 167 - if List.exists opam_version_variable items then 168 - raise Parsing.Parse_error; 169 - r 170 - | {file_contents = items; _} -> 171 - let opam_version_greater_2_0 = function 172 - | {pelem = Variable({pelem = "opam-version"; _}, {pelem = String ver; _}); _} -> 173 - nopatch ver > (2, 0) 174 - | _ -> false 175 - in 176 - (* opam-version: 2.1 or later must be the first item. *) 177 - if List.exists opam_version_greater_2_0 items then 178 - raise Parsing.Parse_error; 177 + | Sys.Break 178 + | Assert_failure _ 179 + | Match_failure _ as e -> raise e 180 + | e -> parsing_exception := e; EOF 181 + in 182 + let r = 183 + try with_clear_parser (main t l) file_name 184 + with Parsing.Parse_error as e -> 185 + parsing_exception := e; 186 + (* Record the tokens captured so far *) 187 + let r = {file_contents = List.rev !parsed_so_far; file_name} in 188 + parsed_so_far := []; 179 189 r 190 + in 191 + match r with 192 + | {file_contents = {pelem = Variable({pelem = "opam-version"; _}, {pelem = String ver; _}); _}::items; _} 193 + when nopatch ver >= (2, 1) -> 194 + let opam_version_variable = function 195 + | {pelem = Variable({pelem = "opam-version"; _}, _); _} -> true 196 + | _ -> false 197 + in 198 + (* For opam-version: 2.1 and later, there must be no other opam-version 199 + fields. *) 200 + if List.exists opam_version_variable items then 201 + raise Parsing.Parse_error; 202 + (* Parsing and lexing errors from future versions of opam are ignored: 203 + the intent is that the tool will abort/ignore because of the 204 + opam-version field rather than through lexer/parser errors. *) 205 + if !parsing_exception != Nothing && nopatch ver <= version then 206 + raise !parsing_exception; 207 + r 208 + | {file_contents = items; _} -> 209 + let opam_version_greater_2_0 = function 210 + | {pelem = Variable({pelem = "opam-version"; _}, {pelem = String ver; _}); _} -> 211 + nopatch ver > (2, 0) 212 + | _ -> false 213 + in 214 + (* opam-version: 2.1 or later must be the first item. *) 215 + if List.exists opam_version_greater_2_0 items then 216 + raise Parsing.Parse_error; 217 + (* If no opam-version field was given, all exceptions must be 218 + raised. *) 219 + if !parsing_exception != Nothing then 220 + raise !parsing_exception; 221 + r 180 222 181 223 let value t l = 182 224 try
+15
vendor/opam/opam-file-format/tests/hygiene/dune
··· 1 + (copy_files ../../src/opamParserTypes.ml) 2 + 3 + (test 4 + (name opamBaseParser) 5 + (libraries opam-file-format) 6 + (modules OpamParserTypes OpamBaseParser) 7 + (action (run %{test} %{version:opam-file-format}))) 8 + 9 + (ocamlyacc OpamBaseParser) 10 + 11 + (rule 12 + (with-stdout-to OpamBaseParser.mly 13 + (progn (cat ../../src/opamBaseParser.mly) 14 + ; If this assertion fails, OpamBaseParser.version is wrong 15 + (echo "let () = assert (Scanf.sscanf Sys.argv.(1) \"%u.%u\" (fun x y -> (x, y)) = version)"))))