# Load Jvm references and libraries class Compiler is partial var _didReadJars = Set() var _jvmTypeToIType = Dictionary() var _jvmTypeCache = Dictionary() # Java specific Reference loading def jvmLoadReference(reference as String) as String? try return __jvmLoadReference(reference) catch fnfe as System.IO.FileNotFoundException throw LoadReferenceException('FileNotFound', fnfe.fileName, fnfe.message) catch fle as System.IO.FileLoadException throw LoadReferenceException('FileLoadException', fle.fileName ? reference, fle.message) catch fiop as InvalidOperationException throw LoadReferenceException('InvalidOperationException', reference, fiop.message) def __jvmLoadReference(reference as String) as String? # uses reference parameter # compiler .referenceVerbosity # fills .loadedReferences # Hopefully this is simpler than .Net case, look for reference which devolves to a pkgSig file # in cwd or as abspathname or in cobra library-path settings. # When running java native would probably also need to check the classpath require reference.endsWith('.jar') reference not in ['.jar'] ensure not result implies .loadedReferences[.loadedReferences.count-1] == reference result implies .loadedReferences.count == old.loadedReferences.count body jarSig as JarSig? = nil rv = .referenceVerbosity assert not (reference.startsWith('-r') and '-r' in reference[2:]) sigFile = reference + '.sig' if rv, print 'Looking for sigfile("[sigFile]").' sigFilePath = _lookForSigFile(sigFile, rv, reference) if not sigFilePath # eventually may also search CLASSPATH if rv, print 'Returning false for __jvmLoadReference("[reference]").' return 'to-do: what to put here? sigFilePath "[sigFilePath]" not found?' if rv, print 'Will read jarsig: [sigFilePath]' try jarSig = JarSig(sigFilePath) catch readExc as Exception if rv, print 'Caught exception during jarSig creation: [readExc]' throw if rv print 'Did find jarSig: [jarSig]' print 'Will read jarsig contents: [jarSig]' try .javaReadJar(jarSig to !) catch readExc as Exception if rv, print 'Caught exception during javaReadJar: [readExc]' throw if rv, print 'Did read jar signature file: [jarSig]' .loadedReferences.add(reference) if rv, print 'Returning nil (=okay) for __jvmLoadReference("[reference]").' return nil def _lookForSigFile(sigFile as String, rv as int, reference as String) as String? """Pathname to sigfile if found in cwd, abspath or in library-directory paths, nil otherwise.""" if File.exists(sigFile) # current directory or abspathname if rv, print '"[reference]" found as file in [sigFile].' return sigFile ccPath = Path.getDirectoryName(CobraCore.exePath) to ! absSigFile = Path.combine(ccPath, sigFile) if File.exists(absSigFile) if rv, print '"[reference]" found as file in [absSigFile].' return absSigFile if rv, print 'File does not exist in std places. Searching library-directory setting' searchPaths = .options.getDefault('library-directory', List()) to List if not searchPaths.count if rv, print 'No lib paths to search.' return nil found = false for searchPath in searchPaths if rv, print 'Checking lib path: "[searchPath]"' combinedPath = Path.combine(searchPath, sigFile) if File.exists(combinedPath) if rv, print '"[reference]" found as file in [combinedPath].' found = true break if not found if rv and searchPaths.count, print 'Did not find "[reference]" in lib paths' return nil return combinedPath def javaReadJar(jSig as JarSig) """ Reads the contents of a jar (actually JarSig) file and make the symbols accessible to the compiler for the program being compiled. """ if jSig.name in _didReadJars, return _didReadJars.add(jSig.name) verbosity = .verbosity if verbosity print 'Reading jar(sig): [jSig.name]' # extra space lines up with 'Loading reference:' print ' at: [jSig.location]' namespaceQualNameToNameSpaceObject = Dictionary() module = AssemblyModule(jSig.location, .globalNS) saveModule, _curModule = _curModule, module nestedTypes = List() try _modules.add(module) for jvmType in jSig.getExportedTypes if jvmType.isNested # or jvmType.declaringType nestedTypes.add(jvmType) continue typeNamespace = jvmType.packageAsCobra #Capitalized if typeNamespace.length == 0 # happens for classes etc. that are not declared in a namespace curNameSpace = module.topNameSpace else namespaceName = typeNamespace if namespaceQualNameToNameSpaceObject.containsKey(namespaceName) curNameSpace = namespaceQualNameToNameSpaceObject[namespaceName] else curNameSpace = module.topNameSpace for name in typeNamespace.split(c'.') curNameSpace = curNameSpace.getOrMakeNameSpaceNamed(Token.empty, name) assert not curNameSpace.isUnified namespaceQualNameToNameSpaceObject[namespaceName] = curNameSpace if verbosity >= 4 print ' Reading type [jvmType.name] in namespace "[namespaceName]"' jvmNative = JvmNativeType(jvmType) if curNameSpace.unifiedNameSpace.declForName(jvmNative.name) .warning(CobraWarning('Already have declaration "[jvmNative.name]" in namespace "[curNameSpace.fullName]".')) else if jvmType.isClass if jvmType.name.startsWith('Extend_') and jvmType.name.count(c'_') >= 2 # e.g.Extend_String - TODO curNameSpace.addDecl(Extension(jvmNative, .backEnd)) else curNameSpace.addDecl(Class(jvmNative, .backEnd)) else if jvmType.isInterface curNameSpace.addDecl(Interface(jvmNative, .backEnd)) else if jvmType.isEnum curNameSpace.addDecl(EnumDecl(curNameSpace, jvmNative, jvmType.modifiers, '')) # TODO: isNames; docString? else if jvmType.isValueType curNameSpace.addDecl(Struct(jvmNative, .backEnd)) else throw FallThroughException(jvmType) finally if nestedTypes.count _setNestedTypes(nestedTypes)# store nestedTypes in parenting type. _curModule = saveModule def _setNestedTypes(nestedTypes as List) for nt in nestedTypes enclType = nt.declaringType if enclType # Hack below suppressing adding nested classes in java.lang Character. (or any Primitive) # boxes.baseBind on primitives with nested classes dies due call fm bindh # and memberName lookup needs .didBindInt - doesnt happen in CLR. (FIXME) if enclType.canonicalName <> 'java.lang.Character' enclType.addNestedType(nt) #if enclType.isInterface, print 'EnclINTERFACE [enclType.canonicalName] [nt.name]' else if .verbosity >= 3, print 'NO class found for enclosing class of nested class [nt.canonicalName]' # just ignore/drop any nested class cant find parent for def jvmFixNilableMemberSigs # fix the listed members below to be non Nilable # called from bindInterface phase so this can only refer to top level Classes in a package. # TODO: this really needs to go in a separate file that the compiler reads each time # fix up member sigs regarding methods returning nilable values # hard coded below. TODO: read from a Cobra config file # _fix is defined in ScanClrType # Included by comparison from .Net ones and examination of javaDoc - INCOMPLETE _fix('Java.Lang.Object', 'toString getClass clone') # ^ regarding .toString, not technically true, but common enough and life is too painful when the return type is nilable _fix('Java.Lang.System', 'in out err lineSeparator') _fix('Java.Lang.String', r'[] length charAt concat remove replace replaceAll replaceFirst substring toLowerCase toUpperCase trim format') #_fix('System.Type', 'assembly name toString') # namespace can return nil if the Type is a generic parameter #_fix('System.Environment', 'commandLine currentDirectory newLine version') _fix('Java.Lang.Exception', 'message') #_fix('java.util.Enumeration', r'getNext') _fix('Java.Lang.Iterable', r'iterator') _fix('Java.Util.Iterator', r'next') _fix('Java.Util.ListIterator', r'next previous') _fix('Java.Util.Collection', r'toArray') #_fix('System.Collections.Generic.IEnumerable', r'getEnumerator') # work out what doing with indexor and apply to [] #_fix('System.Collections.Generic.List', r'[]') _fix('Java.Util.List', r'[] get set remove size') _fix('Java.Util.AbstractList', r'[] get set remove size') _fix('Java.Util.AbstractSequentialList', r'[] get set remove') _fix('Java.Util.ArrayList', r'[] get set remove') #_fix('Java.Util.CopyOnWriteArrayList', r'[] get set remove') #_fix('Java.Util.LinkedList', r'[] get set remove element getFirst getLast peek peekFirst peekLast poll pollFirst pollLast pop removeFirst removeLast') #_fix('Java.Util.Vector', r'[] get set elementAt firstElement lastElement remove') #_fix('Java.Util.Stack', r'[] peek pop push') #_fix('System.Collections.Generic.IDictionary', r'[] keys values') _fix('Java.Util.Map', r'[] get') # _fix('System.Collections.Generic.Dictionary', r'[]') _fix('Java.Util.AbstractMap', r'[] get') _fix('Java.Util.HashMap', r'[] get') #_fix('Java.Util.ConcurrentHashMap', r'[] get') #_fix('Java.Util.ConcurrentSkipListHashMap', r'[] get') #_fix('Java.Util.EnumMap', r'[] get') #_fix('Java.Util.IdentityHash', r'[] get') #_fix('Java.Util.TreeMap', r'[] get') #_fix('Java.Util.WeakHashMap', r'[] get') # Nested classes need to be handled when enclosing class is loaded # see Box._nestedUnNil below #_fix('Java.Util.Map.Entry', r'getKey getValue') #_fix('Java.Util.AbstractMap.SimpleEntry', r'getKey getValue') #_fix('Java.Util.AbstractMap.SimpleImmutableEntry', r'getKey getValue') _fix('Java.Util.Properties', r'getProperty') _fix('Java.Util.Calendar', 'getInstance getTimeZone') #_fix('System.IO.File', 'create createText open openRead openText openWrite readAllBytes readAllLines readAllText') _fix('Java.Io.File', 'create createText open openRead openText openWrite readAllBytes readAllLines readAllText getPath getAbsolutePath') ##_fixFields('Java.Io.File', 'pathSeparator separator pathSeparatorChar seperatorChar') # TODO #_fix('System.IO.FileSystemInfo', 'name fullName') #_fix('System.IO.TextWriter', 'newLine') #_fix('System.IO.Path', 'combine getFullPath') # combine = File(strA, strB).getPath(), getFullPath = File().getAbsolutePath() #_fix('java.lang.StringBuilder', 'toString') # ?? #_fix('java.lang.Text.RegularExpressions.Regex', 'match replace') #_fix('System.Diagnostics.Process', 'processName') _fix('Java.Util.Regex.Pattern', 'matches matcher pattern split compile') _fix('Java.Util.Regex.Matcher', 'group pattern replaceAll replaceFirst') _fix('Java.Lang.ProcessBuilder', 'command start directory') #_fix('java.lang.Process', 'getInputStream getOutputStream getErrorStream') #_fix('System.Reflection.Assembly', 'getEntryAssembly getExecutingAssembly location') #_fix('System.Reflection.MemberInfo', 'name') #_fix('System.Reflection.FieldInfo', 'fieldType') #_fix('System.Reflection.ParameterInfo', 'parameterType') #_fix('System.Reflection.PropertyInfo', 'propertyType') def jvmFixIndexerMemberSigs # Mapping for (simple) Indexers to java methods. # Fix the listed classes to support Indexors using specified members as accessors and mutators. # called from bindInterface phase so this can only refer to top level Classes in a package. # Initially and currently hard coded in JvmJarSig. # TODO: fixup to specify here like nilableMemberSigs # TODO: this really needs to go in a separate file that the compiler reads each time #print 'fixing Indexers' #Format below is #_AddIdxr('FullClassName', 'accessorMethod mutatorMethod') -- Mutator is optional #_addIdxr('Java.Lang.String', 'charAt') #_addIdxr('Java.Util.Map', 'get put') #_addIdxr('Java.Util.List', 'get set') pass # # Jvm Type Cache def typeForJvmType(jvmType as JavaClassType) as IType? """ Returns the Cobra type for a Java type if the Java type was previously scanned. i.e this is access to the Java Type/Class cache. """ return if(_jvmTypeToIType.containsKey(jvmType), _jvmTypeToIType[jvmType], nil) def addTypeForJvmType(type as IType, jvmType as JavaClassType) require .typeForJvmType(jvmType) in [nil, type] _jvmTypeToIType[jvmType] = type def jvmTypeByName(qualifiedName as String) as JavaClassType """ Obtain the Jvm Type (JavaClassType) given by the fully qualified (cobra) name. """ t as JavaClassType? _jvmTypeCache.tryGetValue(qualifiedName, out t) if t is nil # lookup the JavaClassType by name. t = JarSig.lookupClassByCobraName(qualifiedName) _jvmTypeCache[qualifiedName] = t to passthrough # "to passthrough" instead of "to !" to avoid non-nil check return t to passthrough def installJvmNativeMethods(box as Box, nativeType as NativeType) """Install entries for native static methods on box instances.""" pass #TODO support native static methods on box instances #print '++ TODO scanJvmType.installJvmNativeMethods' /# meths = List() _installClrNativeMethodsFrom('System', nativeType, nativeType, box, meths) _installClrNativeMethodsFrom('System', ClrNativeType(System.Math.getType), nativeType, box, meths) # the next statement can be problematic in that you have to add new DecimalTools methods in Snapshot just so the compiler can see them # ultimately, extensions of primitive types should be supported _installClrNativeMethodsFrom('CobraCoreInternal', ClrNativeType(Cobra.Core.DecimalTools.getType), nativeType, box, meths) _printMethods(meths, box) def compareMethodNames(a as Method, b as Method) as int return a.name.compareTo(b.name) def _printMethods(meths as IList, box as Box) # print out the methods, useful for documentation print print 'type', box.name sharedMeths = for meth in meths where meth.isShared if sharedMeths.count sharedMeths.sort(ref .compareMethodNames) print ' shared' for meth in sharedMeths print ' [meth.cobraSourceSignature(false)]' objectMeths = for meth in meths where not meth.isShared if objectMeths.count objectMeths.sort(ref .compareMethodNames) for meth in objectMeths print ' [meth.cobraSourceSignature]' #/ class Box is partial get _jvmType as JavaClassType """ Returns the Jvm NativeType (System.Class eventually)) boxed in the .nativeType. Throws exception rather than return nil. """ return (.nativeType to JvmNativeType).backEndType def isJvmSystemExceptionClass as bool return .name == 'Exception' and .parentNameSpace and .parentNameSpace.fullName == 'Java.Lang' def prepSystemObjectClassJvm # TODO chk thats this has desired result. # map method getType to java getClass # C#'s typeof(X) is X.getType in Cobra. #existing = .declForName('getClass') to BoxMember #overload = MemberOverload(existing) #.registerOverload(overload) meth = Method(TokenFix.empty, TokenFix.empty, this, 'getType', List(), .compiler.typeTypeProxy, nil, ['shared'], AttributeList(), 'Returns the Type instance that defines this type.') meth.aliasedMethodBacking = 'getClass' #meth.sharedMethodBackingIsAlias = true # not static #overload.addMember(meth) .addDecl(meth) def getIteratorMemberJvm as IMember? """ Step1 of 2 step lookup for iterator/enumerator type - return iterator Member for current box """ getEnum as IMember? if .declForName('iterator') is not nil # Collections getEnum = .symbolForName('iterator', true) return getEnum if .declForName('entrySet') is not nil # Map es = .symbolForName('entrySet', true) est = es.resultType.nonNil to Box getEnum = est.symbolForName('iterator', true) # could look for Enumerable here also return getEnum def getIteratorNextTypeJvm(rt as IType) as IType? """ Step2 of 2 step lookup for iterator/Enumerator type - return the type for iterator.next member for current box rt is the resultType from iterator lookup above - i.e the Iterator for this Box """ if rt inherits Box and (rt to Box).isGeneric rType = rt.memberForName('next').resultType else throw FallThroughException('getEnumeratorMemberType - rt not genericBox [rt]') return rType def scanNativeTypeJvm """ Subclasses should invoke base and then invoke the various _scanXXX methods that are appropriate for them. """ ensure not .needScanNativeType _needScanNativeType = false # print '<> _scanNativeType for [.name] in [_parentNameSpace.fullName], class is [.getType.name]' def scanGenericArgsJvm #print 'scanGenericArgsJvm [.name] [_jvmType.isGenericType]' if _jvmType.isGenericType for genArg in _jvmType.getGenericArguments t = (.compiler to Compiler).typeForJvmType(genArg) if t is nil t = GenericParam(JvmNativeType(genArg), parentDefinition=this) (.compiler to Compiler).addTypeForJvmType(t to !, genArg) _genericParams.add(t) #print 'scanGenericArgsJvm', .nameWithGenericParams # _genericParams def _scanJvmIsNames # TODO _isNames.add('extern') # to make the box like the ones that were in SystemInterfaces.cobra def _scanJvmImplements for interf in _jvmType.getInterfaces if not _badJvmRelatedType(interf) _baseInterfaceProxies.add(JvmTypeProxy(interf)) def _scanJvmNestedTypes for type in _jvmType.getNestedTypes assert type.isNested nativeType = JvmNativeType(type) nativeType.nestedName = nativeType.name.after('$') if type.isClass .addDecl(Class(nativeType, .backEnd)) else if type.isInterface .addDecl(Interface(nativeType, .backEnd)) else if type.isEnum .addDecl(EnumDecl(this, nativeType)) else throw FallThroughException(type) if .declsInOrder.count lastDecl = .declsInOrder[.declsInOrder.count-1] to dynamic if (lastDecl to Object).getType.getProperty('ParentBox') # CC: if lastDecl responds to (get parentBox as Box?) lastDecl.parentBox = this def _isStaticConstant( fi as JavaFieldInfo) as bool return fi.isStatic or fi.name == fi.name.toUpper def _scanJvmFields for fieldInfo in _jvmType.getFields #if fieldInfo.declaringType is not _jvmType, continue if fieldInfo.isDefault, continue # pkgprivate if fieldInfo.isPrivate, continue # Unlike C# leave all static constant fieldnames ((mostly) upcase) as is name = if( _isStaticConstant(fieldInfo), fieldInfo.name, Utils.cobraNameForNativeMemberName(fieldInfo.name)) type = _jvmMemberTypeResultProxy(fieldInfo, fieldInfo.type) attrs = AttributeList() if fieldInfo.isProtected isNames = ['protected'] # isNames = ['protected' 'internal'] #else if fieldInfo.isDefault # pkgprivate # isNames = ['internal'] # else isNames = ['public'] # private was guarded against above if fieldInfo.isFinal and fieldInfo.isStatic # java static final fields are constants value = if(fieldInfo.isStatic, fieldInfo.getValue, nil) initExpr = SharpExpr(TokenFix.empty, if(value, .toString, 'nil')) # DocGenerator.cobra uses this boxConst = BoxConst(TokenFix.empty, TokenFix.empty, this, name, type, isNames, initExpr, attrs, '') boxConst.binaryName = fieldInfo.name .addDecl(boxConst) else if fieldInfo.isStatic, isNames.add('shared') if fieldInfo.isFinal, isNames.add('readonly') # final fields are readonly varr = BoxVar(TokenFix.empty, TokenFix.empty, this, name, type, isNames, nil, attrs, '') varr.binaryName = fieldInfo.name .addDecl(varr) def _scanJvmInitializers for ctorInfo in _jvmType.getConstructors if ctorInfo.isPrivate, continue #if ctorInfo.declaringType is not _clrType, continue skip = false for paramInfo in ctorInfo.getParameters if _badJvmRelatedType(paramInfo) skip = true break if skip, continue params = _scanJvmParams(ctorInfo.getParameters, ctorInfo.isVari, false) isNames = _isNamesForJavaMemberInfo(ctorInfo) attribs = _attribsForJavaMemberInfo(ctorInfo) docString = '' # TODO: get doc string for class? initer = Initializer(TokenFix.empty, TokenFix.empty, this, params, isNames, attribs, docString) overload as MemberOverload? = nil other = .declForName('cue.init') if other if other inherits MemberOverload overload = other else if other inherits AbstractMethod overload = MemberOverload(other) .registerOverload(overload to !) else throw FallThroughException([this, initer, other]) if overload overload.addMember(initer) else .addDecl(initer) def _scanJvmProperties for propInfo in _jvmType.getProperties getMethod = propInfo.getter setMethod = propInfo.setter visible = false if getMethod if getMethod.isPublic or getMethod.isProtected theMethod = getMethod visible = true if not visible and setMethod if setMethod.isPublic or setMethod.isProtected theMethod = setMethod to ! visible = true if not visible, continue #if theMethod.declaringType is not _jvmType, continue if propInfo.isIndexer _scanJvmIndexer(propInfo) continue if _badJvmRelatedType(propInfo.type), continue attribs = _attribsForJavaMemberInfo(propInfo) docString = '' # TODO: get doc string isNames = _isNamesForJavaMemberInfo(theMethod) #print propInfo propName = Utils.cobraNameForNativeMemberName(propInfo.name) #if _declsByName.containsKey(propName), propName = propInfo.name0+'_prop' prop = Property(TokenFix.empty, TokenFix.empty, this, propName, _jvmMemberTypeResultProxy(propInfo, propInfo.type), isNames, attribs, docString) prop.binaryName = propInfo.name if propInfo.isReadable prop.makeGetPart(TokenFix.empty) if propInfo.isWritable prop.makeSetPart(TokenFix.empty) if _declsByName.containsKey(prop.name) # for # Double.naN # unfortunately its common for java libs to use method length() rather than getLength() # lose this when enable postSigFixups handling if prop.name <> 'length' print 'DUP name exists already for property "[prop.name]" on', /#_declsByName[prop.name],#/ .name return # just drop the property; field or method still available .addDecl(prop) def _scanJvmIndexer(propInfo as JavaFieldInfo) for paramInfo in propInfo.getIndexParameters if _badJvmRelatedType(paramInfo) return params = _scanJvmParams(propInfo.getIndexParameters, false, true) attribs = _attribsForJavaMemberInfo(propInfo) docString = '' if propInfo.isReadable isNames = _isNamesForJavaMemberInfo(propInfo.getter to !) else if propInfo.isWritable isNames = _isNamesForJavaMemberInfo(propInfo.setter to !) else throw FallThroughException(propInfo) #name = Utils.cobraNameForNativeMemberName(propInfo.name) name = r'[]' indexer = Indexer(TokenFix.empty, TokenFix.empty, this, name, params, _jvmMemberTypeResultProxy(propInfo, propInfo.type), isNames, attribs, docString) overload as MemberOverload? = nil other = .declForName(name) if other if other inherits MemberOverload overload = other else if other inherits Indexer overload = MemberOverload(other) .registerOverload(overload to !) else throw FallThroughException([this, indexer, other]) #print 'Dbg: add IDXR [_jvmType.name][indexer.name] [propInfo.name]' if overload overload.addMember(indexer) else .addDecl(indexer) # In Java properties are methods with leading is/get/set names # Indexers are methods as for properties but with additional indexes in paramList. def _scanJvmMethods for methInfo in _jvmType.getMethods if methInfo.isPrivate, continue if methInfo.isDefault, continue # pkgPrivate #if methInfo.declaringType is not _clrType, continue skip = false if _badJvmRelatedType(methInfo.returnType) skip = true else for param in methInfo.getParameters if _badJvmRelatedType(param) skip = true break if skip, continue name = Utils.cobraNameForNativeMemberName(methInfo.name) other = .declForName(name) genericParams = List() for genArg in methInfo.getGenericArguments genericParams.add(GenericParam(JvmNativeType(genArg))) params = _scanJvmParams(methInfo.getParameters, methInfo.isVari, false) isNames = _isNamesForJavaMemberInfo(methInfo) if methInfo.isOverride, isNames.add('override') # only on methods attribs = _attribsForJavaMemberInfo(methInfo) docString = '' implementsTypeNode as ITypeProxy? # TODO: explicit interface implementation? method = Method(TokenFix.empty, TokenFix.empty, this, name, genericParams, params, _jvmMemberTypeResultProxy(methInfo, methInfo.returnType), implementsTypeNode, isNames, attribs, docString) method.binaryName = methInfo.name overload as MemberOverload? = nil other = .declForName(name) if other if other inherits MemberOverload overload = other else if other inherits AbstractMethod overload = MemberOverload(other) .registerOverload(overload to !) else if not other inherits BoxVar print 'Unexpected overload (existing named decl) for method "[name]":', other throw FallThroughException([this, method, other]) # here we have a field name (BoxVar) shadowing a method name. # In java this is unambiguous cos all methods are called with () suffix. # In cobra we have to do something else... # currently will choose to drop ( make inaccessible) the field... # ...stupid field begone print 'DUP field "[name]" is shadowing the method "[name]" on [.name],' print ' Dropping the field. It will not be accessible from cobra code' .removeDecl(other) if overload overload.addMember(method) else .addDecl(method) def _scanJvmParams(jparams as List?, isVariMethod as bool, isNotNullable as bool) as List """ Returns a list of Cobra Params given a list of Java ClassTypes (presumably a java parameterList) """ params = List() if not jparams or not jparams.count return params paramN = 0 for javaParam in jparams paramN +=1 isVari = paramN == jparams.count and isVariMethod #and javaParam is an array # TODO support varags detection. #java encodes a variable length paramlist as method.isVarArgs==TRUE and varargs parameter as an array of the the LCD Type ( Object[], String[] ) ( and perhaps args has transient modifier) # TODO: detect nullable on paramlist types ? # To support nilable on params need change representation to a javaParamType containing type + attributes (for param) ( + direction possibly) # Java not support nilable directly so ignore for moment #isNotNull = javaParam.isNonNullable #isNotNullable = false # indexer params not be null others can be parameterType = javaParam type = _jvmMemberTypeProxy(parameterType, isNotNullable) #if isNotNullable, print '>>', javaParam, ' ', type if isVari, type = VariTypeProxy(type) name = 'unkname' # java not keep names of given formal parameters param = Param(name, type) #if isNotNullable # print '>>>' stop # param.writeDeepString param.direction = Direction.In # Java doesnt have Out or InOut equivs params.add(param) return params def _isNamesForJavaMemberInfo(mi as JavaMemberInfo) as List """ Returns the Cobra "is names" such as ['public', 'static'] that correspond to the properties of the JavaMember. """ isNames = List(8) if mi.isDefault, isNames.add('internal') # pkgPrivate/internal and protected # actually #if mi.isProtected # isNames.add('protected') # isNames.add('internal') # TODO: address this later if mi.isProtected, isNames.add('protected') if mi.isPrivate, isNames.add('private') if mi.isPublic, isNames.add('public') if mi.isStatic, isNames.add('shared') if mi.isAbstract, isNames.add('abstract') if mi.isFinal, isNames.add('readonly') return isNames def _attribsForJavaMemberInfo(mi as JavaMemberInfo) as AttributeList return AttributeList() # TODO: def _badJvmRelatedType(t as JavaClassType?) as bool """ Returns true if the given type, which comes from a parameter or return value, is unsupported. For example, it's not public or it's nested. Members with bad types are skipped when scanning DLLs. """ if t is nil return false if t.isNested and not (t.isPublic or t.isProtected)and not t.isGenericParameter # TODO: need the generic param check? print 'Type t.name is nested and not public,protected' return true #if t.isByRef # TODO: or t.isArray # return _badJvmRelatedType(t.getElementType) return false def _jvmMemberTypeProxy(jvmType as JavaClassType?) as ITypeProxy return _jvmMemberTypeProxy(jvmType, false) def _jvmMemberTypeProxy(jvmType as JavaClassType?, notNull as bool) as ITypeProxy """ Returns a type proxy for a member type such as a parameter type. In Java, reference types are nilable by default, but you can pass `true` for `notNull` to indicate there was a NotNull Annotation in the jar metadata. """ if jvmType is nil return .compiler.voidType else if jvmType.isValueType return JvmTypeProxy(jvmType) else # TODO: for generic types, should look at constraints. if constraints don't dictate nilable or not, then need to treat type special during generic construction tp = JvmTypeProxy(jvmType) to ITypeProxy if not notNull tp = NilableTypeProxy(tp) return tp def _jvmMemberTypeResultProxy(member as JavaMemberInfo, jvmType as JavaClassType?) as ITypeProxy """ Returns a type proxy for a member type such as a method return type, property or field. In Java, reference types are nilable by default. """ if jvmType is nil return .compiler.voidType else if jvmType.isValueType return JvmTypeProxy(jvmType) else if jvmType.isValueType or jvmType.isGenericParameter return JvmTypeProxy(jvmType) else notNull = member.isNonNullable t = JvmTypeProxy(jvmType) to ITypeProxy return if(notNull, t, NilableTypeProxy(t)) # Can only do these after bindImplementation phase. Nested classes #_fix('java.util.Map.Entry', r'getKey getValue') #_fix('java.util.AbstractMap.SimpleEntry', r'getKey getValue') #_fix('java.util.AbstractMap.SimpleImmutableEntry', r'getKey getValue') var _nestedUnNil as Dictionary = { 'Java.Util.Map.Entry' : r'getKey getValue', 'Java.Util.AbstractMap.SimpleEntry': r'getKey getValue', 'Java.Util.AbstractMap.SimpleImmutableEntry': r'getKey getValue' } def _fixNestedNilables if .parentBox # nested query = '[.parentBox.qualifiedName].[.name]' #print 'fixNest', query memberNames = _nestedUnNil.get(query, '') if memberNames.length .parentBox.membersToUnNil = memberNames #print ' unNil', memberNames class Class is partial def scanNativeTypeJvm base.scanNativeTypeJvm #print 'scanJvmNativeType ', .name _scanJvmIsNames _scanJvmImplements _scanJvmNestedTypes _scanJvmFields _scanJvmInitializers _scanJvmMethods _scanJvmProperties # do props last since they are synthesized ##_scanJvmEvents TODO # TODO: _scanJvmEnums # TODO: scan all other nested types _fixNestedNilables class Interface is partial def scanNativeTypeJvm base.scanNativeTypeJvm _scanJvmIsNames _scanJvmImplements _scanJvmNestedTypes _scanJvmFields _scanJvmMethods _scanJvmProperties #_scanJvmEvents #TODO _fixNestedNilables class Struct is partial def scanNativeTypeJvm base.scanNativeTypeJvm _scanJvmIsNames _scanJvmImplements _scanJvmNestedTypes _scanJvmFields _scanJvmInitializers _scanJvmMethods _scanJvmProperties #_scanJvmEvents class Extension is partial def scanNativeTypeJvm # this only for Cobra specific extensions. Example: class Extend_String_1939 base.scanNativeTypeJvm _scanJvmIsNames #_scanJvmImplements #_scanJvmNestedTypes #_scanJvmFields #_scanJvmInitializers #_scanJvmProperties _scanJvmMethods #_scanJvmEvents def _scanJvmParams(jparams as List?, isVariMethod as bool, isNotNullable as bool) as List is override # the first argument is implicit in an Extension results = base._scanJvmParams(jparams, isVariMethod, isNotNullable) return results[1:] def jvmExtnNativeType(nativeType as NativeType) as NativeType # the real extended type is the type of the first argument of any method for methInfo in _jvmType.getMethods nativeType = JvmNativeType(methInfo.getParameters[0]) break return nativeType class EnumDecl is partial def setUnderlyingTypeJvm pass def scanNativeTypeJvm # TODO: read attribs _needScanNativeType = false _storageType = .compiler.anyIntType # Not relevant ?? #TODO fake up support for values() and valueOf() and getValue() synthesized in codegen # - or not - how much of C#/Cobra enum capability to support?? /# Enable when have Enum and JavaEnumType in PkgSig and JarSig jvmType = (_nativeType to JvmNativeType).backEndType assert jvmType inherits JavaEnumType # temporary for name, value in jvmType.getConstantValues # list of names and values member = EnumMember(name, value) member.enumDecl = this .addDecl(member) #/ #/