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.ArrayList;
  26 import java.util.List;
  27 import java.util.Set;
  28 import com.sun.tools.jextract.tree.FunctionTree;
  29 import com.sun.tools.jextract.tree.VarTree;
  30 
  31 /**
  32  * A helper class to generate static forwarder header class in source form.
  33  * After aggregating various constituents of a .java source, build method
  34  * is called to get overall generated source string.
  35  */
  36 final class JavaSourceBuilderExt extends JavaSourceBuilder {
  37     JavaSourceBuilderExt(int align) {
  38         super(align);
  39     }
  40 
  41     JavaSourceBuilderExt() {
  42         super();
  43     }
  44 
  45     protected void addImportSection() {
  46         sb.append("import java.foreign.*;\n");
  47         sb.append("import java.foreign.memory.*;\n");
  48         sb.append("import java.lang.invoke.*;\n\n");
  49     }
  50 
  51     protected void classBegin(String name, boolean isStatic) {
  52         classBegin(name, isStatic, null);
  53     }
  54 
  55     protected void classBegin(String name, boolean isStatic, String superType) {
  56         check();
  57         indent();
  58         sb.append("public ");
  59         if (isStatic) {
  60             sb.append("static ");
  61         }
  62         sb.append("class ");
  63         sb.append(name);
  64         if (superType != null) {
  65             sb.append(" extends ");
  66             sb.append(superType);
  67         }
  68         sb.append(" {\n\n");
  69     }
  70 
  71     protected void classEnd() {
  72         interfaceEnd();
  73     }
  74 
  75     // implement LibraryScope scope(LibraryInterfaceObject) method
  76     protected void emitScopeAccessor(String libraryField) {
  77         check();
  78         incrAlign();
  79         indent();
  80         sb.append("public static Scope scope() {\n");
  81         incrAlign();
  82         indent();
  83         sb.append("return Libraries.libraryScope(");
  84         sb.append(libraryField);
  85         sb.append(");\n");
  86         decrAlign();
  87         indent();
  88         sb.append("}\n\n");
  89         decrAlign();
  90     }
  91 
  92     // add private static field for the underlying header interface (bound) object
  93     protected void addLibraryField(String className, String libraryField) {
  94         check();
  95         incrAlign();
  96         indent();
  97         sb.append("private static final ");
  98         sb.append(className);
  99         sb.append(' ');
 100         sb.append(libraryField);
 101         sb.append(" = Libraries.bind(MethodHandles.lookup(), ");
 102         sb.append(className);
 103         sb.append(".class);\n\n");
 104         decrAlign();
 105     }
 106 
 107     // add a static final field for enum constant or a C macro
 108     protected void addField(String name, JType type, Object value, String libraryField) {
 109         check();
 110         incrAlign();
 111         indent();
 112         sb.append("public static final ");
 113         sb.append(type.getSourceSignature(false));
 114         sb.append(' ');
 115         sb.append(name);
 116         sb.append(" = ");
 117         if (value != null) {
 118             boolean isChar = value instanceof Character;
 119             if (isChar) {
 120                 sb.append('\'');
 121             }
 122             sb.append(value);
 123             if (isChar) {
 124                 sb.append('\'');
 125             }
 126             if (value instanceof Long) {
 127                 sb.append('L');
 128             } else if (value instanceof Double) {
 129                 sb.append('D');
 130             }
 131         } else {
 132             sb.append(libraryField);
 133             sb.append('.');
 134             sb.append(name);
 135             sb.append("()");
 136         }
 137         sb.append(";\n\n");
 138         decrAlign();
 139     }
 140 
 141     // emit static forwarder methods for a variable getter, setter and pointer getter
 142     protected void emitStaticForwarder(VarTree varTree, JType type, String libraryField) {
 143         check();
 144         incrAlign();
 145 
 146         String fieldName = varTree.name();
 147 
 148         // getter
 149         indent();
 150         sb.append("public static ");
 151         sb.append(type.getSourceSignature(false));
 152         sb.append(' ');
 153         sb.append(fieldName);
 154         sb.append("$get() {\n");
 155         incrAlign();
 156         indent();
 157         sb.append("return ");
 158         sb.append(libraryField);
 159         sb.append('.');
 160         sb.append(fieldName);
 161         sb.append("$get();\n");
 162         decrAlign();
 163         indent();
 164         sb.append("}\n\n");
 165 
 166         // setter
 167         indent();
 168         sb.append("public static void ");
 169         sb.append(fieldName);
 170         sb.append("$set(");
 171         sb.append(type.getSourceSignature(true));
 172         sb.append(" value) {\n");
 173         incrAlign();
 174         indent();
 175         sb.append(libraryField);
 176         sb.append('.');
 177         sb.append(fieldName);
 178         sb.append("$set(value);\n");
 179         decrAlign();
 180         indent();
 181         sb.append("}\n\n");
 182 
 183         // ptr getter
 184         JType ptrType = JType.GenericType.ofPointer(type);
 185         indent();
 186         sb.append("public static ");
 187         sb.append(ptrType.getSourceSignature(false));
 188         sb.append(' ');
 189         sb.append(fieldName);
 190         sb.append("$ptr() {\n");
 191         incrAlign();
 192         indent();
 193         sb.append("return ");
 194         sb.append(libraryField);
 195         sb.append('.');
 196         sb.append(fieldName);
 197         sb.append("$ptr();\n");
 198         decrAlign();
 199         indent();
 200         sb.append("}\n\n");
 201 
 202         decrAlign();
 203     }
 204 
 205     // emit static forwarder method of a function
 206     protected void emitStaticForwarder(FunctionTree funcTree, JType.Function fn, String libraryField) {
 207         check();
 208         incrAlign();
 209         indent();
 210         sb.append("public static ");
 211         sb.append(fn.returnType.getSourceSignature(false));
 212         sb.append(' ');
 213         sb.append(funcTree.name());
 214         sb.append('(');
 215         final int arg_cnt = funcTree.numParams();
 216         final List<String> argNames = new ArrayList<>();
 217         for (int i = 0; i < fn.args.length; i++) {
 218             sb.append(fn.args[i].getSourceSignature(false));
 219             sb.append(' ');
 220             String pname = funcTree.paramName(i);
 221             pname = pname == null || pname.isEmpty()? ("$arg" + i) : pname;
 222             argNames.add(pname);
 223             sb.append(pname);
 224             if (fn.isVarArgs || i != arg_cnt - 1) {
 225                 sb.append(", ");
 226             }
 227         }
 228         if (fn.isVarArgs) {
 229             sb.append("Object... ");
 230             String pname = funcTree.paramName(arg_cnt - 1);
 231             pname = pname == null || pname.isEmpty()? "$args" : pname;
 232             argNames.add(pname);
 233             sb.append(pname);
 234         }
 235 
 236         sb.append(") {\n");
 237         incrAlign();
 238         indent();
 239         if (fn.returnType != JType.Void) {
 240             sb.append("return ");
 241         }
 242         sb.append(libraryField);
 243         sb.append('.');
 244         sb.append(funcTree.name());
 245         sb.append('(');
 246         int size = argNames.size();
 247         int j = 0;
 248         for (String an : argNames) {
 249             sb.append(an);
 250             if (j != size - 1) sb.append(", ");
 251             j++;
 252         }
 253         sb.append(");\n");
 254         decrAlign();
 255         indent();
 256         sb.append("}\n\n");
 257         decrAlign();
 258     }
 259 }