Commit c4af203f authored by POTTIER Francois's avatar POTTIER Francois

Renamed [resume] to [handle].

Added a phantom type parameter to the type [env] so as to prevent
the user from confusing [offer] and [handle], thus eliminating a
runtime check, while keeping the ability of offering functions that
operate on an arbitrary environment (such as stack inspection).
parent cc85d061
......@@ -13,10 +13,11 @@ module Make (T : TABLE) = struct
include T
type dummy =
(state, semantic_value, token) env
type env =
dummy
type input_needed
type handling_error
type 'a env =
(state, semantic_value, token) EngineTypes.env
(* --------------------------------------------------------------------------- *)
......@@ -24,8 +25,8 @@ module Make (T : TABLE) = struct
parser. See [EngineTypes]. *)
type result =
| InputNeeded of env
| HandlingError of env
| InputNeeded of input_needed env
| HandlingError of handling_error env
| Accepted of semantic_value
| Rejected
......@@ -357,31 +358,19 @@ module Make (T : TABLE) = struct
if the state [s] has a default reduction on [#], that is, if
this starting state accepts only the empty word. *)
(* [offer result triple] is invoked by the user in response to [result],
which must be an [InputNeeded] result. *)
(* [offer] checks that the result is indeed of the form [InputNeeded env],
then passes control to [discard], resuming the suspended computation.
This runtime check prevents the user from passing an environment that
does not make sense here. *)
(* [offer env triple] is invoked by the user in response to a result
of the form [InputNeeded env]. The phantom type constraint on [env]
ensures that the user cannot pass [offer] an environment that comes
from some other source (e.g., a [HandlingError] result). *)
(* TEMPORARY using a phantom type parameter would be safer / more efficient. *)
let offer : input_needed env -> token * Lexing.position * Lexing.position -> result =
discard
let offer result triple =
match result with
| InputNeeded env ->
discard env triple
| _ ->
(* User error. *)
raise (Invalid_argument "[offer] expects [InputNeeded _]")
(* [handle env] is invoked by the user in response to a result of the
form [HandlingError env]. *)
let resume result =
match result with
| HandlingError env ->
error env
| _ ->
(* User error. *)
raise (Invalid_argument "[resume] expects [HandlingError _]")
let handle : handling_error env -> result =
error
(* --------------------------------------------------------------------------- *)
(* --------------------------------------------------------------------------- *)
......@@ -406,24 +395,24 @@ module Make (T : TABLE) = struct
(* 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]). *)
terms of the incremental interface ([start], [offer], [handle]). *)
(* 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 _ ->
| InputNeeded env ->
(* 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
let result = offer env triple in
loop read result
| HandlingError _ ->
| HandlingError env ->
(* The parser has suspended itself, but does not need
new input. Just resume the parser. Then, repeat. *)
let result = resume result in
let result = handle env in
loop read result
| Accepted v ->
(* The parser has succeeded and produced a semantic value.
......
......@@ -306,8 +306,9 @@ 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, which means that the parser
records the parser's current state, and allows parsing to be resumed. *)
(* [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
......@@ -315,11 +316,19 @@ module type ENGINE = sig
opportunity to handle this error in a different manner, if desired.
[Accepted] and [Rejected] are final results. *)
type env
(* The type ['a env] is shared by [InputNeeded] and [HandlingError].
The phantom type parameter ['a] is instantiated with [input_needed]
or [handling_error], as appropriate. This prevents the user from
calling [offer] when he/she should call [handle], or vice-versa. *)
type input_needed
type handling_error
type 'a env
type result = private
| InputNeeded of env
| HandlingError of env
type result =
| InputNeeded of input_needed env
| HandlingError of handling_error env
| Accepted of semantic_value
| Rejected
......@@ -334,26 +343,26 @@ module type ENGINE = sig
result
(* [offer] allows the user to resume the parser after it has suspended
itself with an [InputNeeded] result. [offer] expects this result, as
well as a new token, and produces a new result. It does not raise any
exception. *)
itself with a result of the form [InputNeeded env] result. [offer]
expects [env] as well as a new token and produces a new result. It
does not raise any exception. *)
val offer:
result ->
input_needed env ->
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. *)
(* [handle] allows the user to resume the parser after it has suspended
itself with a result of the form [HandlingError env]. [handle] expects
[env] and produces a new result. It does not raise any exception. *)
val resume:
result ->
val handle:
handling_error env ->
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] and [resume] in a loop, until a final result
then calling [offer] and [handle] 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