Dave Doty
2017-11-26 23:42:10 UTC
I thought I'd re-ask this question to see if anyone has any ideas. My
original post is a bit long so I'll be briefer:
TL/DR: how does one replace an error message generated by elm-tools/parser
with a custom error message?
If an error condition is detected by directly my code while parsing, then I
can use
P.fail "my custom error message"
But what if the problem is found not directly in my code, but in
elm-tools/parser code that I call? For example,
Parser.list spaces Parser.int
If the current text doesn't look like a list of integers, then Parser.list will
generate a Problem. But suppose I want to output a custom error message
instead of simply reporting the error message contained in the Problem generated
by Parser.list. How can I do this?
It's analogous to (in imperative languages with exceptions) catching an
exception thrown by a called function and throwing a new, more informative
exception.
original post is a bit long so I'll be briefer:
TL/DR: how does one replace an error message generated by elm-tools/parser
with a custom error message?
If an error condition is detected by directly my code while parsing, then I
can use
P.fail "my custom error message"
But what if the problem is found not directly in my code, but in
elm-tools/parser code that I call? For example,
Parser.list spaces Parser.int
If the current text doesn't look like a list of integers, then Parser.list will
generate a Problem. But suppose I want to output a custom error message
instead of simply reporting the error message contained in the Problem generated
by Parser.list. How can I do this?
It's analogous to (in imperative languages with exceptions) catching an
exception thrown by a called function and throwing a new, more informative
exception.
I'm a bit confused what is the intended usage of elm-tools/parser to
generate custom error messages. In particular, when creating a Parser
value, but before calling run, there's no way to specify what sorts of
errors can happen and messages to generate in response.
The only interface in the module with errors seems to happen when calling
the Parser.run function, which happens just once in client code.
For instance, suppose I build up a big Parser hierarchically out of
fullParser : Parser ...
fullParser =
succeed identity
|. keyword "key1"
|= (inContext "subparser 1" <| subparser1)
|. keyword "key2"
|= (inContext "subparser 2" <| subparser2)
|. P.keyword "key3"
|= (inContext "subparser 3" <| subparser3)
subparser1 : Parser ...
subparser1 =
succeed identity
|. keyword "subkey1"
|= (inContext "subsubparser 1:1" <| subparser11)
|. keyword "subkey2"
|= (inContext "subsubparser 1:2" <| subparser12)
And at the base level, perhaps I call library code, for instance from
subparser11 : P.Parser (List Int)
subparser11 =
sequence
{ start = "{"
, separator = ","
, end = "}"
, spaces = spaces
, item = int
, trailing = Forbidden
}
Now, to run the parser, I call
case run fullParser source of
Ok parsedValue ->
parsedValue
Err { row, col, source, problem, context } ->
<generate some error message>
Suppose a problem happened in subparser11 because
Parser.LanguageKit.sequence detected an error such as a missing comma ("{34,
56 78}"). So in the Err, the information we have access to is the Problem
generated by Parser.LanguageKit.sequence, which will be something like
BadOneOf ([ExpectingSymbol ",",ExpectingSymbol "}"])
That's not a terrible thing to print, but we can do better. I also have access to the Context value with description "subsubparser 1:1" and a row and col.
It seems that to create a custom error message that says something like "I was expecting either , or } at this point in the 'subparser 1:1' set",
I can use the context description string, but it seems necessary to use a big case statement after the call to run
that uses context strings and the type of Errors that are returned to tell where in the parsing the problem failed, and then customize the error message.
In a language with exceptions, I would do something like this at the point in the parser code itself, where the Problem is generated
subparser1(source)
...
subparser11(source)
...
Parser.LanguageKit.sequence(source)
raise CustomException()
In other words, I could catch the BadOneOf exception generated by the library code, and based on the local context in which I caught that exception,
create a custom Exception of my own.
But I don't see a way to do that sort of "Problem transforming" with elm-tools/parser,
i.e., put the error-transforming code at the point in the definition of the parser where it is relevant.
It seems the only option is to put lots of information into the context string at that point, and then have a big case statement after calling Parser.run
to see where exactly in the parser hierarchy the problem occurred. But this anti-pattern of using Strings as poor man's Enums seems very un-Elm to me.
generate custom error messages. In particular, when creating a Parser
value, but before calling run, there's no way to specify what sorts of
errors can happen and messages to generate in response.
The only interface in the module with errors seems to happen when calling
the Parser.run function, which happens just once in client code.
For instance, suppose I build up a big Parser hierarchically out of
fullParser : Parser ...
fullParser =
succeed identity
|. keyword "key1"
|= (inContext "subparser 1" <| subparser1)
|. keyword "key2"
|= (inContext "subparser 2" <| subparser2)
|. P.keyword "key3"
|= (inContext "subparser 3" <| subparser3)
subparser1 : Parser ...
subparser1 =
succeed identity
|. keyword "subkey1"
|= (inContext "subsubparser 1:1" <| subparser11)
|. keyword "subkey2"
|= (inContext "subsubparser 1:2" <| subparser12)
And at the base level, perhaps I call library code, for instance from
subparser11 : P.Parser (List Int)
subparser11 =
sequence
{ start = "{"
, separator = ","
, end = "}"
, spaces = spaces
, item = int
, trailing = Forbidden
}
Now, to run the parser, I call
case run fullParser source of
Ok parsedValue ->
parsedValue
Err { row, col, source, problem, context } ->
<generate some error message>
Suppose a problem happened in subparser11 because
Parser.LanguageKit.sequence detected an error such as a missing comma ("{34,
56 78}"). So in the Err, the information we have access to is the Problem
generated by Parser.LanguageKit.sequence, which will be something like
BadOneOf ([ExpectingSymbol ",",ExpectingSymbol "}"])
That's not a terrible thing to print, but we can do better. I also have access to the Context value with description "subsubparser 1:1" and a row and col.
It seems that to create a custom error message that says something like "I was expecting either , or } at this point in the 'subparser 1:1' set",
I can use the context description string, but it seems necessary to use a big case statement after the call to run
that uses context strings and the type of Errors that are returned to tell where in the parsing the problem failed, and then customize the error message.
In a language with exceptions, I would do something like this at the point in the parser code itself, where the Problem is generated
subparser1(source)
...
subparser11(source)
...
Parser.LanguageKit.sequence(source)
raise CustomException()
In other words, I could catch the BadOneOf exception generated by the library code, and based on the local context in which I caught that exception,
create a custom Exception of my own.
But I don't see a way to do that sort of "Problem transforming" with elm-tools/parser,
i.e., put the error-transforming code at the point in the definition of the parser where it is relevant.
It seems the only option is to put lots of information into the context string at that point, and then have a big case statement after calling Parser.run
to see where exactly in the parser hierarchy the problem occurred. But this anti-pattern of using Strings as poor man's Enums seems very un-Elm to me.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.