Multiple stringtemplates from one rule - antlr

Being new to ANTLR I am trying to figure out how stringtemplates work. I would like to generate a piece of Java code based on a very simple input file. Because of its flexible concept I would like to use (string)templates.
In Java, one typically has to generate member declaration, initialize them somewhere else, and use them in even another place. The identifier names should match and are thus repeated. This means little template instantiations are needed here and there. Surely it can be done, but I cannot seem to find out how, maybe I am missing some important 'clue'?
I wrote a test program to investigate the concept. It takes a simple input file:
red = #FF0000
green = #00FF00
blue = #0000FF
and should produce something like the following output:
class MyColors {
// Class members
public java.awt.Color red;
public java.awt.Color green;
public java.awt.Color blue;
// Constructor
/* Question: How to access the right initializer value here?!? The values are not accessible at this level of the grammar*/
public MyColors() {
red = java.awt.Color.getColor("#FF0000");
green = java.awt.Color.getColor("#00FF00");
blue = java.awt.Color.getColor("#0000FF");
}
};
...where the names of the variables and initializers in the constructor are filled in according to the input.
The grammar I have defined is as follows:
grammar Test;
options {
output=template;
}
colors: (a+=def)+ -> colorClassDef(name={$a});
def: ident '=' name -> colorDef(id={$ident.text}, name={$name.text});
ident: ID;
name: ID;
ID: ('a'..'z'|'A'..'Z'|'#'|'0'..'9')+;
WS: (' '|'\t'|'\r'|'\n')+ { skip(); };
The template definitions are as follows:
group Test;
colorClassDef(name, id) ::= <<
class MyColors {
// Class members
<name:{ v | public java.awt.Color <v>;
}>
// Constructor
/* Question: How to access the initializer value here?!? */
public MyColors() {
<name:{ v | <v> = java.awt.Color.getColor("<id>");
}>
}
};
>>
/* How to return both id and name here seperately, as ID should go into the declaration and name should to into the init? */
colorDef(id, name) ::= <<
<id>
>>
Can anyone suggest how I can get <id> and <name> out of the rule 'def' inorder to include them in the right portion of the generated code?
I have found multiple questions regarding multiple return values, like Returning multiple values in ANTLR rule and antlr2 return multiple values, but none include stringtemplates.
I even bought 'the book' and worked my way trought the java bytecode generator, but did not find my answer there. All examples seem to generate one bit of output for one bit of input. (No regrets though, the book makes excellent bed-time reading ;-)
Can anyone point out to me what clue I am missing? What would be the most appropriate way to fix this problem? Some examplary code and pointers to the documentation would be much appreciated.
Thanks,
Maarten

Can anyone suggest how I can get and out of the rule 'def' inorder to include them in the right portion of the generated code?
Here's a straight-forward Java-centric approach to getting what you want. It's not as graceful as I would like (I assume there's room for improvement), but I think it solves the problem without a great deal of hassle. I renamed a few things, but I think I kept the spirit of your approach intact.
First, the template. Note that template colorClassDef requires every bit of information that's determined by the grammar: every id, every name, and the association between each id with its corresponding name. Here's one of accessing all of that from the template:
group Colors;
colorClassDef(ids, colors) ::= <<
class MyColors {
// Class members
<ids:{ id | public java.awt.Color <id>;
}>
// Constructor
public MyColors() {
<ids:{ id | <id> = java.awt.Color.getColor("<colors.(id)>");
}>
}
};
>>
Here I'm using parameter ids to store a list of all the incoming ids and parameter colors to store a map that associates an id (the key) to a name (the value). For the constructor portion, ST accesses the id's name from colors with the "indirect property lookup" syntax: <colors.(id)>. Since colors is a map, id is used as a key into the map and the value is written into the template.
Template colorClassDef handles everything, so I removed template colorDef.
Second, the grammar. It needs to provide the ids and color map. Here's one way of doing that:
grammar Colors;
options {
output=template;
}
colors
#init {
java.util.LinkedList<String> ids = new java.util.LinkedList<String>();
java.util.HashMap<String, String> colors = new java.util.HashMap<String, String>();
}
: (ident '=' name
{ids.add($ident.text); colors.put($ident.text, $name.text);}
)+ EOF
-> colorClassDef(ids={ids}, colors={colors})
;
ident: ID;
name: ID;
ID: ('a'..'z'|'A'..'Z'|'#'|'0'..'9')+;
WS: (' '|'\t'|'\r'|'\n')+ { skip(); };
(To keep the grammar relatively simple, I merged rules colors and def into colors.)
Each ident is added to list ids and each name is added to map colors as the value to the corresponding ident key. Then off they go to the template.
Here is a test class to test out the works:
public class ColorsTest {
public static void main(String[] args) throws Exception {
final String code = "red = #FF0000\ngreen = #00FF00\nblue = #0000FF";
process(code, "Colors.stg");
}
private static void process(final String code, String templateResourceName)
throws IOException, RecognitionException, Exception {
CharStream input = new ANTLRStringStream(code);
ColorsLexer lexer = new ColorsLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ColorsParser parser = new ColorsParser(tokens);
InputStream stream = ColorsTest.class.getResourceAsStream(templateResourceName);
Reader reader = new InputStreamReader(stream);
parser.setTemplateLib(new StringTemplateGroup(reader));
reader.close();
stream.close();
ColorsParser.colors_return result = parser.colors();
if (parser.getNumberOfSyntaxErrors() > 0){
throw new Exception("Syntax Errors encountered!");
}
System.out.println(result.toString());
}
}
Here's a test case based on the input in your question.
Input
red = #FF0000
green = #00FF00
blue = #0000FF
Output
class MyColors {
// Class members
public java.awt.Color red;
public java.awt.Color green;
public java.awt.Color blue;
// Constructor
public MyColors() {
red = java.awt.Color.getColor("#FF0000");
green = java.awt.Color.getColor("#00FF00");
blue = java.awt.Color.getColor("#0000FF");
}
};

Related

Regenerate source from Antlr4 ParseTree preserving whitespaces

I am able to use Java.g4 grammar and generate lexers and parsers. This grammar is used to get started. I have a ParseTree and I walk it and change whatever I want and write it back to a Java source code file. The ParseTree is not directly changed though.
So for example this is the code. But I also modify method names and add annotations to methods. In some cases I also remove method parameters
#Override
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
printer.write( intervals );
printer.writeList(importFilter );
ParseTree pt = ctx.getChild(1);
/*
The class name is changed by a visitor because
we get a ParseTree back
*/
pt.accept(new ParseTreeVisitor<Object>() {
#Override
public Object visitChildren(RuleNode ruleNode) {
return null;
}
#Override
public Object visitErrorNode(ErrorNode errorNode) {
return null;
}
#Override
public Object visit(ParseTree parseTree) {
return null;
}
#Override
public Object visitTerminal(TerminalNode terminalNode) {
String className = terminalNode.getText();
System.out.println("Name of the class is [ " + className + "]");
printer.writeText( classModifier.get() + " class " + NEW_CLASS_IDENTIFIER );
return null;
}
});
}
But I am not sure how to print the changed Java code while preserving all the original whitespaces.
How is that done ?
Update : It seems that the whitespaces and comments are there but not accessible easily. So it looks like I need to specifically keep track of them and write them along with the code. Not sure though.
So more specifically the code is this.
package x;
import java.util.Enumeration;
import java.util.*;
As I hit the first ImportDeclarationContext I need to store all the hidden space tokens. When I write this code back I want to include those spaces too.
Solution :
Don't skip but add to a HIDDEN channel
//
// Whitespace and comments
//
WS : [ \t\r\n\u000C]+ -> channel(HIDDEN)
;
COMMENT
: '/*' .*? '*/' -> channel(HIDDEN)
;
Use code like this to get them back
I use this to get the whitespaces and comments before each method. But it should be possible to get whitespaces from other places too. I think.
((CommonTokenStream) tokens).getHiddenTokensToLeft( classOrInterfaceModifierContext.getStart().getTokenIndex(),
Token.HIDDEN_CHANNEL);

Abstraction with variables

So I'm taking a highschool online Java class and well my teacher doesn't help...
so we are learning about abstraction and I had already done this with my "alien" class that moves, he will face one way going forward and another going backward by switching two images... However when they showed the code in an example it seemed overcomplicated and I was wondering if I am just missing something.
My Code
private String avatarRight = "Alien.png";
private String avatarLeft = "Alien1.png";
/**
* Act - do whatever the Alien wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
movement(avatarRight, avatarLeft);
gatherPart();
}
(Superclass containing movement method)
/**
* Sets up the movement keys and facing for the Object
*/
public void movement(String avatarRight,String avatarLeft)
{
if (atWorldEdge() == false)
{
if (Greenfoot.isKeyDown("w"))
{
setLocation(getX(), getY()-2);
}
if (Greenfoot.isKeyDown("d"))
{
setImage(avatarRight);
setLocation(getX()+2, getY());
}
if (Greenfoot.isKeyDown("s"))
{
setLocation(getX(), getY()+2);
}
if (Greenfoot.isKeyDown("a"))
{
setImage(avatarLeft);
setLocation(getX()-2, getY());
}
}
else
{
}
}
Their Code
{
private GreenfootImage image1;
private GreenfootImage image2;
private boolean isKeyDown;
private String key;
private String sound;
/**
* Create a Duke and initialize his two images. Link Duke to a specific keyboard
* key and sound.
*/
public Duke(String keyName, String soundFile)
{
key = keyName;
sound = soundFile
image1 = new GreenfootImage("Duke.png")
image3 = new GreenfootImage("duke2.png")
setImage(image1);
}
}
Where I just say avatarRight = "this image"
they say key = keyname
key = "key"
edit:
So the way the set it up and I set mine up initially was
private int rotation;
public Capsule(int rot)
{
rotation = rot
setRotation(rotation);
}
but the one below works perfectly fine, as far as I can tell. Is there any reason why I would do the above code rather than the one below
public Capsule(int rot)
{
setRotation(rot);
}
OK, based on the commentary I'm inclined to say you're not comparing the same things.
Where I just say avatarRight = "this image" they say key = keyname key
= "key"
That doesn't seem to be exactly accurate. Where you say
private String avatarRight = "Alien.png"; and
private String avatarLeft = "Alien1.png";
they have the png hard coded in the constructor as "Duke.png" and "duke2.png", which by the way contains an error because as far as I can see there's no image3.
So the keyName doesn't seem to directly map as you say it does. Perhaps you should investigate the code further to see how they use the key or provide equal code for both examples so we can further see the differences.
By looking at it perhaps there's a map somewhere and the key would be used to access the specific alien or other type of game object.
To address your edit.
Is there any reason why I would do the above code rather than the one
below
It's not possible to tell by that code if the reason has any value; it doesn't appear to by what you've shown. I can tell you that the reason I would do that is because I need that value elsewhere but not now. That could be for any number of reasons. You have to look at all the code available to you and see if they ever use that variable anywhere else without passing it in. Then you have found the reason or the lack there of.

NUnit - Multiple properties of the same name? Linking to requirements

I'm linking all our our System Tests to test cases and to our Requirements. Every requirement has an ID. Every Test Case / System Tests tests a variety of requirements. Every module of code links to multiple requirements.
I'm trying to find the best way to link every system test to its driving requirements.
I was hoping to do something like:
[NUnit.Framework.Property("Release", "6.0.0")]
[NUnit.Framework.Property("Requirement", "FR50082")]
[NUnit.Framework.Property("Requirement", "FR50084")]
[NUnit.Framework.Property("Requirement", "FR50085")]
[TestCase(....)]
public void TestSomething(string a, string b...)
However, that will break because Property is a Key-Value pair. The system will not allow me to have multiple Properties with the same key.
The reason I'm wanting this is to be able to test specific requirements in our system if a module changes that touches these requirements.
Rather than run over 1,000 system tests on every build, this would allow us to target what to test based on changes done to our code.
Some system tests run upwards of 5 minutes (Enterprise healthcare system), so "Just run all of them" isn't a viable solution. We do that, but only before promoting through our environments.
Thoughts?
Have you considered a custom property attribute derived from NUnit.Framework.Property?
Something like the following seems like it might work for you judging by a LINQPad 4 "query" with Language set to C# Program and a reference to nunit.framework.dll (version 2.4.8) added:
// main method to exercise a our PoC test case
void Main()
{
TestSomething("a", "b");
}
// our PoC custom property attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class RequirementsAttribute : NUnit.Framework.PropertyAttribute
{
public RequirementsAttribute(string[] requirements)
: base(requirements)
{
}
}
// a test case using our custom property attribute to relate it to multiple requirements
[Requirements(new string[] { "FR50082", "FR50084" })]
[TestCase("PoCTest")]
public void TestSomething(string a, string b)
{
// blah, blah, blah
Assert.AreNotEqual(a, b);
}
For some reason I could not add the link to the google discussion post to the comment above, so I have added the post here too. (The link is https://groups.google.com/forum/#!topic/nunit-discuss/ndV3VTPndck)
A Category is always displayed in TE as "Category [xxxxxxx]", where xxxxx is whatever string you send in, if you don't specify any, it will be the name of the class derived from CategoryAttribute.
If you want to use Category, you should, as Charlie said on the google post, use one entry per requirement. If you add the string Requirement to the value, it can look pretty good, but most follow the rules in (1) above, it could be like:
Category[Requirement:FR12345]
Code:
public class RequirementAttribute : CategoryAttribute
{
public RequirementAttribute(string s)
: base("Requirement:" + s)
{ }
}
If you want it to display like : Requirement[FR12345], then you MUST use a Property, but you can't have multiple Keys, so only one such per test.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string s)
: base(s)
{}
}
4: If you want to have multiple requirements per test and still have something like the display in (3), you must make the keys unique. It doesn't need to look too bad. In the code below I have just added a counter to it.
It will display as :
Requirement-1[FR12345]
Requirement-2[FR23456]
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
int i = 0;
foreach (var s in array)
{
Properties.Add("Requirement-" + i, s);
i++;
}
}
}
and you use it like:
[Requirement(new[] { "1234", "2345" })]
[Test]
public void Test()
{ }
(And if you want a syntax without the "new", the previous answer show that syntax with the param instead.)
Option 4 will not group by requirement number, but by the counter. If you want to group by requirement number you can use option 5:
5.
Add the requirement number to the key, but leave the value blank.
It will look like:
Requirement-FR12345
In this way, you also skip the prefix and have each requirement as its own kind of category in the TE.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
foreach (var s in array)
{
Properties.Add("Requirement-" + s,"");
}
}
}
And, you could of course also skip the prefix altogether.

How to implement just some basic keywords highlighting in text editor?

I'm a novice programmer trying to learn plug-in development. I'd like to upgrade the sample XML editor so that some words like "cat", "dog", "hamster", "rabbit" and "bird" would be highlighted when it appears in an XML file (it's just for learning purpose). Can anyone give me some implementation tips or suggestions? I am clueless.. (But I am carrying out my research on this as well, I'm not being lazy. You have my word.) Thanks in advance.
You can detect words in the plain text part of the XML by modifying the sample XML editor as follows.
We can use the provided WordRule class to detect the words. The XMLScanner class which scans the plain text needs to be updated to include the word rule:
public XMLScanner(final ColorManager manager)
{
IToken procInstr = new Token(new TextAttribute(manager.getColor(IXMLColorConstants.PROC_INSTR)));
WordRule words = new WordRule(new WordDetector());
words.addWord("cat", procInstr);
words.addWord("dog", procInstr);
// TODO add more words here
IRule [] rules = new IRule [] {
// Add rule for processing instructions
new SingleLineRule("<?", "?>", procInstr),
// Add generic whitespace rule.
new WhitespaceRule(new XMLWhitespaceDetector()),
// Words rules
words
};
setRules(rules);
}
I have used the existing processing instruction token here to reduce the amount of new code, but you should define a new color and use a new token.
The WordRule constructor requires an IWordDetector class, we can use a very simple detector here:
class WordDetector implements IWordDetector
{
#Override
public boolean isWordStart(final char c)
{
return Character.isLetter(c);
}
#Override
public boolean isWordPart(final char c)
{
return Character.isLetter(c);
}
}
This is just accepting letters in words.

ANTLR forward references

I need to create a grammar for a language with forward references. I think that the easiest way to achieve this is to make several passes on the generated AST, but I need a way to store symbol information in the tree.
Right now my parser correctly generates an AST and computes scopes of the variables and function definitions. The problem is, I don't know how to save the scope information into the tree.
Fragment of my grammar:
composite_instruction
scope JScope;
#init {
$JScope::symbols = new ArrayList();
$JScope::name = "level "+ $JScope.size();
}
#after {
System.out.println("code block scope " +$JScope::name + " = " + $JScope::symbols);
}
: '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*)
;
I would like to put a reference to current scope into a tree, something like:
: '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction* {$JScope::symbols})
Is it even possible? Is there any other way to store current scopes in a generated tree? I can generate the scope info in a tree grammar, but it won't change anything, because I still have to store it somewhere for the second pass on the tree.
To my knowledge, the syntax for the rewrite rules doesn't allows for directly assigning values as your tentative snippet suggests. This is in part due to the fact that the parser wouldn't really know to what part of the tree/node the values should be added to.
However, one of the cool features of ANTLR-produced ASTs is that the parser makes no assumptions about the type of the Nodes. One just needs to implement a TreeAdapator which serves as a factory for new nodes and as a navigator of the tree structure. One can therefore stuff whatever info may be needed in the nodes, as explained below.
ANTLR provides a default tree node implementation, CommonTree, and in most cases (as in the situation at hand) we merely need to
subclass CommonTree by adding some custom fields to it
subclass the CommonTreeAdaptor to override its create() method, i.e. the way it produces new nodes.
but one could also create a novel type of node altogher, for some odd graph structure or whatnot. For the case at hand, the following should be sufficient (adapt for the specific target language if this isn't java)
import org.antlr.runtime.tree.*;
import org.antlr.runtime.Token;
public class NodeWithScope extends CommonTree {
/* Just declare the extra fields for the node */
public ArrayList symbols;
public string name;
public object whatever_else;
public NodeWithScope (Token t) {
super(t);
}
}
/* TreeAdaptor: we just need to override create method */
class NodeWithScopeAdaptor extends CommonTreeAdaptor {
public Object create(Token standardPayload) {
return new NodeWithScope(standardPayload);
}
}
One then needs to slightly modify the way the parsing process is started, so that ANTLR (or rather the ANTLR-produced parser) knows to use the NodeWithScopeAdaptor rather than CommnTree.
(Step 4.1 below, the rest if rather standard ANTLR test rig)
// ***** Typical ANTLR pipe rig *****
// ** 1. input stream
ANTLRInputStream input = new ANTLRInputStream(my_input_file);
// ** 2, Lexer
MyGrammarLexer lexer = new MyGrammarLexer(input);
// ** 3. token stream produced by lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// ** 4. Parser
MyGrammarParser parser = new MyGrammarParser(tokens);
// 4.1 !!! Specify the TreeAdapter
NodeWithScopeAdaptor adaptor = new NodeWithScopeAdaptor();
parser.setTreeAdaptor(adaptor); // use my adaptor
// ** 5. Start process by invoking the root rule
r = parser.MyTopRule();
// ** 6. AST tree
NodeWithScope t = (NodeWithScope)r.getTree();
// ** 7. etc. parse the tree or do whatever is needed on it.
Finally your grammar would have to be adapted with something akin to what follows
(note that the node [for the current rule] is only available in the #after section. It may however reference any token attribute and other contextual variable from the grammar-level, using the usual $rule.atrribute notation)
composite_instruction
scope JScope;
#init {
$JScope::symbols = new ArrayList();
$JScope::name = "level "+ $JScope.size();
}
#after {
($composite_instruction.tree).symbols = $JScope::symbols;
($composite_instruction.tree).name = $JScope::name;
($composite_instruction.tree).whatever_else
= new myFancyObject($x.Text, $y.line, whatever, blah);
}
: '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*)
;