Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Irony: How to disallow a space between 2 tokens?

Tags:

c#

grammar

irony

I'm trying to define PHP-style variables in Irony like so:

variable.Rule = "$" + identifier;

Works great, except that you're allowed to put spaces between the $ and the identifier. I want to prevent that. How?

Do I have to create a new customized terminal? If so, will I still be able to take advantage of the IdentifierTerminal magic?


Digging around in IdentifierTerminal I see there's actually a flag for "NameIncludesPrefix", but it's only used in one place. Looks like the prefix is stored in this CompoundTokenDetails object... which I'm not sure how to use. Edit: Nevermind, this was a dead-end. Those flags are for adding modifiers to how the variable behaves.


This kinda works...

class VariableTerminal : Terminal
{
    public VariableTerminal(string name) : base(name)
    {
    }

    public override IList<string> GetFirsts()
    {
        return new[] { "$" };
    }

    public override Token TryMatch(ParsingContext context, ISourceStream source)
    {
        if (source.PreviewChar != '$') return null;
        do
        {
            source.PreviewPosition++;
        } while (!source.EOF() && char.IsLetter(source.PreviewChar));

        var token = source.CreateToken(OutputTerminal);
        return token;
    }
}

I'm not really sure what OuputTerminal is though.. I guess it's some kind of dynamic property based on the current preview position? The way parsing is done in Irony is a little strange I think...

Anyway, the problem with this is what when I use this VariableTerminal, instead of how I was doing it before with "$" + IdentifierTerminal", when there's a syntax error, such as in this code:

p cat

The identifier terminal used to say

Syntax error, expected: { real string $ true false ...

But the variable gives me this error instead:

Invalid character: 'c'

The former error was more useful I think. I don't really understand why it's spitting out a different error...how can I get it to say that instead?

like image 660
mpen Avatar asked Feb 21 '11 01:02

mpen


1 Answers

for me it looks clear that what you want is currently not supported (checked in the sources). See the discussion on the pascal character (the very botoom) as well which is identified as '#number' not allowing space between.

To go with non-terminal is not a way I believe. Grammars work by nature that you can have whitespaces between tokens. So what you really need is to follow advice given on the project wiki - section Custom Terminals on the bottom of the page and extend the Terminal class to fit your needs.

Or the easiest option would be to introduce flag which can make the prefix mandatory. Extending the IdentifierTerminal class and overriding TryMatch method.

If you look on this method in CompoundTerminalBase class what the TryMatch method does is basically:

  1. ReadPrefix (but more less ignore if the prefix was found or not)
  2. ReadBody (fails if the body wasn't read)
  3. ReadSuffix

The ReadPrefix method sets a details.Prefix flag if a prefix is found. So after calling ReadPrefix you may want to check your newly introduced flag for mandatory prefix and if it is set you can check if the details.Prefix flag is set as well, otherwise you emit an error.

Good luck :)

like image 173
Jan Zyka Avatar answered Oct 06 '22 11:10

Jan Zyka