Commit cc85d061 authored by POTTIER Francois's avatar POTTIER Francois

Added a [HandlingError] result, so the parser suspends itself at

every step of error handling. Compared to Frédéric's patch, this
code is "more incremental" in that the parser will try to handle
the error, pop one cell, suspend itself, try to handle the error,
pop one cell, suspend itself, etc. In other words, *every call*
to [error env] has been replaced with [HandlingError env], whereas
in Frédéric's patch only 2 out of 3 calls were replaced.
parent c0ba0031
......@@ -20,12 +20,12 @@ module Make (T : TABLE) = struct
(* --------------------------------------------------------------------------- *)
(* A continuation is returned to the user when the parser pauses itself. In
normal mode, this happens when the parser wishes to request another token.
In error-handling mode, this happens when ... TEMPORARY *)
(* The type [result] represents an intermediate or final result of the
parser. See [EngineTypes]. *)
type result =
| InputNeeded of env
| HandlingError of env
| Accepted of semantic_value
| Rejected
......@@ -132,11 +132,14 @@ module Make (T : TABLE) = struct
(* Note that, if [please_discard] was true, then we have just called
[discard], so the lookahead token cannot be [error]. *)
(* Returning [HandlingError env] is equivalent to calling [error env]
directly, except it allows the user to regain control. *)
let (token, _, _) = env.triple in
if token == error_token then begin
if log then
Log.resuming_error_handling();
error env
HandlingError env
end
else
......@@ -252,7 +255,7 @@ module Make (T : TABLE) = struct
let (_, startp, endp) = env.triple in
let triple = (error_token, startp, endp) in
let env = { env with triple } in
error env
HandlingError env
(* [error] handles errors. *)
......@@ -311,7 +314,7 @@ module Make (T : TABLE) = struct
stack = next;
current = cell.state
} in
error env
HandlingError env
end
......@@ -372,6 +375,14 @@ module Make (T : TABLE) = struct
(* User error. *)
raise (Invalid_argument "[offer] expects [InputNeeded _]")
let resume result =
match result with
| HandlingError env ->
error env
| _ ->
(* User error. *)
raise (Invalid_argument "[resume] expects [HandlingError _]")
(* --------------------------------------------------------------------------- *)
(* --------------------------------------------------------------------------- *)
......@@ -393,21 +404,33 @@ module Make (T : TABLE) = struct
(* --------------------------------------------------------------------------- *)
(* The main loop repeatedly calls [read] and [offer] in response to every
[InputNeeded] intermediate result. In the end, we obtain an [Accepted]
or [Rejected] result, which we report to the user. By convention,
acceptance is reported by returning a semantic value, whereas rejection
is reported by raising [Error]. *)
(* The main loop repeatedly handles intermediate results, until a final result
is obtained. This allows implementing the monolithic interface ([entry]) in
terms of the incremental interface ([start], [offer], [resume]). *)
(* By convention, acceptance is reported by returning a semantic value, whereas
rejection is reported by raising [Error]. *)
let rec loop (read : reader) (result : result) : semantic_value =
match result with
| InputNeeded _ ->
(* The parser needs a token. Request one from the lexer,
and offer it to the parser, which will produce a new
result. Then, repeat. *)
let triple = read() in
let result = offer result triple in
loop read result
| HandlingError _ ->
(* The parser has suspended itself, but does not need
new input. Just resume the parser. Then, repeat. *)
let result = resume result in
loop read result
| Accepted v ->
(* The parser has succeeded and produced a semantic value.
Return this semantic value to the user. *)
v
| Rejected ->
(* The parser rejects this input. Raise an exception. *)
raise Error
let entry (s : state) lexer lexbuf : semantic_value =
......
......@@ -307,14 +307,19 @@ module type ENGINE = sig
(* The type [result] represents an intermediate or final result of the
parser. An intermediate result can be thought of as a suspension: it
records the parser's current state, and allows parsing to be resumed.
[InputNeeded] is an intermediate result, and means that the parser
wishes to read one token before continuing. [Accepted] and [Rejected]
are final results. *)
[InputNeeded] is an intermediate result, which means that the parser
wishes to read one token before continuing. [HandlingError] is also
an intermediate result, which means that the parser has detected and
is trying to handle an error. It does not need more input at this
point; it is suspending itself only in order to give the user an
opportunity to handle this error in a different manner, if desired.
[Accepted] and [Rejected] are final results. *)
type env
type result = private
| InputNeeded of env
| HandlingError of env
| Accepted of semantic_value
| Rejected
......@@ -338,8 +343,17 @@ module type ENGINE = sig
token * Lexing.position * Lexing.position ->
result
(* [resume] allows the user to resume the parser after it has suspended
itself with a [HandlingError] result. [resume] expects this result
and produces a new result. It does not raise any exception. *)
val resume:
result ->
result
(* The incremental interface is more general than the monolithic one.
[entry] can be (and is indeed) implemented by first calling [start],
then calling [offer] in a loop, until a final result is obtained. *)
then calling [offer] and [resume] in a loop, until a final result
is obtained. *)
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment