/* * 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.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import xtc.Constants; import xtc.Limits; import xtc.lang.CAnalyzer; import xtc.lang.JavaAnalyzer; import xtc.lang.JavaEntities; import xtc.lang.JavaTypeConverter; import xtc.tree.GNode; import xtc.tree.LineMarker; import xtc.tree.Locatable; import xtc.tree.Node; import xtc.tree.Visitor; import xtc.type.ClassOrInterfaceT; import xtc.type.ClassT; import xtc.type.FunctionT; import xtc.type.MethodT; import xtc.type.PointerT; import xtc.type.Type; import xtc.type.VariableT; import xtc.type.VoidT; import xtc.type.Type.Tag; import xtc.util.Runtime; import xtc.util.SymbolTable; import xtc.util.SymbolTable.Scope; /** * A visitor that constructs separate C and Java ASTs from a JNI AST. Assumes * that the input AST has been simplified with jeannie.AstSimplifier, and its types * have been analyzed with jeannie.Analyzer. * * @author Martin Hirzel */ public class CodeGenerator extends Visitor { public static final class Context { final String _activeLanguage; final String _cEnvStructName; final boolean _cHasEnv; final String _javaEnvClassName; final String _javaEnvPackageName; final boolean _javaIsStatic; final String _openArray; final Type _snippetType; public Context(final Context other, final String activeLanguage) { this(activeLanguage, other._cEnvStructName, other._cHasEnv, other._javaEnvClassName, other._javaEnvPackageName, other._javaIsStatic, other._openArray, other._snippetType); } public Context(final String activeLanguage, final String cEnvStructName, final boolean cHasEnv, final String javaEnvClassName, final String javaEnvPackageName, final boolean javaIsStatic, final String openArray, final Type snippetType) { _activeLanguage = activeLanguage; _cEnvStructName = cEnvStructName; _cHasEnv = cHasEnv; _javaEnvClassName = javaEnvClassName; _javaEnvPackageName = javaEnvPackageName; _javaIsStatic = javaIsStatic; _openArray = openArray; _snippetType = snippetType; } } public static final class Out { public final List<Node> _cExternalDeclarations; public final List<Node> _cMembers; public final Node _cNode; public final List<Node> _javaMembers; public final Node _javaNode; public Out(final List<Node> cExternalDeclarations, final List<Node> cMembers, final Node cNode, final List<Node> javaMembers, final Node javaNode) { _cExternalDeclarations = cExternalDeclarations; _cMembers = cMembers; _cNode = cNode; _javaMembers = javaMembers; _javaNode = javaNode; } public final Out addAll(final Out other) { if (null != other) { _cExternalDeclarations.addAll(other._cExternalDeclarations); _cMembers.addAll(other._cMembers); _javaMembers.addAll(other._javaMembers); } return this; } } static final class StringString { final String _s1; final String _s2; StringString(final String s1, final String s2) { _s1 = s1; _s2 = s2; } } static final class Substitutions implements Iterable<StringString>{ private final Map<String, Map<String, String>> _map = new HashMap<String, Map<String, String>>(); final String get(final SymbolTable.Scope scope, final String srcId) { final Map<String, String> m = _map.get(scope.getQualifiedName()); return null == m ? null : m.get(srcId); } public Iterator<StringString> iterator() { final List<StringString> l = new ArrayList<StringString>(); for (final String scopeName : _map.keySet()) for (final String srcId : _map.get(scopeName).keySet()) l.add(new StringString(scopeName, srcId)); return l.iterator(); } final Substitutions put(final SymbolTable.Scope scope, final String srcId, final String tgtId) { final String scopeName = scope.getQualifiedName(); if (!_map.containsKey(scopeName)) _map.put(scopeName, new HashMap<String, String>()); _map.get(scopeName).put(srcId, tgtId); return this; } } private static String getFileStem(final GNode n) { final String fileName = n.getLocation().file; final int lastSlash = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\')); final int firstDot = fileName.indexOf('.', lastSlash); final int end = -1 == firstDot ? fileName.length() : firstDot; return fileName.substring(1 + lastSlash, end); } private static Type getType(final GNode n) { return (Type) n.getProperty(Constants.TYPE); } private static GNode idNode(final Locatable loc, final String id) { return setLoc(loc, GNode.create("PrimaryIdentifier", id)); } /** Set location from loc to n, return n. */ public static GNode setLoc(final Locatable loc, final GNode n) { n.setLocation(loc); return n; } final Substitutions _cSubstitutions; final Substitutions _javaSubstitutions; final Map<String, String> _methodSubstitutions; final JeannieJavaFactory _astFactoryJava; final JeannieCFactory _astFactoryC; final Stack<Context> _contexts; final Map<String, Integer> _freshIdCount; final Runtime _runtime; final SymbolTable _table; Set<String> _usedIdentifiers; public CodeGenerator(final Runtime runtime, final SymbolTable table) { _astFactoryC = new JeannieCFactory(); _astFactoryJava = new JeannieJavaFactory(); _contexts = new Stack<Context>(); _cSubstitutions = new Substitutions(); _freshIdCount = new HashMap<String, Integer>(); _javaSubstitutions = new Substitutions(); _methodSubstitutions = new HashMap<String, String>(); _runtime = runtime; _table = table; } private GNode abruptFlowCheck(final Locatable loc, final List<Node> cMembers, final List<Node> javaMembers) { final GNode fieldName = cStringNode(liftIdJava(currentMethodScope(), loc, "returnAbrupt", JavaEntities.nameToBaseType("boolean"), javaMembers)); final GNode jump = abruptFlowJump(loc, cMembers); final GNode result; if (existsOpenArrayInSameSnippet()) { final String arr = context()._openArray; final String releaseAbrupt = liftIdC(declaringScope(arr), arr + "ReleaseAbrupt", typedefType("jint"), cMembers); result = (GNode) _astFactoryC.abruptFlowCheckOpenArray(releaseAbrupt, fieldName, jump); } else { result = (GNode) _astFactoryC.abruptFlowCheck(fieldName, jump); } return setLoc(loc, result); } private GNode abruptFlowJump(final Locatable loc, final List<Node> cMembers) { final GNode jumpStatement; if (existsOpenArrayInSameSnippet()) { final String arr = context()._openArray; final String label = liftIdCLabel(declaringScope(arr), "release_" + arr); jumpStatement = (GNode) _astFactoryC.abruptFlowJumpOpenArray(label); } else { final Type returnType = context()._snippetType; final GNode value = returnType.hasTag(Tag.VOID) ? null : GNode.create("CastExpression", Utilities.cTypeToAst(returnType, null, "TypeName"), GNode.create("IntegerConstant", "0")); jumpStatement = GNode.create("ReturnStatement", value); } return setLoc(loc, jumpStatement); } private GNode cEnvJavaTypeAst() { final String name; switch (Limits.POINTER_SIZE) { case 4: name = "int"; break; case 8: name = "long"; break; default: throw new Error(); } return JavaEntities.javaTypeToAst(_table, JavaEntities.nameToBaseType(name)); } private Out cInJavaCode(final GNode n, final boolean isExpression) { assert "Java".equals(context()._activeLanguage); final GNode childNode = n.getGeneric(0); final Type childType = isExpression ? getType(childNode) : VoidT.TYPE; _contexts.push(new Context("C", context()._cEnvStructName, true, context()._javaEnvClassName, context()._javaEnvPackageName, context()._javaIsStatic, context()._openArray, childType)); final Out childOut = (Out) dispatch(childNode); _contexts.pop(); final Type ownType = isExpression ? getType(n) : JavaEntities.nameToBaseType("void"); final String methodName = freshIdentifier("j2c"); final List<Node> javaMembers = cInJavaCode_javaMembers(methodName, ownType, childOut); final Out ownOut = new Out( cInJavaCode_cExternalDeclarations(methodName, childType, childOut), childOut._cMembers, null, javaMembers, cInJavaCode_javaNode(n, methodName, javaMembers, isExpression)); return ownOut; } private List<Node> cInJavaCode_cExternalDeclarations( final String methodName, final Type childType, final Out childOut) { final String functionName = mangledFunctionName(methodName); _methodSubstitutions.put(functionName, Utilities.currentFunctionOrMethodName(_table)); final GNode function; { //parse prototype with empty body first final String jniCall = _runtime.getString("jniCall"); // on cygwin: "__attribute__((__stdcall__))" final String core = null == jniCall ? functionName : jniCall + " " + functionName; final Type pure = Utilities.pureCType(_table, _runtime, childType); String code = Utilities.cTypeToString(pure, core) + "("; code = Utilities.copyDropAuto(code); code += " JNIEnv *env, jobject jEnv"; // represent C pointer as Java long, i.e., using 64 bits if (context()._cHasEnv) switch (Limits.POINTER_SIZE) { case 4: code += ", const jint cEnv"; break; case 8: code += ", const jlong cEnv"; break; default: throw new Error(); } code += ") { }"; final Set<String> typedefs = Utilities.typedefs(childType); typedefs.addAll(Utilities.standardJniTypeDefs()); function = Utilities.cStringToAst("FunctionDefinition", code, typedefs); } { //then plug in real body final String tag = context()._cEnvStructName; final Node action = childOut._cNode; final Node body; if (context()._cHasEnv) body = childType.isVoid() ? _astFactoryC.cInJavaStatementWithCEnv(tag, action) : _astFactoryC.cInJavaExpressionWithCEnv(tag, action); else body = childType.isVoid() ? _astFactoryC.cInJavaStatementWithoutCEnv(tag, action) : _astFactoryC.cInJavaExpressionWithoutCEnv(tag, action); function.set(function.size() - 1, setLoc(childOut._cNode, (GNode)body)); } final List<Node> result = childOut._cExternalDeclarations; result.add(function); return result; } private List<Node> cInJavaCode_javaMembers( final String methodName, final Type ownType, final Out childOut) { final GNode returnType = JavaEntities.javaTypeToAst(_table, ownType); final Node n = context()._cHasEnv ? _astFactoryJava.cInJavaCodeWithCEnv(returnType, methodName, cEnvJavaTypeAst()) : _astFactoryJava.cInJavaCodeWithoutCEnv(returnType, methodName); //TD 41 throws clause on j2c native method final List<Node> result = childOut._javaMembers; result.add(setLoc(childOut._cNode, (GNode)n)); return result; } private GNode cInJavaCode_javaNode(final Locatable loc, final String methodName, final List<Node> javaMembers, final boolean isExpression) { final Node result; if (isExpression) { result = context()._cHasEnv ? _astFactoryJava.cInJavaExpressionWithCEnv(methodName) : _astFactoryJava.cInJavaExpressionWithoutCEnv(methodName); } else { final String returnAbruptName = liftIdJava(currentMethodScope(), loc, "returnAbrupt", JavaEntities.nameToBaseType("boolean"), javaMembers); result = context()._cHasEnv ? _astFactoryJava.cInJavaStatementWithCEnv(methodName, returnAbruptName) : _astFactoryJava.cInJavaStatementWithoutCEnv(methodName, returnAbruptName); } return setLoc(loc, (GNode)result); } private final Context context() { return _contexts.peek(); } private GNode cStringNode(final String string) { return GNode.create("StringConstant", "\"" + string + "\""); } private SymbolTable.Scope currentMethodScope() { for (SymbolTable.Scope s = _table.current(); !s.isRoot(); s = s.getParent()) { final String scopeName = s.getName(); if ( SymbolTable.isInNameSpace(scopeName, "method") || SymbolTable.isFunctionScopeName(scopeName) || SymbolTable.isMacroScopeName(scopeName)) return s; } return null; } private SymbolTable.Scope declaringScope(final String id) { return _table.lookupScope(id); } private boolean existsOpenArrayInSameSnippet() { final String o = context()._openArray; if (null == o) return false; final String a = context()._activeLanguage; for (int i=_contexts.size() - 2; i >= 0; i--) { final Context c = _contexts.get(i); if (!a.equals(c._activeLanguage)) return false; if (!o.equals(c._openArray)) return true; } return true; } /** * Returns a new globally unique identifier that starts with the base name. * Takes care to avoid shadowing other identifiers that the program already * uses, including free identifiers that are bound in imports or superclasses, * and even "funny names" that programmers are unlikely to write but that may * arise in other automatically generated code. */ private String freshIdentifier(final String base) { int i = _freshIdCount.containsKey(base) ? _freshIdCount.get(base) .intValue() : -1; String result; do { i++; result = (0 == i) ? base : base + i; } while (_usedIdentifiers.contains(result)); _freshIdCount.put(base, new Integer(i)); _usedIdentifiers.add(result); return result; } private boolean isUtf8(final Type cPtrType, final Type javaType) { if (JavaTypeConverter.isIdentical(javaType, JavaEntities.tString(_table))) { final Type cTgtType = ((PointerT)Utilities.c().pointerize(cPtrType)).getType(); return Utilities.hasTypedefName(cTgtType, "jbyte"); } return false; } private Out javaInCCode(final GNode n, final boolean isExpression) { assert "C".equals(context()._activeLanguage); _contexts.push(new Context(context(), "Java")); final Out javaOut = (Out) dispatch(n); _contexts.pop(); final Type javaType = isExpression ? JavaAnalyzer.getRValueNoError(getType(n)) : JavaEntities.nameToBaseType("void"); final String methodName = freshIdentifier("c2j"); recordMethodSubstitution(methodName); final List<Node> cMembers = javaOut._cMembers; final List<Node> javaMembers = javaOut._javaMembers; final boolean isNonVoidExpression = isExpression && !getType(n).isVoid(); final Out ownOut = new Out(javaOut._cExternalDeclarations, cMembers, javaInCCode_cNode(methodName, javaType, isNonVoidExpression, n, cMembers, javaMembers), javaInCCode_javaMembers(methodName, javaType, isExpression, javaOut), null); return ownOut; } private GNode javaInCCode_cNode( final String methodName, final Type javaType, final boolean isExpression, final GNode n, final List<Node> cMembers, final List<Node> javaMembers) { final GNode name = cStringNode(methodName); final boolean is32bit = 4 == Limits.POINTER_SIZE; assert is32bit || 8 == Limits.POINTER_SIZE; final GNode signature = cStringNode((is32bit ? "(I)" : "(J)") + JavaEntities.typeToDescriptor(_table, javaType)); final String apiFunction = "CallNonvirtual" + Utilities.javaTypeToApiType(javaType, true, false) + "Method"; final GNode abruptFlowCheck = abruptFlowCheck(n, cMembers, javaMembers); final Node result; if (isExpression) { final Type cType = Utilities.javaTypeToCType(_table, _runtime, n, javaType, false); final GNode tmpDeclaration = Utilities.cTypeToAst(cType, "tmp", "Declaration"); result = is32bit ? _astFactoryC.javaInCExpression32(name, signature, tmpDeclaration, apiFunction, abruptFlowCheck) : _astFactoryC.javaInCExpression64(name, signature, tmpDeclaration, apiFunction, abruptFlowCheck); } else { result = is32bit ? _astFactoryC.javaInCStatement32(name, signature, apiFunction, abruptFlowCheck) : _astFactoryC.javaInCStatement64(name, signature, apiFunction, abruptFlowCheck); } return setLoc(n, (GNode) result); } private List<Node> javaInCCode_javaMembers( final String methodName, final Type javaType, final boolean isExpression, final Out javaOut) { final GNode typeAst = JavaEntities.javaTypeToAst(_table, javaType); final Node n = isExpression ? javaType.isVoid() ? _astFactoryJava.javaInCExpressionVoid(methodName, cEnvJavaTypeAst(), javaOut._javaNode) : _astFactoryJava.javaInCExpression(typeAst, methodName, cEnvJavaTypeAst(), javaOut._javaNode) : _astFactoryJava.javaInCStatement(methodName, cEnvJavaTypeAst(), javaOut._javaNode); final List<Node> result = javaOut._javaMembers; result.add(setLoc(javaOut._javaNode, (GNode)n)); return result; } private Out jeannieCancelOrCommit(final Locatable loc, final String arr, final boolean isCommit) { final List<Node> cMembers = new ArrayList<Node>(); final GNode jump = abruptFlowJump(loc, cMembers); final String field = liftIdC(declaringScope(arr), arr + "ReleaseAbrupt", typedefType("jint"), cMembers); final Node n = isCommit ? _astFactoryC.commit(field, jump) : _astFactoryC.cancel(field, jump); setLoc(loc, (GNode) n); final Out ownOut = new Out(new ArrayList<Node>(0), cMembers, (GNode)n, new ArrayList<Node>(0), null); return ownOut; } private String jeannieCopyApiFunction(final Type javaType, final boolean isAcquire, final boolean isUtf8) { final StringBuffer result = new StringBuffer(); result.append(isAcquire ? "Get" : "Set"); if (JavaTypeConverter.isIdentical(javaType, JavaEntities.tString(_table))) result.append(isUtf8 ? "StringUTF" : "String"); else result.append(Utilities.javaTypeToApiType(javaType, true, true)); result.append("Region"); return result.toString(); } private String liftIdC(final SymbolTable.Scope scope, final String srcId, final Type type, final List<Node> cMembers) { if (null == _cSubstitutions.get(scope, srcId)) { final String tgtId = freshIdentifier("_" + srcId); final Type pureCType = Utilities.c().pointerize(Utilities.pureCType(_table, _runtime, type)); final GNode fieldDecl = Utilities.cTypeToAst(pureCType, tgtId, "StructureDeclaration"); cMembers.add(fieldDecl); _cSubstitutions.put(scope, srcId, tgtId); } return _cSubstitutions.get(scope, srcId); } private String liftIdCLabel(final SymbolTable.Scope scope, final String srcId) { //TD 41 avoid clashes with locals if (null == _cSubstitutions.get(scope, srcId)) { final String tgtId = freshIdentifier(srcId); _cSubstitutions.put(scope, srcId, tgtId); } return _cSubstitutions.get(scope, srcId); } private String liftIdJava(final SymbolTable.Scope scope, final Locatable loc, final String srcId, final Type type, final List<Node> javaMembers) { if (null == _javaSubstitutions.get(scope, srcId)) { final String tgtId = freshIdentifier("_" + srcId); final Type r = JavaEntities.isGeneralLValueT(type) ? JavaEntities.dereference(type) : type; final Node n = _astFactoryJava.declareField(JavaEntities.javaTypeToAst(_table, r), tgtId); javaMembers.add(setLoc(loc, (GNode)n)); _javaSubstitutions.put(scope, srcId, tgtId); } return _javaSubstitutions.get(scope, srcId); } private String mangledFunctionName(final String methodName) { final String packageAndClass; if (null == context()._javaEnvPackageName) { final ClassT baseClass = JavaEntities.currentType(_table).toClass(); final String baseName = JavaEntities.qNameWithDollars(_table, baseClass); packageAndClass = baseName + "$" + context()._javaEnvClassName; } else { final String slashes = context()._javaEnvPackageName + context()._javaEnvClassName; packageAndClass = slashes.replace('/', '.'); } final String qualifiedName = packageAndClass + '.' + methodName; final String result = "Java_" + Utilities.jniMangledName(qualifiedName); return result; } private Out processBuiltin(final GNode n) { assert "C".equals(context()._activeLanguage); final String name = n.getGeneric(0).getString(0); final Out argsOut = (Out) dispatch(n.getGeneric(1)); assert null == argsOut._javaNode; if ("_copyFromJava".equals(name)) { final GNode cArray = argsOut._cNode.getGeneric(0); final GNode cArrayStart = argsOut._cNode.getGeneric(1); final GNode javaArray = argsOut._cNode.getGeneric(2); final GNode javaArrayStart = argsOut._cNode.getGeneric(3); final GNode length = argsOut._cNode.getGeneric(4); final GNode abruptFlowCheck = abruptFlowCheck(n, argsOut._cMembers, argsOut._javaMembers); final Type javaType = Utilities.cTypeToJavaType(_table, _runtime, n.getGeneric(1).getGeneric(2), getType(n.getGeneric(1).getGeneric(2))); final boolean primiv = JavaTypeConverter.isIdentical(javaType, JavaEntities.tString(_table)) || javaType.isArray() && JavaEntities.isPrimitiveT(JavaEntities.arrayElementType(javaType.toArray())); final Node ownNode; if (primiv) { final boolean utf8 = isUtf8(getType(n.getGeneric(1).getGeneric(0)), javaType); final String apiFunction = jeannieCopyApiFunction(javaType, true, utf8); ownNode = utf8 ? _astFactoryC.copyBetweenJavaAndCUTF(javaArray, javaArrayStart, length, apiFunction, cArray, cArrayStart, abruptFlowCheck) : _astFactoryC.copyBetweenJavaAndC(apiFunction, javaArray, javaArrayStart, length, cArray, cArrayStart, abruptFlowCheck); } else { ownNode = _astFactoryC.copyFromJavaReference(javaArray, javaArrayStart, length, cArray, cArrayStart, abruptFlowCheck); } setLoc(n, (GNode)ownNode); final Out ownOut = new Out(argsOut._cExternalDeclarations, argsOut._cMembers, (GNode) ownNode, argsOut._javaMembers, null); return ownOut; } else if ("_copyToJava".equals(name)) { final GNode javaArray = argsOut._cNode.getGeneric(0); final GNode javaArrayStart = argsOut._cNode.getGeneric(1); final GNode cArray = argsOut._cNode.getGeneric(2); final GNode cArrayStart = argsOut._cNode.getGeneric(3); final GNode length = argsOut._cNode.getGeneric(4); final GNode abruptFlowCheck = abruptFlowCheck(n, argsOut._cMembers, argsOut._javaMembers); final Type javaType = Utilities.cTypeToJavaType(_table, _runtime, n.getGeneric(1).getGeneric(0), getType(n.getGeneric(1).getGeneric(0))); final boolean primiv = JavaTypeConverter.isIdentical(javaType, JavaEntities.tString(_table)) || javaType.isArray() && JavaEntities.isPrimitiveT(JavaEntities.arrayElementType(javaType.toArray())); final Node ownNode; if (primiv) { final boolean utf8 = isUtf8(getType(n.getGeneric(1).getGeneric(2)), javaType); final String apiFunction = jeannieCopyApiFunction(javaType, false, utf8); ownNode = utf8 ? _astFactoryC.copyBetweenJavaAndCUTF(javaArray, javaArrayStart, length, apiFunction, cArray, cArrayStart, abruptFlowCheck) : _astFactoryC.copyBetweenJavaAndC(apiFunction, javaArray, javaArrayStart, length, cArray, cArrayStart, abruptFlowCheck); } else { ownNode = _astFactoryC.copyToJavaReference(javaArray, javaArrayStart, length, cArray, cArrayStart, abruptFlowCheck); } setLoc(n, (GNode)ownNode); final Out ownOut = new Out(argsOut._cExternalDeclarations, argsOut._cMembers, (GNode) ownNode, argsOut._javaMembers, null); return ownOut; } else if ("_newJavaString".equals(name)) { final Type t = getType(n.getGeneric(1).getGeneric(0)); final String apiFunction = "NewString" + (Utilities.isPtrTypedef(t, "jchar") ? "" : "UTF"); final GNode cString = argsOut._cNode.getGeneric(0); final GNode abruptFlowCheck = abruptFlowCheck(n, argsOut._cMembers, argsOut._javaMembers); final GNode cNode = (GNode) _astFactoryC.newJavaString(apiFunction, cString, abruptFlowCheck); setLoc(n, (GNode)cNode); final Out ownOut = new Out(argsOut._cExternalDeclarations, argsOut._cMembers, cNode, argsOut._javaMembers, null); return ownOut; } else if ("_stringUTFLength".equals(name)) { final Node ac = argsOut._cNode; final Node javaString = ac.getNode(0); final Node cNode; if (1 == n.getGeneric(1).size()) cNode = _astFactoryC.stringUTFLength1(javaString); else cNode = _astFactoryC.stringUTFLength3(javaString, ac.getNode(1), ac.getNode(2)); final Out ownOut = new Out(argsOut._cExternalDeclarations, argsOut._cMembers, setLoc(n, (GNode)cNode), argsOut._javaMembers, null); return ownOut; } else { throw new Error("builtin " + name + " not (yet) implemented"); } } private List<Node> processDeclarators(final GNode declarators, final List<Node> cExternalDeclarations, final List<Node> cMembers, final List<Node> javaMembers) { assert "Java".equals(context()._activeLanguage) && declarators.hasName("Declarators"); final List<Node> result = new ArrayList<Node>(); for (final Object declObj : declarators) { final GNode declNode = (GNode) declObj; final GNode initNode = declNode.getGeneric(2); if (null == initNode) continue; final Out initOut = (Out) dispatch(initNode); assert null == initOut._cNode; cExternalDeclarations.addAll(initOut._cExternalDeclarations); cMembers.addAll(initOut._cMembers); javaMembers.addAll(initOut._javaMembers); final VariableT type = getType(declNode).toVariable(); final String srcId = type.getName(); final String subst = liftIdJava(declaringScope(srcId), declNode, srcId, type, javaMembers); final Node javaNode; if (initOut._javaNode.hasName("ArrayInitializer")) { final GNode typeAst = JavaEntities.javaTypeToAst(_table, type.getType()); javaNode = setLoc(initOut._javaNode, GNode.create("NewArrayExpression", typeAst.getGeneric(0), null, typeAst.getGeneric(1), initOut._javaNode)); } else { javaNode = initOut._javaNode; } result.add(setLoc(javaNode, (GNode) _astFactoryJava.setThisDotField(subst, javaNode))); } return result; } private void recordMethodSubstitution(final String methodName) { final String src = Utilities.currentFunctionOrMethodName(_table); final StringBuilder tgt = new StringBuilder(); final ClassOrInterfaceT t = JavaEntities.currentType(_table); if (null == t) { final String p = context()._javaEnvPackageName; if (0 < p.length()) tgt.append(p.substring(0, p.length() - 1).replace('/', '.') + '$'); } else { tgt.append(JavaEntities.qNameWithDollars(_table, t)).append('$'); } tgt.append(context()._javaEnvClassName).append('.').append(methodName); _methodSubstitutions.put(tgt.toString(), src); } private Type typedefType(final String symbol) { final Type result = (Type) _table.root().lookup(symbol); assert null != result; return result; } public final Out visit(final LineMarker m) { final boolean c = "C".equals(context()._activeLanguage); final Node n = m.getNode(); if (null == n) return new Out(new ArrayList<Node>(0), new ArrayList<Node>(0), c ? m : null, new ArrayList<Node>(0), c ? null : m); final Out childOut = (Out) dispatch(n); if (c) { assert null != childOut._cNode && null == childOut._javaNode; m.setNode(childOut._cNode); } else { assert null == childOut._cNode && null != childOut._javaNode; m.setNode(childOut._javaNode); } final Out result = new Out(childOut._cExternalDeclarations, childOut._cMembers, c ? m : null, childOut._javaMembers, c ? null : m); return result; } /** Catch-all visit method. */ public final Out visit(final Node n) { _table.enter(n); //TD 42 don't create a new node, just rewrite the old node's children final GNode ownNode = setLoc(n, GNode.create(n.getName(), n.size())); final boolean c = "C".equals(context()._activeLanguage); final Out ownOut = new Out(new ArrayList<Node>(), new ArrayList<Node>(), c ? ownNode : null, new ArrayList<Node>(), c ? null : ownNode); for (int i = 0; i < n.size(); i++) if (n.get(i) instanceof Node) { final Out childOut = (Out) dispatch(n.getNode(i)); ownNode.add(i, c ? childOut._cNode : childOut._javaNode); ownOut.addAll(childOut); assert null == (c ? childOut._javaNode : childOut._cNode); } else { ownNode.add(i, n.get(i)); } _table.exit(n); return ownOut; } /** * Visit a BasicForControl = Modifiers Type Declarators [Expression] [ExpressionList] * / null null [ExpressionList] [Expression] [ExpressionList] (gosling_et_al_2000 * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40898">§8.3</a>). */ public final Out visitBasicForControl(final GNode n) { assert "Java".equals(context()._activeLanguage); if (null == context()._javaEnvClassName || null == n.get(0)) return visit(n); final List<Node> cExternalDeclarations = new ArrayList<Node>(); final List<Node> cMembers = new ArrayList<Node>(); final List<Node> javaMembers = new ArrayList<Node>(); final List<Node> decls = processDeclarators(n.getGeneric(2), cExternalDeclarations, cMembers, javaMembers); final GNode initNode = 0 == decls.size() ? null : setLoc(n.getGeneric(2), (GNode)GNode.create("ExpressionList", decls.size()).addAll(decls)); final Out testOut = (Out) dispatch(n.getGeneric(3)); final Out incrOut = (Out) dispatch(n.getGeneric(4)); final GNode javaNode = setLoc(n, GNode.create("BasicForControl", null, null, initNode, testOut._javaNode, incrOut._javaNode)); final Out ownOut = new Out(cExternalDeclarations, cMembers, null, javaMembers, javaNode); ownOut.addAll(testOut).addAll(incrOut); return ownOut; } /** Visit a CancelStatement = JeannieC.PrimaryIdentifier. */ public final Out visitCancelStatement(final GNode n) { return jeannieCancelOrCommit(n, n.getGeneric(0).getString(0), false); } /** Visit a CDeclarations = ExternalDeclaration* Annotations. */ public final Out visitCDeclarations(final GNode n) { final Out ownOut = new Out(new ArrayList<Node>(), new ArrayList<Node>(), null, new ArrayList<Node>(), null); assert _table.current().isRoot(); assert 1 == _contexts.size() && "C".equals(context()._activeLanguage); for (int i=0; i<n.size() - 1; i++) { final Out childOut = (Out) dispatch(n.getNode(i)); assert null == childOut._javaNode; ownOut._javaMembers.addAll(childOut._javaMembers); ownOut._cExternalDeclarations.addAll(childOut._cExternalDeclarations); ownOut._cExternalDeclarations.add(childOut._cNode); } assert _table.current().isRoot(); return ownOut; } /** Visit a CInCBlock = LocalLabelDeclaration* JeannieC.DeclarationOrStatement* Annotations. */ public final Out visitCInCBlock(final GNode n) { assert "C".equals(context()._activeLanguage); final Out genericOut = visit(n); assert genericOut._cNode.hasName("CInCBlock"); final List<Node> cNodes = new ArrayList<Node>(n.size() - 1); for (int i=0; i<n.size() - 1; i++) { final GNode src = n.getGeneric(i), tgt = genericOut._cNode.getGeneric(i); if (src.hasName("Declaration")) { if (tgt.hasName("CompoundStatement")) //flatten, to expand scope of auxiliary declarations for (final Object t : tgt) cNodes.add((GNode) t); else if (!tgt.hasName("EmptyStatement")) //skip, to keep code more readable cNodes.add(tgt); } else { cNodes.add(tgt); } } final Out ownOut = new Out(genericOut._cExternalDeclarations, genericOut._cMembers, setLoc(n, GNode.create("CompoundStatement", cNodes.size() + 1)), genericOut._javaMembers, genericOut._javaNode); for (int i=0; i<cNodes.size(); i++) ownOut._cNode.add(i, cNodes.get(i)); return ownOut; } /** Visit a CInJavaBlock = CInCBlock. */ public final Out visitCInJavaBlock(final GNode n) { return cInJavaCode(n, false); } /** Visit a CInJavaExpression = JeannieC.UnaryExpression. */ public final Out visitCInJavaExpression(final GNode n) { return cInJavaCode(n, true); } /** * Visit a ClassBody = Declaration* (gosling_et_al_2000 * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#18988">§8.1.5</a>, * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#236431">§9.1.3</a>, * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">§15.9</a>). */ public final Out visitClassBody(final GNode n) { assert "Java".equals(context()._activeLanguage); _table.enter(n); final Out ownOut = new Out(new ArrayList<Node>(), new ArrayList<Node>(), null, new ArrayList<Node>(), setLoc(n, GNode.create("ClassBody"))); if (Utilities.containsJavaToCTransition(n)) { if (JavaEntities.isTypeTopLevel(JavaEntities.currentType(_table))) { final GNode name = GNode.create("StringLiteral", "\"" + getFileStem(n) + "\""); final Node block = _astFactoryJava.loadLibrary(name); ownOut._javaNode.add(setLoc(n, GNode.create("BlockDeclaration", "static", block))); } } for (final Object child : n) { final Out childOut = (Out) dispatch((GNode) child); ownOut._cExternalDeclarations.addAll(childOut._cExternalDeclarations); assert childOut._cMembers.isEmpty() && null == childOut._cNode; ownOut._javaNode.add(childOut._javaNode); ownOut._javaNode.addAll(childOut._javaMembers); } _table.exit(n); return ownOut; } /** Visit a CommitStatement = JeannieC.PrimaryIdentifier. */ public final Out visitCommitStatement(final GNode n) { return jeannieCancelOrCommit(n, n.getGeneric(0).getString(0), true); } /** Visit a CompilationUnit = [PackageDeclaration] JavaImports CDeclarations JeannieJava.Declaration*. * (gosling_et_al_2000 * <a href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#40031">§7.3</a>). */ public final Out visitCompilationUnit(final GNode n) { assert _contexts.isEmpty(); _usedIdentifiers = JavaEntities.allUsedIdentifiers(n); final GNode cNode = setLoc(n, GNode.create("TranslationUnit")); final Out cChildOut; { final StringBuffer packageName = new StringBuffer(); if (null != n.get(0)) for (final Object o : n.getNode(0).getNode(1)) packageName.append(o).append('/'); _contexts.push(new Context("C", null, false, null, packageName.toString(), true, null, null)); cChildOut = (Out) dispatch(n.getGeneric(2)); _contexts.pop(); } assert cChildOut._cMembers.isEmpty() && null == cChildOut._cNode && null == cChildOut._javaNode; cNode.addAll(cChildOut._cExternalDeclarations); final GNode javaNode = setLoc(n, GNode.create("CompilationUnit")); javaNode.add(n.getGeneric(0)); for (final Object o : n.getGeneric(1)) javaNode.add(o); _contexts.push(new Context("Java", null, false, null, null, true, null, null)); JavaEntities.enterScopeByQualifiedName(_table, (String) n.getProperty(Constants.SCOPE)); for (int i = 3; i < n.size(); i++) { final Out javaChildOut = (Out) dispatch(n.getGeneric(i)); cNode.addAll(javaChildOut._cExternalDeclarations); javaNode.add(javaChildOut._javaNode); assert javaChildOut._cMembers.isEmpty() && null == javaChildOut._cNode && javaChildOut._javaMembers.isEmpty(); } javaNode.addAll(cChildOut._javaMembers); _contexts.pop(); final Out ownOut = new Out(null, null, cNode, null, javaNode); return ownOut; } /** Visit a JeannieC.Declaration = ["__extension__"] DeclarationSpecifiers [InitializedDeclaratorList]. */ public final Out visitDeclaration(final GNode n) { assert "C".equals(context()._activeLanguage); if (null == context()._cEnvStructName || null == n.get(2)) return visit(n); final List<Node> cExternalDeclarations = new ArrayList<Node>(); final List<Node> cMembers = new ArrayList<Node>(); final List<Node> javaMembers = new ArrayList<Node>(); final List<Node> declResults = new ArrayList<Node>(); for (final Object declObj : n.getGeneric(2)) { final GNode declNode = (GNode) declObj; final String srcId = Utilities.getSimpleDeclarator(declNode); final Type type = Utilities.pureCType(_table, _runtime, (Type) _table.lookup(srcId)); final String tgtId = liftIdC(declaringScope(srcId), srcId, type, cMembers); if (declNode.getGeneric(1).hasName("ArrayDeclarator")) { final Out specsOut = (Out) dispatch(n.getGeneric(1)); assert null == specsOut._javaNode; cExternalDeclarations.addAll(specsOut._cExternalDeclarations); cMembers.addAll(specsOut._cMembers); javaMembers.addAll(specsOut._javaMembers); final Out declOut = (Out) dispatch(declNode); assert null == declOut._javaNode; cExternalDeclarations.addAll(declOut._cExternalDeclarations); cMembers.addAll(declOut._cMembers); javaMembers.addAll(declOut._javaMembers); final GNode declLocal = setLoc(declNode, GNode.create("Declaration", n.getString(0), specsOut._cNode, GNode.create("InitializedDeclaratorList", declOut._cNode))); declResults.add(declLocal); final GNode setField = (GNode) _astFactoryC.setPCEnvField(tgtId, GNode.create("PrimaryIdentifier", srcId)); declResults.add(setLoc(declNode, setField)); } else if (null != declNode.getGeneric(4)) { final Out initOut = (Out) dispatch(declNode.getGeneric(4)); assert null == initOut._javaNode; cExternalDeclarations.addAll(initOut._cExternalDeclarations); cMembers.addAll(initOut._cMembers); javaMembers.addAll(initOut._javaMembers); final GNode typeAST = Utilities.cTypeToAst(type, null, "TypeName"); final GNode cast = GNode.create("CastExpression", typeAST, initOut._cNode); declResults.add(setLoc(declNode, (GNode) _astFactoryC.setPCEnvField(tgtId, cast))); } } final Node cNode = (0 == declResults.size()) ? GNode.create("EmptyStatement") : (1 == declResults.size()) ? declResults.get(0) : /* else */ _astFactoryC.block(declResults); final Out ownOut = new Out(cExternalDeclarations, cMembers, setLoc(n.getGeneric(2), (GNode)cNode), javaMembers, null); return ownOut; } /** * Visit a FieldDeclaration = Modifiers Type Declarators (gosling_et_al_2000 * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40898">§8.3</a>). */ public final Out visitFieldDeclaration(final GNode n) { assert "Java".equals(context()._activeLanguage); if (null == context()._javaEnvClassName) return visit(n); final List<Node> cExternalDeclarations = new ArrayList<Node>(); final List<Node> cMembers = new ArrayList<Node>(); final List<Node> javaMembers = new ArrayList<Node>(); final List<Node> decls = processDeclarators(n.getGeneric(2), cExternalDeclarations, cMembers, javaMembers); final GNode javaNode; if (0 == decls.size()) { javaNode = GNode.create("EmptyStatement"); } else if (1 == decls.size()) { javaNode = GNode.create("ExpressionStatement", decls.get(0)); } else { javaNode = GNode.create("Block", decls.size()); for (final Node d : decls) javaNode.add(GNode.create("ExpressionStatement", d)); } final Out ownOut = new Out(cExternalDeclarations, cMembers, null, javaMembers, setLoc(n.getGeneric(2), javaNode)); return ownOut; } /** * Visit a ForStatement = (Declaration / [Expression]) [Expression] [Expression] Statement. */ public final Out visitForStatement(final GNode n) { if ("Java".equals(context()._activeLanguage) || null == context()._cEnvStructName || null == n.get(0) || !n.getGeneric(0).hasName("Declaration")) return visit(n); _table.enter(n); final Out initOut = (Out) dispatch(n.getGeneric(0)); final Out testOut = (Out) dispatch(n.getGeneric(1)); final Out incrOut = (Out) dispatch(n.getGeneric(2)); final Out bodyOut = (Out) dispatch(n.getGeneric(3)); final GNode loopNode = GNode.create("ForStatement", null, null == testOut ? null : testOut._cNode, null == incrOut ? null : incrOut._cNode, bodyOut._cNode); final GNode cNode = GNode.create("CompoundStatement", initOut._cNode, loopNode, null); final Out ownOut = new Out(new ArrayList<Node>(), new ArrayList<Node>(), setLoc(n, cNode), new ArrayList<Node>(), null); ownOut.addAll(initOut).addAll(testOut).addAll(incrOut).addAll(bodyOut); _table.exit(n); return ownOut; } /** Visit a FunctionCall = (PrimaryIdentifier / JeannieC.PostfixExpression) JeannieC.ExpressionList. */ public final Out visitFunctionCall(final GNode n) { assert "C".equals(context()._activeLanguage); if (null == context()._javaEnvClassName) return visit(n); if (n.getGeneric(0).hasName("PrimaryIdentifier") && Analyzer.BUILTINS.contains(n.getGeneric(0).getString(0))) return processBuiltin(n); final Out plainOut = visit(n); final Type cType = getType(n); final GNode cNode; final Node call = plainOut._cNode; final GNode abruptFlowCheck = abruptFlowCheck(n, plainOut._cMembers, plainOut._javaMembers); final Type cTypeMinusAnnotations = cType.isAnnotated() ? cType.toAnnotated().getType() : cType; if (cTypeMinusAnnotations.isVoid()) { cNode = (GNode) _astFactoryC.checkedFunctionCallVoid(call, abruptFlowCheck); } else { final GNode tmpDeclaration = Utilities.cTypeToAst(cType, "tmp", "Declaration"); cNode = (GNode) _astFactoryC.checkedFunctionCallResult(tmpDeclaration, call, abruptFlowCheck); } setLoc(n, cNode); final Out ownOut = new Out(plainOut._cExternalDeclarations, plainOut._cMembers, cNode, plainOut._javaMembers, plainOut._javaNode); return ownOut; } /** Visit a FunctionDeclarator = (ParameterTypeList / IdentifierList) JavaThrows. */ public final Out visitFunctionDeclarator(final GNode n) { assert "C".equals(context()._activeLanguage); /* TD 41 jeannie.CodeGenerator.visitFunctionDeclarator: drop the throws clause */ return visit(n); } /** Visit a FunctionDefinition = ["__extension__"] [DeclarationSpecifiers] Declarator * [DeclarationList] CompoundStatement. */ public final Out visitFunctionDefinition(final GNode n) { assert "C".equals(context()._activeLanguage); if (!Utilities.containsCToJavaTransition(n)) return visit(n); _table.enter(n); final String functionName = SymbolTable.fromNameSpace(_table.current().getName()); final String javaEnvClassName = freshIdentifier("JavaEnvFor_" + functionName); final String cEnvStructName = freshIdentifier("CEnvFor_" + functionName); final FunctionT function = ((Type) _table.current().getParent().lookupLocally(functionName)).resolve().toFunction(); _contexts.push(new Context("C", cEnvStructName, true, javaEnvClassName, context()._javaEnvPackageName, true, null, function.getResult())); final Out childOut = (Out) dispatch(n.getNode(4)); final GNode cNode; { final Node body; final GNode javaEnvNode = GNode.create("StringConstant", '"' + context()._javaEnvPackageName + javaEnvClassName + '"'); final GNode copyFormals = setLoc(n.getGeneric(2), GNode.create("CompoundStatement", function.getParameters().size() - 1)); for (final Type formal : function.getParameters()) { final String srcId = formal.toVariable().getName(); if (!"env".equals(srcId)) { final String fieldName = liftIdC(declaringScope(srcId), srcId, formal.toVariable().getType(), childOut._cMembers); final Node copy = _astFactoryC.setPCEnvField(fieldName, GNode.create("PrimaryIdentifier", srcId)); copyFormals.add(copy); } } assert function.getResult().hasTag(Tag.VOID); //TD 06 C function definition that also contains Java code somewhere and returns non-void body = _astFactoryC.closureStatement(cEnvStructName, copyFormals, javaEnvNode, childOut._cNode); cNode = n; cNode.set(4, setLoc(childOut._cNode, (GNode)body)); } final List<Node> cExternalDeclarations = visitMethodDeclaration_cExternalDeclarations(childOut); final List<Node> javaTopLevelDeclarations; { final GNode classBody = GNode.create("ClassBody", childOut._javaMembers.size()); classBody.addAll(childOut._javaMembers); final GNode modifiers = GNode.create("Modifiers", GNode.create("Modifier", "final")); final GNode classDecl = setLoc(n, GNode.create("ClassDeclaration", modifiers, context()._javaEnvClassName, null, null, null, classBody)); javaTopLevelDeclarations = new ArrayList<Node>(1); javaTopLevelDeclarations.add(classDecl); } final Out ownOut = new Out(cExternalDeclarations, new ArrayList<Node>(), cNode, javaTopLevelDeclarations, null); _contexts.pop(); _table.exit(n); return ownOut; } /** Visit a JavaImports = ImportDeclaration*. */ public final Out visitJavaImports(final GNode n) { assert "C".equals(context()._activeLanguage); /* TD 41 jeannie.CodeGenerator.visitJavaImports: drop (or don't dispatch in first place) */ return visit(n); } /** Visit a JavaInCBlock = JavaInJavaBlock. */ public final Out visitJavaInCBlock(final GNode n) { return javaInCCode(n.getGeneric(0), false); } /** Visit a JavaInCExpression = JeannieJava.UnaryExpression. */ public final Out visitJavaInCExpression(final GNode n) { return javaInCCode(n.getGeneric(0), true); } /** Visit a JavaInCStatement = TryStatement / SynchronizedStatement / ThrowStatement. */ public final Out visitJavaInCStatement(final GNode n) { return javaInCCode(n.getGeneric(0), false); } /** Visit a JavaInJavaBlock = JeannieJava.DeclarationOrStatement*. */ public final Out visitJavaInJavaBlock(final GNode n) { assert "Java".equals(context()._activeLanguage); final Out genericOut = visit(n); assert genericOut._javaNode.hasName("JavaInJavaBlock"); final Out ownOut = new Out(genericOut._cExternalDeclarations, genericOut._cMembers, genericOut._cNode, genericOut._javaMembers, setLoc(n, GNode.create("Block", n.size()))); for (int i = 0; i < n.size(); i++) ownOut._javaNode.add(i, genericOut._javaNode.get(i)); return ownOut; } /** Visit a JavaThrows = [ThrowsClause]. */ public final Out visitJavaThrows(final GNode n) { assert "C".equals(context()._activeLanguage); /* TD 41 jeannie.CodeGenerator.visitJavaThrows: drop (or don't dispatch in first place) */ return visit(n); } /** Visit a JavaType = Java.TypeName. */ public final Out visitJavaType(final GNode n) { assert "C".equals(context()._activeLanguage); final Type cType = Utilities.pureCType(_table, _runtime, getType(n)); final GNode ownNode = Utilities.cTypeToAst(cType, null, "TypeName"); final Out ownOut = new Out(new ArrayList<Node>(), new ArrayList<Node>(), ownNode, new ArrayList<Node>(), null); return ownOut; } /** * Visit a MethodDeclaration = Modifiers null Type Identifier FormalParameters [Dimensions] * [ThrowsClause] [Block] (gosling_et_al_2000 <a * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40420">§8.4</a>, * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#41652">8.8</a>, * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#78651">9.4</a>). */ public final Out visitMethodDeclaration(final GNode n) { assert "Java".equals(context()._activeLanguage); if (!Utilities.containsJavaToCTransition(n)) return visit(n); _table.enter(n); final MethodT method = JavaEntities.currentMethod(_table); final String javaEnvClassName = freshIdentifier("JavaEnvFor_" + method.getName()); final String cEnvStructName = freshIdentifier("CEnvFor_" + Utilities.jniMangledName(_table, method)); _contexts.push(new Context("Java", cEnvStructName, false, javaEnvClassName, context()._javaEnvPackageName, Utilities.javaIsStaticMethod(n), null, method.getResult())); final Out childOut = (Out) dispatch(n.getGeneric(7)); final Out ownOut = new Out( visitMethodDeclaration_cExternalDeclarations(childOut), new ArrayList<Node>(), null, visitMethodDeclaration_javaMembers(n, childOut), visitMethodDeclaration_javaNode(n)); _contexts.pop(); _table.exit(n); return ownOut; } private List<Node> visitMethodDeclaration_cExternalDeclarations(final Out childOut) { final List<Node> members = new ArrayList<Node>(childOut._cMembers.size()); members.addAll(childOut._cMembers); final List<Node> result = new ArrayList<Node>(1 + childOut._cExternalDeclarations.size()); final GNode struct = (GNode)_astFactoryC.declareStruct(context()._cEnvStructName, members); result.add(setLoc(null == childOut._cNode ? childOut._javaNode : childOut._cNode, struct)); result.addAll(childOut._cExternalDeclarations); return result; } private List<Node> visitMethodDeclaration_javaMembers(final GNode n, final Out childOut) { final GNode nodeFormals = n.getGeneric(4); // field for caching result and formals if (!Utilities.javaIsVoidMethod(n)) liftIdJava(currentMethodScope(), n, "returnResult", getType(n).toMethod().getResult(), childOut._javaMembers); for (final Object o : nodeFormals) { final GNode formal = (GNode) o; final String srcId = formal.getString(3); liftIdJava(declaringScope(srcId), formal, srcId, getType(formal), childOut._javaMembers); } // constructor final List<Node> statements = new ArrayList<Node>(); final String idAbrupt = liftIdJava(currentMethodScope(), n, "returnAbrupt", JavaEntities.nameToBaseType("boolean"), childOut._javaMembers); statements.add(GNode.create("ExpressionStatement", _astFactoryJava.setThisDotField(idAbrupt, GNode.create("BooleanLiteral", "false")))); for (final Object o : nodeFormals) { final GNode formal = (GNode) o; final String srcId = formal.getString(3); final String tgtId = _javaSubstitutions.get(declaringScope(srcId), srcId); statements.add(GNode.create("ExpressionStatement", _astFactoryJava.setThisDotField(tgtId, idNode(formal, srcId)))); } statements.add(childOut._javaNode); final GNode constructor = GNode.create("ConstructorDeclaration", GNode.create("Modifiers", false), null, context()._javaEnvClassName, nodeFormals, null, _astFactoryJava.block(statements)); { final String s = Utilities.currentFunctionOrMethodName(_table); _methodSubstitutions.put(s.substring(0, s.indexOf('(')), s); } recordMethodSubstitution("<init>"); // class declaration childOut._javaMembers.add(constructor); final GNode classBody = GNode.create("ClassBody", childOut._javaMembers.size()); classBody.addAll(childOut._javaMembers); final GNode modifiers = context()._javaIsStatic ? GNode.create("Modifiers", GNode.create("Modifier", "private"), GNode.create("Modifier", "static"), GNode.create("Modifier", "final")) : GNode.create("Modifiers", GNode.create("Modifier", "private"), GNode.create("Modifier", "final")); final GNode classDecl = setLoc(n, GNode.create("ClassDeclaration", modifiers, context()._javaEnvClassName, null, null, null, classBody)); final List<Node> result = new ArrayList<Node>(1); result.add(classDecl); return result; } private GNode visitMethodDeclaration_javaNode(final GNode n) { final List<Node> actuals = new ArrayList<Node>(n.getGeneric(4).size()); for (final Object o : n.getGeneric(4)) actuals.add(idNode((Locatable)o, ((Node)o).getString(3))); final GNode clazz = GNode.create("QualifiedIdentifier", context()._javaEnvClassName); final Node body; if (Utilities.javaIsVoidMethod(n)) { body = _astFactoryJava.closureStatement(clazz, actuals); } else { final String resultFieldName = _javaSubstitutions.get(currentMethodScope(), "returnResult"); body = _astFactoryJava.closureExpression(clazz, actuals, resultFieldName); } final GNode result = setLoc(n, GNode.create("MethodDeclaration", 8)); result.add(0, GNode.create("Modifiers")); for (final Object o : n.getGeneric(0)) if (!"native".equals(((Node)o).getString(0))) result.getGeneric(0).add(o); for (int i = 1; i < 7; i++) result.add(i, n.get(i)); result.add(7, body); return result; } /** * Visit a PrimaryIdentifier = Identifier (gosling_et_al_2000 <a * href="http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#106941">§6.5</a>). */ public final Out visitPrimaryIdentifier(final GNode n) { final String id = n.getString(0); final Out ownOut; final Type type = getType(n); if ("C".equals(context()._activeLanguage)) { final GNode cNode; final List<Node> cMembers = new ArrayList<Node>(); if (null == type || null == context()._cEnvStructName) { cNode = n; } else if (!type.isVariable()) { if (type.hasAttribute(Constants.ATT_STORAGE_AUTO, true)) cNode = (GNode) _astFactoryC.getPCEnvField(liftIdC(declaringScope(id), id, type, cMembers)); else cNode = n; } else { final VariableT var = type.toVariable(); if (VariableT.Kind.LOCAL == var.getKind() || VariableT.Kind.PARAMETER == var.getKind()) cNode = (GNode) _astFactoryC.getPCEnvField(liftIdC(declaringScope(id), id, var.getType(), cMembers)); else cNode = n; } ownOut = new Out(new ArrayList<Node>(0), cMembers, setLoc(n, cNode), new ArrayList<Node>(0), null); } else { final GNode javaNode; final List<Node> javaMembers = new ArrayList<Node>(); if (null == context()._javaEnvClassName || !JavaEntities.isParameterT(type) && !JavaEntities.isLocalT(type)) javaNode = n; else javaNode = (GNode)_astFactoryJava.getThisDotField(liftIdJava(declaringScope(id), n, id, type, javaMembers)); ownOut = new Out(new ArrayList<Node>(0), new ArrayList<Node>(0), null, javaMembers, setLoc(n, javaNode)); } return ownOut; } /** * Visit a ReturnStatement = [Expression] (gosling_et_al_2000 <a * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6767">§14.16</a>). */ public final Out visitReturnStatement(final GNode n) { final Out ownOut; if ("C".equals(context()._activeLanguage)) { if (null == context()._cEnvStructName) { ownOut = visit(n); } else { final List<Node> cExternalDeclarations = new ArrayList<Node>(); final List<Node> cMembers = new ArrayList<Node>(); final List<Node> javaMembers = new ArrayList<Node>(); final GNode ownNode; final GNode jumpStatement = abruptFlowJump(n, cMembers); final GNode abruptStringAst = cStringNode(liftIdJava(currentMethodScope(), n, "returnAbrupt", JavaEntities.nameToBaseType("boolean"), javaMembers)); if (null == n.get(0)) { ownNode = (GNode)_astFactoryC.returnVoid(abruptStringAst, jumpStatement); } else { final Out childOut = (Out) dispatch(n.getGeneric(0)); cExternalDeclarations.addAll(childOut._cExternalDeclarations); cMembers.addAll(childOut._cMembers); javaMembers.addAll(childOut._javaMembers); final Type fun = Utilities.currentFunctionOrMethod(_table); assert fun.isMethod(); //TD 06 C return statement in C function that also contains Java code somewhere final Type javaType = Utilities.returnType(fun); final GNode resultStringAst = cStringNode(liftIdJava(currentMethodScope(), n, "returnResult", javaType, javaMembers)); final GNode signatureStringAst = cStringNode(JavaEntities.typeToDescriptor(_table, javaType)); final String setter = "Set" + Utilities.javaTypeToApiType(javaType, true, false) + "Field"; ownNode = (GNode)_astFactoryC.returnResult(resultStringAst, signatureStringAst, setter, childOut._cNode, abruptStringAst, jumpStatement); } ownOut = new Out(cExternalDeclarations, cMembers, setLoc(n, ownNode), javaMembers, null); } } else { if (null == context()._javaEnvClassName) { ownOut = visit(n); } else { final List<Node> cExternalDeclarations = new ArrayList<Node>(); final List<Node> cMembers = new ArrayList<Node>(); final List<Node> javaMembers = new ArrayList<Node>(); final Type fun = Utilities.currentFunctionOrMethod(_table); assert fun.isMethod(); //TD 06 Java return statement in C function final Type javaType = fun.toMethod().getResult(); final Node ownNode; final String substAbrupt = liftIdJava(currentMethodScope(), n, "returnAbrupt", JavaEntities.nameToBaseType("boolean"), javaMembers); if (null == n.get(0)) { ownNode = _astFactoryJava.returnVoid(substAbrupt); } else { final Out childOut = (Out) dispatch(n.getGeneric(0)); cExternalDeclarations.addAll(childOut._cExternalDeclarations); cMembers.addAll(childOut._cMembers); javaMembers.addAll(childOut._javaMembers); final String substResult = liftIdJava(currentMethodScope(), n, "returnResult", javaType, javaMembers); ownNode = _astFactoryJava.returnResult(substResult, childOut._javaNode, substAbrupt); } ownOut = new Out(cExternalDeclarations, cMembers, null, javaMembers, setLoc(n, (GNode)ownNode)); } } return ownOut; } /** * Visit a ThisExpression = [Expression] (gosling_et_al_2000 * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251519">§15.8.3</a>, * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251603">§15.8.4</a>). */ public final Out visitThisExpression(final GNode n) { assert "Java".equals(context()._activeLanguage); assert null == n.get(0); //TD 41 allow qualified this expressions in input final String s = JavaEntities.currentType(_table).toClass().getName(); final GNode ownNode = setLoc(n, GNode.create("ThisExpression", GNode.create("Type", GNode.create("QualifiedIdentifier", s), GNode.create("Dimensions")))); return visit(ownNode); } /** Visit a TranslationUnit = [JavaImports] ExternalDeclaration* Annotations. */ public final Out visitTranslationUnit(final GNode n) { assert _contexts.isEmpty(); assert false && null == n; /* TD 41 jeannie.CodeGenerator.visitTranslationUnit: invocation API, when outermost language is C */ return null; } /** Visit a WithStatement = (JeannieC.Declaration / JeannieC.AssignmentExpression) CInCBlock. */ public final Out visitWithStatement(final GNode n) { assert "C".equals(context()._activeLanguage); _table.enter(n); final GNode initNode = n.getGeneric(0); final String id; final Type cPtrType, javaType; final Out lhsOut, rhsOut; if (initNode.hasName("Declaration")) { final GNode dtor = initNode.getGeneric(2).getGeneric(0); final GNode jNode = dtor.getGeneric(4); id = CAnalyzer.getDeclaredId(dtor.getGeneric(1)).getString(0); lhsOut = (Out) dispatch(setLoc(dtor.getGeneric(1), GNode.create("PrimaryIdentifier", id))); rhsOut = (Out) dispatch(jNode); cPtrType = ((Type) _table.current().lookupLocally(id)); javaType = Utilities.cTypeToJavaType(_table, _runtime, jNode, getType(jNode)); } else { assert initNode.hasName("AssignmentExpression"); final GNode cNode = initNode.getGeneric(0), jNode = initNode.getGeneric(2); id = cNode.getString(0); lhsOut = (Out) dispatch(cNode); rhsOut = (Out) dispatch(jNode); cPtrType = getType(cNode); javaType = Utilities.cTypeToJavaType(_table, _runtime, jNode, getType(jNode)); } _contexts.push(new Context(context()._activeLanguage, context()._cEnvStructName, context()._cHasEnv, context()._javaEnvClassName, context()._javaEnvPackageName, context()._javaIsStatic, id, context()._snippetType)); final Out blockOut = (Out) dispatch(n.getGeneric(1)); _contexts.pop(); final List<Node> cMembers = new ArrayList<Node>(), javaMembers = new ArrayList<Node>(); final Node ownNode; { final GNode abruptFlowCheck = abruptFlowCheck(n, cMembers, javaMembers); final Node init = rhsOut._cNode; final Scope scope = declaringScope(id); final String label = liftIdCLabel(scope, "release_" + id); final Node body = blockOut._cNode; final String caField = liftIdC(scope, id, cPtrType, cMembers); final String releaseAbrupt = liftIdC(scope, id + "ReleaseAbrupt", typedefType("jint"), cMembers); if (JavaTypeConverter.isIdentical(javaType, JavaEntities.tString(_table))) { final Type cJniType = typedefType("jstring"); final String jsField = liftIdC(scope, id + "JavaString", cJniType, cMembers); ownNode = isUtf8(cPtrType, javaType) ? _astFactoryC.withStringUTF(jsField, init, releaseAbrupt, caField, body, label, abruptFlowCheck) : _astFactoryC.withString(jsField, init, releaseAbrupt, caField, body, label, abruptFlowCheck); } else { final Type tElem = JavaEntities.arrayElementType(javaType.toArray()); final boolean primiv = JavaEntities.isPrimitiveT(tElem); final Type cJniType = typedefType(primiv ? "j" + Utilities.javaTypeToApiType(javaType) : "jobject"); final String jaField = liftIdC(scope, id + "JavaArray", cJniType, cMembers); if (primiv){ final String arrayDeclString = "j" + Utilities.javaTypeToApiType(tElem) + " ca[length];"; final GNode caNode = Utilities.cStringToAst("Declaration", arrayDeclString, Utilities.standardJniTypeDefs()); final String getRegion = withArrayFunction(javaType, true); final String setRegion = withArrayFunction(javaType, false); ownNode = _astFactoryC.withPrimitiveArray(jaField, init, releaseAbrupt, caNode, caField, getRegion, body, label, setRegion, abruptFlowCheck); } else { ownNode = _astFactoryC.withReferenceArray(jaField, init, releaseAbrupt, caField, body, label, abruptFlowCheck); } } } final Out ownOut = new Out(new ArrayList<Node>(0), cMembers, setLoc(n, (GNode) ownNode), javaMembers, null); ownOut.addAll(lhsOut).addAll(rhsOut).addAll(blockOut); _table.exit(n); return ownOut; } private String withArrayFunction(final Type javaType, final boolean isAquire) { final StringBuffer result = new StringBuffer(); result.append(isAquire ? "Get" : "Set"); result.append(Utilities.javaTypeToApiType(javaType, true, true)); result.append("Region"); return result.toString(); } }