/* * xtc - The eXTensible Compiler * Copyright (C) 2007 IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.lang.jeannie; import java.io.CharArrayWriter; import java.io.File; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import xtc.Constants; import xtc.lang.CAnalyzer; import xtc.lang.JavaEntities; import xtc.lang.JavaTypeConverter; import xtc.lang.JavaUnitTests; import xtc.parser.Result; import xtc.parser.SemanticValue; import xtc.tree.GNode; import xtc.tree.LineMarker; import xtc.tree.Location; import xtc.tree.Node; import xtc.tree.Printer; import xtc.tree.Visitor; import xtc.type.AliasT; import xtc.type.C; import xtc.type.ClassOrInterfaceT; import xtc.type.ErrorT; import xtc.type.Language; import xtc.type.MethodT; import xtc.type.NumberT; import xtc.type.PointerT; import xtc.type.SourcePrinter; import xtc.type.Type; import xtc.type.VoidT; import xtc.type.WrappedT; import xtc.util.Runtime; import xtc.util.SymbolTable; /** * Static helper routines related to JNI and Jeannie. * This is a good place to put code that is useful for more than one visitor. * * @author Martin Hirzel * @version $Revision: 1.30 $ */ public final class Utilities { static class MiniVisitor_containsCToJavaTransition extends Visitor { public final Boolean visit(final LineMarker m) { final Node n = m.getNode(); return null == n ? Boolean.FALSE : (Boolean)dispatch(n); } public final Boolean visit(final Node n) { for (int i = 0; i < n.size(); i++) if (n.get(i) instanceof Node) if (((Boolean) dispatch(n.getNode(i))).booleanValue()) return Boolean.TRUE; return Boolean.FALSE; } public final Boolean visitJavaImports(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitJavaInCBlock(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitJavaInCExpression(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitJavaInCStatement(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitJavaThrows(final GNode n) { return Boolean.valueOf(null != n && null != n.get(0)); } public final Boolean visitJavaType(final GNode n) { return Boolean.valueOf(null != n); } } static class MiniVisitor_containsJavaToCTransition extends Visitor { public final Boolean visit(final Node n) { for (int i = 0; i < n.size(); i++) if (n.get(i) instanceof Node) if (((Boolean) dispatch(n.getNode(i))).booleanValue()) return Boolean.TRUE; return Boolean.FALSE; } public final Boolean visitCDeclarations(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitCInJavaBlock(final GNode n) { return Boolean.valueOf(null != n); } public final Boolean visitCInJavaExpression(final GNode n) { return Boolean.valueOf(null != n); } } static class MiniVisitor_findScopeBoundaries extends Visitor { private final Map<String, Location> _ends = new HashMap<String, Location>(); private final Map<String, Location> _starts = new HashMap<String, Location>(); private final List<String> _willEnd = new ArrayList<String>(); public final void visit(final Node n) { if (n.hasLocation()) { final Location loc = n.getLocation(); for (final String scope : _willEnd) _ends.put(scope, loc); _willEnd.clear(); if (n.hasProperty(Constants.SCOPE)) _starts.put((String) n.getProperty(Constants.SCOPE), loc); } for (final Object o : n) if (o instanceof Node) dispatch((Node)o); if (n.hasLocation() && n.hasProperty(Constants.SCOPE)) _willEnd.add((String) n.getProperty(Constants.SCOPE)); } } static class MiniVisitor_getSimpleDeclarators extends Visitor { public final Set<String> visit(final Node n) { Set<String> result = Utilities.EMPTY_SET; for (final Object o : n) { if (o instanceof Node) { final Set<String> childSet = Utilities.stringSet(dispatch((Node)o)); if (!childSet.isEmpty()) { if (result.isEmpty()) result = childSet; else result.addAll(childSet); } } } return result; } public final Set<String> visitSimpleDeclarator(final GNode n) { final Set<String> result = new HashSet<String>(1); result.add(n.getString(0)); return result; } } static class MiniVisitor_getTopLevelDeclarations extends Visitor { public final Set<String> visit(final Node n) { Set<String> result = Utilities.EMPTY_SET; for (final Object o : n) { if (o instanceof Node) { final Set<String> childSet = Utilities.stringSet(dispatch((Node)o)); if (!childSet.isEmpty()) { if (result.isEmpty()) result = childSet; else result.addAll(childSet); } } } return result; } public final Set<String> visitClassDeclaration(final GNode n) { final Set<String> result = new HashSet<String>(1); result.add(n.getString(1)); return result; } public final Set<String> visitInterfaceDeclaration(final GNode n) { final Set<String> result = new HashSet<String>(1); result.add(n.getString(1)); return result; } } private static final String[] JAVA_BASE_TYPES = { "boolean", "byte", "char", "short", "int", "long", "float", "double" }; public static final Set<String> EMPTY_SET = Collections.emptySet(); private static final Set<String> STANDARD_JNI_TYPE_DEFS = new HashSet<String>(); private static final Pattern AUTO_PATTERN = Pattern.compile("\\bauto\\b"); // private static C C = (new Analyzer.JeannieCAnalyzer(new Analyzer(UnitTests.newRuntime(), new SymbolTable(), null))).c(); private static C C = (new Analyzer.JeannieCAnalyzer(null)).c(); public static C c() { return C; } /** * Don't use this method gratuitously. Originally, I used this to serialize * ASTs into strings, then concatenated the strings into more code, then * reparsed the result to a larger AST. But that is not only slow, it is also * brittle, since the same typedefs must be available during both parses. * Chances are you can use the ast directly as a parameter to an AST factory * generated by FactoryFactory. */ public static String cAstToString(final Node ast) { return JavaUnitTests.cAstToString(ast); } public static boolean containsCToJavaTransition(final Node n) { final MiniVisitor_containsCToJavaTransition v = new MiniVisitor_containsCToJavaTransition(); final Boolean result = (Boolean) v.dispatch(n); return result.booleanValue(); } public static boolean containsJavaToCTransition(final GNode n) { final MiniVisitor_containsJavaToCTransition v = new MiniVisitor_containsJavaToCTransition(); final Boolean result = (Boolean) v.dispatch(n); return result.booleanValue(); } public static String copyDropAuto(final String string) { return AUTO_PATTERN.matcher(string).replaceAll("").trim(); } public static Type cPtrToBaseType(final Type cPtrType) { return ((PointerT)C.pointerize(cPtrType)).getType(); } public static GNode cStringToAst(final String production, final String code) { return cStringToAst(production, code, null); } public static GNode cStringToAst(final String production, final String code, final Set<String> typedefs) { try { final GNode result = JavaUnitTests.cStringToAst(production, code, typedefs); return JavaEntities.scrubLocations(result); } catch (final Exception e) { throw new Error(e); } } public static Type cStringToType(final String code) { return cStringToType(code, EMPTY_SET); } public static Type cStringToType(final String code, final Set<String> typedefs) { final GNode ast = cStringToAst("TypeName", code, typedefs); final CAnalyzer cAnalyzer = new CAnalyzer(newRuntime()); try { final Field field = CAnalyzer.class.getDeclaredField("table"); field.setAccessible(true); field.set(cAnalyzer, new SymbolTable()); } catch (final Exception e) { throw new Error(e); } final Type result = cAnalyzer.visitTypeName(ast); return result; } public static GNode cTypeToAst(final Type type, final String id, final String production) { final String code; if (null == id) { assert "TypeName".equals(production); code = cTypeToString(type); } else { assert "StructureDeclaration".equals(production) || "Declaration".equals(production); code = cTypeToString(type, id) + ";"; } final GNode result = cStringToAst(production, copyDropAuto(code), typedefs(type)); return result; } public static Type cTypeToJavaType(final SymbolTable tab, final Runtime runtime, final Node n, final Type cType) { if (cType.isVoid()) return JavaEntities.nameToBaseType("void"); { final Type c = Utilities.getJavaClassOrInterfaceT(cType); if (JavaEntities.isWrappedClassT(c) || JavaEntities.isWrappedInterfaceT(c)) return c; } for (final String s : Utilities.JAVA_BASE_TYPES) { if (Utilities.hasTypedefName(cType, "j" + s)) return JavaEntities.nameToBaseType(s); if (Utilities.hasTypedefName(cType, "j" + s + "Array")) return JavaEntities.typeWithDimensions(JavaEntities.nameToBaseType(s), 1); } if (Utilities.hasTypedefName(cType, "jsize")) return JavaEntities.nameToBaseType("int"); if (Utilities.hasTypedefName(cType, "jclass")) return JavaEntities.tClass(tab); if (Utilities.hasTypedefName(cType, "jstring")) return JavaEntities.tString(tab); if (Utilities.hasTypedefName(cType, "jthrowable")) return JavaEntities.tThrowable(tab); if (Utilities.hasTypedefName(cType, "jobjectArray")) return JavaEntities.typeWithDimensions(JavaEntities.tObject(tab), 1); if (Utilities.hasTypedefName(cType, "jobject")) return JavaEntities.tObject(tab); if (C.isIntegral(cType)) { String tgt = "long"; final Type jInt = (Type) tab.root().lookup("jint"); if (null != jInt && jInt.equals(C.convert(jInt, cType))) tgt = "int"; else if (null != n) runtime.warning("converting C type '" + cType + "' to Java type '" + tgt + "'", n); return JavaEntities.nameToBaseType(tgt); } if (C.isArithmetic(cType) && !C.isIntegral(cType)) { String tgt = "double"; final Type jFloat = (Type) tab.root().lookup("jfloat"); if (null != jFloat && jFloat.equals(C.convert(jFloat, cType))) tgt = "float"; if (null != n) runtime.warning("converting C type '" + cType + "' to Java type '" + tgt + "'", n); return JavaEntities.nameToBaseType(tgt); } runtime.error("illegal C type '" + cType + "' in Java expression", n); return JavaEntities.nameToBaseType("int"); } public static String cTypeToString(final Type type) { return cTypeToString(type, null); } public static String cTypeToString(final Type type, final String id) { final CharArrayWriter writer = new CharArrayWriter(); final Printer printer = new Printer(writer); final SourcePrinter sourcePrinter = new SourcePrinter(printer); if (null == id) sourcePrinter.print(type); else sourcePrinter.print(type, id); printer.flush(); return writer.toString(); } public static Type currentFunctionOrMethod(final SymbolTable tab) { for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s.getParent()) { final String scopeName = s.getName(); if (SymbolTable.isInNameSpace(scopeName, "method")) return JavaEntities.currentMethod(tab); if (SymbolTable.isFunctionScopeName(scopeName) || SymbolTable.isMacroScopeName(scopeName)) { final String functionName = SymbolTable.fromNameSpace(scopeName); return (Type) s.getParent().lookupLocally(functionName); } } return null; } public static String currentFunctionOrMethodName(final SymbolTable tab) { for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s.getParent()) { final String scopeName = s.getName(); if (SymbolTable.isInNameSpace(scopeName, "method")) { final MethodT m = JavaEntities.currentMethod(tab); return JavaEntities.typeToString(tab, false, m) + JavaEntities.typeToDescriptor(tab, m); } if (SymbolTable.isFunctionScopeName(scopeName) || SymbolTable.isMacroScopeName(scopeName)) return SymbolTable.fromNameSpace(scopeName); } return null; } public static void dumpLineMarkers(final Set<LineMarker> ms, final int limit) { System.err.print("dumpLineNumbers(" + limit + " / " + ms.size() + ")"); int i = -1 == limit ? Integer.MAX_VALUE : limit; for (final LineMarker m : ms) { i--; if (0 > i) break; System.err.print(" " + m.line + ":"); Node j; for (j = m; null != j && j instanceof LineMarker; j = ((LineMarker)j).getNode()); System.err.print(null == j ? "null" : j.getName()); } System.err.println(); } public static Type getJavaClassOrInterfaceT(final Type t) { Type i = t; do { if (JavaEntities.isWrappedClassT(i) || JavaEntities.isWrappedInterfaceT(i)) return i; if (!(i instanceof WrappedT)) return t; i = ((WrappedT) i).getType(); } while (true); } public static String getSimpleDeclarator(final GNode declNode) { final Set<String> all = getSimpleDeclarators(declNode); if (all.size() != 1) return null; return all.iterator().next(); } public static Set<String> getSimpleDeclarators(final GNode declNode) { final Visitor v = new MiniVisitor_getSimpleDeclarators(); @SuppressWarnings("unchecked") final Set<String> result = (Set<String>) v.dispatch(declNode); return result; } public static boolean hasTypedefName(final Type t, final String name) { Type i = t; while (i instanceof WrappedT) { if (i instanceof AliasT) { final String n = i.toAlias().getName(); if (n.equals(name)) return true; } i = ((WrappedT) i).getType(); } return false; } public static boolean isJavaEntity(final Type e) { if (JavaEntities.isWrappedClassT(e) || JavaEntities.isWrappedInterfaceT(e)) return true; if (e.isMethod() || e.isPackage()) return true; if (JavaEntities.isParameterT(e) || JavaEntities.isFieldT(e) || JavaEntities.isLocalT(e)) return Language.JAVA == e.getLanguage(); return false; } public static boolean isPtrChar(final Type t) { final Type p = c().pointerize(t); if (!p.isPointer()) return false; final Type e = p.toPointer().getType().resolve(); return e.isNumber() && NumberT.Kind.CHAR == e.toNumber().getKind(); } public static boolean isPtrTypedef(final Type t, final String typedefName) { final Type p = c().pointerize(t); return p.isPointer() && hasTypedefName(p.toPointer().getType(), typedefName); } public static String javaAstToString(final Node ast) { return JavaEntities.javaAstToString(ast); } public static boolean javaIsStaticMethod(final GNode n) { final Type type = (Type) n.getProperty(Constants.TYPE); assert type.isMethod(); return type.hasAttribute(JavaEntities.nameToModifier("static")); } public static boolean javaIsVoidMethod(final GNode n) { final Type returnType = ((Type) n.getProperty(Constants.TYPE)).toMethod().getResult(); return returnType.isVoid(); } public static String javaTypeToApiType(final Type type) { return javaTypeToApiType(type, false, true); } public static String javaTypeToApiType(final Type type, final boolean upcase, final boolean arrays) { if (type.isVoid()) return "Void"; if (JavaEntities.isGeneralLValueT(type)) return javaTypeToApiType(JavaEntities.dereference(type), upcase, arrays); final boolean isArray = type.isArray(); final Type elemType = isArray ? JavaEntities.arrayElementType(type.toArray()) : null; String result = "Object"; for (final String s : JAVA_BASE_TYPES) { final Type jBaseType = JavaEntities.nameToBaseType(s); if (arrays && isArray) { if (JavaTypeConverter.isIdentical(elemType, jBaseType)) { result = s + "Array"; break; } } else { if (JavaTypeConverter.isIdentical(type, jBaseType)) { result = s; break; } } } return upcase ? upcaseFirstLetter(result) : result; } public static Type javaTypeToCType(final SymbolTable tab, final Runtime runtime, final Node n, final Type jType, final boolean keepIfClassOrInterface) { if (jType.isError()) return ErrorT.TYPE; if (jType.isVoid()) return VoidT.TYPE; assert JavaEntities.isGeneralRValueT(jType); if (JavaEntities.isNullT(jType)) return C.typeInteger("0"); if (keepIfClassOrInterface) if (JavaEntities.isWrappedClassT(jType) || JavaEntities.isWrappedInterfaceT(jType)) return jType; String cTypeName = null; for (final String s : Utilities.JAVA_BASE_TYPES) { final Type jBaseType = JavaEntities.nameToBaseType(s); if (JavaTypeConverter.isIdentical(jType, jBaseType)) cTypeName = "j" + s; else if (JavaTypeConverter.isIdentical(jType, JavaEntities .typeWithDimensions(jBaseType, 1))) cTypeName = "j" + s + "Array"; if (null != cTypeName) break; } final List<File> paths = JavaEntities.classpath(runtime); if (null == cTypeName && JavaTypeConverter.isAssignable(tab, paths, JavaEntities.tClass(tab), jType)) cTypeName = "jclass"; if (null == cTypeName && JavaTypeConverter.isAssignable(tab, paths, JavaEntities.tString(tab), jType)) cTypeName = "jstring"; if (null == cTypeName && JavaTypeConverter.isAssignable(tab, paths, JavaEntities.tThrowable(tab), jType)) cTypeName = "jthrowable"; if (null == cTypeName && jType.isArray()) { assert JavaEntities.isReferenceT(JavaEntities.arrayElementType(jType.toArray())); cTypeName = "jobjectArray"; } if (null == cTypeName) { assert JavaEntities.isReferenceT(jType); cTypeName = "jobject"; } final Type cType = (Type) tab.root().lookup(cTypeName); if (null != cType) return cType; runtime.error("C typedef for '" + cTypeName + "' missing; did you forget to #include <jni.h>?", n); return ErrorT.TYPE; } public static String jeannieAstToString(final GNode ast, final String language) { final CharArrayWriter writer = new CharArrayWriter(); final JeanniePrinter printer = new JeanniePrinter(new Printer(writer), language); printer.dispatch(ast); return writer.toString(); } public static GNode jeannieStringToAst(final String production, final String language, final String code) { try { return jeannieStringToAst(production, language, code, true); } catch (final Exception e) { throw new Error(e); } } public static GNode jeannieStringToAst(final String production, final String language, final String escaped, final boolean simple) throws Exception { final Class[] paramTypes = { Integer.TYPE }; final Method method = JeannieParser.class.getDeclaredMethod("p" + production, paramTypes); method.setAccessible(true); final String string = JavaEntities.unicodeUnescape(escaped); final JeannieParser parser = new JeannieParser(new StringReader(string), "<input>", string.length()); final Object[] paramValues = { new Integer(0) }; final Result parseResult = (Result) method.invoke(parser, paramValues); if (parseResult.hasValue()) { final SemanticValue val = (SemanticValue) parseResult; if (val.index != string.length()) parser.signal(parseResult.parseError()); final GNode ast = (GNode) val.value; if (simple) return (GNode) new AstSimplifier(language).dispatch(ast); return ast; } parser.signal(parseResult.parseError()); return null; } /** * Part of name of C function implementing Java method as expected by linker, * see JNI Specification <a * href="http://java.sun.com/docs/books/jni/html/design.html#9984">§11.3</a>. */ public static String jniMangledName(final String name) { final StringBuffer b = new StringBuffer(name.length()); for (int i = 0; i < name.length(); i++) { final char c = name.charAt(i); switch (c) { case '.': b.append('_'); break; case '_': b.append("_1"); break; case ';': b.append("_2"); break; case '[': b.append("_3"); break; default: if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9') { b.append(c); } else { final String hex = Integer.toHexString(c); b.append("_0"); for (int j=0; j<4-hex.length(); j++) b.append('0'); b.append(hex); } } } return b.toString(); } public static String jniMangledName(final SymbolTable tab, final Type type) { if (type.isClass()) return jniMangledName(JavaEntities.qNameWithDollars(tab, type.toClass())); if (type.isInterface()) return jniMangledName(JavaEntities.qNameWithDollars(tab, type.toInterface())); assert type.isMethod(); final ClassOrInterfaceT declaringType = JavaEntities.declaringType(tab, type); final String declaringMangled = jniMangledName(tab, declaringType); final String nameMangled = jniMangledName(type.toMethod().getName()); final String md = JavaEntities.typeToDescriptor(tab, type); final String ad = md.substring(1 + md.indexOf('('), md.indexOf(')')); if (0 == ad.length()) return declaringMangled + "_" + nameMangled; return declaringMangled + "_" + nameMangled + "__" + jniMangledName(ad); } public static Runtime newRuntime() { final Runtime runtime = new Runtime(); runtime.dir("in", Runtime.INPUT_DIRECTORY, true, "").setValue(Runtime.INPUT_DIRECTORY, JavaEntities.TEMP_DIR); runtime.bool("markAST", "optionMarkAST", true, "Mark AST nodes with types.").setValue("optionMarkAST", true); runtime.bool("strict", "optionStrict", true, "Enforce strict C99 compliance.").setValue("optionStrict", true); runtime.bool("pedantic", "optionPedantic", false, "Enforce strict C99 compliance.").setValue("optionPedantic", true); runtime.word("jniCall", "jniCall", false, "Calling conventions qualifier to C JNI functions.").setValue("jniCall", ""); runtime.initDefaultValues(); return runtime; } static void printLocalVariableMap(final PrintWriter out, final Node root, final SymbolTable tab, final CodeGenerator.Substitutions cSubstitutions, final CodeGenerator.Substitutions javaSubstitutions) { final MiniVisitor_findScopeBoundaries boundaries = new MiniVisitor_findScopeBoundaries(); boundaries.dispatch(root); out.println("LocalVariableMap:"); out.println("# file startLine startCol endLine endCol lang srcId tgtId"); printLocalVariableMap_helper(out, tab, boundaries, "C", cSubstitutions); printLocalVariableMap_helper(out, tab, boundaries, "Java", javaSubstitutions); out.println(); } static void printLocalVariableMap_helper(final PrintWriter out, final SymbolTable tab, final MiniVisitor_findScopeBoundaries boundaries, final String language, final CodeGenerator.Substitutions substitutions) { for (final CodeGenerator.StringString ss : substitutions) { final String scopeName = ss._s1; Location start = null; if (false) { start = boundaries._starts.get(scopeName); } else { for (String s = scopeName; 0 < s.length(); s = xtc.util.Utilities.getQualifier(s)) { start = boundaries._starts.get(s); if (null != start) break; } } assert null != start; final Location end = boundaries._ends.get(scopeName); assert null == end || end.file.equals(start.file); final String srcId = ss._s2; final String tgtId = substitutions.get(tab.getScope(scopeName), srcId); out.print(" " + start.file + " " + start.line + " " + start.column); if (null == end) out.print(" - -"); else out.print(" " + end.line + " " + end.column); out.println(" " + language + " " + srcId + " " + tgtId); } } public static void printMethodMap(final PrintWriter out, final SymbolTable tab, final Map<String, String> substitutions) { out.println("MethodMap:"); out.println("# srcMethod tgtFunctionOrMethod:"); for (final String tgt : substitutions.keySet()) out.println(" " + substitutions.get(tgt) + " " + tgt); out.println(); } public static void printTopLevelDeclarations(final PrintWriter out, final Node root) { final Visitor v = new MiniVisitor_getTopLevelDeclarations(); out.print("TopLevelClassesOrInterfaces:"); for (final String s : JavaEntities.stringSet(v.dispatch(root))) out.print(" " + s); out.println(); out.println(); } public static Type pureCType(final SymbolTable tab, final Runtime runtime, final Type javaOrCType) { if (isJavaEntity(javaOrCType)) return javaTypeToCType(tab, runtime, null, javaOrCType, false); if (javaOrCType.isAnnotated()) return pureCType(tab, runtime, javaOrCType.toAnnotated().getType()); if (javaOrCType.isVariable()) return pureCType(tab, runtime, javaOrCType.toVariable().getType()); return javaOrCType; } public static String qualifiedIdentifierToString(final GNode n) { final StringBuilder b = new StringBuilder(); for (int i = 0; i < n.size(); i++) { if (0 < i) b.append(Constants.QUALIFIER); b.append(n.getString(i)); } return b.toString(); } public static Type returnType(final Type functionOrMethod) { if (functionOrMethod.isMethod()) return functionOrMethod.toMethod().getResult(); else return functionOrMethod.resolve().toFunction().getResult(); } public static Set<String> standardJniTypeDefs() { if (STANDARD_JNI_TYPE_DEFS.isEmpty()) { for (final String s : JAVA_BASE_TYPES) { STANDARD_JNI_TYPE_DEFS.add("j" + s); STANDARD_JNI_TYPE_DEFS.add("j" + s + "Array"); } final String[] a = { "JNIEnv", "jclass", "jfieldID", "jmethodID", "jobject", "jstring" }; for (final String s : a) STANDARD_JNI_TYPE_DEFS.add(s); } return STANDARD_JNI_TYPE_DEFS; } @SuppressWarnings("unchecked") public static Set<String> stringSet(final Object s) { return (Set<String>)s; } public static String stringSetToString(final Set<String> s) { final StringBuilder result = new StringBuilder(); for (final String e : s) { if (0 < result.length()) result.append(' '); result.append(e); } return result.toString(); } public static Set<String> typedefs(Type r) { final Set<String> result = new HashSet<String>(); while (true) { if (r.isAlias()) result.add(r.toAlias().getName()); if (r instanceof WrappedT) r = ((WrappedT)r).getType(); else if (r instanceof PointerT) r = ((PointerT)r).getType(); else break; } return result; } public static String upcaseFirstLetter(final String s) { final char[] chars = s.toCharArray(); chars[0] = Character.toUpperCase(chars[0]); return new String(chars); } private Utilities() { assert false; } }