Skip to content

Commit 128dfa5

Browse files
author
dlsmith
committed
DynamicJava: Implemented annotation parsing.
git-svn-id: file:///tmp/test-svn/trunk@4828 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 1676fcc commit 128dfa5

File tree

7 files changed

+131
-24
lines changed

7 files changed

+131
-24
lines changed

dynamicjava/src/koala/dynamicjava/parser/grammar.jj

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import java.util.*;
1414
import java.io.File;
1515

1616
import edu.rice.cs.plt.tuple.Option;
17+
import edu.rice.cs.plt.tuple.Pair;
1718
import edu.rice.cs.plt.collect.ConsList;
1819
import edu.rice.cs.plt.collect.CollectUtil;
1920

@@ -1319,12 +1320,6 @@ PARSER_END(Parser)
13191320
{ return new ModifierSet(flags, annots, _range(first, token)); }
13201321
}
13211322

1322-
Annotation annotation() :
1323-
{}
1324-
{
1325-
"@" { return _throwParseException("Annotation parsing is not yet implemented"); }
1326-
}
1327-
13281323
PackageDeclaration packageDeclaration(DeclType level) :
13291324
{ ModifierSet mods; PackageDeclaration decl; }
13301325
{
@@ -2110,19 +2105,13 @@ PARSER_END(Parser)
21102105
}
21112106
{
21122107
b="{" [ init=variableInitializer()
2113-
{
2114-
list.add(init);
2115-
}
2108+
{ list.add(init); }
21162109
( LOOKAHEAD(2)
21172110
"," init=variableInitializer()
2118-
{
2119-
list.add(init);
2120-
}
2111+
{ list.add(init); }
21212112
)* ]
21222113
[ t="," ] e="}"
2123-
{
2124-
return new ArrayInitializer(list, _range(b, e));
2125-
}
2114+
{ return new ArrayInitializer(list, _range(b, e)); }
21262115
}
21272116
21282117
/**
@@ -3576,6 +3565,53 @@ PARSER_END(Parser)
35763565
}
35773566

35783567

3568+
// Productions for Annotations /////////////////////////////////////////////////////
3569+
3570+
Annotation annotation() :
3571+
{
3572+
Token first;
3573+
ReferenceTypeName type;
3574+
Token id;
3575+
Expression exp;
3576+
List<Pair<String, Expression>> vals = new LinkedList<Pair<String, Expression>>();
3577+
}
3578+
{
3579+
first="@" type=referenceTypeName()
3580+
[
3581+
"("
3582+
(
3583+
LOOKAHEAD(2) id=<IDENTIFIER> "=" exp=annotationValue() { vals.add(Pair.make(id.image, exp)); }
3584+
( "," id=<IDENTIFIER> "=" exp=annotationValue() { vals.add(Pair.make(id.image, exp)); } )*
3585+
|
3586+
exp=annotationValue() { vals.add(Pair.make("value", exp)); }
3587+
)
3588+
")"
3589+
]
3590+
{ return new Annotation(type, vals, _range(first, token)); }
3591+
}
3592+
3593+
Expression annotationValue() :
3594+
{ Expression exp; }
3595+
{
3596+
exp=conditionalExpression() { return exp; }
3597+
| exp=annotation() { return exp; }
3598+
| exp=annotationArrayValue() { return exp; }
3599+
}
3600+
3601+
ArrayInitializer annotationArrayValue() :
3602+
{ Token first; Expression val; List<Expression> vals = new LinkedList<Expression>(); }
3603+
{
3604+
first="{"
3605+
[
3606+
val=annotationValue() { vals.add(val); }
3607+
( LOOKAHEAD(2) "," val=annotationValue() { vals.add(val); } )*
3608+
]
3609+
[ "," ]
3610+
"}"
3611+
{ return new ArrayInitializer(vals, _range(first, token)); }
3612+
}
3613+
3614+
35793615
// Lookahead productions ////////////////////////////////////////////////////////
35803616

35813617
/** Distinguish a cast expression from a parenthesized expression. */

dynamicjava/src/koala/dynamicjava/parser/wrapper/ParserTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
import java.io.StringReader;
4646
import java.util.*;
4747

48+
import edu.rice.cs.plt.collect.CollectUtil;
49+
import edu.rice.cs.plt.iter.IterUtil;
50+
import edu.rice.cs.plt.tuple.Pair;
51+
4852
import static koala.dynamicjava.tree.ModifierSet.Modifier.*;
4953

5054
/**
@@ -161,6 +165,67 @@ public void testLocalVariableDeclarationList() throws ParseException {
161165
verifyOutput("int i=0, j, k=2;", expectedAST);
162166
}
163167

168+
private Annotation makeAnnotation(String name, String[] argNames, Expression... argVals) {
169+
if (argNames.length != argVals.length) { throw new IllegalArgumentException("Mistmatched name/value pairs"); }
170+
ReferenceTypeName type = new ReferenceTypeName(name);
171+
List<Pair<String, Expression>> vals =
172+
CollectUtil.makeList(IterUtil.zip(IterUtil.make(argNames), IterUtil.make(argVals)));
173+
return new Annotation(type, vals);
174+
}
175+
176+
public void testMarkerAnnotation() throws ParseException {
177+
Annotation a = makeAnnotation("Marker", new String[0]);
178+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
179+
verifyOutput("@Marker int x;", expectedAST);
180+
}
181+
182+
public void testSingleValueAnnotation() throws ParseException {
183+
Annotation a = makeAnnotation("Single", new String[]{"value"}, new IntegerLiteral("23"));
184+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
185+
verifyOutput("@Single(23) int x;", expectedAST);
186+
}
187+
188+
public void testArrayValueAnnotation() throws ParseException {
189+
List<Expression> cells = Arrays.<Expression>asList(new IntegerLiteral("1"),
190+
new IntegerLiteral("2"),
191+
new IntegerLiteral("3"));
192+
Annotation a = makeAnnotation("Single", new String[]{"value"}, new ArrayInitializer(cells));
193+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
194+
verifyOutput("@Single({1, 2, 3}) int x;", expectedAST);
195+
}
196+
197+
public void testArrayValueWithCommaAnnotation() throws ParseException {
198+
List<Expression> cells = Arrays.<Expression>asList(new IntegerLiteral("1"),
199+
new IntegerLiteral("2"),
200+
new IntegerLiteral("3"));
201+
Annotation a = makeAnnotation("Single", new String[]{"value"}, new ArrayInitializer(cells));
202+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
203+
verifyOutput("@Single({1, 2, 3, }) int x;", expectedAST);
204+
}
205+
206+
public void testEmptyArrayValueAnnotation() throws ParseException {
207+
List<Expression> cells = Collections.emptyList();
208+
Annotation a = makeAnnotation("Single", new String[]{"value"}, new ArrayInitializer(cells));
209+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
210+
verifyOutput("@Single({}) int x;", expectedAST);
211+
}
212+
213+
public void testAnnotationValueAnnotation() throws ParseException {
214+
Annotation a = makeAnnotation("Single", new String[]{"value"}, new IntegerLiteral("23"));
215+
Annotation b = makeAnnotation("Wrapper", new String[]{"value"}, a);
216+
expectedAST.add(new VariableDeclaration(ModifierSet.make(b), new IntTypeName(), "x", null));
217+
verifyOutput("@Wrapper(@Single(23)) int x;", expectedAST);
218+
}
219+
220+
public void testNormalAnnotation() throws ParseException {
221+
Annotation a = makeAnnotation("Normal", new String[]{"a", "b", "c"},
222+
new StringLiteral("\"foo\""),
223+
new StringLiteral("\"bar\""),
224+
new IntegerLiteral("15"));
225+
expectedAST.add(new VariableDeclaration(ModifierSet.make(a), new IntTypeName(), "x", null));
226+
verifyOutput("@Normal(a=\"foo\", b=\"bar\", c=15) int x;", expectedAST);
227+
}
228+
164229
public void testLabeledStatement() throws ParseException {
165230

166231
expectedAST.add(new LabeledStatement("v", new ExpressionStatement(new SimpleAllocation(new ReferenceTypeName("Object"), null), true)));

dynamicjava/src/koala/dynamicjava/tree/Annotation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import edu.rice.cs.plt.tuple.Pair;
66
import koala.dynamicjava.tree.visitor.Visitor;
77

8-
public class Annotation extends Node {
8+
public class Annotation extends Expression {
99

1010
private final ReferenceTypeName type;
1111
private final List<Pair<String, Expression>> values;

dynamicjava/src/koala/dynamicjava/tree/ArrayInitializer.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,9 @@ public void setCells(List<? extends Expression> l) {
101101
}
102102

103103
/**
104-
* Returns the element type
105-
* @exception IllegalStateException if elementType is null
104+
* Returns the element type, or {@code null} if it's not set
106105
*/
107106
public TypeName getElementType() {
108-
if (elementType == null) throw new IllegalStateException("elementType == null");
109-
110107
return elementType;
111108
}
112109

dynamicjava/src/koala/dynamicjava/tree/CharacterLiteral.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ public CharacterLiteral(String rep,
5858

5959
/**
6060
* Decodes the representation of a Java literal character.
61-
* The input is not checked since this method always called
62-
* on a string produced by the parser.
6361
* @param rep the representation of the character
6462
* @return the character represented by the given string
6563
*/
6664
private static char decodeCharacter(String rep) {
65+
if (rep.charAt(0) != '\'' || rep.charAt(rep.length()-1) != '\'') {
66+
throw new IllegalArgumentException("Malformed character literal");
67+
}
6768
if (rep.length() == 3) {
6869
return rep.charAt(1);
6970
}

dynamicjava/src/koala/dynamicjava/tree/ModifierSet.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ public static ModifierSet make(Modifier mod, Modifier... mods) {
8383
return new ModifierSet(EnumSet.of(mod, mods), new LinkedList<Annotation>());
8484
}
8585

86+
public static ModifierSet make(Annotation ann, Annotation... anns) {
87+
LinkedList<Annotation> l = new LinkedList<Annotation>();
88+
l.add(ann);
89+
for (Annotation a : anns) { l.add(a); }
90+
return new ModifierSet(EnumSet.noneOf(Modifier.class), l);
91+
}
92+
8693
public enum Modifier {
8794
PUBLIC {
8895
public int getBits() { return 0x0001; }

dynamicjava/src/koala/dynamicjava/tree/StringLiteral.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ public StringLiteral(String rep,
5858

5959
/**
6060
* Decodes the representation of a Java literal string.
61-
* The input is not checked since this method always called
62-
* on a string produced by the parser.
6361
* @param rep the representation of the character
6462
* @return the character represented by the given string
6563
*/
6664
public static String decodeString(String rep) {
65+
if (rep.charAt(0) != '"' || rep.charAt(rep.length()-1) != '"') {
66+
throw new IllegalArgumentException("Malformed String literal");
67+
}
6768
char[] buf = new char[rep.length()-2];
6869
int len = 0;
6970
int i = 1;

0 commit comments

Comments
 (0)