This patch includes various improvements to the parser/lexer.
Rough edges abound. Will require revising after applying the logseq
patch...
More of my thoughts are in various comments in the code.
I can confirm that golden-forest builds successfully.
In a nutshell:
- feature: Add Grammar.messages file for declarative error messages
- feature? Add Comment to parse tree. Doesn't get parsed yet, haven't
mucked around with the lexer and parser.
- feature: better error reporting during the lexing phase, and a fatal
bug was fixed: failure to close the verbatim block is now handled
gracefully, and a helpful message is provided.
- FEATURE! The reported range upon encountering an unmatched delimiter
now includes everthing including that delimiter.
---
lib/compiler/Code.ml | 1 +
lib/compiler/Expand.ml | 2 +
lib/compiler/Grammar.messages | 1010 +++++++++++++++++++++++++++++++++
lib/compiler/Grammar.mly | 1 +
lib/compiler/Lexer.mll | 60 +-
lib/compiler/Parse.ml | 320 ++++++-----
lib/compiler/Parse.mli | 5 -
lib/compiler/dune | 6 +
lib/frontend/Forester.ml | 18 +-
lib/frontend/Import_graph.ml | 2 +-
test/dune | 4 +-
test/parse.expected | 13 -
test/parse.ml | 25 -
13 files changed, 1251 insertions(+), 216 deletions(-)
create mode 100644 lib/compiler/Grammar.messages
delete mode 100644 lib/compiler/Parse.mli
delete mode 100644 test/parse.expected
delete mode 100644 test/parse.ml
diff --git a/lib/compiler/Code.ml b/lib/compiler/Code.ml
index af3e6e0..5c18de5 100644
--- a/lib/compiler/Code.ml
+++ b/lib/compiler/Code.ml
@@ -37,6 +37,7 @@ type node =
| Decl_xmlns of string * string
| Alloc of Trie.path
| Namespace of Trie.path * t
+ | Comment of string
[@@deriving show, repr]
and t = node Range.located list
diff --git a/lib/compiler/Expand.ml b/lib/compiler/Expand.ml
index 5f9caca..2cb145d 100644
--- a/lib/compiler/Expand.ml
+++ b/lib/compiler/Expand.ml
@@ -172,6 +172,8 @@ let rec expand : Code.t -> Syn.t = function
let symbol = Symbol.named path in
Sc.include_singleton path @@ Term [Range.locate_opt loc (Syn.Sym symbol)];
expand rest
+ | { value = Comment _; loc } :: rest ->
+ expand rest
and expand_method (key, body) =
key, expand body
diff --git a/lib/compiler/Grammar.messages b/lib/compiler/Grammar.messages
new file mode 100644
index 0000000..f9ba540
--- /dev/null
+++ b/lib/compiler/Grammar.messages
@@ -0,0 +1,1010 @@
+main: TEXT
+##
+## Ends in an error in state: 0.
+##
+## main' -> . main [ # ]
+##
+## The known suffix of the stack is as follows:
+##
+##
+
+<YOUR 11 ERROR MESSAGE HERE>
+
+main: SUBTREE XML_ELT_IDENT
+##
+## Ends in an error in state: 4.
+##
+## head_node -> SUBTREE . option(squares(wstext)) LBRACE ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## SUBTREE
+##
+
+<YOUR 23 ERROR MESSAGE HERE>
+
+main: SUBTREE LSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 5.
+##
+## option(squares(wstext)) -> LSQUARE . wstext RSQUARE [ LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE
+##
+
+<YOUR 35 ERROR MESSAGE HERE>
+
+main: SUBTREE LSQUARE TEXT RBRACE
+##
+## Ends in an error in state: 8.
+##
+## option(squares(wstext)) -> LSQUARE wstext . RSQUARE [ LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE wstext
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 10, spurious reduction of production list(ws_or_text) ->
+## In state 11, spurious reduction of production list(ws_or_text) -> ws_or_text list(ws_or_text)
+## In state 12, spurious reduction of production wstext -> list(ws_or_text)
+##
+
+<YOUR 55 ERROR MESSAGE HERE>
+
+main: DECL_XMLNS LBRACE TEXT XML_ELT_IDENT
+##
+## Ends in an error in state: 10.
+##
+## list(ws_or_text) -> ws_or_text . list(ws_or_text) [ RSQUARE RBRACE ]
+##
+## The known suffix of the stack is as follows:
+## ws_or_text
+##
+
+<YOUR 67 ERROR MESSAGE HERE>
+
+main: SUBTREE LSQUARE RSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 13.
+##
+## head_node -> SUBTREE option(squares(wstext)) . LBRACE ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## SUBTREE option(squares(wstext))
+##
+
+<YOUR 79 ERROR MESSAGE HERE>
+
+main: SUBTREE LBRACE TEXT
+##
+## Ends in an error in state: 14.
+##
+## head_node -> SUBTREE option(squares(wstext)) LBRACE . ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## SUBTREE option(squares(wstext)) LBRACE
+##
+
+<YOUR 91 ERROR MESSAGE HERE>
+
+main: SCOPE XML_ELT_IDENT
+##
+## Ends in an error in state: 15.
+##
+## head_node -> SCOPE . arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## SCOPE
+##
+
+<YOUR 103 ERROR MESSAGE HERE>
+
+main: SCOPE LBRACE RSQUARE
+##
+## Ends in an error in state: 17.
+##
+## arg -> LBRACE . list(locate(textual_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LBRACE
+##
+
+<YOUR 115 ERROR MESSAGE HERE>
+
+main: PUT XML_ELT_IDENT
+##
+## Ends in an error in state: 20.
+##
+## head_node -> PUT . ident arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PUT
+##
+
+<YOUR 127 ERROR MESSAGE HERE>
+
+main: PUT IDENT XML_ELT_IDENT
+##
+## Ends in an error in state: 22.
+##
+## head_node -> PUT ident . arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PUT ident
+##
+
+<YOUR 139 ERROR MESSAGE HERE>
+
+main: PATCH XML_ELT_IDENT
+##
+## Ends in an error in state: 24.
+##
+## head_node -> PATCH . LBRACE ws_list(locate(head_node)) RBRACE option(squares(bvar)) LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH
+##
+
+<YOUR 151 ERROR MESSAGE HERE>
+
+main: PATCH LBRACE TEXT
+##
+## Ends in an error in state: 25.
+##
+## head_node -> PATCH LBRACE . ws_list(locate(head_node)) RBRACE option(squares(bvar)) LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH LBRACE
+##
+
+<YOUR 163 ERROR MESSAGE HERE>
+
+main: OPEN XML_ELT_IDENT
+##
+## Ends in an error in state: 26.
+##
+## head_node -> OPEN . ident [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## OPEN
+##
+
+<YOUR 175 ERROR MESSAGE HERE>
+
+main: OBJECT XML_ELT_IDENT
+##
+## Ends in an error in state: 28.
+##
+## head_node -> OBJECT . option(squares(bvar)) LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## OBJECT
+##
+
+<YOUR 187 ERROR MESSAGE HERE>
+
+main: OBJECT LSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 29.
+##
+## option(squares(bvar)) -> LSQUARE . bvar RSQUARE [ LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE
+##
+
+<YOUR 199 ERROR MESSAGE HERE>
+
+main: OBJECT LSQUARE TEXT XML_ELT_IDENT
+##
+## Ends in an error in state: 31.
+##
+## option(squares(bvar)) -> LSQUARE bvar . RSQUARE [ LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE bvar
+##
+
+<YOUR 211 ERROR MESSAGE HERE>
+
+main: OBJECT LSQUARE TEXT RSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 33.
+##
+## head_node -> OBJECT option(squares(bvar)) . LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## OBJECT option(squares(bvar))
+##
+
+<YOUR 223 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 34.
+##
+## head_node -> OBJECT option(squares(bvar)) LBRACE . ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## OBJECT option(squares(bvar)) LBRACE
+##
+
+<YOUR 235 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE LSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 36.
+##
+## method_decl -> LSQUARE . TEXT RSQUARE list(WHITESPACE) arg [ WHITESPACE RBRACE LSQUARE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE
+##
+
+<YOUR 247 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE LSQUARE TEXT XML_ELT_IDENT
+##
+## Ends in an error in state: 37.
+##
+## method_decl -> LSQUARE TEXT . RSQUARE list(WHITESPACE) arg [ WHITESPACE RBRACE LSQUARE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE TEXT
+##
+
+<YOUR 259 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE LSQUARE TEXT RSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 38.
+##
+## method_decl -> LSQUARE TEXT RSQUARE . list(WHITESPACE) arg [ WHITESPACE RBRACE LSQUARE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE TEXT RSQUARE
+##
+
+<YOUR 271 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE LSQUARE TEXT RSQUARE WHITESPACE XML_ELT_IDENT
+##
+## Ends in an error in state: 39.
+##
+## list(WHITESPACE) -> WHITESPACE . list(WHITESPACE) [ VERBATIM LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## WHITESPACE
+##
+
+<YOUR 283 ERROR MESSAGE HERE>
+
+main: OBJECT LBRACE WHITESPACE XML_ELT_IDENT
+##
+## Ends in an error in state: 43.
+##
+## list(ws_or(method_decl)) -> ws_or(method_decl) . list(ws_or(method_decl)) [ RBRACE ]
+##
+## The known suffix of the stack is as follows:
+## ws_or(method_decl)
+##
+
+<YOUR 295 ERROR MESSAGE HERE>
+
+main: NAMESPACE XML_ELT_IDENT
+##
+## Ends in an error in state: 49.
+##
+## head_node -> NAMESPACE . ident LBRACE ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## NAMESPACE
+##
+
+<YOUR 307 ERROR MESSAGE HERE>
+
+main: NAMESPACE IDENT XML_ELT_IDENT
+##
+## Ends in an error in state: 50.
+##
+## head_node -> NAMESPACE ident . LBRACE ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## NAMESPACE ident
+##
+
+<YOUR 319 ERROR MESSAGE HERE>
+
+main: NAMESPACE IDENT LBRACE TEXT
+##
+## Ends in an error in state: 51.
+##
+## head_node -> NAMESPACE ident LBRACE . ws_list(locate(head_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## NAMESPACE ident LBRACE
+##
+
+<YOUR 331 ERROR MESSAGE HERE>
+
+main: LSQUARE RPAREN
+##
+## Ends in an error in state: 52.
+##
+## head_node -> LSQUARE . list(locate(textual_node)) RSQUARE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE
+##
+
+<YOUR 343 ERROR MESSAGE HERE>
+
+main: LPAREN RSQUARE
+##
+## Ends in an error in state: 53.
+##
+## head_node -> LPAREN . list(locate(textual_node)) RPAREN [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LPAREN
+##
+
+<YOUR 355 ERROR MESSAGE HERE>
+
+main: LET XML_ELT_IDENT
+##
+## Ends in an error in state: 54.
+##
+## head_node -> LET . ident list(squares(bvar_with_strictness)) arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LET
+##
+
+<YOUR 367 ERROR MESSAGE HERE>
+
+main: LET IDENT XML_ELT_IDENT
+##
+## Ends in an error in state: 55.
+##
+## head_node -> LET ident . list(squares(bvar_with_strictness)) arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LET ident
+##
+
+<YOUR 379 ERROR MESSAGE HERE>
+
+main: FUN LSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 56.
+##
+## list(squares(bvar_with_strictness)) -> LSQUARE . bvar_with_strictness RSQUARE list(squares(bvar_with_strictness)) [ VERBATIM LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE
+##
+
+<YOUR 391 ERROR MESSAGE HERE>
+
+main: FUN LSQUARE TEXT XML_ELT_IDENT
+##
+## Ends in an error in state: 58.
+##
+## list(squares(bvar_with_strictness)) -> LSQUARE bvar_with_strictness . RSQUARE list(squares(bvar_with_strictness)) [ VERBATIM LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE bvar_with_strictness
+##
+
+<YOUR 403 ERROR MESSAGE HERE>
+
+main: FUN LSQUARE TEXT RSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 59.
+##
+## list(squares(bvar_with_strictness)) -> LSQUARE bvar_with_strictness RSQUARE . list(squares(bvar_with_strictness)) [ VERBATIM LBRACE ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE bvar_with_strictness RSQUARE
+##
+
+<YOUR 415 ERROR MESSAGE HERE>
+
+main: LBRACE RSQUARE
+##
+## Ends in an error in state: 63.
+##
+## head_node -> LBRACE . list(locate(textual_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LBRACE
+##
+
+<YOUR 427 ERROR MESSAGE HERE>
+
+main: IMPORT XML_ELT_IDENT
+##
+## Ends in an error in state: 64.
+##
+## head_node -> IMPORT . LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## IMPORT
+##
+
+<YOUR 439 ERROR MESSAGE HERE>
+
+main: IMPORT LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 65.
+##
+## head_node -> IMPORT LBRACE . wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## IMPORT LBRACE
+##
+
+<YOUR 451 ERROR MESSAGE HERE>
+
+main: IMPORT LBRACE TEXT RSQUARE
+##
+## Ends in an error in state: 66.
+##
+## head_node -> IMPORT LBRACE wstext . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## IMPORT LBRACE wstext
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 10, spurious reduction of production list(ws_or_text) ->
+## In state 11, spurious reduction of production list(ws_or_text) -> ws_or_text list(ws_or_text)
+## In state 12, spurious reduction of production wstext -> list(ws_or_text)
+##
+
+<YOUR 471 ERROR MESSAGE HERE>
+
+main: HASH_LBRACE RSQUARE
+##
+## Ends in an error in state: 68.
+##
+## head_node -> HASH_LBRACE . list(locate(textual_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## HASH_LBRACE
+##
+
+<YOUR 483 ERROR MESSAGE HERE>
+
+main: HASH_HASH_LBRACE RSQUARE
+##
+## Ends in an error in state: 70.
+##
+## head_node -> HASH_HASH_LBRACE . list(locate(textual_node)) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## HASH_HASH_LBRACE
+##
+
+<YOUR 495 ERROR MESSAGE HERE>
+
+main: GET XML_ELT_IDENT
+##
+## Ends in an error in state: 71.
+##
+## head_node -> GET . ident [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## GET
+##
+
+<YOUR 507 ERROR MESSAGE HERE>
+
+main: FUN XML_ELT_IDENT
+##
+## Ends in an error in state: 73.
+##
+## head_node -> FUN . list(squares(bvar_with_strictness)) arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## FUN
+##
+
+<YOUR 519 ERROR MESSAGE HERE>
+
+main: EXPORT XML_ELT_IDENT
+##
+## Ends in an error in state: 76.
+##
+## head_node -> EXPORT . LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## EXPORT
+##
+
+<YOUR 531 ERROR MESSAGE HERE>
+
+main: EXPORT LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 77.
+##
+## head_node -> EXPORT LBRACE . wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## EXPORT LBRACE
+##
+
+<YOUR 543 ERROR MESSAGE HERE>
+
+main: EXPORT LBRACE TEXT RSQUARE
+##
+## Ends in an error in state: 78.
+##
+## head_node -> EXPORT LBRACE wstext . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## EXPORT LBRACE wstext
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 10, spurious reduction of production list(ws_or_text) ->
+## In state 11, spurious reduction of production list(ws_or_text) -> ws_or_text list(ws_or_text)
+## In state 12, spurious reduction of production wstext -> list(ws_or_text)
+##
+
+<YOUR 563 ERROR MESSAGE HERE>
+
+main: DEFAULT XML_ELT_IDENT
+##
+## Ends in an error in state: 80.
+##
+## head_node -> DEFAULT . ident arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DEFAULT
+##
+
+<YOUR 575 ERROR MESSAGE HERE>
+
+main: DEFAULT IDENT XML_ELT_IDENT
+##
+## Ends in an error in state: 81.
+##
+## head_node -> DEFAULT ident . arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DEFAULT ident
+##
+
+<YOUR 587 ERROR MESSAGE HERE>
+
+main: DEF XML_ELT_IDENT
+##
+## Ends in an error in state: 83.
+##
+## head_node -> DEF . ident list(squares(bvar_with_strictness)) arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DEF
+##
+
+<YOUR 599 ERROR MESSAGE HERE>
+
+main: DEF IDENT XML_ELT_IDENT
+##
+## Ends in an error in state: 84.
+##
+## head_node -> DEF ident . list(squares(bvar_with_strictness)) arg [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DEF ident
+##
+
+<YOUR 611 ERROR MESSAGE HERE>
+
+main: DECL_XMLNS XML_ELT_IDENT
+##
+## Ends in an error in state: 87.
+##
+## head_node -> DECL_XMLNS . LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DECL_XMLNS
+##
+
+<YOUR 623 ERROR MESSAGE HERE>
+
+main: DECL_XMLNS LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 88.
+##
+## head_node -> DECL_XMLNS LBRACE . wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DECL_XMLNS LBRACE
+##
+
+<YOUR 635 ERROR MESSAGE HERE>
+
+main: DECL_XMLNS LBRACE TEXT RSQUARE
+##
+## Ends in an error in state: 89.
+##
+## head_node -> DECL_XMLNS LBRACE wstext . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## DECL_XMLNS LBRACE wstext
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 10, spurious reduction of production list(ws_or_text) ->
+## In state 11, spurious reduction of production list(ws_or_text) -> ws_or_text list(ws_or_text)
+## In state 12, spurious reduction of production wstext -> list(ws_or_text)
+##
+
+<YOUR 655 ERROR MESSAGE HERE>
+
+main: CALL XML_ELT_IDENT
+##
+## Ends in an error in state: 91.
+##
+## head_node -> CALL . LBRACE ws_list(locate(head_node)) RBRACE LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL
+##
+
+<YOUR 667 ERROR MESSAGE HERE>
+
+main: CALL LBRACE TEXT
+##
+## Ends in an error in state: 92.
+##
+## head_node -> CALL LBRACE . ws_list(locate(head_node)) RBRACE LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL LBRACE
+##
+
+<YOUR 679 ERROR MESSAGE HERE>
+
+main: ALLOC XML_ELT_IDENT
+##
+## Ends in an error in state: 93.
+##
+## head_node -> ALLOC . ident [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## ALLOC
+##
+
+<YOUR 691 ERROR MESSAGE HERE>
+
+main: IDENT TEXT
+##
+## Ends in an error in state: 95.
+##
+## list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) . list(ws_or(locate(head_node))) [ RBRACE EOF ]
+##
+## The known suffix of the stack is as follows:
+## ws_or(locate(head_node))
+##
+
+<YOUR 703 ERROR MESSAGE HERE>
+
+main: CALL LBRACE IDENT EOF
+##
+## Ends in an error in state: 99.
+##
+## head_node -> CALL LBRACE ws_list(locate(head_node)) . RBRACE LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL LBRACE ws_list(locate(head_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 95, spurious reduction of production list(ws_or(locate(head_node))) ->
+## In state 96, spurious reduction of production list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) list(ws_or(locate(head_node)))
+## In state 104, spurious reduction of production ws_list(locate(head_node)) -> list(ws_or(locate(head_node)))
+##
+
+<YOUR 723 ERROR MESSAGE HERE>
+
+main: CALL LBRACE RBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 100.
+##
+## head_node -> CALL LBRACE ws_list(locate(head_node)) RBRACE . LBRACE wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL LBRACE ws_list(locate(head_node)) RBRACE
+##
+
+<YOUR 735 ERROR MESSAGE HERE>
+
+main: CALL LBRACE RBRACE LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 101.
+##
+## head_node -> CALL LBRACE ws_list(locate(head_node)) RBRACE LBRACE . wstext RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL LBRACE ws_list(locate(head_node)) RBRACE LBRACE
+##
+
+<YOUR 747 ERROR MESSAGE HERE>
+
+main: CALL LBRACE RBRACE LBRACE TEXT RSQUARE
+##
+## Ends in an error in state: 102.
+##
+## head_node -> CALL LBRACE ws_list(locate(head_node)) RBRACE LBRACE wstext . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## CALL LBRACE ws_list(locate(head_node)) RBRACE LBRACE wstext
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 10, spurious reduction of production list(ws_or_text) ->
+## In state 11, spurious reduction of production list(ws_or_text) -> ws_or_text list(ws_or_text)
+## In state 12, spurious reduction of production wstext -> list(ws_or_text)
+##
+
+<YOUR 767 ERROR MESSAGE HERE>
+
+main: HASH_HASH_LBRACE IDENT EOF
+##
+## Ends in an error in state: 105.
+##
+## list(locate(textual_node)) -> textual_node . list(locate(textual_node)) [ RSQUARE RPAREN RBRACE ]
+##
+## The known suffix of the stack is as follows:
+## textual_node
+##
+
+Did you forget to a closing brace?
+
+main: HASH_HASH_LBRACE IDENT RSQUARE
+##
+## Ends in an error in state: 108.
+##
+## head_node -> HASH_HASH_LBRACE list(locate(textual_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## HASH_HASH_LBRACE list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 798 ERROR MESSAGE HERE>
+
+main: HASH_LBRACE IDENT RSQUARE
+##
+## Ends in an error in state: 110.
+##
+## head_node -> HASH_LBRACE list(locate(textual_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## HASH_LBRACE list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 817 ERROR MESSAGE HERE>
+
+main: LBRACE IDENT RSQUARE
+##
+## Ends in an error in state: 112.
+##
+## head_node -> LBRACE list(locate(textual_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LBRACE list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 836 ERROR MESSAGE HERE>
+
+main: LPAREN IDENT RSQUARE
+##
+## Ends in an error in state: 114.
+##
+## head_node -> LPAREN list(locate(textual_node)) . RPAREN [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LPAREN list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 855 ERROR MESSAGE HERE>
+
+main: LSQUARE IDENT RPAREN
+##
+## Ends in an error in state: 116.
+##
+## head_node -> LSQUARE list(locate(textual_node)) . RSQUARE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LSQUARE list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 874 ERROR MESSAGE HERE>
+
+main: NAMESPACE IDENT LBRACE IDENT EOF
+##
+## Ends in an error in state: 118.
+##
+## head_node -> NAMESPACE ident LBRACE ws_list(locate(head_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## NAMESPACE ident LBRACE ws_list(locate(head_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 95, spurious reduction of production list(ws_or(locate(head_node))) ->
+## In state 96, spurious reduction of production list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) list(ws_or(locate(head_node)))
+## In state 104, spurious reduction of production ws_list(locate(head_node)) -> list(ws_or(locate(head_node)))
+##
+
+<YOUR 894 ERROR MESSAGE HERE>
+
+main: PATCH LBRACE IDENT EOF
+##
+## Ends in an error in state: 120.
+##
+## head_node -> PATCH LBRACE ws_list(locate(head_node)) . RBRACE option(squares(bvar)) LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH LBRACE ws_list(locate(head_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 95, spurious reduction of production list(ws_or(locate(head_node))) ->
+## In state 96, spurious reduction of production list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) list(ws_or(locate(head_node)))
+## In state 104, spurious reduction of production ws_list(locate(head_node)) -> list(ws_or(locate(head_node)))
+##
+
+<YOUR 914 ERROR MESSAGE HERE>
+
+main: PATCH LBRACE RBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 121.
+##
+## head_node -> PATCH LBRACE ws_list(locate(head_node)) RBRACE . option(squares(bvar)) LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH LBRACE ws_list(locate(head_node)) RBRACE
+##
+
+<YOUR 926 ERROR MESSAGE HERE>
+
+main: PATCH LBRACE RBRACE LSQUARE TEXT RSQUARE XML_ELT_IDENT
+##
+## Ends in an error in state: 122.
+##
+## head_node -> PATCH LBRACE ws_list(locate(head_node)) RBRACE option(squares(bvar)) . LBRACE ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH LBRACE ws_list(locate(head_node)) RBRACE option(squares(bvar))
+##
+
+<YOUR 938 ERROR MESSAGE HERE>
+
+main: PATCH LBRACE RBRACE LBRACE XML_ELT_IDENT
+##
+## Ends in an error in state: 123.
+##
+## head_node -> PATCH LBRACE ws_list(locate(head_node)) RBRACE option(squares(bvar)) LBRACE . ws_list(method_decl) RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## PATCH LBRACE ws_list(locate(head_node)) RBRACE option(squares(bvar)) LBRACE
+##
+
+<YOUR 950 ERROR MESSAGE HERE>
+
+main: SCOPE LBRACE IDENT RSQUARE
+##
+## Ends in an error in state: 126.
+##
+## arg -> LBRACE list(locate(textual_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## LBRACE list(locate(textual_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 105, spurious reduction of production list(locate(textual_node)) ->
+## In state 106, spurious reduction of production list(locate(textual_node)) -> textual_node list(locate(textual_node))
+##
+
+<YOUR 969 ERROR MESSAGE HERE>
+
+main: SUBTREE LBRACE IDENT EOF
+##
+## Ends in an error in state: 129.
+##
+## head_node -> SUBTREE option(squares(wstext)) LBRACE ws_list(locate(head_node)) . RBRACE [ XML_ELT_IDENT WHITESPACE VERBATIM TEXT SUBTREE SCOPE RSQUARE RPAREN RBRACE PUT PATCH OPEN OBJECT NAMESPACE LSQUARE LPAREN LET LBRACE IMPORT IDENT HASH_LBRACE HASH_IDENT HASH_HASH_LBRACE GET FUN EXPORT EOF DEFAULT DEF DECL_XMLNS CALL ALLOC ]
+##
+## The known suffix of the stack is as follows:
+## SUBTREE option(squares(wstext)) LBRACE ws_list(locate(head_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 95, spurious reduction of production list(ws_or(locate(head_node))) ->
+## In state 96, spurious reduction of production list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) list(ws_or(locate(head_node)))
+## In state 104, spurious reduction of production ws_list(locate(head_node)) -> list(ws_or(locate(head_node)))
+##
+
+<YOUR 989 ERROR MESSAGE HERE>
+
+main: IDENT RBRACE
+##
+## Ends in an error in state: 131.
+##
+## main -> ws_list(locate(head_node)) . EOF [ # ]
+##
+## The known suffix of the stack is as follows:
+## ws_list(locate(head_node))
+##
+## WARNING: This example involves spurious reductions.
+## This implies that, although the LR(1) items shown above provide an
+## accurate view of the past (what has been recognized so far), they
+## may provide an INCOMPLETE view of the future (what was expected next).
+## In state 95, spurious reduction of production list(ws_or(locate(head_node))) ->
+## In state 96, spurious reduction of production list(ws_or(locate(head_node))) -> ws_or(locate(head_node)) list(ws_or(locate(head_node)))
+## In state 104, spurious reduction of production ws_list(locate(head_node)) -> list(ws_or(locate(head_node)))
+##
+
+This brace is unmatched.
+
diff --git a/lib/compiler/Grammar.mly b/lib/compiler/Grammar.mly
index 612f9b2..512686f 100644
--- a/lib/compiler/Grammar.mly
+++ b/lib/compiler/Grammar.mly
@@ -6,6 +6,7 @@
%token <string> XML_ELT_IDENT
%token <string> DECL_XMLNS
%token <string> TEXT VERBATIM
+%token <string> COMMENT
%token <string> WHITESPACE
%token <string> IDENT
%token <string> HASH_IDENT
diff --git a/lib/compiler/Lexer.mll b/lib/compiler/Lexer.mll
index 1818243..451894f 100644
--- a/lib/compiler/Lexer.mll
+++ b/lib/compiler/Lexer.mll
@@ -1,10 +1,14 @@
{
open Forester_prelude
let drop_sigil c str = 1 |> List.nth @@ String.split_on_char c str
- let raise_err lexbuf =
+ exception Lex_err of (Lexing.lexbuf * string option)
+
+ let raise_err lexbuf ?msg =
let loc = Asai.Range.of_lexbuf lexbuf in
- Forester_core.Reporter.fatalf ~loc Forester_core.Reporter.Message.Parse_error "unrecognized token `%s`" @@
- String.escaped @@ Lexing.lexeme lexbuf
+ Forester_core.Reporter.fatalf
+ ~loc
+ Forester_core.Reporter.Message.Parse_error
+ "unrecognized token `%s`.@ %a" (String.escaped @@ Lexing.lexeme lexbuf) Format.(pp_print_option pp_print_string) msg
}
let digit = ['0'-'9']
@@ -24,6 +28,7 @@ let verbatim_herald_sep = '|'
rule token = parse
| "\\%" { Grammar.TEXT "%" }
+ (* I added comments to the syntax tree, but how to proceed here? *)
| "%" { comment lexbuf }
| "##{" { Grammar.HASH_HASH_LBRACE }
| "#{" { Grammar.HASH_LBRACE }
@@ -79,7 +84,7 @@ rule token = parse
| wschar+ { Grammar.WHITESPACE (Lexing.lexeme lexbuf) }
| newline { Lexing.new_line lexbuf; Grammar.WHITESPACE (Lexing.lexeme lexbuf) }
| eof { Grammar.EOF }
- | _ { raise_err lexbuf }
+ | _ { raise_err lexbuf ?msg:None}
and comment = parse
| newline_followed_by_ws { Lexing.new_line lexbuf; token lexbuf }
@@ -88,13 +93,13 @@ and comment = parse
and custom_verbatim_herald = parse
| verbatim_herald as herald { eat_verbatim_herald_sep (custom_verbatim herald (Buffer.create 2000)) lexbuf }
- | newline { Lexing.new_line lexbuf; raise_err lexbuf }
- | _ { raise_err lexbuf }
+ | newline { Lexing.new_line lexbuf; raise_err lexbuf ?msg:None }
+ | _ { raise_err lexbuf ?msg:None }
and eat_verbatim_herald_sep kont = parse
| verbatim_herald_sep { kont lexbuf }
- | newline { Lexing.new_line lexbuf; raise_err lexbuf }
- | _ { raise_err lexbuf }
+ | newline { Lexing.new_line lexbuf; raise_err ~msg:"Did you forget to start the verbatim block with `|`?" lexbuf }
+ | _ { raise_err ?msg:None lexbuf }
and custom_verbatim herald buffer = parse
| newline as c
@@ -106,31 +111,34 @@ and custom_verbatim herald buffer = parse
| _ as c
{
Buffer.add_char buffer c;
- let buff_len = Buffer.length buffer in
- let herald_len = String.length herald in
- let offset = buff_len - herald_len in
- if offset >= 0 && Buffer.sub buffer offset herald_len = herald then
- let text =
- String_util.trim_trailing_whitespace @@
- String_util.trim_newlines @@
- Buffer.sub buffer 0 offset
- in
- Grammar.VERBATIM text
- else
- custom_verbatim herald buffer lexbuf
+ try
+ let buff_len = Buffer.length buffer in
+ let herald_len = String.length herald in
+ let offset = buff_len - herald_len in
+ if offset >= 0 && Buffer.sub buffer offset herald_len = herald then
+ let text =
+ String_util.trim_trailing_whitespace @@
+ String_util.trim_newlines @@
+ Buffer.sub buffer 0 offset
+ in
+ Grammar.VERBATIM text
+ else
+ custom_verbatim herald buffer lexbuf
+ (* How can we report the location where the verbatim block was opened?*)
+ with _ -> raise_err lexbuf ~msg:(Format.sprintf "Did you forget to close the verbatim block with `%s`?" herald);
}
and xml_qname = parse
| xml_qname as qname { qname }
- | newline { Lexing.new_line lexbuf; raise_err lexbuf }
- | _ { raise_err lexbuf }
+ | newline { Lexing.new_line lexbuf; raise_err ?msg:None lexbuf }
+ | _ { raise_err ?msg:None lexbuf }
and xml_base_ident = parse
| xml_base_ident as x { x }
- | newline { Lexing.new_line lexbuf; raise_err lexbuf }
- | _ { raise_err lexbuf }
+ | newline { Lexing.new_line lexbuf; raise_err ?msg:None lexbuf }
+ | _ { raise_err ?msg:None lexbuf }
and rangle = parse
| ">" { () }
- | newline { Lexing.new_line lexbuf; raise_err lexbuf }
- | _ { raise_err lexbuf }
+ | newline { Lexing.new_line lexbuf; raise_err ?msg:None lexbuf }
+ | _ { raise_err ?msg:None lexbuf }
diff --git a/lib/compiler/Parse.ml b/lib/compiler/Parse.ml
index e5f276c..d821cea 100644
--- a/lib/compiler/Parse.ml
+++ b/lib/compiler/Parse.ml
@@ -4,155 +4,197 @@ open Lexing
module I = Grammar.MenhirInterpreter
-(* debugging helpers *)
-let _string_of_token token =
- match token with
- | Grammar.LBRACE -> "LBRACE"
- | Grammar.RBRACE -> "RBRACE"
- | Grammar.LSQUARE -> "LSQUARE"
- | Grammar.RSQUARE -> "RSQUARE"
- | Grammar.LPAREN -> "LPAREN"
- | Grammar.RPAREN -> "RPAREN"
- | Grammar.HASH_LBRACE -> "HASH_LBRACE"
- | Grammar.HASH_HASH_LBRACE -> "HASH_HASH_LBRACE"
- | Grammar.WHITESPACE w -> w
- | Grammar.TEXT s -> s
- | Grammar.EOF -> "EOF"
- | Grammar.IDENT s -> Format.sprintf "IDENT(%s)" s
- | _ -> "<unimplemented>"
+(* NOTE:
+ I am unsure if we should ever fail during lexing. I propose: We should
+ introduce an `Error` syntax node so that the parse tree is capable of
+ representing arbitrary erroneous input. We never want this during batch
+ compilation, but always want this for the IDE. Depending on the context in
+ which the parser is running, we can immediately fail when encountering
+ such a node, or continue. This is what the `I.AboutToReduce` state is for.
+ *)
-let _char_of_token token =
- match token with
- | Grammar.LBRACE -> '{'
- | Grammar.RBRACE -> '}'
- | Grammar.LSQUARE -> '['
- | Grammar.RSQUARE -> ']'
- | Grammar.LPAREN -> '('
- | Grammar.RPAREN -> ')'
- | Grammar.HASH_LBRACE -> '#'
- | Grammar.HASH_HASH_LBRACE -> '#'
- | _ -> 'x'
+(* NOTE: Menhir generates a .messages file with one message per possible
+ error state. The incremental API associates a number to each state,
+ which we use to look up the custom parse error
+ *)
+let get_parse_error env =
+ match I.stack env with
+ | lazy(Nil) -> "Invalid syntax"
+ | lazy(Cons (I.Element (state, _, _, _), _)) ->
+ try
+ let msg = (Grammar_messages.message (I.number state)) in
+ (* HACK: messages are currently placeholders that start with '<'. We want
+ to hide those "in production". During development, remove this check.
+ Whenever you encounter a parse error, the number in the returned
+ message will tell you the line number where it is defined in the
+ `Grammar.messages` file. You can then write a more helpful message.
+ *)
+ match msg.[0] with
+ | '<' -> ""
+ | _ -> msg
+ with
+ | Not_found -> "invalid syntax (no specific message for this eror)"
-(* drive the parser to the next InputNeeded checkpoint *)
-let rec resumes checkpoint =
- match checkpoint with
- | I.InputNeeded env -> I.input_needed env
- | I.Shifting _ | I.AboutToReduce _ -> resumes @@ I.resume checkpoint
- | _ -> assert false
+let get_range : I.element option -> (position * position) option = fun el ->
+ match el with
+ | Some (I.Element (_, _, start_pos, end_pos)) ->
+ Some (start_pos, end_pos)
+ | None -> None
-(* strategy: whenever we hit an unexpected closing delimiter, we look for a matching opening delimiter in the past
- if we find one, close all intermediate (hanging) delimiters and then continue parsing
- otherwise just continue parsing
- if we hit a premature EOF, try to close all delimiters, and if that fails return the last good parse
- (on each token, we test if the ending here would have produced a valid parse) *)
-let try_parse lexbuf =
- let rec fail bracketing last_token last_accept before supplier chkpt =
- match chkpt with
- | I.HandlingError _ ->
- let loc = Asai.Range.of_lexbuf lexbuf in
- Reporter.emitf ~loc Parse_error "syntax error, unexpected `%s`\n" (Lexing.lexeme lexbuf);
- begin
- match last_token with
- | Grammar.RPAREN
- | Grammar.RSQUARE
- | Grammar.RBRACE ->
- begin
- match List.find_index (fun c -> c = last_token) bracketing with
- | Some i ->
- (* try to find a small enclosing scope *)
- let consume = List.to_seq bracketing |> Seq.take (i + 1) in
- let remaining = List.to_seq bracketing |> Seq.drop i |> List.of_seq in
- let continue = Seq.fold_left (fun acc t -> resumes @@ I.offer acc (t, lexbuf.lex_curr_p, lexbuf.lex_curr_p)) before consume in
- run remaining last_token last_accept before supplier continue
- | None ->
- (* ignore this token and move on *)
- run bracketing Grammar.EOF last_accept before supplier before
- end
- | Grammar.EOF ->
- if not @@ List.is_empty bracketing then
- (* have hanging delimiters to close *)
- let continue = List.fold_left (fun acc t -> resumes @@ I.offer acc (t, lexbuf.lex_curr_p, lexbuf.lex_curr_p)) before bracketing in
- run [] last_token last_accept before supplier continue
- else
- (* can't continue, give up and use last_accept *)
- run [] last_token last_accept before supplier last_accept
- | _ ->
- (* ignore this token and move on *)
- run bracketing Grammar.EOF last_accept before supplier before
- end
- | _ -> Reporter.fatal Parse_error "unreachable parser state"
+(* This is an attempt to create a function that better illustrates the
+ range in which an error occurs, but it turns out this is not really
+ the right design, and we probably need to use the full flexibility
+ of the incremental api, like in `incr_parse`.
- and run bracketing last_token last_accept last_input_needed supplier checkpoint =
- match checkpoint with
- | I.InputNeeded _ ->
- (* last_token has been accepted, update bracketing *)
- let bracketing =
- match last_token with
- | Grammar.RPAREN
- | Grammar.RSQUARE
- | Grammar.RBRACE ->
- assert (List.hd bracketing = last_token); List.tl bracketing
- | _ -> bracketing
- in
- (* get new token *)
- let token, start, end_ = supplier () in
- let bracketing =
- match token with
- | Grammar.LPAREN -> Grammar.RPAREN :: bracketing
- | Grammar.LSQUARE -> Grammar.RSQUARE :: bracketing
- | Grammar.LBRACE
- | Grammar.HASH_LBRACE
- | Grammar.HASH_HASH_LBRACE ->
- Grammar.RBRACE :: bracketing
- | _ -> bracketing
- in
- (* check if it's possible to end parsing here, update last_accept *)
- let la =
- if I.acceptable checkpoint Grammar.EOF start then checkpoint
- else last_accept
- in
- run bracketing token la checkpoint supplier @@ I.offer checkpoint (token, start, end_)
- | I.Accepted v -> v
- | I.Rejected
- | I.HandlingError _ ->
- fail bracketing last_token last_accept last_input_needed supplier checkpoint
- | I.Shifting _
- | I.AboutToReduce _ ->
- run bracketing last_token last_accept last_input_needed supplier @@ I.resume checkpoint
- in
- let checkpoint = Grammar.Incremental.main lexbuf.lex_curr_p in
- let supplier = I.lexer_lexbuf_to_supplier Lexer.token lexbuf in
- run [] Grammar.EOF checkpoint checkpoint supplier checkpoint
-let maybe_with_errors (f : unit -> 'a) : ('a, 'a * 'b list) result =
- let errors = ref Bwd.Emp in
- let result =
- let@ () =
- Reporter.map_diagnostic @@
- fun d ->
- errors := Bwd.snoc !errors d;
- d
+ The motivation is to report things like
+ ```
+ \foo{
+ ^ this brace is unmatched
+ ```
+ The problem here is that the opening brace and the point at which the
+ parser realizes that it is not getting closed might be arbitrarily far
+ apart. It might happen on EOF, or when an outer delimiter is closed,
+ like this:
+ ```
+ {foo bar ]
+ ```
+
+ The function `loop_handle_undo` thus does not provide us with enough
+ context to compute the location of the unmatched brace.
+ *)
+
+let parse lexbuf =
+ I.loop_handle_undo
+ Result.ok
+ (
+ fun last_successful_checkpt first_error_checkpt ->
+ match last_successful_checkpt, first_error_checkpt with
+ | I.InputNeeded succ_env, I.HandlingError err_env ->
+ let success_range = get_range @@ I.top succ_env in
+ let failure_range = get_range @@ I.top err_env in
+ let loc =
+ match success_range, failure_range with
+ | (Some (s, _), Some (_, e))
+ | (_, Some (s, e))
+ | (Some (s, e), _) ->
+ Option.some @@ Range.of_lex_range (s, e)
+ | None, None -> None
+ in
+ let message = get_parse_error err_env in
+ let diagnostic =
+ Reporter.diagnostic ?loc ~severity: Error Parse_error message
+ in
+ Error diagnostic
+ (*This should never ever happen. Report a bug at menhir!*)
+ | _, _ -> assert false
+ )
+ (I.lexer_lexbuf_to_supplier Lexer.token lexbuf)
+ (Grammar.Incremental.main lexbuf.lex_curr_p)
+
+let closed_by c o =
+ match (o, c) with
+ | (Grammar.LSQUARE, Grammar.RSQUARE)
+ | (Grammar.LPAREN, Grammar.RPAREN)
+ | (Grammar.LBRACE, Grammar.RBRACE)
+ | (Grammar.HASH_LBRACE, Grammar.RBRACE)
+ | (Grammar.HASH_HASH_LBRACE, Grammar.RBRACE) ->
+ true
+ | _ -> false
+
+let is_opening_delim = function
+ | Grammar.LSQUARE
+ | Grammar.LPAREN
+ | Grammar.LBRACE
+ | Grammar.HASH_LBRACE
+ | Grammar.HASH_HASH_LBRACE ->
+ true
+ | _ -> false
+
+let is_closing_delim = function
+ | Grammar.RSQUARE
+ | Grammar.RPAREN
+ | Grammar.RBRACE ->
+ true
+ | _ -> false
+
+let incr_parse
+ : lexbuf ->
+ (Code.t, Reporter.Message.t Asai.Diagnostic.t) Result.t
+ = fun lexbuf ->
+ let delim_stack = Stack.create () in
+ let supplier = I.lexer_lexbuf_to_supplier (Lexer.token) lexbuf in
+ (* The idea is simple: push opening delimiters onto the stack, pop them
+ once they are closed. Upon encountering an error, the reported range
+ includes the last unclosed delimiter.
+ *)
+ let initial_checkpoint = (Grammar.Incremental.main lexbuf.lex_curr_p) in
+ let rec run
+ : _ I.checkpoint ->
+ (Code.t, Reporter.Message.t Asai.Diagnostic.t) Result.t
+ = fun checkpoint ->
+ match checkpoint with
+ | I.InputNeeded _env ->
+ (* In this phase we push and pop delimiters onto the stack.*)
+ let token = Lexer.token lexbuf in
+ let start_position = lexbuf.lex_start_p in
+ let end_position = lexbuf.lex_curr_p in
+ if is_opening_delim token then
+ let range = Range.of_lex_range (start_position, end_position) in
+ Stack.push (token, range) delim_stack; ;
+ let range_of_last_opening_delim =
+ if is_closing_delim token then
+ match Stack.top_opt delim_stack with
+ | Some (open_delim, range) ->
+ if (open_delim |> closed_by token) then
+ Option.map snd @@ Stack.pop_opt delim_stack
+ else None
+ | None -> None
+ else None
+ in
+ let checkpoint = I.offer checkpoint (token, start_position, end_position) in
+ run checkpoint
+ | I.Shifting((_, _, _): Code.t I.env * Code.t I.env * bool) ->
+ let checkpoint = I.resume checkpoint ~strategy: `Simplified in
+ run checkpoint
+ | I.AboutToReduce (_, production) ->
+ let checkpoint = I.resume checkpoint ~strategy: `Simplified in
+ run checkpoint
+ | I.HandlingError env ->
+ let err = get_parse_error env in
+ let range_of_last_unclosed =
+ match Stack.top_opt delim_stack with
+ | Some (token, range) ->
+ Some range
+ | None -> None
+ in
+ let loc =
+ match Option.map Range.view range_of_last_unclosed with
+ | Some (`Range (start_pos, end_pos)) ->
+ Range.make
+ (start_pos, Range.of_lex_position @@ Lexing.lexeme_start_p lexbuf)
+ | Some (`End_of_file _) -> Range.of_lexbuf lexbuf
+ | None -> Range.of_lexbuf lexbuf
+ in
+ Reporter.fatalf ~loc Parse_error "syntax error, unexpected `%s`. %s" (Lexing.lexeme lexbuf) err
+ | I.Accepted code -> Ok code
+ | I.Rejected ->
+ assert false
in
- f ()
- in
- match !errors with
- | Emp -> Result.ok result
- | errs -> Result.error (result, Bwd.prepend errs [])
+ run initial_checkpoint
let parse_channel filename ch =
- let@ () = Reporter.tracef "when parsing file `%s`" filename in
let lexbuf = Lexing.from_channel ch in
lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename };
- let@ () = maybe_with_errors in
- try_parse lexbuf
+ try
+ incr_parse lexbuf
+ with
+ | Grammar.Error ->
+ Reporter.fatalf ~loc: (Range.of_lexbuf lexbuf) Parse_error "failed to parse"
+ | exn -> raise exn
let parse_file filename =
let ch = open_in filename in
- let@ () = Fun.protect ~finally: (fun _ -> close_in ch) in
- parse_channel filename ch
-
-let parse_string str =
- let@ () = Reporter.tracef "when parsing string" in
- let lexbuf = Lexing.from_string str in
- let@ () = maybe_with_errors in
- try_parse lexbuf
+ Fun.protect ~finally: (fun _ -> close_in ch) @@
+ fun _ ->
+ parse_channel filename ch
diff --git a/lib/compiler/Parse.mli b/lib/compiler/Parse.mli
deleted file mode 100644
index 1a0a374..0000000
--- a/lib/compiler/Parse.mli
@@ -1,5 +0,0 @@
-open Forester_core
-
-val parse_file : string -> (Code.t, Code.t * Reporter.Message.t Asai.Diagnostic.t list) result
-
-val parse_string : string -> (Code.t, Code.t * Reporter.Message.t Asai.Diagnostic.t list) result
diff --git a/lib/compiler/dune b/lib/compiler/dune
index 1d38bc8..12742b5 100644
--- a/lib/compiler/dune
+++ b/lib/compiler/dune
@@ -5,6 +5,12 @@
(explain true)
(flags --inspection --table --dump))
+; The target for saving menhir's stdout to Grammar_messages.ml
+(rule
+ (targets Grammar_messages.ml)
+ (deps Grammar.messages Grammar.mly)
+ (action (with-stdout-to %{targets} (run menhir --compile-errors %{deps}))))
+
(library
(name Forester_compiler)
(preprocess
diff --git a/lib/frontend/Forester.ml b/lib/frontend/Forester.ml
index 002a5bf..cdb1232 100644
--- a/lib/frontend/Forester.ml
+++ b/lib/frontend/Forester.ml
@@ -118,11 +118,19 @@ let parse_trees_in_dirs ~dev ?(ignore_malformed = false) dirs =
let addr = Filename.chop_extension basename in
let native = EP.native_exn fp in
let source_path = if dev then Some (Unix.realpath native) else None in
- match Parse.parse_file native with
- | Result.Ok code -> Some Code.{ source_path; addr = Some addr; code }
- | Result.Error _ -> None
- | exception exn ->
- if ignore_malformed then None else raise exn
+ try
+ match Parse.parse_file native with
+ | Ok code -> Some Code.{ source_path; addr = Some addr; code }
+ | Error diagnostic ->
+ if ignore_malformed then None
+ else
+ begin
+ Reporter.Tty.display diagnostic;
+ None
+ end
+ with
+ | exn ->
+ if ignore_malformed then None else raise exn
let plant_forest_from_dirs ~env ~host ~dev ~tree_dirs ~asset_dirs : unit =
let parsed_trees = parse_trees_in_dirs ~dev tree_dirs in
diff --git a/lib/frontend/Import_graph.ml b/lib/frontend/Import_graph.ml
index 42dee1a..cd1d42c 100644
--- a/lib/frontend/Import_graph.ml
+++ b/lib/frontend/Import_graph.ml
@@ -34,7 +34,7 @@ let build (trees : Code.tree list) =
| Object { methods; _ } | Patch { methods; _ } ->
let@ _, code = List.iter @~ methods in
analyse_code roots code
- | Text _ | Hash_ident _ | Angle_ident _ | Verbatim _ | Ident _ | Open _ | Put _ | Default _ | Get _ | Decl_xmlns _ | Call _ | Alloc _ -> ()
+ | Text _ | Hash_ident _ | Angle_ident _ | Verbatim _ | Ident _ | Open _ | Put _ | Default _ | Get _ | Decl_xmlns _ | Call _ | Alloc _ | Comment _ -> ()
in
begin
let@ tree = List.iter @~ trees in
diff --git a/test/dune b/test/dune
index 7db3d0d..f14d778 100644
--- a/test/dune
+++ b/test/dune
@@ -1,5 +1,5 @@
-(tests
- (names parse dsl)
+(test
+ (name dsl)
(preprocess
(pps ppx_deriving.show))
(libraries
diff --git a/test/parse.expected b/test/parse.expected
deleted file mode 100644
index 5cbb180..0000000
--- a/test/parse.expected
@@ -1,13 +0,0 @@
-parse_good_result:
-[(Code.Ident title); (Code.Group (Base.Braces, [(Code.Text "Good")]));
- (Code.Ident taxon); (Code.Group (Base.Braces, [(Code.Text "Test")]));
- (Code.Ident author); (Code.Group (Base.Braces, [(Code.Text "Testy")]));
- (Code.Ident p);
- (Code.Group (Base.Braces,
- [(Code.Text "\n"); (Code.Text " "); (Code.Text "This");
- (Code.Text " "); (Code.Text "should"); (Code.Text " ");
- (Code.Text "parse"); (Code.Text " "); (Code.Text "correctly.");
- (Code.Text "\n"); (Code.Text " ")]
- ))
- ]
-
diff --git a/test/parse.ml b/test/parse.ml
deleted file mode 100644
index 862167c..0000000
--- a/test/parse.ml
@@ -1,25 +0,0 @@
-open Forester_core
-open Forester_compiler
-
-let emit _ = () (* ignore *)
-
-let fatal _ = exit 1
-
-let _ =
- Reporter.run ~emit ~fatal @@
- fun () ->
- let good =
- Result.get_ok @@
- Parse.parse_string
- {|
- \title{Good}
- \taxon{Test}
- \author{Testy}
-
- \p{
- This should parse correctly.
- }
- |}
- in
- Format.printf "parse_good_result:\n%s\n\n" (Code.show good)
-
--
2.46.0