Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error recovery is poorly documented #67

Open
chrismacklin opened this issue Nov 13, 2016 · 6 comments
Open

error recovery is poorly documented #67

chrismacklin opened this issue Nov 13, 2016 · 6 comments

Comments

@chrismacklin
Copy link

Documentation for options for parse error handling and recovery are nonexistent. When a parse error occurs, what happens? What options are available for handling this error? How can I provide custom behavior for the exception that is raised when a parse error occurs?

@chrismacklin chrismacklin changed the title error recovery is pretty much totally undocumented error recovery is poorly documented Nov 13, 2016
@artempyanykh
Copy link

Faced a similar problem. I'm trying to use FsLexYacc in my project, and although I can draw some parallels with OCaml's tooling or lex/yacc this helps only to some extent and I still can't figure out how to do high fidelity error handling.

Of course, a Menhir-like manual on error recovery would be great, but even an real-world example parser (non-toy with real error handling) would be of great help: examples I have found in the repo and the docs are not complex enough and/or don't have any error recovery. So, any links would be appreciated.

@daz10000
Copy link

daz10000 commented Feb 11, 2022 via email

@robreno
Copy link

robreno commented Oct 27, 2022

First off, I love F# and FsLexYacc. I am working on creating a query engine (lexer/parser) for a custom query language for a 2091 page text I have reverse indexed. I have successfully created a very simply query language (lexer/parser) that works really well.

I too have encountered this problem and trying to solve it right now. I downloaded the solution/projects and have them compiling locally (getting some interesting warnings that might be bugs, like inconsistent parameter names stuff. Will document more fully and when I figure out who to ask if this is a real issue will do so). I am too afraid to do it on Git right now as I am really new to using Git and don't want to offend anyone or do something stupid. But I entered a Term with the wrong syntax (paraid instead of parid) and threw an exception. Stepping into the QueryParser.fsi file I set a breakpoint at :

// Implementation file for parser generated by fsyacc
parseError = (fun (ctxt:FSharp.Text.Parsing.ParseErrorContext<_>) -> 
                              match parse_error_rich with 
                              | Some f -> f ctxt
                              | None -> parse_error ctxt.Message);

image

The ctxt.Message is "syntax error", but of course this does not propagate error message "syntax error" to the exception handler in the F# code I am calling the parser from. Or at least I don't see it or know how to get it, but that would be very useful as a syntax error is good to know in a query so I can handle it correctly in my application. I really want to figure out how to propagate a more verbose error message like "syntax error" in such a case.

Here is all the error context I can get in my code:

System.Exception
HResult=0x80131500
Message=parse error
Source=FsLexYacc.Runtime

This exception was originally thrown at this call stack:
  [External Code]
  UBViews.Query.Parser.engine<a>(Microsoft.FSharp.Core.FSharpFunc<FSharp.Text.Lexing.LexBuffer<a>, UBViews.Query.Parser.token>, FSharp.Text.Lexing.LexBuffer<a>, int) in QueryParser.fs
  UBViews.Query.Parser.start<a>(Microsoft.FSharp.Core.FSharpFunc<FSharp.Text.Lexing.LexBuffer<a>, UBViews.Query.Parser.token>, FSharp.Text.Lexing.LexBuffer<a>) in QueryParser.fs
  UBViews.Query.Local.SimpleParse.parseQuery(string) in SimpleParse.fs

I found the following in the FsLexYacc.Runtime:

#if INTERNALIZED_FSLEXYACC_RUNTIME
module internal ParseHelpers = 
#else
module ParseHelpers = 
#endif
    let parse_error (_s:string) = ()
    let parse_error_rich = (None : (ParseErrorContext<_> -> unit) option)

I would like to know how to get access to the ParseHelpers which may allow access to parse_error_rich which may carry the correct error message.

@fxf06
Copy link

fxf06 commented Dec 2, 2022

Got similar problem on how error is handled. Though is supposed to behaves like Ocamlyacc, it is hard to handle the "error" token right.
Regarding the error message, the parse_error_rich function is defined to None in the source. I did this is my code:

let my_parse_error (ctx:ParseErrorContext<_>) =
    let debugText = ref ""
    let (startPos, endPos) = ctx.ParseState.ResultRange
    debugText.Value <- debugText.Value + $"{startPos.FileName}({startPos.Line},{startPos.Column}): Parse error: token: '{ctx.CurrentToken}'\n"
    let sp =
        {
            CommentStart = -1;
            CommentEnd   = -1;
            CommentCol   = -1;
            SourceStart  = startPos.AbsoluteOffset;
            SourceEnd    = endPos.AbsoluteOffset;
            SourceCol    = startPos.Column;
            LineStart    = startPos.Line;
            LineEnd      = endPos.Line
        }
    debugText.Value <- debugText.Value + $"Input:\n{sp.fragment()}\n"
    debugText.Value <- debugText.Value + $"ReduceTokens        : {ctx.ReduceTokens}\n"
    debugText.Value <- debugText.Value + $"ReducibleProductions: {ctx.ReducibleProductions}\n"
    debugText.Value <- debugText.Value + $"ShiftTokens         : {ctx.ShiftTokens}\n"
    debugText.Value <- debugText.Value + $"StateStack          : {ctx.StateStack}\n"
    ParserTools.SetParseErrorContext debugText.Value

let parse_error_rich = Some my_parse_error

which is:

  1. define your parser error function
  2. set parser_error_rich to Some "your_function"

I used a reference in a other module to get the data once the parser engine returns.

What is also unfortunate is that Fsyacc skips anything below the last "%%", which is normally code that would be simply added at end of the generated F# code. Then, we could have access also to everything defined like tokens values, rules values, etc...

@mcgowanr-mtw
Copy link

Could we get an update on this?

The fsyacc page does give us RaiseError as part of the parseState and then says "You can call RaiseError if you like." Is that what I'm supposed to use for parser errors? If so, how would I do that?

@daz10000
Copy link

daz10000 commented May 18, 2023

Put me in the loves fsyacc category and I maintain a huge DNA compiler using it.. That said, I never worked out how to do error handling :( My vague recollection of the journey was

  • for fsyacc docs... see ocaml docs
  • ocaml docs.. see yacc docs
  • tries the error token - strange errors. Maybe it's the _ pattern... ? stranger errors..
  • looked at the F# compiler source 😢 - too complex

I'd weep for even 5 mins of typed simple examples showing how to intercept lack rules where none of the expected tokens match..

To keep this more concrete, I want to be add something like an | error -> { throw an expected X, Y,Z message here} to a block like this., Apologies if it all works now, but I got nowhere when I last gave up,

Exp:
    | IntLiteral                    { $1 }
    | StringLiteral                 { $1 }
    | FloatLiteral                  { $1 }
    | VARIABLE                      { (tokenToVariable $1 NotYetTyped) }
    | LPAREN Exp RPAREN             { $2 }
    | HYPHEN Exp %prec UMINUS       { (negate $2) }
    | Exp STAR Exp                  { (createBinaryOp Multiply $1 $3) }
    | Exp SLASH Exp                 { (createBinaryOp Divide $1 $3) }
    | Exp PLUS Exp                  { (createBinaryOp Add $1 $3) }
    | Exp HYPHEN Exp                { (createBinaryOp Subtract $1 $3) }
  (* want to add  a handler here for anything else*)

Searching in 2023 gets me this question on stack overflow which is the second hit (first is how to calculate line numbers after wrapping whole parser in a try/with block). There must be something more sophisticated? (if not, that's probably good to know too).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants