1/* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package separate; 25 26import java.util.*; 27import java.io.StringWriter; 28import java.io.PrintWriter; 29 30public class SourceModel { 31 32 public static final String stdMethodName = "m"; 33 34 public static interface SourceProcessor { 35 // Called with a generated source file 36 void process(String name, String content); 37 } 38 39 public static abstract class Element { 40 41 protected abstract void generate(PrintWriter pw); 42 43 public String toString() { 44 StringWriter sw = new StringWriter(); 45 PrintWriter pw = new PrintWriter(sw); 46 generate(pw); 47 return sw.toString(); 48 } 49 }; 50 51 public static class AccessFlag extends Element { 52 private String flag; 53 54 public AccessFlag(String name) { flag = name; } 55 56 protected void generate(PrintWriter pw) { 57 pw.print(flag); 58 } 59 60 public String toString() { return flag; } 61 62 public static final AccessFlag PUBLIC = new AccessFlag("public"); 63 public static final AccessFlag PRIVATE = new AccessFlag("private"); 64 public static final AccessFlag PROTECTED = new AccessFlag("protected"); 65 public static final AccessFlag STATIC = new AccessFlag("static"); 66 public static final AccessFlag FINAL = new AccessFlag("final"); 67 public static final AccessFlag SYNCHRONIZED = new AccessFlag("synchronized"); 68 public static final AccessFlag VOLATILE = new AccessFlag("volatile"); 69 public static final AccessFlag NATIVE = new AccessFlag("native"); 70 public static final AccessFlag ABSTRACT = new AccessFlag("abstract"); 71 public static final AccessFlag STRICTFP = new AccessFlag("strictfp"); 72 public static final AccessFlag DEFAULT = new AccessFlag("default"); 73 } 74 75 public static class TypeParameter extends Element { 76 private String parameter; 77 78 public TypeParameter(String str) { 79 this.parameter = str; 80 } 81 82 protected void generate(PrintWriter pw) { 83 pw.print(parameter); 84 } 85 } 86 87 public static class TypeArgument extends Element { 88 private String argument; 89 90 public TypeArgument(String str) { 91 this.argument = str; 92 } 93 94 protected void generate(PrintWriter pw) { 95 pw.print(argument); 96 } 97 } 98 99 public static class MethodParameter extends Element { 100 private String type; 101 private String name; 102 103 public MethodParameter(String type, String name) { 104 this.type = type; 105 this.name = name; 106 } 107 108 protected void generate(PrintWriter pw) { 109 pw.printf("%s %s", this.type, this.name); 110 } 111 112 public String toString() { return type + " " + name; } 113 } 114 115 public static abstract class Type extends Element { 116 private String name; 117 private List<AccessFlag> accessFlags; 118 private List<TypeParameter> parameters; 119 private List<Extends> supertypes; 120 private List<Method> methods; 121 122 // methods from superclasses that are required for compilation 123 // (and thus will be present in stubs) 124 private Set<Method> methodDependencies; 125 private List<Type> typeDependencies; 126 127 protected Type(String name, 128 List<AccessFlag> flags, List<TypeParameter> params, 129 List<Extends> ifaces, List<Method> methods) { 130 this.name = name; 131 this.accessFlags = flags == null ? new ArrayList<>() : flags; 132 this.parameters = params == null ? new ArrayList<>() : params; 133 this.supertypes = ifaces == null ? new ArrayList<>() : ifaces; 134 this.methods = methods == null ? new ArrayList<>() : methods; 135 this.methodDependencies = new HashSet<>(); 136 this.typeDependencies = new ArrayList<>(); 137 } 138 139 public String getName() { return this.name; } 140 public List<AccessFlag> getAccessFlags() { return this.accessFlags; } 141 public List<TypeParameter> getParameters() { return this.parameters; } 142 public List<Extends> getSupertypes() { return this.supertypes; } 143 public List<Method> getMethods() { return this.methods; } 144 public Set<Method> methodDependencies() { 145 return this.methodDependencies; 146 } 147 148 public Class getSuperclass() { return null; } 149 protected abstract void setSuperClass(Extends supertype); 150 151 public void addSuperType(Extends sup) { 152 assert sup.getType() instanceof Interface : "Must be an interface"; 153 this.supertypes.add(sup); 154 } 155 public void addSuperType(Interface iface) { 156 this.supertypes.add(new Extends(iface)); 157 } 158 159 public void addMethod(Method m) { 160 this.methods.add(m); 161 } 162 163 public void addAccessFlag(AccessFlag f) { 164 this.accessFlags.add(f); 165 } 166 167 // Convenience method for creation. Parameters are interpreted 168 // according to their type. Class (or Extends with a Class type) is 169 // considered a superclass (only one allowed). TypeParameters are 170 // generic parameter names. Interface (or Extends with an Interface 171 // type) is an implemented supertype. Methods are methods (duh!). 172 protected void addComponent(Element p) { 173 if (p instanceof Class) { 174 setSuperClass(new Extends((Class)p)); 175 } else if (p instanceof Extends) { 176 Extends ext = (Extends)p; 177 if (ext.supertype instanceof Class) { 178 setSuperClass(ext); 179 } else if (ext.supertype instanceof Interface) { 180 addSuperType(ext); 181 } else { 182 assert false : "What is this thing?"; 183 } 184 } else if (p instanceof Interface) { 185 addSuperType((Interface)p); 186 } else if (p instanceof TypeParameter) { 187 this.parameters.add((TypeParameter)p); 188 } else if (p instanceof Method) { 189 addMethod((Method)p); 190 } else if (p instanceof AccessFlag) { 191 addAccessFlag((AccessFlag)p); 192 } else { 193 assert false : "What is this thing?"; 194 } 195 } 196 197 // Find and return the first method that has name 'name' 198 public Method findMethod(String name) { 199 for (Method m : methods) { 200 if (m.name.equals(name)) { 201 return m; 202 } 203 } 204 return null; 205 } 206 207 public void addCompilationDependency(Type t) { 208 typeDependencies.add(t); 209 } 210 211 public void addCompilationDependency(Method m) { 212 methodDependencies.add(m); 213 } 214 215 // Convenience method for creating an Extends object using this 216 // class and specified type arguments. 217 public Extends with(String ... args) { 218 return new Extends(this, args); 219 } 220 221 public abstract void generate(SourceProcessor sp); 222 public abstract void generateAsDependency( 223 SourceProcessor sp, Set<Method> neededMethods); 224 225 protected void generateName(PrintWriter pw) { 226 pw.print(this.name); 227 StringJoiner joiner = new StringJoiner(",", "<", ">").setEmptyValue(""); 228 this.parameters.stream().map(Element::toString).forEach(joiner::add); 229 pw.print(joiner.toString()); 230 pw.print(" "); 231 } 232 233 protected void generateBody(PrintWriter pw, String superSpec) { 234 StringJoiner joiner = new StringJoiner(",", superSpec + " ", " ") 235 .setEmptyValue(""); 236 supertypes.stream().map(Element::toString).forEach(joiner::add); 237 pw.print(joiner.toString()); 238 pw.println("{ "); 239 joiner = new StringJoiner("\n ", "\n ", "\n").setEmptyValue(""); 240 methods.stream().map(Element::toString).forEach(joiner::add); 241 pw.print(joiner.toString()); 242 pw.println("}"); 243 } 244 245 protected void generateAccessFlags(PrintWriter pw) { 246 StringJoiner joiner = new StringJoiner(" ", "", " "); 247 accessFlags.stream().map(AccessFlag::toString).forEach(joiner::add); 248 pw.print(joiner.toString()); 249 } 250 251 protected void generateBodyAsDependency( 252 PrintWriter pw, Set<Method> neededMethods) { 253 pw.println(" {"); 254 for (Method m : this.methods) { 255 if (neededMethods.contains(m)) { 256 pw.print(" "); 257 m.generate(pw); 258 pw.println(); 259 } 260 } 261 pw.println("}"); 262 } 263 264 public Collection<Type> typeDependencies() { 265 HashMap<String,Type> dependencies = new HashMap<>(); 266 Type superclass = getSuperclass(); 267 if (superclass != null) { 268 dependencies.put(superclass.getName(), superclass); 269 } 270 for (Extends e : getSupertypes()) 271 dependencies.put(e.getType().getName(), e.getType()); 272 // Do these last so that they override 273 for (Type t : this.typeDependencies) 274 dependencies.put(t.getName(), t); 275 return dependencies.values(); 276 } 277 } 278 279 public static class Class extends Type { 280 private Extends superClass; 281 282 public Class(String name, List<AccessFlag> flags, 283 List<TypeParameter> params, Extends sprClass, 284 List<Extends> interfaces, List<Method> methods) { 285 super(name, flags, params, interfaces, methods); 286 this.superClass = sprClass; 287 addAccessFlag(AccessFlag.PUBLIC); // should remove this 288 } 289 290 public Class(String name, Element ... components) { 291 super(name, null, null, null, null); 292 this.superClass = null; 293 294 for (Element p : components) { 295 addComponent(p); 296 } 297 addAccessFlag(AccessFlag.PUBLIC); // should remove this 298 } 299 300 public boolean isAbstract() { 301 for (AccessFlag flag : getAccessFlags()) { 302 if (flag == AccessFlag.ABSTRACT) { 303 return true; 304 } 305 } 306 return false; 307 } 308 309 @Override 310 public void setSuperClass(Extends ext) { 311 assert this.superClass == null : "Multiple superclasses defined"; 312 assert ext.getType() instanceof Class : "Must be a class"; 313 this.superClass = ext; 314 } 315 316 public void setSuperClass(Class c) { 317 setSuperClass(new Extends(c)); 318 } 319 320 @Override 321 public Class getSuperclass() { 322 return superClass == null ? null : (Class)superClass.supertype; 323 } 324 325 public void generate(SourceProcessor processor) { 326 StringWriter sw = new StringWriter(); 327 PrintWriter pw = new PrintWriter(sw); 328 generate(pw); 329 processor.process(getName(), sw.toString()); 330 } 331 332 public void generate(PrintWriter pw) { 333 generateAccessFlags(pw); 334 pw.print("class "); 335 generateName(pw); 336 if (superClass != null) { 337 pw.print("extends "); 338 superClass.generate(pw); 339 pw.print(" "); 340 } 341 generateBody(pw, "implements"); 342 } 343 344 public void generateAsDependency( 345 SourceProcessor processor, Set<Method> neededMethods) { 346 StringWriter sw = new StringWriter(); 347 PrintWriter pw = new PrintWriter(sw); 348 generateAccessFlags(pw); 349 pw.print("class "); 350 generateName(pw); 351 pw.print(" "); 352 generateBodyAsDependency(pw, neededMethods); 353 354 processor.process(getName(), sw.toString()); 355 } 356 } 357 358 public static class Interface extends Type { 359 360 public Interface(String name, 361 List<AccessFlag> flags, List<TypeParameter> params, 362 List<Extends> interfaces, List<Method> methods) { 363 super(name, flags, params, interfaces, methods); 364 } 365 366 public Interface(String name, Element ... components) { 367 super(name, null, null, null, null); 368 for (Element c : components) { 369 addComponent(c); 370 } 371 } 372 373 protected void setSuperClass(Extends ext) { 374 assert false : "Interfaces cannot have Class supertypes"; 375 } 376 377 public void generate(SourceProcessor processor) { 378 StringWriter sw = new StringWriter(); 379 PrintWriter pw = new PrintWriter(sw); 380 generate(pw); 381 processor.process(getName(), sw.toString()); 382 } 383 384 public void generate(PrintWriter pw) { 385 generateAccessFlags(pw); 386 pw.print("interface "); 387 generateName(pw); 388 pw.print(" "); 389 generateBody(pw, "extends"); 390 } 391 392 public void generateAsDependency( 393 SourceProcessor processor, Set<Method> neededMethods) { 394 StringWriter sw = new StringWriter(); 395 PrintWriter pw = new PrintWriter(sw); 396 397 generateAccessFlags(pw); 398 pw.print("interface "); 399 generateName(pw); 400 pw.print(" "); 401 generateBodyAsDependency(pw, neededMethods); 402 403 processor.process(getName(), sw.toString()); 404 } 405 } 406 407 /** 408 * Represents a type extension that might contain type arguments 409 */ 410 public static class Extends extends Element { 411 private final Type supertype; 412 private final List<TypeArgument> arguments; 413 414 public Type getType() { return supertype; } 415 public List<TypeArgument> getArguments() { 416 return arguments; 417 } 418 419 public Extends(Type supertype, String ... args) { 420 assert supertype != null : "Null supertype"; 421 this.supertype = supertype; 422 this.arguments = new ArrayList<>(); 423 for (String arg : args) { 424 this.arguments.add(new TypeArgument(arg)); 425 } 426 } 427 428 public void generate(PrintWriter pw) { 429 StringJoiner joiner = new StringJoiner(",", "<", ">").setEmptyValue(""); 430 getArguments().stream().map(Element::toString).forEach(joiner::add); 431 pw.print(supertype.getName()); 432 pw.print(joiner.toString()); 433 } 434 } 435 436 public static abstract class Method extends Element { 437 private String name; 438 private String returnType; 439 private List<AccessFlag> accessFlags; 440 private List<MethodParameter> parameters; 441 private boolean emitSuppressWarnings; 442 443 protected Method(String ret, String name, Element ... params) { 444 this.name = name; 445 this.returnType = ret; 446 this.accessFlags = new ArrayList<>(); 447 this.parameters = new ArrayList<>(); 448 this.emitSuppressWarnings = false; 449 450 Arrays.asList(params).stream() 451 .filter(x -> x instanceof MethodParameter) 452 .map(x -> (MethodParameter)x) 453 .forEach(this.parameters::add); 454 Arrays.asList(params).stream() 455 .filter(x -> x instanceof AccessFlag) 456 .map(x -> (AccessFlag)x) 457 .forEach(this.accessFlags::add); 458 assert accessFlags.size() + parameters.size() == params.length : 459 "Non method parameters or access flags in constructor"; 460 } 461 462 public String getName() { return this.name; } 463 public String getReturnType() { return this.returnType; } 464 public List<MethodParameter> getParameters() { 465 return this.parameters; 466 } 467 public List<AccessFlag> getAccessFlags() { 468 return this.accessFlags; 469 } 470 public Element[] getElements() { 471 ArrayList<Element> elements = new ArrayList<>(); 472 getParameters().stream().forEach(elements::add); 473 getAccessFlags().stream().forEach(elements::add); 474 return elements.toArray(new Element[elements.size()]); 475 } 476 477 public void suppressWarnings() { this.emitSuppressWarnings = true; } 478 479 public void generateWarningSuppression(PrintWriter pw) { 480 if (this.emitSuppressWarnings) { 481 pw.printf("@SuppressWarnings(\"unchecked\")\n "); 482 } 483 } 484 485 protected void generateDecl(PrintWriter pw) { 486 generateWarningSuppression(pw); 487 StringJoiner joiner = new StringJoiner(" ", "", " "); 488 accessFlags.stream().map(AccessFlag::toString).forEach(joiner::add); 489 pw.print(joiner.toString()); 490 joiner = new StringJoiner(","); 491 pw.printf("%s %s(", returnType, name); 492 parameters.stream().map(MethodParameter::toString).forEach(joiner::add); 493 pw.print(joiner.toString()); 494 pw.print(")"); 495 } 496 } 497 498 public static class AbstractMethod extends Method { 499 public AbstractMethod( 500 String ret, String name, Element ... params) { 501 super(ret, name, params); 502 this.getAccessFlags().add(AccessFlag.ABSTRACT); 503 } 504 505 public void generate(PrintWriter pw) { 506 generateDecl(pw); 507 pw.print(";"); 508 } 509 510 public static AbstractMethod std() { 511 return new AbstractMethod( 512 "int", SourceModel.stdMethodName, AccessFlag.PUBLIC); 513 } 514 } 515 516 public static class ConcreteMethod extends Method { 517 protected String body; 518 519 public ConcreteMethod(String ret, String name, 520 String body, Element ... params) { 521 super(ret, name, params); 522 this.body = body; 523 } 524 525 public void generate(PrintWriter pw) { 526 generateDecl(pw); 527 pw.printf(" { %s }", this.body); 528 } 529 530 public static ConcreteMethod std(String value) { 531 return new ConcreteMethod( 532 "int", SourceModel.stdMethodName, "return " + value + ";", 533 AccessFlag.PUBLIC); 534 } 535 } 536 537 // When the default method flag gets moved into the traditional 538 // access flags location, we can remove this class completely and 539 // use a ConcreteMethod with an AccessFlag("default") in the constructor 540 public static class DefaultMethod extends Method { 541 protected String body; 542 543 public DefaultMethod(String ret, String name, String body, 544 Element ... params) { 545 super(ret, name, params); 546 this.body = body; 547 this.getAccessFlags().add(AccessFlag.DEFAULT); 548 } 549 550 public void generate(PrintWriter pw) { 551 generateDecl(pw); 552 pw.printf(" { %s }", this.body); 553 } 554 555 public static DefaultMethod std(String value) { 556 return new DefaultMethod( 557 "int", SourceModel.stdMethodName, "return " + value + ";"); 558 } 559 } 560} 561