package sharpen.xobotos.api.bindings; import org.eclipse.jdt.core.dom.*; import sharpen.core.Sharpen; import sharpen.core.SharpenProblem; import sharpen.core.SharpenProblem.ProblemKind; import sharpen.core.csharp.ast.*; import sharpen.core.framework.BindingUtils; import sharpen.core.framework.CompilationUnitPair; import sharpen.core.framework.IBindingManager; import sharpen.core.framework.Types; import sharpen.xobotos.api.TypeReference; import sharpen.xobotos.api.Visibility; import sharpen.xobotos.api.interop.*; import sharpen.xobotos.api.interop.NativeMethodBuilder.ElementInfo; import sharpen.xobotos.api.interop.Signature.Flags; import sharpen.xobotos.api.interop.marshal.MarshalAsBoolean; import sharpen.xobotos.api.interop.marshal.MarshalAsNativeType; import sharpen.xobotos.api.interop.marshal.MarshalAsPrimitive; import sharpen.xobotos.api.interop.marshal.MarshalInfo; import sharpen.xobotos.api.templates.*; import sharpen.xobotos.generator.CompilationUnitBuilder; import sharpen.xobotos.generator.SharpenGenerator; import sharpen.xobotos.output.IOutputProvider; import sharpen.xobotos.output.OutputMode; import sharpen.xobotos.output.OutputType; import java.util.*; import java.util.logging.Level; public class BindingManager implements IBindingManager { private final NativeConfiguration _nativeConfig; private final HashMap<CompilationUnit, Visitor> _compilationUnits = new HashMap<CompilationUnit, Visitor>(); private final HashMap<ITypeBinding, AbstractTypeBinding> _typeBindings = new HashMap<ITypeBinding, AbstractTypeBinding>(); private final HashMap<IMethodBinding, MethodBinding> _methodBindings = new HashMap<IMethodBinding, MethodBinding>(); private final HashMap<IVariableBinding, VariableBinding> _variableBindings = new HashMap<IVariableBinding, VariableBinding>(); private final HashMap<IMethodBinding, NativeMethodEntry> _nativeMethods = new HashMap<IMethodBinding, NativeMethodEntry>(); private final HashMap<ITypeBinding, NativeTypeEntry> _nativeTypes = new HashMap<ITypeBinding, NativeTypeEntry>(); private final HashMap<ITypeBinding, ArrayHelperClass> _sharedArrayHelpers = new HashMap<ITypeBinding, ArrayHelperClass>(); private final HashMap<IMethodBinding, MethodEntry> _methodHash = new HashMap<IMethodBinding, MethodEntry>(); private final ITypeBinding _objectType; private final ITypeBinding _classType; private final ITypeBinding _stringType; private final ITypeBinding _charType; private final ITypeBinding _byteType; private final ITypeBinding _boolType; private final ITypeBinding _intType; private final ITypeBinding _longType; private final ITypeBinding _floatType; private final ITypeBinding _serializableType; private final MarshalInfo _charMarshal; private final MarshalInfo _byteMarshal; private final MarshalInfo _boolMarshal; private NativeBuilder _sharedNativeBuilder; private CSCompilationUnit _sharedManagedBuilder; private CSClass _sharedTypedef; private StringHelperClass _stringHelper; private MarshalInfo _stringMarshal; public static final CSTypeReference MANAGED_SHARED_HELPER = new CSTypeReference("XobotOS.Runtime.MarshalGlue"); public static boolean DEBUG = false; public BindingManager(AST ast, NativeConfiguration config) { this._nativeConfig = config; _objectType = resolveWellKnownType(ast, "java.lang.Object"); _classType = resolveWellKnownType(ast, "java.lang.Class"); _stringType = resolveWellKnownType(ast, "java.lang.String"); _charType = resolveWellKnownType(ast, "char"); _byteType = resolveWellKnownType(ast, "byte"); _boolType = resolveWellKnownType(ast, "boolean"); _intType = resolveWellKnownType(ast, "int"); _longType = resolveWellKnownType(ast, "long"); _floatType = resolveWellKnownType(ast, "float"); _serializableType = resolveWellKnownType(ast, "java.io.Serializable"); _charMarshal = new MarshalAsPrimitive(_charType, "char", "char16_t"); _byteMarshal = new MarshalAsPrimitive(_byteType, "byte", "uint8_t"); _boolMarshal = new MarshalAsBoolean(_boolType); } private ITypeBinding resolveWellKnownType(AST ast, String name) { ITypeBinding type = ast.resolveWellKnownType(name); if (type == null) throw new RuntimeException(String.format("Cannot resolve well known type '%s'", name)); return type; } public CompilationUnitBuilder preprocess(CompilationUnitPair pair, CompilationUnitTemplate template, String name, IOutputProvider defaultOutput) { Visitor visitor = new Visitor(pair, template, name, defaultOutput); _compilationUnits.put(pair.ast, visitor); pair.ast.accept(visitor); visitor.setup(); return visitor; } private NativeBuilder createNativeBuilder(NativeConfiguration config, String name) { if (_sharedNativeBuilder == null) { _sharedNativeBuilder = new NativeBuilder(config, "XobotOS.MarshalGlue"); _sharedManagedBuilder = new CSCompilationUnit(); _sharedManagedBuilder.namespace("XobotOS.Runtime"); _sharedTypedef = new CSClass("MarshalGlue", CSClassModifier.Static); _sharedTypedef.visibility(CSVisibility.Internal); _sharedManagedBuilder.addType(_sharedTypedef); _sharedManagedBuilder.addUsing(new CSUsing("System.Runtime.InteropServices")); _stringHelper = new StringHelperClass(_sharedNativeBuilder, _stringType); _stringMarshal = new MarshalAsNativeType(_stringType, _stringHelper); _sharedNativeBuilder.registerNativeType(_stringHelper); createSharedArrayHelper(_charType, _charMarshal); createSharedArrayHelper(_byteType, _byteMarshal); createSharedArrayHelper(_intType, new MarshalAsPrimitive(_intType, "int", "int")); createSharedArrayHelper(_longType, new MarshalAsPrimitive(_longType, "long", "long")); createSharedArrayHelper(_floatType, new MarshalAsPrimitive(_floatType, "float", "float")); } NativeBuilder builder = new NativeBuilder(config, name); builder.getCompilationUnit().getIncludeSection().addInclude(_sharedNativeBuilder.getHeaderInclude()); return builder; } private void createSharedArrayHelper(ITypeBinding type, MarshalInfo marshal) { ElementInfo info = new ElementInfo(type, marshal, null, Flags.ELEMENT); ArrayHelperClass helper = new ArrayHelperClass(type, "Array_" + type.getName(), _sharedNativeBuilder, info, true); _sharedArrayHelpers.put(type, helper); _sharedNativeBuilder.registerNativeType(helper); } public boolean resolveTypes() { boolean ok = true; for (Visitor visitor : _compilationUnits.values()) { if (!visitor.resolveTypes()) { Sharpen.Log(Level.SEVERE, "Failed to resolve native type '%s'", visitor.getName()); ok = false; } } for (Visitor visitor : _compilationUnits.values()) { if (!visitor.resolveMethods()) { Sharpen.Log(Level.SEVERE, "Failed to resolve native type '%s'", visitor.getName()); ok = false; } } for (Visitor visitor : _compilationUnits.values()) { if (!visitor.emitHelpers()) { Sharpen.Log(Level.SEVERE, "Failed to resolve native type '%s'", visitor.getName()); ok = false; } } return ok; } public boolean postProcess() { if (_sharedNativeBuilder == null) return true; _sharedNativeBuilder.build(true); _stringHelper.createManagedType(_sharedTypedef); for (ArrayHelperClass helper : _sharedArrayHelpers.values()) helper.createManagedType(_sharedTypedef); if (!_sharedNativeBuilder.printManagedType(_sharedManagedBuilder)) return false; return _sharedNativeBuilder.writeOutput(); } @Override public ITypeBinding getObjectType() { return _objectType; } @Override public ITypeBinding getClassType() { return _classType; } @Override public ITypeBinding getStringType() { return _stringType; } @Override public ITypeBinding getCharType() { return _charType; } @Override public ITypeBinding getByteType() { return _byteType; } @Override public ITypeBinding getIntType() { return _intType; } @Override public ITypeBinding getLongType() { return _longType; } @Override public ITypeBinding getFloatType() { return _floatType; } @Override public ITypeBinding getSerializableType() { return _serializableType; } public boolean isBlittable(ITypeBinding type) { return type.equals(_byteType) || type.equals(_charType) || type.equals(_floatType) || type.equals(_intType) || type.equals(_longType) || type.equals(_boolType); } public AbstractTypeBinding resolveBinding(ITypeBinding binding) { return _typeBindings.get(binding.getTypeDeclaration()); } public MethodBinding resolveBinding(IMethodBinding binding) { return _methodBindings.get(binding.getMethodDeclaration()); } public VariableBinding resolveBinding(IVariableBinding binding) { return _variableBindings.get(binding.getVariableDeclaration()); } public NativeMethodBuilder resolveNativeBinding(IMethodBinding binding) { NativeMethodEntry entry = _nativeMethods.get(binding.getMethodDeclaration()); return entry != null ? entry.Builder : null; } public AbstractNativeTypeBuilder getNativeTypeBuilder(ITypeBinding binding) { if (binding.equals(_stringType)) return _stringHelper; NativeTypeEntry entry = _nativeTypes.get(binding.getTypeDeclaration()); return entry != null ? entry.Builder : null; } public MethodEntry lookupMethod(IMethodBinding binding) { return _methodHash.get(binding.getMethodDeclaration()); } @Override public ITypeInfo getTypeInfo(ITypeBinding type) { AbstractTypeBinding binding = _typeBindings.get(type.getTypeDeclaration()); if (binding instanceof TypeBinding) return (TypeBinding) binding; else return null; } @Override public IMethodInfo getMethodInfo(IMethodBinding method) { return _methodBindings.get(method.getMethodDeclaration()); } @Override public IMethodBinding getBaseMethod(IMethodBinding method) { MethodEntry entry = _methodHash.get(method.getMethodDeclaration()); return entry != null ? entry.BaseMethod : null; } @Override public IVariableInfo getVariableInfo(IVariableBinding variable) { return _variableBindings.get(variable.getVariableDeclaration()); } @Override public IExtractedEnumInfo getExtractedEnumInfo(ITypeBinding type) { AbstractTypeBinding binding = resolveBinding(type); if (binding instanceof EnumBinding) return ((EnumBinding) binding).getExtractionInfo(); return null; } public static boolean reportStubUsage() { return false; } private class Visitor extends ASTVisitor implements CompilationUnitBuilder { private final CompilationUnitPair _pair; private final CompilationUnitTemplate _template; private final String _name; private final CSCompilationUnit _unit; private final SharpenGenerator _generator; private final Stack<ITypeEntry> _typeStack = new Stack<ITypeEntry>(); private final Stack<IOutputProvider> _outputProviderStack = new Stack<IOutputProvider>(); private final Stack<ScopeEntry> _scopeStack = new Stack<ScopeEntry>(); private final List<NativeMethodEntry> _nativeMethodList = new ArrayList<NativeMethodEntry>(); private final List<NativeTypeEntry> _nativeTypeList = new ArrayList<NativeTypeEntry>(); private final HashMap<ITypeBinding, ArrayHelperClass> _arrayHelpers = new HashMap<ITypeBinding, ArrayHelperClass>(); private NativeBuilder _nativeBuilder; private ITypeBinding _nativeTypeContainer; private boolean _needsHeader; private MethodEntry _currentMethod; public Visitor(CompilationUnitPair pair, CompilationUnitTemplate template, String name, IOutputProvider defaultOutput) { this._pair = pair; this._template = template; this._name = name; this._unit = new CSCompilationUnit(); if (defaultOutput != null) _outputProviderStack.push(defaultOutput); _outputProviderStack.push(template); _generator = new Generator(defaultOutput); } private void setup() { if (_nativeTypeContainer == null) return; _nativeBuilder = createNativeBuilder(_nativeConfig, _name); _unit.addUsing(new CSUsing("System.Runtime.InteropServices")); } @Override public String getName() { return _name; } @Override public CompilationUnitPair getPair() { return _pair; } @Override public CompilationUnitTemplate getTemplate() { return _template; } @Override public CSCompilationUnit getCompilationUnit() { return _unit; } @Override public NativeBuilder getNativeBuilder() { return _nativeBuilder; } private ITypeContainer getCurrentType() { if (_typeStack.size() == 0) return _template; return _typeStack.peek().getTemplate(); } private OutputType getOutputType() { for (int i = _outputProviderStack.size() - 1; i >= 0; i--) { IOutputProvider provider = _outputProviderStack.get(i); if (provider == null) continue; OutputType type = provider.getOutputType(); if (type != null) return type; } return OutputType.NAKED_STUB; } private void pushScope() { ScopeEntry scope; if (_scopeStack.size() > 0) scope = new ScopeEntry(_scopeStack.peek()); else scope = new ScopeEntry(); _scopeStack.push(scope); } private ScopeEntry getScope() { return _scopeStack.peek(); } private void popScope() { _scopeStack.pop(); } @Override public boolean visit(AnonymousClassDeclaration node) { final IMemberContainer type = _typeStack.peek().getTemplate(); final AnonymousClassTemplate template = type.findAnonymousClassTemplate(node); if (template == null) return false; final OutputType output = getOutputType(); final OutputMode mode = output.getModeForMember(node); if (mode == OutputMode.NOTHING) return false; ITypeEntry entry = new AnonymousClassEntry(node, template, output); _outputProviderStack.push(template); _typeStack.push(entry); for (final Object o : node.bodyDeclarations()) { if (!(o instanceof ASTNode)) continue; ASTNode member = (ASTNode) o; member.accept(this); } _typeStack.pop(); _outputProviderStack.pop(); return false; } @Override public boolean visit(CompilationUnit node) { return true; } @Override public boolean visit(EnumDeclaration node) { final EnumTemplate template = getCurrentType().findEnumTemplate(node); if (template == null) return false; EnumBinding binding = template.getBinding(); if (binding != null) _typeBindings.put(node.resolveBinding(), binding); return false; } @Override public boolean visit(TypeDeclaration node) { final TypeTemplate template = getCurrentType().findTypeTemplate(node); if (template == null) return false; final ITypeBinding typeBinding = node.resolveBinding(); final NativeTypeEntry nativeType; if (template.getNativeType() != null) { if (_nativeTypeContainer == null) _nativeTypeContainer = typeBinding; nativeType = new NativeTypeEntry(typeBinding, template.getNativeType()); _nativeTypes.put(typeBinding, nativeType); _nativeTypeList.add(nativeType); } else if (template.getNativeHandle() != null) { if (_nativeTypeContainer == null) _nativeTypeContainer = typeBinding; nativeType = new NativeTypeEntry(typeBinding, template.getNativeHandle()); _nativeTypes.put(typeBinding, nativeType); _nativeTypeList.add(nativeType); } else if (template.getNativeStruct() != null) { if (_nativeTypeContainer == null) _nativeTypeContainer = typeBinding; nativeType = new NativeTypeEntry(typeBinding, template.getNativeStruct()); _nativeTypes.put(typeBinding, nativeType); _nativeTypeList.add(nativeType); } else { nativeType = null; } _outputProviderStack.push(template); final OutputType output = getOutputType(); TypeEntry type = new TypeEntry(node, template, output, nativeType); _typeStack.push(type); TypeBinding binding = template.getBinding(); if (binding != null) { _typeBindings.put(typeBinding, binding); if (binding.isEventInterface()) checkValidEventInterface(node); } for (final Object o : node.bodyDeclarations()) { if (!(o instanceof ASTNode)) continue; ASTNode member = (ASTNode) o; member.accept(this); } _typeStack.pop(); _outputProviderStack.pop(); return false; } @Override public boolean visit(FieldDeclaration node) { final ITypeEntry entry = _typeStack.peek(); final FieldTemplate template = entry.getTemplate().findFieldTemplate(node); if (template == null) return false; final NativeHandle nativeHandle; final NativeTypeEntry nativeType = entry.getNativeType(); if ((nativeType != null) && (nativeType.Template instanceof NativeHandle)) nativeHandle = (NativeHandle) nativeType.Template; else nativeHandle = null; VariableBinding binding = template.getBinding(); for (Object o : node.fragments()) { VariableDeclarationFragment fragment = (VariableDeclarationFragment) o; final IVariableBinding vb = fragment.resolveBinding(); final String name = vb.getName(); if ((nativeHandle != null) && name.equals(nativeHandle.getField())) nativeHandleField(vb, nativeHandle); else if (binding != null) _variableBindings.put(vb, binding); checkFieldAndMethodNameClash(fragment, vb); if (fragment.getInitializer() != null) fragment.getInitializer().accept(this); } return false; } void nativeHandleField(IVariableBinding binding, final NativeHandle handle) { _variableBindings.put(binding, new VariableBinding() { @Override public boolean isPointer() { return false; } @Override public NativeHandle getNativeHandle() { return handle; } }); } private void checkFieldAndMethodNameClash(VariableDeclarationFragment node, IVariableBinding binding) { final ITypeBinding declType = binding.getDeclaringClass(); final String name = binding.getName(); final List<String> visibleMethods = getVisibleMethodNames(declType); if (!visibleMethods.contains(name)) return; int mods = binding.getModifiers(); boolean isNonPrivate = Modifier.isPublic(mods) || Modifier.isProtected(mods); if (isNonPrivate && !autoRenameFields()) { addProblem(node, ProblemKind.PARSING_ERROR, "Non-private field %s.%s clashes with visible method", BindingUtils.qualifiedName(declType), name); } int i = 0; String newName = name.startsWith("_") ? name + '_' + (++i) : '_' + name; while (visibleMethods.contains(newName)) { newName = name + '_' + (++i); } final String renamed = newName; addRenamedVariable(binding, renamed); } private boolean autoRenameFields() { CompilationUnitBinding binding = _template.getBinding(); if (binding == null) return false; return binding.autoRenameFields(); } @Override public boolean visit(MethodDeclaration node) { final ITypeEntry entry = _typeStack.peek(); final AbstractMethodTemplate<?> template = entry.getTemplate().findMethodTemplate(node); if (template == null) return false; pushScope(); final IMethodBinding methodBinding = node.resolveBinding(); MethodBinding binding = template.getBinding(); if (binding != null) _methodBindings.put(methodBinding, binding); final ASTNode parent = node.getParent(); final ITypeBinding declaringType; if (parent instanceof TypeDeclaration) { declaringType = ((TypeDeclaration) parent).resolveBinding(); } else if (parent instanceof AnonymousClassDeclaration) { declaringType = ((AnonymousClassDeclaration) parent).resolveBinding(); } else { declaringType = null; } if (declaringType != null) { List<String> visibleMethods = getVisibleMethodNames(declaringType); getScope().addVisibleMethods(visibleMethods); } int index = 0; for (final Object p : node.parameters()) { final VariableDeclaration vdecl = (VariableDeclaration) p; final IVariableBinding vb = vdecl.resolveBinding(); ParameterTemplate param = template.findParameterTemplate(index++); if (param != null) { VariableBinding pb = param.getBinding(); if (pb != null) _variableBindings.put(vb, pb); } createVariableDeclaration(vb); } if ((template instanceof MethodTemplate) && (entry instanceof TypeEntry)) { MethodTemplate mt = (MethodTemplate) template; if (Modifier.isNative(node.getModifiers()) || (mt.getNativeMethod() != null)) addNativeMethod((TypeEntry) entry, (MethodTemplate) template, node); } _outputProviderStack.push(template); final OutputType output = getOutputType(); final MethodEntry oldMethod = _currentMethod; final IMethodBinding baseMethod = BindingUtils.getBaseMethod(methodBinding, false, false); _currentMethod = new MethodEntry(node, template, baseMethod, output); _methodHash.put(node.resolveBinding(), _currentMethod); Block body = node.getBody(); if (body != null) body.accept(this); popScope(); _currentMethod = oldMethod; _outputProviderStack.pop(); return false; } @Override public boolean visit(VariableDeclarationFragment node) { final IVariableBinding vb = node.resolveBinding(); if (_currentMethod != null) { VariableTemplate template = _currentMethod.Template.findVariableTemplate(node); if (template != null) { VariableBinding binding = template.getBinding(); if (binding != null) _variableBindings.put(vb, binding); } } createVariableDeclaration(vb); return false; } private void createVariableDeclaration(IVariableBinding binding) { final ScopeEntry scope = getScope(); final String name = binding.getName(); final String renamed = scope.renameVariable(binding, name); if (renamed != null) addRenamedVariable(binding, renamed); } private void addNativeMethod(TypeEntry type, MethodTemplate template, MethodDeclaration node) { if ((template == null) || (template.getNativeMethod() == null) || (type.NativeType == null)) return; final NativeMethod method = template.getNativeMethod(); final IMethodBinding binding = node.resolveBinding(); NativeMethodEntry entry = new NativeMethodEntry(type.NativeType, node, method); _nativeMethods.put(binding, entry); _nativeMethodList.add(entry); } private void addRenamedVariable(IVariableBinding binding, String name) { VariableBinding old = _variableBindings.get(binding); VariableBinding renamed = new RenamedVariable(old, name); _variableBindings.put(binding, renamed); } @Override public boolean visit(Block node) { pushScope(); return super.visit(node); } @Override public void endVisit(Block node) { popScope(); super.endVisit(node); } @Override public boolean visit(TryStatement node) { node.getBody().accept(this); for (Object o : node.catchClauses()) { CatchClause clause = (CatchClause) o; pushScope(); clause.accept(this); popScope(); } if (node.getFinally() != null) node.getFinally().accept(this); return true; } private void collectVisibleMethodNames(ArrayList<String> list, ITypeBinding type) { for (final IMethodBinding method : type.getDeclaredMethods()) { if (!list.contains(method.getName())) list.add(method.getName()); } ITypeBinding superClass = type.getSuperclass(); if (superClass != null) collectVisibleMethodNames(list, superClass); for (final ITypeBinding iface : type.getInterfaces()) { collectVisibleMethodNames(list, iface); } } protected List<String> getVisibleMethodNames(ITypeBinding type) { ArrayList<String> list = new ArrayList<String>(); collectVisibleMethodNames(list, type); return Collections.unmodifiableList(list); } private void addProblem(ASTNode node, ProblemKind kind, String message, Object... args) { _pair.addProblem(new SharpenProblem(_pair.ast, node, kind, String.format(message, args))); } private void addProblem(ASTNode node, String message, Object... args) { addProblem(node, ProblemKind.PARSING_ERROR, message, args); } private boolean checkValidEventInterface(TypeDeclaration node) { final ITypeBinding type = node.resolveBinding(); final ITypeBinding declType = type.getDeclaringClass().getTypeDeclaration(); if (!type.isInterface() || !type.isNested()) { addProblem(node, "Type '%s' is not a valid even interface.", BindingUtils.qualifiedName(type)); return false; } for (ASTNode member : Types.<ASTNode> cast(node.bodyDeclarations())) { if (!(member instanceof MethodDeclaration)) { addProblem(node, "Event interface '%s' must only contain methods.", BindingUtils.qualifiedName(type)); return false; } } for (MethodDeclaration method : node.getMethods()) { final IMethodBinding binding = method.resolveBinding(); final ITypeBinding[] ptypes = binding.getParameterTypes(); if (ptypes.length < 1) { addProblem(node, "Method '%s' in event interface must have at least one parameter.", BindingUtils.qualifiedSignature(binding)); return false; } ITypeBinding sender = ptypes[0]; if (!sender.getTypeDeclaration().equals(declType)) { addProblem(node, "Method '%s' in event interface has invalid first argument.", BindingUtils.qualifiedSignature(binding)); return false; } } return true; } public boolean resolveTypes() { final IMarshalContext context = new IMarshalContext() { @Override public NativeConfiguration getConfig() { return _nativeConfig; } @Override public HelperClassBuilder getHelperClass(ITypeBinding type) { return Visitor.this.getHelperClass(this, type); } @Override public MarshalInfo getMarshalInfo(ITypeBinding type) { return Visitor.this.getMarshalInfo(this, type); } }; boolean foundErrors = false; for (NativeTypeEntry entry : _nativeTypeList) { final String name = BindingUtils.qualifiedName(entry.Binding); if (DEBUG) Sharpen.Debug("RESOLVE NATIVE TYPE: %s", name); if (entry.Template instanceof NativeHandle) entry.Builder = new NativeHandleBuilder(_nativeBuilder, entry.Binding, (NativeHandle) entry.Template); else if (entry.Template instanceof NativeStruct) { entry.Builder = new StructHelperClass(_nativeBuilder, entry.Binding, (NativeStruct) entry.Template); _needsHeader = true; } else { if (DEBUG) Sharpen.Debug("RESOLVE NATIVE TYPE EMPTY: %s", name); continue; } boolean ok = entry.Builder.resolve(context); if (DEBUG) Sharpen.Debug("RESOLVE NATIVE TYPE DONE: %s - %s", name, ok); if (!ok) foundErrors = true; _nativeBuilder.registerNativeType(entry.Builder); } return !foundErrors; } public boolean resolveMethods() { final IMarshalContext context = new IMarshalContext() { @Override public NativeConfiguration getConfig() { return _nativeConfig; } @Override public HelperClassBuilder getHelperClass(ITypeBinding type) { return Visitor.this.getHelperClass(this, type); } @Override public MarshalInfo getMarshalInfo(ITypeBinding type) { return Visitor.this.getMarshalInfo(this, type); } }; boolean foundErrors = false; for (NativeMethodEntry entry : _nativeMethodList) { final String name = BindingUtils.qualifiedSignature(entry.Node.resolveBinding()); if(DEBUG) Sharpen.Debug("RESOLVE NATIVE METHOD: %s", name); entry.Builder = _nativeBuilder.registerNativeMethod( entry.Node, entry.Template, (NativeHandleBuilder) entry.Type.Builder); boolean ok = entry.Builder.resolve(context); if(DEBUG) Sharpen.Debug("RESOLVE NATIVE METHOD DONE: %s - %s", name, ok); if (!ok) foundErrors = true; } return !foundErrors; } private HelperClassBuilder getHelperClass(IMarshalContext context, ITypeBinding type) { if (type.isClass()) { AbstractNativeTypeBuilder builder = getNativeTypeBuilder(type); if (builder != null) return (HelperClassBuilder) builder; } if (type.equals(_stringType)) return _stringHelper; if (type.isArray()) { ITypeBinding elementType = type.getElementType(); ArrayHelperClass helper = _sharedArrayHelpers.get(elementType); if (helper != null) return helper; helper = _arrayHelpers.get(elementType); if (helper != null) return helper; MarshalInfo marshal = getMarshalInfo(context, elementType); if (marshal == null) return null; ElementInfo element = new ElementInfo(elementType, marshal, null, Flags.ELEMENT); String name = "Array_" + elementType.getName(); helper = new ArrayHelperClass(type, name, _nativeBuilder, element, false); _arrayHelpers.put(elementType, helper); if (!helper.resolve(context)) return null; _nativeBuilder.registerNativeType(helper); return helper; } return null; } private MarshalInfo getMarshalInfo(IMarshalContext context, ITypeBinding type) { if(type.equals(_charType)) return _charMarshal; else if(type.equals(_byteType)) return _byteMarshal; else if(type.equals(_stringType)) return _stringMarshal; else if (type.equals(_boolType)) return _boolMarshal; else if(type.isPrimitive()) return new MarshalAsPrimitive(type, type.getName(), type.getName()); HelperClassBuilder helper = getHelperClass(context, type); if (helper != null) return new MarshalAsNativeType(type, helper); return null; } public boolean emitHelpers() { if (_nativeBuilder != null) { if (!_nativeBuilder.build(_needsHeader)) return false; } return true; } private void registerType(ITypeBinding binding, CSTypeDeclaration type) { if(DEBUG) Sharpen.Debug("REGISTER TYPE: %s", BindingUtils.qualifiedName(binding)); if (binding == _nativeTypeContainer) { for (HelperClassBuilder helper : _arrayHelpers.values()) { if(DEBUG) Sharpen.Debug("REGISTER TYPE - HELPER: %s", helper.getName()); helper.createManagedType(type); } } NativeTypeEntry entry = _nativeTypes.get(binding.getTypeDeclaration()); if ((entry != null) && (entry.Builder != null)) entry.Builder.createManagedType(type); } @Override public boolean build() { return _generator.generate(); } @Override public boolean writeOutput() { if (_nativeBuilder == null) return true; if (DEBUG) Sharpen.Debug("WRITING OUTPUT: %s", _name); return _nativeBuilder.writeOutput(); } private class Generator extends SharpenGenerator { public Generator(IOutputProvider defaultOutput) { super(Visitor.this, defaultOutput); } @Override protected void registerType(ITypeBinding binding, CSTypeDeclaration type) { Visitor.this.registerType(binding, type); } @Override protected void registerMethod(IMethodBinding binding, CSMethod method) { ; } } } private interface ITypeEntry { ASTNode getNode(); IMemberContainer getTemplate(); OutputType getOutput(); NativeTypeEntry getNativeType(); } public class AnonymousClassEntry implements ITypeEntry { public final AnonymousClassDeclaration Declaration; public final AnonymousClassTemplate Template; public final OutputType Output; public AnonymousClassEntry(AnonymousClassDeclaration node, AnonymousClassTemplate template, OutputType output) { this.Declaration = node; this.Template = template; this.Output = output; } @Override public ASTNode getNode() { return Declaration; } @Override public IMemberContainer getTemplate() { return Template; } @Override public OutputType getOutput() { return Output; } @Override public NativeTypeEntry getNativeType() { return null; } } public class TypeEntry implements ITypeEntry { public final TypeDeclaration Declaration; public final TypeTemplate Template; public final OutputType Output; public final NativeTypeEntry NativeType; public TypeEntry(TypeDeclaration node, TypeTemplate template, OutputType output, NativeTypeEntry nativeType) { this.Declaration = node; this.Template = template; this.Output = output; this.NativeType = nativeType; } @Override public ASTNode getNode() { return Declaration; } @Override public IMemberContainer getTemplate() { return Template; } @Override public OutputType getOutput() { return Output; } @Override public NativeTypeEntry getNativeType() { return NativeType; } @Override public String toString() { return String.format("TypeEntry[%s:%s:%s]", BindingUtils.qualifiedName(Declaration.resolveBinding()), Template, Output); } } public class MethodEntry { public final MethodDeclaration Declaration; public final AbstractMethodTemplate<?> Template; public final IMethodBinding BaseMethod; public final OutputType Output; public MethodEntry(MethodDeclaration node, AbstractMethodTemplate<?> template, IMethodBinding baseMethod, OutputType output) { this.Declaration = node; this.Template = template; this.BaseMethod = baseMethod; this.Output = output; } @Override public String toString() { return String.format("MethodEntry[%s:%s:%s]", BindingUtils.qualifiedName(Declaration.resolveBinding()), Template, Output); } } private class ScopeEntry { private final ScopeEntry _parent; private final Set<String> _localBlockVariables = new HashSet<String>(); private final Set<String> _blockVariables = new HashSet<String>(); public ScopeEntry() { _parent = null; } public ScopeEntry(ScopeEntry parent) { _parent = parent; _localBlockVariables.addAll(parent._localBlockVariables); _blockVariables.addAll(_localBlockVariables); } void addVisibleMethods(List<String> methods) { _localBlockVariables.addAll(methods); _blockVariables.addAll(methods); } String renameVariable(IVariableBinding binding, String name) { String renamed = null; if (_blockVariables.contains(name)) { int count = 1; while (_blockVariables.contains(name + "_" + count)) { count++; } name = name + "_" + count; renamed = name; } _localBlockVariables.add(name); _blockVariables.add(name); ScopeEntry parent = _parent; while (parent != null) { parent._blockVariables.add(name); parent = parent._parent; } return renamed; } } private class RenamedVariable extends VariableBinding { private final VariableBinding _parent; private final String _renamed; public RenamedVariable(VariableBinding parent, String renamed) { this._parent = parent; this._renamed = renamed; } @Override public String rename() { return _renamed; } @Override public boolean isPointer() { return _parent != null ? _parent.isPointer() : false; } @Override public TypeReference modifyType() { return _parent != null ? _parent.modifyType() : null; } @Override public NativeHandle getNativeHandle() { return _parent != null ? _parent.getNativeHandle() : null; } @Override public Visibility getVisibility() { return _parent != null ? _parent.getVisibility() : null; } } private class NativeTypeEntry { private final ITypeBinding Binding; private final NativeTypeTemplate Template; private AbstractNativeTypeBuilder Builder; public NativeTypeEntry(ITypeBinding type, NativeTypeTemplate template) { this.Binding = type; this.Template = template; } } private class NativeMethodEntry { private final NativeTypeEntry Type; private final MethodDeclaration Node; private final NativeMethod Template; private NativeMethodBuilder Builder; public NativeMethodEntry(NativeTypeEntry type, MethodDeclaration method, NativeMethod template) { this.Type = type; this.Node = method; this.Template = template; } } }