Skip to content

How to execute some code assertion while parsing and get the position? #121

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

Closed
johnny0914 opened this issue Oct 18, 2018 · 3 comments
Closed
Labels

Comments

@johnny0914
Copy link

johnny0914 commented Oct 18, 2018

E.g we have the parsers below. I want to

  1. check the value of a state variable ( foo : bool )
  2. get the position of the current line and column (the current position)
  3. if the code assertion fails stop trying this rule (when foo is false this rule should not succeed).
    Is this possible in Sprache?
public static readonly Parser<string> QuotedText =
    (from open in Parse.Char('"') if(foo()){ Console.WriteLine(_the current position_)} else {stop to parse this rule};
     from content in Parse.CharExcept('"').Many().Text()
     from close in Parse.Char('"')
     select content).Token();
static readonly Parser<string> Identifier =
            from first in Parse.Letter.Once()
            from rest in Parse.LetterOrDigit.XOr(Parse.Char('-')).XOr(if(foo()){ Console.WriteLine(_the current position_)} else {stop to parse this rule}; Parse.Char('_')).Many()
            select new string(first.Concat(rest).ToArray());
@yallie
Copy link
Member

yallie commented Oct 18, 2018

Use Span() to obtain the position and Where() to fail conditionally.
Here is a sample parser that fails if the position of b is greater than 10:

static Parser<string> Sample =
	from a in Parse.Char('a').Many().Text().Token()
	from b in Parse.Char('b').Many().Text().Token().Span()
	where b.Start.Pos <= 10
	select a + b.Value;

...

var success = Sample.Parse(" aaa bbb "); // returns "aaabbb"
var failure = Sample.Parse(" aaaaaaa      bbbbbb "); // fails

@johnny0914
Copy link
Author

How to add line and column to an ParseException? As I see Sprache does not add them to the exception.Data object? Is there a global state?

    static readonly Parser<string> _char =
        from first in Parse.Letter select first.ToString();

    static readonly Parser<string> nl =
        from first in Parse.String("\n")
        .XOr(Parse.String("\r\n"))
            .XOr(Parse.String("\r"))
        select "";


    public static Parser<string> verb =
         from aa in Parse.String("verb")
         from a2 in Parse.String("*").Optional()
         from a3 in _char.Not()
         from a4 in Parse.AnyChar
         from a5 in Parse.AnyChar.Except(Parse.Char(a4)).Except(nl).Many().Text()
         from a6 in Parse.AnyChar
         where a4 == a6 ? true : throw new ParseException("MESSAGE") (HOW TO ADD LINE, COLUMN)
         select a2.IsEmpty ? "isVerb" : "isVerb*";

@yallie
Copy link
Member

yallie commented Oct 20, 2018

Sprache is stateless, so there is no global state.
To get the position, use Span(), something like this (not tested):

public static Parser<string> verb =
     // ... the first 5 lines are the same ...
     from a6 in Parse.AnyChar.Span()
     where a4 == a6.Value ? true : 
       throw new Exception($"Error at: {a6.Start.Line}, {a6.Start.Column}")
     select a2.IsEmpty ? "isVerb" : "isVerb*";

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

No branches or pull requests

2 participants