1 /* 2 * Copyright (c) 2019, 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 package com.sun.tools.jextract; 24 25 import java.util.Map; 26 import java.util.Set; 27 import com.sun.tools.jextract.tree.FunctionTree; 28 29 /** 30 * A helper class to generate header interface class in source form. 31 * After aggregating various constituents of a .java source, build 32 * method is called to get overall generated source string. 33 */ 34 class JavaSourceBuilder { 35 // buffer 36 protected StringBuffer sb; 37 // current line alignment (number of 4-spaces) 38 protected int align; 39 40 JavaSourceBuilder(int align) { 41 this.align = align; 42 this.sb = new StringBuffer(); 43 } 44 45 JavaSourceBuilder() { 46 this(0); 47 } 48 49 protected int align() { 50 return align; 51 } 52 53 protected void addPackagePrefix(String pkgName) { 54 sb.append("// Generated by jextract\n\n"); 55 if (!pkgName.isEmpty()) { 56 sb.append("package "); 57 sb.append(pkgName); 58 sb.append(";\n\n"); 59 } 60 addImportSection(); 61 } 62 63 protected void addImportSection() { 64 sb.append("import java.foreign.*;\n"); 65 sb.append("import java.foreign.annotations.*;\n"); 66 sb.append("import java.foreign.memory.*;\n"); 67 sb.append("import java.lang.annotation.*;\n\n"); 68 } 69 70 protected void interfaceBegin(String name, boolean isStatic) { 71 interfaceBegin(name, isStatic, false); 72 } 73 74 protected void interfaceBegin(String name, boolean isStatic, boolean isAnnotation) { 75 check(); 76 indent(); 77 sb.append("public "); 78 if (isStatic) { 79 sb.append("static "); 80 } 81 if (isAnnotation) { 82 sb.append('@'); 83 } 84 sb.append("interface "); 85 sb.append(name); 86 sb.append(" {\n\n"); 87 } 88 89 protected void interfaceEnd() { 90 check(); 91 indent(); 92 sb.append("}\n\n"); 93 } 94 95 protected void addAnnotation(String annoName, Map<String, Object> fields) { 96 addAnnotation(true, annoName, fields); 97 } 98 99 protected void addAnnotation(boolean incrAlign, String annoName, Map<String, Object> fields) { 100 check(); 101 if (incrAlign) { 102 incrAlign(); 103 } 104 105 indent(); 106 sb.append('@'); 107 sb.append(annoName); 108 if (fields.isEmpty()) { 109 sb.append('\n'); 110 return; 111 } 112 boolean singleProperty = (fields.size() == 1); 113 114 if (singleProperty) { 115 sb.append('('); 116 } else { 117 sb.append("(\n"); 118 incrAlign(); 119 } 120 Set<String> keys = fields.keySet(); 121 int size = keys.size(); 122 for (String key : keys) { 123 if (!singleProperty) { 124 indent(); 125 } 126 127 if (!singleProperty || !key.equals("value")) { 128 sb.append(key); 129 sb.append('='); 130 } 131 132 Object value = fields.get(key); 133 if (value instanceof String) { 134 sb.append('"'); 135 sb.append(value.toString()); 136 sb.append('"'); 137 } else if (value instanceof Enum) { 138 sb.append(value.getClass().getSimpleName()); 139 sb.append('.'); 140 sb.append(((Enum)value).name()); 141 } else if (value instanceof Long) { 142 sb.append(value); 143 sb.append("L"); 144 } else if (value instanceof String[]) { 145 sb.append("{ "); 146 String[] strs = (String[])value; 147 for (int i = 0; i < strs.length; i++) { 148 sb.append('"'); 149 sb.append(strs[i]); 150 sb.append('"'); 151 if (i != strs.length - 1) { 152 sb.append(", "); 153 } 154 } 155 sb.append(" }"); 156 } else if (value instanceof JType.ClassType[]) { 157 sb.append("{ "); 158 JType.ClassType[] types = (JType.ClassType[])value; 159 for (int i = 0; i < types.length; i++) { 160 sb.append(types[i].externalName); 161 sb.append(".class"); 162 if (i != types.length - 1) { 163 sb.append(", "); 164 } 165 } 166 sb.append(" }"); 167 } else { 168 sb.append(value); 169 } 170 if (!singleProperty && size > 1) { 171 sb.append(",\n"); 172 } 173 size--; 174 } 175 176 if (!singleProperty) { 177 decrAlign(); 178 sb.append("\n"); 179 indent(); 180 } 181 sb.append(")\n"); 182 183 if (incrAlign) { 184 decrAlign(); 185 } 186 } 187 188 protected void addGetter(String name, JType jt) { 189 check(); 190 incrAlign(); 191 indent(); 192 sb.append("public "); 193 sb.append(jt.getSourceSignature(false)); 194 sb.append(' '); 195 sb.append(name); 196 sb.append("();\n\n"); 197 decrAlign(); 198 } 199 200 protected void addSetter(String name, JType jt) { 201 check(); 202 incrAlign(); 203 indent(); 204 sb.append("public "); 205 sb.append("void "); 206 sb.append(name); 207 sb.append('('); 208 sb.append(jt.getSourceSignature(true)); 209 sb.append(" value"); 210 sb.append(");\n\n"); 211 decrAlign(); 212 } 213 214 private void fillArgTypes(JType.Function fn, String[] argTypes) { 215 for (int i = 0; i < fn.args.length; i++) { 216 argTypes[i] = fn.args[i].getSourceSignature(true); 217 } 218 if (fn.isVarArgs) { 219 argTypes[argTypes.length - 1] = "Object..."; 220 } 221 } 222 223 private void fillArgNames(JType.Function fn, FunctionTree funcTree, String[] argNames) { 224 for (int i = 0; i < fn.args.length; i++) { 225 String name = funcTree != null? funcTree.paramName(i) : null; 226 argNames[i] = (name == null || name.isEmpty())? ("$arg" + i) : name; 227 } 228 if (fn.isVarArgs) { 229 argNames[argNames.length - 1] = "$args"; 230 } 231 } 232 233 private void addMethod(String name, JType.Function fn, FunctionTree funcTree) { 234 final int numArgs = fn.isVarArgs? fn.args.length + 1 : fn.args.length; 235 final String[] argTypes = new String[numArgs]; 236 final String[] argNames = new String[numArgs]; 237 fillArgTypes(fn, argTypes); 238 fillArgNames(fn, funcTree, argNames); 239 240 check(); 241 incrAlign(); 242 indent(); 243 sb.append("public "); 244 sb.append(fn.returnType.getSourceSignature(false)); 245 sb.append(' '); 246 sb.append(name); 247 sb.append('('); 248 for (int i = 0; i < numArgs; i++) { 249 sb.append(argTypes[i]); 250 sb.append(' '); 251 sb.append(argNames[i]); 252 if (i != argTypes.length - 1) { 253 sb.append(", "); 254 } 255 } 256 sb.append(");\n\n"); 257 decrAlign(); 258 } 259 260 protected void addMethod(String name, JType.Function fn) { 261 addMethod(name, fn, null); 262 } 263 264 protected void addMethod(FunctionTree funcTree, JType.Function fn) { 265 addMethod(funcTree.name(), fn, funcTree); 266 } 267 268 protected void addNestedType(JavaSourceBuilder jsb) { 269 check(); 270 sb.append(jsb.build()); 271 } 272 273 protected String build() { 274 check(); 275 String res = sb.toString(); 276 this.sb = null; 277 return res.toString(); 278 } 279 280 protected void indent() { 281 for (int i = 0; i < align; i++) { 282 sb.append(" "); 283 } 284 } 285 286 protected void incrAlign() { 287 align++; 288 } 289 290 protected void decrAlign() { 291 align--; 292 } 293 294 protected void check() { 295 if (sb == null) { 296 throw new IllegalStateException("source already built"); 297 } 298 } 299 }