test/tools/javac/diags/MessageFile.java

Wed, 06 Apr 2011 20:33:44 -0700

author
ohair
date
Wed, 06 Apr 2011 20:33:44 -0700
changeset 962
0ff2bbd38f10
parent 842
3da26790ccb7
child 1657
f4500abff1fd
permissions
-rw-r--r--

7033660: Update copyright year to 2011 on any files changed in 2011
Reviewed-by: dholmes

jjg@842 1 /*
jjg@842 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
jjg@842 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@842 4 *
jjg@842 5 * This code is free software; you can redistribute it and/or modify it
jjg@842 6 * under the terms of the GNU General Public License version 2 only, as
jjg@842 7 * published by the Free Software Foundation.
jjg@842 8 *
jjg@842 9 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@842 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@842 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@842 12 * version 2 for more details (a copy is included in the LICENSE file that
jjg@842 13 * accompanied this code).
jjg@842 14 *
jjg@842 15 * You should have received a copy of the GNU General Public License version
jjg@842 16 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@842 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@842 18 *
jjg@842 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@842 20 * or visit www.oracle.com if you need additional information or have any
jjg@842 21 * questions.
jjg@842 22 */
jjg@842 23
jjg@842 24 import java.io.*;
jjg@842 25 import java.util.*;
jjg@842 26 import java.util.regex.Matcher;
jjg@842 27 import java.util.regex.Pattern;
jjg@842 28
jjg@842 29 /**
jjg@842 30 * Class to facilitate manipulating compiler.properties.
jjg@842 31 */
jjg@842 32 class MessageFile {
jjg@842 33 static final Pattern emptyOrCommentPattern = Pattern.compile("( *#.*)?");
jjg@842 34 static final Pattern infoPattern = Pattern.compile("# ([0-9]+: [-A-Za-z ]+, )*[0-9]+: [-A-Za-z ]+");
jjg@842 35
jjg@842 36 /**
jjg@842 37 * A line of text within the message file.
jjg@842 38 * The lines form a doubly linked list for simple navigation.
jjg@842 39 */
jjg@842 40 class Line {
jjg@842 41 String text;
jjg@842 42 Line prev;
jjg@842 43 Line next;
jjg@842 44
jjg@842 45 Line(String text) {
jjg@842 46 this.text = text;
jjg@842 47 }
jjg@842 48
jjg@842 49 boolean isEmptyOrComment() {
jjg@842 50 return emptyOrCommentPattern.matcher(text).matches();
jjg@842 51 }
jjg@842 52
jjg@842 53 boolean isInfo() {
jjg@842 54 return infoPattern.matcher(text).matches();
jjg@842 55 }
jjg@842 56
jjg@842 57 boolean hasContinuation() {
jjg@842 58 return (next != null) && text.endsWith("\\");
jjg@842 59 }
jjg@842 60
jjg@842 61 Line insertAfter(String text) {
jjg@842 62 Line l = new Line(text);
jjg@842 63 insertAfter(l);
jjg@842 64 return l;
jjg@842 65 }
jjg@842 66
jjg@842 67 void insertAfter(Line l) {
jjg@842 68 assert prev == null && next == null;
jjg@842 69 l.prev = this;
jjg@842 70 l.next = next;
jjg@842 71 if (next == null)
jjg@842 72 lastLine = l;
jjg@842 73 else
jjg@842 74 next.prev = l;
jjg@842 75 next = l;
jjg@842 76 }
jjg@842 77
jjg@842 78 Line insertBefore(String text) {
jjg@842 79 Line l = new Line(text);
jjg@842 80 insertBefore(l);
jjg@842 81 return l;
jjg@842 82 }
jjg@842 83
jjg@842 84 void insertBefore(Line l) {
jjg@842 85 assert prev == null && next == null;
jjg@842 86 l.prev = prev;
jjg@842 87 l.next = this;
jjg@842 88 if (prev == null)
jjg@842 89 firstLine = l;
jjg@842 90 else
jjg@842 91 prev.next = l;
jjg@842 92 prev = l;
jjg@842 93 }
jjg@842 94
jjg@842 95 void remove() {
jjg@842 96 if (prev == null)
jjg@842 97 firstLine = next;
jjg@842 98 else
jjg@842 99 prev.next = next;
jjg@842 100 if (next == null)
jjg@842 101 lastLine = prev;
jjg@842 102 else
jjg@842 103 next.prev = prev;
jjg@842 104 prev = null;
jjg@842 105 next = null;
jjg@842 106 }
jjg@842 107 }
jjg@842 108
jjg@842 109 /**
jjg@842 110 * A message within the message file.
jjg@842 111 * A message is a series of lines containing a "name=value" property,
jjg@842 112 * optionally preceded by a comment describing the use of placeholders
jjg@842 113 * such as {0}, {1}, etc within the property value.
jjg@842 114 */
jjg@842 115 static final class Message {
jjg@842 116 final Line firstLine;
jjg@842 117 private Info info;
jjg@842 118
jjg@842 119 Message(Line l) {
jjg@842 120 firstLine = l;
jjg@842 121 }
jjg@842 122
jjg@842 123 boolean needInfo() {
jjg@842 124 Line l = firstLine;
jjg@842 125 while (true) {
jjg@842 126 if (l.text.matches(".*\\{[0-9]+\\}.*"))
jjg@842 127 return true;
jjg@842 128 if (!l.hasContinuation())
jjg@842 129 return false;
jjg@842 130 l = l.next;
jjg@842 131 }
jjg@842 132 }
jjg@842 133
jjg@842 134 Set<Integer> getPlaceholders() {
jjg@842 135 Pattern p = Pattern.compile("\\{([0-9]+)\\}");
jjg@842 136 Set<Integer> results = new TreeSet<Integer>();
jjg@842 137 Line l = firstLine;
jjg@842 138 while (true) {
jjg@842 139 Matcher m = p.matcher(l.text);
jjg@842 140 while (m.find())
jjg@842 141 results.add(Integer.parseInt(m.group(1)));
jjg@842 142 if (!l.hasContinuation())
jjg@842 143 return results;
jjg@842 144 l = l.next;
jjg@842 145 }
jjg@842 146 }
jjg@842 147
jjg@842 148 /**
jjg@842 149 * Get the Info object for this message. It may be empty if there
jjg@842 150 * if no comment preceding the property specification.
jjg@842 151 */
jjg@842 152 Info getInfo() {
jjg@842 153 if (info == null) {
jjg@842 154 Line l = firstLine.prev;
jjg@842 155 if (l != null && l.isInfo())
jjg@842 156 info = new Info(l.text);
jjg@842 157 else
jjg@842 158 info = new Info();
jjg@842 159 }
jjg@842 160 return info;
jjg@842 161 }
jjg@842 162
jjg@842 163 /**
jjg@842 164 * Set the Info for this message.
jjg@842 165 * If there was an info comment preceding the property specification,
jjg@842 166 * it will be updated; otherwise, one will be inserted.
jjg@842 167 */
jjg@842 168 void setInfo(Info info) {
jjg@842 169 this.info = info;
jjg@842 170 Line l = firstLine.prev;
jjg@842 171 if (l != null && l.isInfo())
jjg@842 172 l.text = info.toComment();
jjg@842 173 else
jjg@842 174 firstLine.insertBefore(info.toComment());
jjg@842 175 }
jjg@842 176
jjg@842 177 /**
jjg@842 178 * Get all the lines pertaining to this message.
jjg@842 179 */
jjg@842 180 List<Line> getLines(boolean includeAllPrecedingComments) {
jjg@842 181 List<Line> lines = new ArrayList<Line>();
jjg@842 182 Line l = firstLine;
jjg@842 183 if (includeAllPrecedingComments) {
jjg@842 184 // scan back to find end of prev message
jjg@842 185 while (l.prev != null && l.prev.isEmptyOrComment())
jjg@842 186 l = l.prev;
jjg@842 187 // skip leading blank lines
jjg@842 188 while (l.text.isEmpty())
jjg@842 189 l = l.next;
jjg@842 190 } else {
jjg@842 191 if (l.prev != null && l.prev.isInfo())
jjg@842 192 l = l.prev;
jjg@842 193 }
jjg@842 194
jjg@842 195 // include any preceding lines
jjg@842 196 for ( ; l != firstLine; l = l.next)
jjg@842 197 lines.add(l);
jjg@842 198
jjg@842 199 // include message lines
jjg@842 200 for (l = firstLine; l != null && l.hasContinuation(); l = l.next)
jjg@842 201 lines.add(l);
jjg@842 202 lines.add(l);
jjg@842 203
jjg@842 204 // include trailing blank line if present
jjg@842 205 l = l.next;
jjg@842 206 if (l != null && l.text.isEmpty())
jjg@842 207 lines.add(l);
jjg@842 208
jjg@842 209 return lines;
jjg@842 210 }
jjg@842 211 }
jjg@842 212
jjg@842 213 /**
jjg@842 214 * An object to represent the comment that may precede the property
jjg@842 215 * specification in a Message.
jjg@842 216 * The comment is modelled as a list of fields, where the fields correspond
jjg@842 217 * to the placeholder values (e.g. {0}, {1}, etc) within the message value.
jjg@842 218 */
jjg@842 219 static final class Info {
jjg@842 220 /**
jjg@842 221 * An ordered set of descriptions for a placeholder value in a
jjg@842 222 * message.
jjg@842 223 */
jjg@842 224 static class Field {
jjg@842 225 boolean unused;
jjg@842 226 Set<String> values;
jjg@842 227 boolean listOfAny = false;
jjg@842 228 boolean setOfAny = false;
jjg@842 229 Field(String s) {
jjg@842 230 s = s.substring(s.indexOf(": ") + 2);
jjg@842 231 values = new LinkedHashSet<String>(Arrays.asList(s.split(" or ")));
jjg@842 232 for (String v: values) {
jjg@842 233 if (v.startsWith("list of"))
jjg@842 234 listOfAny = true;
jjg@842 235 if (v.startsWith("set of"))
jjg@842 236 setOfAny = true;
jjg@842 237 }
jjg@842 238 }
jjg@842 239
jjg@842 240 /**
jjg@842 241 * Return true if this field logically contains all the values of
jjg@842 242 * another field.
jjg@842 243 */
jjg@842 244 boolean contains(Field other) {
jjg@842 245 if (unused != other.unused)
jjg@842 246 return false;
jjg@842 247
jjg@842 248 for (String v: other.values) {
jjg@842 249 if (values.contains(v))
jjg@842 250 continue;
jjg@842 251 if (v.equals("null") || v.equals("string"))
jjg@842 252 continue;
jjg@842 253 if (v.equals("list") && listOfAny)
jjg@842 254 continue;
jjg@842 255 if (v.equals("set") && setOfAny)
jjg@842 256 continue;
jjg@842 257 return false;
jjg@842 258 }
jjg@842 259 return true;
jjg@842 260 }
jjg@842 261
jjg@842 262 /**
jjg@842 263 * Merge the values of another field into this field.
jjg@842 264 */
jjg@842 265 void merge(Field other) {
jjg@842 266 unused |= other.unused;
jjg@842 267 values.addAll(other.values);
jjg@842 268
jjg@842 269 // cleanup unnecessary entries
jjg@842 270
jjg@842 271 if (values.contains("null") && values.size() > 1) {
jjg@842 272 // "null" is superceded by anything else
jjg@842 273 values.remove("null");
jjg@842 274 }
jjg@842 275
jjg@842 276 if (values.contains("string") && values.size() > 1) {
jjg@842 277 // "string" is superceded by anything else
jjg@842 278 values.remove("string");
jjg@842 279 }
jjg@842 280
jjg@842 281 if (values.contains("list")) {
jjg@842 282 // list is superceded by "list of ..."
jjg@842 283 for (String s: values) {
jjg@842 284 if (s.startsWith("list of ")) {
jjg@842 285 values.remove("list");
jjg@842 286 break;
jjg@842 287 }
jjg@842 288 }
jjg@842 289 }
jjg@842 290
jjg@842 291 if (values.contains("set")) {
jjg@842 292 // set is superceded by "set of ..."
jjg@842 293 for (String s: values) {
jjg@842 294 if (s.startsWith("set of ")) {
jjg@842 295 values.remove("set");
jjg@842 296 break;
jjg@842 297 }
jjg@842 298 }
jjg@842 299 }
jjg@842 300
jjg@842 301 if (other.values.contains("unused")) {
jjg@842 302 values.clear();
jjg@842 303 values.add("unused");
jjg@842 304 }
jjg@842 305 }
jjg@842 306
jjg@842 307 void markUnused() {
jjg@842 308 values = new LinkedHashSet<String>();
jjg@842 309 values.add("unused");
jjg@842 310 listOfAny = false;
jjg@842 311 setOfAny = false;
jjg@842 312 }
jjg@842 313
jjg@842 314 @Override
jjg@842 315 public String toString() {
jjg@842 316 return values.toString();
jjg@842 317 }
jjg@842 318 }
jjg@842 319
jjg@842 320 /** The fields of the Info object. */
jjg@842 321 List<Field> fields = new ArrayList<Field>();
jjg@842 322
jjg@842 323 Info() { }
jjg@842 324
jjg@842 325 Info(String text) throws IllegalArgumentException {
jjg@842 326 if (!text.startsWith("# "))
jjg@842 327 throw new IllegalArgumentException();
jjg@842 328 String[] segs = text.substring(2).split(", ");
jjg@842 329 fields = new ArrayList<Field>();
jjg@842 330 for (String seg: segs) {
jjg@842 331 fields.add(new Field(seg));
jjg@842 332 }
jjg@842 333 }
jjg@842 334
jjg@842 335 Info(Set<String> infos) throws IllegalArgumentException {
jjg@842 336 for (String s: infos)
jjg@842 337 merge(new Info(s));
jjg@842 338 }
jjg@842 339
jjg@842 340 boolean isEmpty() {
jjg@842 341 return fields.isEmpty();
jjg@842 342 }
jjg@842 343
jjg@842 344 boolean contains(Info other) {
jjg@842 345 if (other.isEmpty())
jjg@842 346 return true;
jjg@842 347
jjg@842 348 if (fields.size() != other.fields.size())
jjg@842 349 return false;
jjg@842 350
jjg@842 351 Iterator<Field> oIter = other.fields.iterator();
jjg@842 352 for (Field values: fields) {
jjg@842 353 if (!values.contains(oIter.next()))
jjg@842 354 return false;
jjg@842 355 }
jjg@842 356
jjg@842 357 return true;
jjg@842 358 }
jjg@842 359
jjg@842 360 void merge(Info other) {
jjg@842 361 if (fields.isEmpty()) {
jjg@842 362 fields.addAll(other.fields);
jjg@842 363 return;
jjg@842 364 }
jjg@842 365
jjg@842 366 if (other.fields.size() != fields.size())
jjg@842 367 throw new IllegalArgumentException();
jjg@842 368
jjg@842 369 Iterator<Field> oIter = other.fields.iterator();
jjg@842 370 for (Field d: fields) {
jjg@842 371 d.merge(oIter.next());
jjg@842 372 }
jjg@842 373 }
jjg@842 374
jjg@842 375 void markUnused(Set<Integer> used) {
jjg@842 376 for (int i = 0; i < fields.size(); i++) {
jjg@842 377 if (!used.contains(i))
jjg@842 378 fields.get(i).markUnused();
jjg@842 379 }
jjg@842 380 }
jjg@842 381
jjg@842 382 @Override
jjg@842 383 public String toString() {
jjg@842 384 return fields.toString();
jjg@842 385 }
jjg@842 386
jjg@842 387 String toComment() {
jjg@842 388 StringBuilder sb = new StringBuilder();
jjg@842 389 sb.append("# ");
jjg@842 390 String sep = "";
jjg@842 391 int i = 0;
jjg@842 392 for (Field f: fields) {
jjg@842 393 sb.append(sep);
jjg@842 394 sb.append(i++);
jjg@842 395 sb.append(": ");
jjg@842 396 sep = "";
jjg@842 397 for (String s: f.values) {
jjg@842 398 sb.append(sep);
jjg@842 399 sb.append(s);
jjg@842 400 sep = " or ";
jjg@842 401 }
jjg@842 402 sep = ", ";
jjg@842 403 }
jjg@842 404 return sb.toString();
jjg@842 405 }
jjg@842 406 }
jjg@842 407
jjg@842 408 Line firstLine;
jjg@842 409 Line lastLine;
jjg@842 410 Map<String, Message> messages = new TreeMap<String, Message>();
jjg@842 411
jjg@842 412 MessageFile(File file) throws IOException {
jjg@842 413 Reader in = new FileReader(file);
jjg@842 414 try {
jjg@842 415 read(in);
jjg@842 416 } finally {
jjg@842 417 in.close();
jjg@842 418 }
jjg@842 419 }
jjg@842 420
jjg@842 421 MessageFile(Reader in) throws IOException {
jjg@842 422 read(in);
jjg@842 423 }
jjg@842 424
jjg@842 425 final void read(Reader in) throws IOException {
jjg@842 426 BufferedReader br = (in instanceof BufferedReader)
jjg@842 427 ? (BufferedReader) in
jjg@842 428 : new BufferedReader(in);
jjg@842 429 String line;
jjg@842 430 while ((line = br.readLine()) != null) {
jjg@842 431 Line l;
jjg@842 432 if (firstLine == null)
jjg@842 433 l = firstLine = lastLine = new Line(line);
jjg@842 434 else
jjg@842 435 l = lastLine.insertAfter(line);
jjg@842 436 if (line.startsWith("compiler.")) {
jjg@842 437 int eq = line.indexOf("=");
jjg@842 438 if (eq > 0)
jjg@842 439 messages.put(line.substring(0, eq), new Message(l));
jjg@842 440 }
jjg@842 441 }
jjg@842 442 }
jjg@842 443
jjg@842 444 void write(File file) throws IOException {
jjg@842 445 Writer out = new FileWriter(file);
jjg@842 446 try {
jjg@842 447 write(out);
jjg@842 448 } finally {
jjg@842 449 out.close();
jjg@842 450 }
jjg@842 451 }
jjg@842 452
jjg@842 453 void write(Writer out) throws IOException {
jjg@842 454 BufferedWriter bw = (out instanceof BufferedWriter)
jjg@842 455 ? (BufferedWriter) out
jjg@842 456 : new BufferedWriter(out);
jjg@842 457 for (Line l = firstLine; l != null; l = l.next) {
jjg@842 458 bw.write(l.text);
jjg@842 459 bw.write("\n"); // always use Unix line endings
jjg@842 460 }
jjg@842 461 bw.flush();
jjg@842 462 }
jjg@842 463 }

mercurial