antlr / antlr4

ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files.
http://antlr.org
BSD 3-Clause "New" or "Revised" License
16.99k stars 3.26k forks source link

Configure parser rules to implement an interface / base class #2840

Open jasonf20 opened 4 years ago

jasonf20 commented 4 years ago

I have a use case where I have similar rules which I would like to handle with some common code. Currently I handle this by writing "generic" code that checks the types of the child rules of my current context. I would like to write an interface which would include some fields I know will exist in the generated ParserRuleContext. However, as far as I was able to find there is no way to set a common interface that both those rules would implement.

For example (made up example):

exp1: field  ":BOOLEAN";
exp2: field ":STRING";

In some future parser rules I want to allow only exp1, only exp2 and sometimes either. However to reduce code I handle these two expressions (converting to my runtime representation) with generic code. I realize I can merge these two rules and check at runtime if I got the one that is allowed in any given context, but I find it simpler and safer to let the grammar prevent incorrect usages.

I would like to be able to add something like:

exp1: field ":BOOLEAN" {implement com.sompackage.FieldExpression }
exp2: field ":STRING" {implement com.somepackage.FieldExpression }

And then later I could use that interface (which would have a "field" field with the correct ParserRuleContext subtype).

I was unable to find functionality like this. There might be a way to do it by embedding "java" code in my grammar file. However, I use this grammar across Java and Javascript and would like to keep it language neutral (the "implement ..." should generate the correct "extends" depending on the target language. It shouldn't be embedded target language code).

I should also mention that this problem is less of an issue if using a visitor/listener pattern. Since using that pattern I could call a common method with the args extracted from the rule context, it it still has some duplicate code. Also I've found the visitor/listener pattern less suitable for my use case (but it may be worth re-considering at some point).

If there is a way to achieve this that I missed, or if for some reason I'm off track please let me know.

ds1709 commented 9 months ago

In my case, I generates parser for C#. All output classes are partial, so I can implement any interface for generated classes in non-gerated part of code for any rule I want.