1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.attributes.compiler;
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import org.apache.tools.ant.BuildException;
  20. /**
  21. * Parser for attribute expressions.
  22. */
  23. public class AttributeExpressionParser {
  24. public static class Argument {
  25. public final String field;
  26. public final String text;
  27. public final int length;
  28. public Argument (String field, String text, int length) {
  29. this.field = field;
  30. this.text = text;
  31. this.length = length;
  32. }
  33. public boolean equalsOrNull (String a, String b) {
  34. if (a == null) {
  35. return b == null;
  36. } else {
  37. return b != null && a.equals (b);
  38. }
  39. }
  40. public boolean equals (Object o) {
  41. return o instanceof Argument &&
  42. equalsOrNull (field, ((Argument) o).field) &&
  43. ((Argument) o).text.equals (text);
  44. }
  45. public String toString () {
  46. return "[Argument: " + field + ", " + text + ", " + length + "]";
  47. }
  48. }
  49. public static class ParseResult {
  50. public final List arguments = new ArrayList ();
  51. public final String className;
  52. public ParseResult (String className) {
  53. this.className = className;
  54. }
  55. public boolean equals (Object o) {
  56. return o instanceof ParseResult &&
  57. className.equals (((ParseResult) o).className) &&
  58. arguments.equals (((ParseResult) o).arguments);
  59. }
  60. public String toString () {
  61. return "[ParseResult: " + className + ", " + arguments + "]";
  62. }
  63. }
  64. protected static Argument nextArgument (String string, int startPos, String filename, int line) {
  65. if (string.charAt (startPos) == ')') {
  66. return null;
  67. }
  68. StringBuffer sb = new StringBuffer ();
  69. int i = startPos;
  70. int depth = 0;
  71. while (!( (string.charAt (i) == ',' || string.charAt (i) == ')') && depth == 0)) {
  72. switch (string.charAt (i)) {
  73. case '[':
  74. case '{':
  75. case '(': depth++; break;
  76. case ']':
  77. case '}':
  78. case ')': depth--; break;
  79. case '\'':
  80. case '"': {
  81. // handle string literals
  82. char endChar = string.charAt (i);
  83. sb.append (string.charAt (i));
  84. i++;
  85. while (true) {
  86. char ch = string.charAt (i);
  87. if (ch == '\\') {
  88. sb.append (ch);
  89. i++;
  90. ch = string.charAt (i);
  91. sb.append (ch);
  92. } else {
  93. if (ch == endChar) {
  94. break;
  95. }
  96. sb.append (ch);
  97. }
  98. i++;
  99. }
  100. }
  101. }
  102. sb.append (string.charAt (i));
  103. i++;
  104. if (i == string.length ()) {
  105. throw new BuildException (filename + ":" + line + ": Unterminated argument: " + string);
  106. }
  107. }
  108. if (string.charAt (i) == ',') {
  109. i++;
  110. }
  111. String text = sb.toString ();
  112. String field = null;
  113. int eqPos = text.indexOf ('=');
  114. if (eqPos > -1) {
  115. boolean identifier = true;
  116. for (int j = 0; j < eqPos; j++) {
  117. char ch = text.charAt (j);
  118. if (Character.isJavaIdentifierPart (ch) || ch == ' ') {
  119. } else {
  120. identifier = false;
  121. }
  122. }
  123. if (identifier) {
  124. field = text.substring (0, eqPos).trim ();
  125. text = text.substring (eqPos + 1).trim ();
  126. }
  127. }
  128. Argument arg = new Argument (field, text, i - startPos);
  129. return arg;
  130. }
  131. public static ParseResult parse (String string, String filename, int line) {
  132. StringBuffer sb = new StringBuffer ();
  133. int i = 0;
  134. while (i < string.length () && (Character.isJavaIdentifierPart (string.charAt (i)) || string.charAt (i) == '.' || string.charAt (i) == ' ')) {
  135. sb.append (string.charAt (i));
  136. i++;
  137. }
  138. if (i == string.length () || string.charAt (i) != '(') {
  139. throw new BuildException (filename + ":" + line + ": Illegal expression: " + string);
  140. }
  141. ParseResult result = new ParseResult (sb.toString ());
  142. i++;
  143. Argument arg = null;
  144. boolean seenField = false;
  145. while ((arg = nextArgument (string, i, filename, line)) != null) {
  146. if (arg.field != null) {
  147. seenField = true;
  148. }
  149. if (seenField && arg.field == null) {
  150. throw new BuildException (filename + ":" + line + ": Un-named parameters must come before the named parameters: " + string);
  151. }
  152. result.arguments.add (arg);
  153. i += arg.length;
  154. }
  155. return result;
  156. }
  157. }