# NativeType wrapper for Java Classes # Eventually will use/handle java native classes but pending that and while cross compiling # wrap a JavaClassType (declared in JvmJarSig.cobra) class JvmNativeType inherits NativeType shared def nativeType(t0 as IType?) as JavaClassType? """Obtain Jvm backEnd Native type from given IType (nonnil Box).""" assert t0 t = t0 to ! if t inherits Box tn = t.nativeType if tn assert tn inherits JvmNativeType return (tn to JvmNativeType).backEndType return nil var _type as JavaClassType # java.lang.Class eventually var nestedName as String? cue init(type as JavaClassType) base.init _type = type def equals(other as Object?) as bool is override if other is this return true if other inherits JvmNativeType return .backEndType == other.backEndType else return false def getHashCode as int is override return .backEndType.getHashCode get backEndType as JavaClassType return _type get name as String is override return .nestedName ? _type.name get fullName as String is override return _type.canonicalName get isValueType as bool is override #return _type.isValueType # fix for char, int, bool, long etc vs Boxed Classes return false get baseType as NativeType? is override super = _type.getSuperClass if not super, return nil return JvmNativeType(super) # cache? #if(_type.superclass.length, JvmNativeType(_type.superclass), nil) def customAttributes as IList is override return .backEndType.getAnnotations #to IList get isSystemObjectClass as bool is override return /#_type and #/ .fullName == 'java.lang.Object' get isSystemTypeClass as bool is override return /# _type and #/ .fullName == 'java.lang.Class' def toString as String is override return 'JvmNativeType([_type])' def toTechString as String return .toString class JvmTypeProxy inherits NativeTypeProxy """ Acts as an ITypeProxy where the Jvm type is known. Typically used when scanning DLLs. """ shared var _cobraNameForJvmGenericNameCache = Dictionary() def cobraNameForJvmType(jvmType as JavaClassType) as String """ Returns 'Foo' for 'Foo' and 'Foo' for 'Foo' Converts generic and non-generic classes and interfaces. Does *not* work for arrays, etc. """ name = jvmType.name if not jvmType.isGenericType or jvmType.isGenericParameter return name if _cobraNameForJvmGenericNameCache.containsKey(name) return _cobraNameForJvmGenericNameCache[name] else count = jvmType.genericArgsCount assert count >0 cobraName = name + ') Returns 'Foo' for 'Foo' and 'Foo' for 'Foo`2' Works on generic and non-generic classes, structs and interfaces. Does *not* work for arrays etc. """ if '`' not in name, return name if _cobraNameForJvmGenericNameCache.containsKey(name) return _cobraNameForJvmGenericNameCache[name] else parts = name.split(c'`') count = int.parse(parts[1]) cobraName = parts[0] + ' 9 # should have bool, char, all the ints, etc. # Must return the Cobra primitive types in place of System.Boolean, System.Char, System.Int16, etc. # because it's the primitives that are used all over the compiler. jvmPrimitiveToIType = .compiler.primitiveToITypeCache if jvmPrimitiveToIType is nil or jvmPrimitiveToIType.count == 0 _initPrimToITypeCache jvmPrimitiveToIType = .compiler.primitiveToITypeCache assert jvmPrimitiveToIType is not nil and jvmPrimitiveToIType.count <> 0 basicType as IType? if jvmPrimitiveToIType.tryGetValue(jvmType, out basicType) return basicType to ! # handle wrapped types, like arrays, with recursive calls if jvmType.isArray #assert jvmType.name.endsWith(r'[]') # could be [,] so TODO: handle multidim arrays return .typeProvider.arrayType(_realTypeWithCache(jvmType.arrayComponentType to !)) else if jvmType.isNested and not jvmType.isGenericParameter declaringType = _realTypeWithCache(jvmType.declaringType to !) cobraTypeName = .cobraNameForJvmBoxName(jvmType.nestedName) potential = declaringType.memberForName(cobraTypeName) #(jvmType.name) if potential is nil (declaringType to dynamic).dumpDeclNames .throwError('JvmType: Cannot locate nested Jvm type "[jvmType]" (simple name is "[jvmType.name], cobraName is [cobraTypeName]").') else if potential inherits IType return potential else .throwError('JvmType:Located Jvm type spec "[jvmType]" but got a [potential.englishName] instead of a type.') # generic parameters if jvmType.isGenericParameter return GenericParam(JvmNativeType(jvmType)) typeName = _computeCobraTypeName(jvmType) missing = false curNS = _computeNameSpace(jvmType, level, out missing) if missing .throwError('JvmType: Cannot find Jvm type "[jvmType.canonicalName]" in package "[jvmType.package]".') # since the type exists, but cannot be located in our namespaces, # it must be pulled from a dependent DLL that was not directly referenced # but maybe it was already attempted #if level > 0, .throwError('Cannot read Jvm type "[jvmType.fullName]" or its package "[jvmType.package]". Please report to the Cobra discussion forums (http://cobra-language.com/).') #(.compiler to dynamic).jvmReadAssembly(clrType.assembly) #return _realTypeWithoutCache(jvmType, level+1) # recurse. guard is just above. # return namespace member member as IMember? = curNS.declForName(typeName) if member inherits IType if member inherits Box if jvmType.isGenericType and not jvmType.isGenericTypeDefinition # So we have something like ICollection> which is all Generic types. # We need the Cobra types of those args so we can construct the Cobra type from the generic cobra type # otherwise, we would just end up returning the generic definition. #print 'Dbg: JvmType.realTypeWithoutCache generic type [jvmType.canonicalName] [member.name].' member = _typeForJvmArgsOfGeneric(jvmType, member) return member else print '[typeName] not in [curNS.name] declsforName' #curNS.dumpDeclNames msg = 'JvmType: Cannot locate jvm type "[jvmType]".' if jvmType.package.length and jvmType.package.startsWith('java.lang') if .compiler and .compiler.verbosity > 1, print msg # TODO: .compiler.warning(msg) return .compiler.objectType else .throwError(msg) return .compiler.intType # CC: to make C# code gen happy. # make dict same as PrimitiveTypesDict but keyed by dynamic so not typed to nativeType/JavaClassType # and set to Compiler. def _initPrimToITypeCache typeToIType = _makePrimitiveTypesDict jvmPrimitiveToIType = Dictionary() for key in typeToIType.keys jvmPrimitiveToIType[key] = typeToIType[key] (.compiler to Compiler).primitiveCache = jvmPrimitiveToIType #to ! # primitiveTypes java/nativeClassType: cobraBasicType # like Byte: IntType(signed,8), ... Long: IntType(signed, 64) # implies 1:1 nativeClassType: cobraBasicType - needs fixing def _makePrimitiveTypesDict as IDictionary primitiveToIType = Dictionary() for bt in .compiler.basicTypes if bt.systemAliasProxy # lookup by qualified name (includes translation) and pull out (jvm) NativeType key = (.compiler.nativeType((bt.systemAliasProxy to LibraryTypeProxy).qualifiedName) to JvmNativeType).backEndType primitiveToIType[key] = bt #print '<.', key.name, bt #print '<..', primitiveToIType.count assert primitiveToIType.count == 0 or primitiveToIType.count >=8 return primitiveToIType def _computeCobraTypeName(jvmType as JavaClassType) as String typeName = jvmType.name if jvmType.isGenericType # generic like IComparable`1 assert r'[' not in typeName typeName = .cobraNameForJvmType(jvmType) else if not typeName[typeName.length-1].isLetterOrDigit .throwError('JvmType: Cannot locate JVM type "[jvmType.canonicalName]".') return typeName def _computeNameSpace(jvmType as JavaClassType, level as int, missing as out bool) as NameSpace missing = false if not jvmType.package.length, return .compiler.globalNS nameParts = jvmType.packageAsCobra.split(c'.') member = .compiler.globalNS.symbolForName(nameParts[0]) if member inherits NameSpace, curNS = member else, missing = true if not missing i = 1 while i < nameParts.length namePart = nameParts[i] possible = curNS.declForName(namePart) if possible is nil missing = true break else if possible inherits NameSpace curNS = possible else .throwError('JvmType: Found "[namePart]" at component [i+1] of JVM type "[jvmType.canonicalName]", but it is a [possible.englishName].') i += 1 return curNS /# def _typeForArgsOfGeneric(jvmType as JavaClassType, member as IType) as IType args = List() for genArg in jvmType.getGenericArguments args.add(_realTypeWithCache(genArg)) boxMember = member to Box if boxMember.qualifiedName == 'System.Nullable' assert args.count == 1 member = .typeProvider.nilableType(args[0]) else member = boxMember.constructedTypeFor(args) return member #/ def _typeForJvmArgsOfGeneric(jvmType as JavaClassType, member as IType) as IType args = List() for genArg in jvmType.getGenericArguments args.add(_realTypeWithCache(genArg)) boxMember = member to Box #trace jvmType, boxMember, args member = boxMember.constructedTypeFor(args) return member