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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
(* Otags reloaded
*
* Hendrik Tews Copyright (C) 2010 - 2012
*
* This file is part of "Otags reloaded".
*
* "Otags reloaded" is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* "Otags reloaded" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License in file COPYING in this or one of the parent
* directories for more details.
*
* You should have received a copy of the GNU General Public License
* along with "Otags reloaded". If not, see
* <http://www.gnu.org/licenses/>.
*
* $Id: parser_factory.ml,v 1.19 2012/05/21 09:29:29 tews Exp $
*
* build new camlp4 parsers
*
*)
open Monitor_line_directive
open Global
open Types
let camlp4_error msg =
"Camlp4 parse error: " ^ msg
type parser_functions = {
mkloc : string -> loc_t;
parse_implem :
?directive_handler:(str_item_t -> str_item_t option) ->
loc_t -> char Stream.t -> str_item_t;
parse_interf :
?directive_handler:(sig_item_t -> sig_item_t option) ->
loc_t -> char Stream.t -> sig_item_t;
}
let current_parser = ref {
mkloc = (fun _ -> assert false);
parse_implem = (fun ?directive_handler:_dh _ -> assert false);
parse_interf = (fun ?directive_handler:_dh _ -> assert false);
}
(* functor for creating a fresh grammar *)
module FreshGrammar(Unit : sig end)
: Camlp4.Sig.Camlp4Syntax with module Loc = Camlp4.PreCast.Loc
and module Ast = Camlp4.PreCast.Ast
= Camlp4.OCamlInitSyntax.Make
(Camlp4.PreCast.Ast)
(Camlp4.Struct.Grammar.Static.Make(Camlp4.PreCast.Lexer))
(Camlp4.Struct.Quotation.Make(Camlp4.PreCast.Ast))
(* List of camlp4 standard parsers with their long names.
* All these are treated internally in the following function.
*
* Camlp4OCamlRevisedParser
* Camlp4OCamlReloadedParser
* Camlp4OCamlParser
* Camlp4OCamlRevisedParserParser
* Camlp4OCamlParserParser
* Camlp4GrammarParser
* Camlp4MacroParser
* Camlp4QuotationCommon
* Camlp4QuotationExpander
* Camlp4OCamlRevisedQuotationExpander
* Camlp4OCamlOriginalQuotationExpander
* Camlp4ListComprehension
*
* modules not treated Camlp4Bin:
*
* Camlp4DebugParser
*)
(* Build new parsing funktions corresponding to the syntax extensions
* in the parser_list argument.
*
* The syntax extensions must be applied with functor application to
* some Camlp4Syntax module. Therefore, this function makes a local
* Camlp4Syntax module, applies all parsing functions and extracts the
* fields that are necessary for us into a parser_functions record.
*)
let build_parser parser_list =
if !verbose then
Printf.eprintf "Build new parser out of %s\n"
(String.concat " " parser_list);
(* Whether the lexer lexes quotations and antiquotations is controlled
* by the global references in Camlp4_config (which is not very
* modular/reentrant). I beliefe lexing quotations and antiquotations
* should be off by default and only enabled if some parsing extensions
* (notably some that installs quotations) needs them. Antiquotations
* are turned on inside quotations, see
* Camlp4QuotationCommon.add_quotation.
*
* I use the following heuristic here: Adding quotations enables
* quotations and macro parser enables antiquotations (otherwise
* Camlp4MacroParser.ml does not parse.
*)
let parse_quotations = ref false in
let parse_antiquotations = ref false in
(* This is the local module to which all grammar extension are
* applied to. I cannot pass this module into a different function,
* therefore, many utility functions, that I would like to
* factor out, have to be defined inside build_parser.
*)
let module Otags_syntax = FreshGrammar(struct end) in
(* This subfunction applies one parsing extension to Otags_syntax.
* The correspondes between names of parsing extensions (ie. strings)
* and the parsing extension functors is hardwired here.
* It would be much better if there were a hash table that maps
* names to functors, such that each parsing extension could register
* oneself there.
*)
let apply_parsing_extensions = function
| "Camlp4OCamlRevisedParser" ->
let module M = Camlp4OCamlRevisedParser.Make(Otags_syntax) in ()
(*
* | "Camlp4OCamlReloadedParser" ->
* let module M = Camlp4OCamlReloadedParser.Make(Otags_syntax) in ()
*)
| "Camlp4OCamlParser" ->
let module M = Camlp4OCamlParser.Make(Otags_syntax) in ()
| "Camlp4OCamlRevisedParserParser" ->
let module M = Camlp4OCamlRevisedParserParser.Make(Otags_syntax) in ()
| "Camlp4OCamlParserParser" ->
let module M = Camlp4OCamlParserParser.Make(Otags_syntax) in ()
| "Camlp4GrammarParser" ->
let module M = Camlp4GrammarParser.Make(Otags_syntax) in ();
parse_antiquotations := true
| "Camlp4MacroParser" ->
let module M = Camlp4MacroParser.Make(Otags_syntax) in ()
| "Camlp4QuotationCommon" ->
(* The Camlp4QuotationCommon module provides a Make functor,
* but this Make takes two arguments (so it does not fit the pattern
* here) and is not meant to be applied to any syntax when the module
* is loaded. Instead other quotation-building functors rely on
* this Make functor. Therefore we should not do anything here.
*)
()
| "Camlp4QuotationExpander" ->
let module M = Camlp4QuotationExpander.Make(Otags_syntax) in ();
parse_quotations := true
| "Camlp4OCamlRevisedQuotationExpander" ->
let module M =
Add_quotation.Make(Otags_syntax)(Camlp4OCamlRevisedParser.Make)
in ();
parse_quotations := true
| "Camlp4OCamlOriginalQuotationExpander" ->
let module OS =
functor(S : Camlp4.Sig.Camlp4Syntax) ->
struct
include
Camlp4OCamlParser.Make(Camlp4OCamlRevisedParser.Make(S))
end
in
let module M =
Add_quotation.Make(Otags_syntax)(OS)
in ();
parse_quotations := true
| "Camlp4ListComprehension" ->
let module M = Camlp4ListComprehension.Make(Otags_syntax) in ()
| "Camlp4DebugParser" ->
let module M = Camlp4DebugParser.Make(Otags_syntax) in ()
| _ -> assert false
in
List.iter apply_parsing_extensions parser_list;
let module M = Line_directive_monitor(Otags_syntax) in
(* Exceptions catch and error reporting wrapper for a parsing function.
* This wrapper has to stay in the scope of Otags_syntax because
* it accesses exceptions and error formatting functions from it.
*)
let catch_some_exc f = fun ?directive_handler x y ->
try
f ?directive_handler x y
with
| Otags_syntax.Loc.Exc_located(loc, Stream.Error msg) ->
raise(Otags_parsing_error(loc, camlp4_error msg))
| Otags_syntax.Loc.Exc_located(loc, Sys_error msg) ->
raise(Otags_parsing_error(loc, camlp4_error msg))
| Otags_syntax.Loc.Exc_located(loc, Otags_syntax.Quotation.Error.E err) ->
raise(Otags_parsing_error(loc,
camlp4_error (Otags_syntax.Quotation.Error.to_string err)))
| Otags_syntax.Loc.Exc_located(loc, Camlp4.PreCast.Lexer.Error.E err) ->
raise(Otags_parsing_error(loc,
camlp4_error(Camlp4.PreCast.Lexer.Error.to_string err)))
in
(* Wrapper function to set the global variables for lexing/parsing
* quotations and antiquotations in Camlp4_config.
*)
let set_quotation_flags f = fun ?directive_handler x y ->
Camlp4_config.quotations := !parse_quotations;
Camlp4_config.antiquotations := !parse_antiquotations;
f ?directive_handler x y
in
(* Extract the necessary fields from Otags_syntax and store
* them in the result record
*)
{ mkloc = Otags_syntax.Loc.mk;
parse_implem =
catch_some_exc (set_quotation_flags Otags_syntax.parse_implem);
parse_interf =
catch_some_exc (set_quotation_flags Otags_syntax.parse_interf);
}
let current_parser_list = ref []
let update_syntax parser_list =
assert(parser_list <> []);
if !current_parser_list != parser_list
then begin
(* let pa_start = Unix.gettimeofday() in *)
current_parser := build_parser parser_list;
(*
* let time = Unix.gettimeofday() -. pa_start in
* Printf.printf "parser %s build time %.2f ms\n%!"
* (String.concat " " parser_list)
* (time *. 1000.0);
*)
current_parser_list := parser_list;
end;
!current_parser
|