aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/qparser/analyzer.ml80
-rw-r--r--lib/qparser/analyzer.mli4
-rw-r--r--lib/qparser/lexbuf.ml15
-rw-r--r--lib/qparser/lexbuf.mli9
-rw-r--r--lib/qparser/lexer.ml4
-rw-r--r--lib/syntax/S.ml6
6 files changed, 82 insertions, 36 deletions
diff --git a/lib/qparser/analyzer.ml b/lib/qparser/analyzer.ml
index 6d09021..7d9b7d2 100644
--- a/lib/qparser/analyzer.ml
+++ b/lib/qparser/analyzer.ml
@@ -1,16 +1,18 @@
+type 'a result = { content : 'a; report : Qsp_syntax.Report.t list }
+
(**
Run the QSP parser and apply the analyzer over it.
See [syntax/S]
*)
-let parse :
+let rec parse :
type a context.
(module Qsp_syntax.S.Analyzer
with type Location.t = a
and type context = context) ->
Lexbuf.t ->
context ->
- (a * Qsp_syntax.Report.t list, Qsp_syntax.Report.t) Result.t =
+ (a result, Qsp_syntax.Report.t) Result.t =
fun (module S : Qsp_syntax.S.Analyzer
with type Location.t = a
and type context = context) ->
@@ -41,33 +43,53 @@ let parse :
Error err
in
- (* Then apply the checks over the result of the parsing *)
- evaluation
- |> Result.map (fun r ->
- let r' = r context in
- (r', S.Location.v r'))
- |> Result.map_error (fun e ->
- let message =
- match e.IncrementalParser.code with
- | Interpreter.InvalidSyntax -> "Invalid Syntax"
- | Interpreter.UnrecoverableError -> "UnrecoverableError"
- | Interpreter.Custom msg -> msg
- | Interpreter.MenhirCode c ->
- let message_content =
- try Parser_messages.message c
- with Not_found ->
- String.concat "" [ "(Error code "; string_of_int c; ")" ]
- in
+ (* Then evaluate the result *)
+ match (evaluation, Lexbuf.is_recovery l) with
+ | Ok r, _ ->
+ (* We have been able to read the syntax, apply the checkers over the
+ Tree *)
+ let content = r context in
+ Ok { content; report = S.Location.v content }
+ | _, true ->
+ (* This pattern can occur after recovering from an error. The
+ application attempt to start from a clean state in the next
+ location, but may fail to detect the correct position. If so, we
+ just start again until we hook the next location *)
+ parse (module S) l context
+ | Error e, _ ->
+ let message =
+ match e.IncrementalParser.code with
+ | Interpreter.UnrecoverableError -> "UnrecoverableError"
+ | Interpreter.InvalidSyntax -> "Invalid Syntax"
+ | Interpreter.Custom msg -> msg
+ | Interpreter.MenhirCode c ->
+ let message_content =
+ try Parser_messages.message c
+ with Not_found ->
+ String.concat "" [ "(Error code "; string_of_int c; ")" ]
+ in
+ String.concat "" [ String.trim message_content ]
+ in
+
+ let report = Qsp_syntax.Report.error (e.start_pos, e.end_pos) message in
+ (* Rollback the buffer from the latest errror before discarding until
+ the end of the location. This ensure we will read the marker
+ for the end location in the case the error was actually in
+ this line itsef.
+
+ Example :
+
+ # location
+ <ERROR HERE>
- String.concat "" [ String.trim @@ message_content ]
- in
- let report =
- Qsp_syntax.Report.error (e.start_pos, e.end_pos) message
- in
+ ! ------- a
+ --- location ---------------------------------
+ *)
+ Lexbuf.rollback l;
- (* Discard the remaining file to read. The parser is now in a blank
- state, it does not make sense to keep feeding it with the new
- tokens. *)
- let () = try Lexer.discard l with _ -> () in
+ (* Discard the remaining file to read. The parser is now in a blank
+ state, it does not make sense to keep feeding it with the new
+ tokens. *)
+ let () = try Lexer.discard l with _ -> () in
- report)
+ Error report
diff --git a/lib/qparser/analyzer.mli b/lib/qparser/analyzer.mli
index 8033601..949db16 100644
--- a/lib/qparser/analyzer.mli
+++ b/lib/qparser/analyzer.mli
@@ -1,10 +1,12 @@
+type 'a result = { content : 'a; report : Qsp_syntax.Report.t list }
+
val parse :
(module Qsp_syntax.S.Analyzer
with type Location.t = 'a
and type context = 'context) ->
Lexbuf.t ->
'context ->
- ('a * Qsp_syntax.Report.t list, Qsp_syntax.Report.t) Result.t
+ ('a result, Qsp_syntax.Report.t) Result.t
(** Read the source and build a analyzis over it.
This method make the link between the source file and how to read it
diff --git a/lib/qparser/lexbuf.ml b/lib/qparser/lexbuf.ml
index 1d93f67..afc3bac 100644
--- a/lib/qparser/lexbuf.ml
+++ b/lib/qparser/lexbuf.ml
@@ -5,6 +5,7 @@ type t = {
mutable start_p : Lexing.position option;
state : state Stack.t;
reset_line : bool;
+ mutable recovering : bool;
}
and lexer = t -> Tokens.token
@@ -50,7 +51,8 @@ let start : t -> unit =
Sedlexing.set_position t.buffer { end_pos with Lexing.pos_lnum = 1 }
in
Stack.clear t.state;
- t.start_p <- None
+ t.start_p <- None;
+ t.recovering <- false
let positions : t -> Lexing.position * Lexing.position =
fun t ->
@@ -62,7 +64,13 @@ let content : t -> string = fun t -> Sedlexing.Utf8.lexeme t.buffer
let from_lexbuf : ?reset_line:bool -> Sedlexing.lexbuf -> t =
fun ?(reset_line = true) t ->
- { buffer = t; start_p = None; reset_line; state = Stack.create () }
+ {
+ buffer = t;
+ start_p = None;
+ reset_line;
+ state = Stack.create ();
+ recovering = false;
+ }
let set_start_position : t -> Lexing.position -> unit =
fun t position ->
@@ -97,3 +105,6 @@ let overlay : t -> lexer -> lexer =
match layer with
| String wraper | EndString wraper -> wraper.start_string acc
| _ -> acc)
+
+let start_recovery : t -> unit = fun t -> t.recovering <- true
+let is_recovery : t -> bool = fun t -> t.recovering
diff --git a/lib/qparser/lexbuf.mli b/lib/qparser/lexbuf.mli
index f9812a7..4283db1 100644
--- a/lib/qparser/lexbuf.mli
+++ b/lib/qparser/lexbuf.mli
@@ -7,7 +7,7 @@ val from_lexbuf : ?reset_line:bool -> Sedlexing.lexbuf -> t
(** Create a new buffer *)
val start : t -> unit
-(** Intialize a new run *)
+(** Intialize a new run. *)
val buffer : t -> Sedlexing.lexbuf
(** Extract the sedlex buffer. Required in each rule. *)
@@ -82,3 +82,10 @@ val leave_state : t -> unit
(** Leave the current state *)
val overlay : t -> lexer -> lexer
+
+val start_recovery : t -> unit
+(** Set the lexer in recovery mode, the lexer raise this mode after an error,
+ in order to ignore the further errors until a new location *)
+
+val is_recovery : t -> bool
+(** Check if the lexer is in recovery mode *)
diff --git a/lib/qparser/lexer.ml b/lib/qparser/lexer.ml
index 5c093b1..e3524cc 100644
--- a/lib/qparser/lexer.ml
+++ b/lib/qparser/lexer.ml
@@ -277,6 +277,7 @@ let main buffer =
parser buffer
let rec discard buffer =
+ let () = Lexbuf.start_recovery buffer in
let lexbuf = Lexbuf.buffer buffer in
match%sedlex lexbuf with
@@ -291,8 +292,5 @@ let rec discard buffer =
(for example a missing quote). *)
leave_expression buffer;
()
- | '!' ->
- ignore @@ skip_comment buffer;
- discard buffer
| any -> discard buffer
| _ -> raise EOF
diff --git a/lib/syntax/S.ml b/lib/syntax/S.ml
index e691b38..b467863 100644
--- a/lib/syntax/S.ml
+++ b/lib/syntax/S.ml
@@ -114,6 +114,12 @@ module type Analyzer = sig
(** Is the test active or not *)
val is_global : bool
+ (** Declare the checker as global. It requires to run over the whole file and
+ will be disabled if the application only check a single location.
+
+ Also, the test will be disabled if a syntax error is reported during the
+ parsing, because this tell that I haven’t been able to analyse the whole
+ source code. *)
type context
(** Context used to keep information during the whole test *)