Ticket #275: java-jvm-part2.patch
File java-jvm-part2.patch, 165.8 KB (added by hopscc, 13 years ago) |
---|
-
Source/BackEndJvm/JvmJarSig.cobra
1 # Java back end 2 # Responsible for turning a jarfile name into an object holding a description/signature of 3 # the jarfile contents suitable for reflecting on - this is roughly similar to a .Net Assembly. 4 5 # Supporting this requires delving through java jar files and obtaining class info which we cant easily 6 # do in a .Net program 7 # so until we have a java implementation of the cobra compiler we instead rely on a java helper program 8 # (see pkgSig.java and pkgSig.class, pkgSig.jar in the cobra distribution) 9 10 # This is expected to have been run and creates what we call a pkgSignature file (pkgSig File) that is 11 # named the same as a jarfile (or the same as a java package) with a '.sig' extension' and 12 # contains an easily parseable text description of the classes and interfaces in the jarfile or package 13 # this sigfile is expected to be in an obvious place, currently the cwd or same place as the cobra compiler executable.... 14 # 15 # e.g. 'rt.jar' (java runtime classes) has a sigfile 'rt.jar.sig' 16 # 'java.lang' (java package) has a sigfile 'java.lang.sig' 17 18 class JarSig 19 20 var name = '' # jarfile or pkg 21 var location = '' # abs pathname of sigFile 22 var _javaTypes as List<of JavaClassType> # lists of classes, interfaces or Enums in this jarfile or pkg 23 24 shared 25 var classByNameCache = Dictionary<of String, JavaClassType>() 26 """All classes found in all jars keyed by canonical/full name.""" 27 28 def lookupClass(fullName as String) as JavaClassType 29 """ Lookup class by full/canonicalName.""" 30 if not JarSig.classByNameCache.containsKey(fullName) 31 if fullName.startsWith(r'['), .addArrayClass(fullName) 32 else if fullName.contains(r'<'), .addGenericInstClass(fullName) 33 else if not fullName.contains('.'), .addGenericParamClass(fullName) 34 else 35 print 'Dbg:JarSig.lookupClass - unknown class:[fullName]' 36 #print 'Lookup class', fullName 37 return JarSig.classByNameCache[fullName] 38 39 def addArrayClass(aName as String) 40 """Array classes are synthesized on reference assuming element class already exists.""" 41 print 'Dbg crt ArrayClass "[aName]"' 42 elName = aName.replace(r'[','') 43 branch elName 44 on 'Z', elName = 'boolean' 45 on 'B', elName = 'byte' 46 on 'I', elName = 'int' 47 on 'S', elName = 'short' 48 on 'J', elName = 'long' 49 on 'C', elName = 'char' 50 on 'D', elName = 'double' 51 on 'F', elName = 'float' 52 else 53 if elName.startsWith('L') and elName.endsWith(';') 54 elName = elName[1:-1] # e.g. Ljava.lang.Integer; 55 else 56 print 'Unknown arrayName [elName]' 57 assert false, 'arrayName [elName]' 58 if not JarSig.classByNameCache.containsKey(elName) 59 print 'Dbg: class "[elName]" not in classByNameCache "[aName]"' 60 #elType = JarSig.classByNameCache[elName] 61 elType = JarSig.lookupClass(elName) 62 arrayCls = JavaClassType(aName, elType) # ArrayType 63 JarSig.classByNameCache[aName] = arrayCls 64 print 'Dbg: added ArrayOf_[elName] "[aName]"' 65 66 def addGenericInstClass(fullName as String) 67 """ 68 Generic class being instantiated. 69 e.g. com.x.MyClass<com.x.Inst, java.lang.String> 70 Synthesized (here) as a result of being referenced. 71 """ 72 print 'Dbg crt GenericInstClass "[fullName]"' 73 assert fullName.contains('<') and fullName.endsWith('>') 74 canonName = fullName.beforeL('<') 75 assert canonName.contains('.') 76 idx = canonName.lastIndexOf('.') 77 gName = canonName[idx+1:] 78 pkg = canonName[0:idx] 79 paramTypes = fullName.afterL('<')[0:-1] # drop end '>' 80 print 'Dbg: GenericInstanceClass "[pkg]" "[gName]" "[paramTypes]' 81 giCls = JavaClassType(gName, pkg, paramTypes) 82 JarSig.classByNameCache[fullName] = giCls 83 # JarSig.registerClassType(pkg, giCls) 84 print 'Dbg: added GenericInstanceClass "[fullName]"' 85 86 def addGenericParamClass(name as String) 87 print 'Dbg crt Generic Param Class "[name]"' 88 gparamCls = JavaClassType(name, JavaType.GenericParam, '') 89 JarSig.classByNameCache[name] = gparamCls 90 print 'Dbg: added Generic Parameter Class "[name]"' 91 92 def sigFile(name as String) as String is shared 93 """ 94 Check that a sig file exists for the given name (jarfile or pkgname). 95 Return the sig filename if found, InvalidOperationException if not 96 """ 97 assert not name.endsWith('.sig') 98 sigFile = name + '.sig' 99 if File.exists(sigFile) 100 fileName = sigFile 101 #if not Path.IsPathRooted(sigFile) 102 # fileName = Path.getFullPath(sigFile) 103 else 104 ccPath = Path.getDirectoryName(CobraCore.exePath) to ! 105 absName = Path.combine(ccPath, sigFile) 106 if File.exists(absName) 107 fileName = absName 108 else 109 throw InvalidOperationException('Cannot find a PkgSig file for "[name]" ("[sigFile]") in cwd or [ccPath].') 110 return fileName 111 112 cue init(jarName as String) 113 base.init 114 .name = jarName 115 _javaTypes = List<of JavaClassType>() 116 _genTypesList 117 _aliasPrimitives 118 119 def _genTypesList 120 jarName = if(.name.endsWith('.sig'), .name[:-4], .name) 121 fileName = JarSig.sigFile(jarName) 122 .location = fileName 123 desc = List<of String>() 124 for line in File.readAllLines(fileName) 125 if line.trim.startsWith('#'), continue 126 if line.length == 0 127 if desc.count == 0, continue 128 jct = JavaClassType.makeFromDesc(desc) 129 _registerClassType(jct) 130 desc.clear 131 continue 132 desc.add(line) 133 134 if desc.count >0 135 jct = JavaClassType.makeFromDesc(desc) 136 _registerClassType(jct) 137 138 def _registerClassType(jct as JavaClassType) 139 _javaTypes.add(jct) 140 canonName = jct.canonicalName 141 if '`' in canonName # jct.isGeneric 142 canonName = canonName.beforeL('`') 143 #parts = canonName.split('`') 144 #canonName = parts[0] 145 JarSig.classByNameCache[canonName] = jct 146 147 def _aliasPrimitives 148 if JarSig.classByNameCache.containsKey('void') 149 return 150 # ['void', 'boolean','byte', 'short', 'int', 'long', 'float', 'double'] 151 JarSig.classByNameCache['void'] = JarSig.classByNameCache['java.lang.Void'] 152 JarSig.classByNameCache['boolean'] = JarSig.classByNameCache['java.lang.Boolean'] 153 JarSig.classByNameCache['char'] = JarSig.classByNameCache['java.lang.Character'] 154 JarSig.classByNameCache['byte'] = JarSig.classByNameCache['java.lang.Byte'] 155 JarSig.classByNameCache['short'] = JarSig.classByNameCache['java.lang.Short'] 156 JarSig.classByNameCache['int'] = JarSig.classByNameCache['java.lang.Integer'] 157 JarSig.classByNameCache['long'] = JarSig.classByNameCache['java.lang.Long'] 158 JarSig.classByNameCache['float'] = JarSig.classByNameCache['java.lang.Float'] 159 JarSig.classByNameCache['double'] = JarSig.classByNameCache['java.lang.Double'] 160 161 162 163 def getExportedTypes as JavaClassType* 164 return _javaTypes 165 166 def toString as String is override 167 """ For testing dump rep of jarSig""" 168 sb = StringBuilder('[.name]: ') 169 sb.append(' [_javaTypes.count] types') 170 return sb.toString 171 172 # 173 # Below are classes describing JavaTypes (class), JavaFields, Java Ctors and JavaMethods 174 # They are temporary placeholders until can get a native implementation and direct access to Java RTL equivalents. 175 176 enum JavaType 177 NoType, JavaClass, JavaInterface, JavaEnum, GenericParam 178 179 180 class JavaClassType # Simplified System Type for java classes, interface, enum 181 """ Descriptor for a java class - equivalent of java.lang.Class for cobra in .Net""" 182 shared 183 var emptyClassList = List<of JavaClassType>() 184 var _emptyFieldList = List<of JavaFieldInfo>() 185 var _emptyCtorList = List<of JavaCtorInfo>() 186 var _emptyMethodList = List<of JavaMethodInfo>() 187 var _emptyStringList = List<of String>() 188 189 def genClassTypeList(names as List<of String>) as List<of JavaClassType> 190 """ Generate JavaClassType List for list of names.""" 191 classList = List<of JavaClassType>() 192 for name in names 193 cls = JarSig.lookupClass(name) 194 classList.add(cls) 195 return classList 196 197 198 var name = '' 199 var package = '' 200 var type = JavaType.NoType #class,interface, enum 201 var superclass = '' 202 var modifiers as List<of String> 203 var interfaceNames as List<of String> 204 var _interfaces as List<of JavaClassType> = JavaClassType.emptyClassList 205 206 var _fields as List<of JavaFieldInfo> = JavaClassType._emptyFieldList # JavaFieldInfo* 207 var _props as List<of JavaFieldInfo> = JavaClassType._emptyFieldList # JavaFieldInfo* 208 var _ctors as List<of JavaCtorInfo> = JavaClassType._emptyCtorList # JavaCtorInfo* 209 var _methods as List<of JavaMethodInfo> = JavaClassType._emptyMethodList # JavaMethodInfo* 210 211 # TODO split these out as subclass 212 var _isGenericDefn = false 213 var _isGenericInst = false 214 var _isGenericParam = false 215 var _genParamNames as List<of String> = JavaClassType._emptyStringList 216 var _genParams as List<of JavaClassType> = JavaClassType.emptyClassList # generic params list 217 set genParamNames from var 218 219 var _isArray = false 220 var _arrayDimension = 0 221 var _arrayComponentType as JavaClassType? = nil 222 223 def makeFromDesc(descriptor as List<of String>) as JavaClassType is shared 224 """ 225 Generate a populated JavaClassType from a string descriptor. 226 227 Descriptor entry for a Type (as per pkgSig output), single entry per line ( or '-' ), 228 entries nl terminated 229 230 <Type> <absolute classname> 231 <Type> # Class, Interface or Enum 232 <Pkg> 233 <Name> #simple Name 234 <absolute superclass name> 235 <absolute interface names implemented> #comma separated 236 <modifiers> # spc separated 'static', 'default', 'public', 'protected' 237 var <name> # 0 or more fields 238 <modifiers> 239 <full TypeName> 240 <attributes> 241 ... 242 ctor <absClassName> # 0 or more constructors 243 <paramList> # comma sep list of typeNames 244 ... 245 method name # 0 or more methods 246 modifiers 247 returnType 248 paramList 249 throwsList 250 ... 251 Descriptor is parsed and info and various field, ctor, method and property lists populated. 252 """ 253 254 fieldList = List<of JavaFieldInfo>() 255 propList = List<of JavaFieldInfo>() 256 props = Dictionary<of String, JavaFieldInfo>() # cache for inferred propertyNames 257 ctorList = List<of JavaCtorInfo>() 258 methodList = List<of JavaMethodInfo>() 259 260 lines = descriptor 261 assert lines.count >= 7 262 263 # header - fixed length and format; absName, type, pkg, name, superclass, interfacesList, ModifiersList 264 absName = _popTop(lines) # absolute class name 265 CobraCore.noOp(absName) 266 branch _popTop(lines).toLower 267 on 'class', type = JavaType.JavaClass 268 on 'interface', type = JavaType.JavaInterface 269 on 'enum', type = JavaType.JavaEnum 270 else, type = JavaType.NoType 271 pkg = _popTop(lines) 272 name = _popTop(lines) 273 isGen = name.contains('`') 274 super = _popTop(lines) 275 if super == '-', super = '' 276 interfaces = _parseList(_popTop(lines), [c',']) 277 modifiers = _parseList(_popTop(lines), [c' ']) 278 if isGen, gParamNames = _parseList(_popTop(lines), [c',']) 279 while true 280 et = _popTop(lines) 281 if et.length == 0, break 282 283 if et.startsWith('var ') 284 varName = et[3:].trim 285 field = JavaFieldInfo() 286 field.name = varName 287 288 assert lines.count >= 2 289 # procField(et, subline, field, fieldList) 290 field.modifiers = _parseList(_popTop(lines), [c' ']) 291 field.typeName = _popTop(lines) 292 if type == JavaType.JavaEnum 293 field.value = _popTop(lines) 294 #field.attributes = _parseList(_popTop(lines), [c',']) 295 fieldList.add(field) 296 297 else if et.startsWith('ctor ') 298 ctorName = et[4:].trim 299 ctor = JavaCtorInfo() 300 ctor.name = ctorName 301 assert lines.count >= 1 302 ctor.paramNames = _parseList(_popTop(lines), [c',']) 303 # attributes ?? 304 ctorList.add(ctor) 305 306 else if et.startsWith('method ') 307 methodName = et[6:].trim 308 if methodName.endsWith(r'[V]') # hack encoding flags 309 methodName = methodName[:-3] 310 isVari = true 311 method = JavaMethodInfo() 312 method.name = methodName 313 method.modifiers = _parseList(_popTop(lines), [c' ']) 314 method.returnTypeName = _popTop(lines) 315 assert method.returnTypeName <> '-' 316 method.paramNames = _parseList(_popTop(lines), [c',']) 317 method.throwsList = _parseList(_popTop(lines), [c',']) 318 # attributes ?? 319 if isVari, method.attributes = ['IsVari'] 320 methodList.add(method) 321 322 # map method getters and setters to property 323 propName = .chkForProp(methodName, method) 324 if propName 325 _genProp(method, propName, propList, props) 326 else 327 print 'Unknown item in class: [et]' 328 329 jct = JavaClassType(name, pkg, type, super, interfaces, modifiers) 330 if isGen, jct.genParamNames = gParamNames 331 jct._fields = fieldList 332 jct._props = propList 333 jct._ctors = ctorList 334 jct._methods = methodList 335 return jct 336 337 def _parseList(et as String, seps as List<of char> ) as List<of String> is shared 338 if et == '-' 339 l = List<of String>() 340 else 341 l = et.split(seps.toArray).toList 342 return l 343 344 def _popTop(content as List<of String>) as String is shared 345 while true 346 if content.count == 0 347 return '' 348 e = content[0] 349 content.removeAt(0) 350 351 if e.trim.startsWith('#') # commentline 352 continue 353 idx = e.indexOf('#') # trailing comment 354 if idx >= 0 355 e = e[:idx] 356 e = e.trimEnd to ! 357 if not e.length, continue 358 break 359 return e.trim 360 361 # property: get<Propname> and no paramList and returnType is Property Type or 362 # is<PropName> and no paramList and returnType is bool 363 # and set<PropName> and 1 parameter (value to set) 364 def chkForProp(methodName as String, method as JavaMethodInfo) as String? is shared 365 tag = methodName[:3] 366 if tag in [ 'get', 'set'] and methodName.length > 3 and method.modifiers.contains('public') 367 if tag == 'set' and method.paramNames.count <> 1 # setXXXX without a single param 368 return nil 369 return methodName[3:] 370 if methodName.startsWith('is') and method.paramNames.count == 0 and method.returnTypeName == 'boolean' and method.modifiers.contains('public') 371 return methodName[2:] 372 return nil 373 374 # indexer: get<Propname> and has params - first param in paramList is index (retType is Property Type) 375 # or set<PropName> and more than value in paramList, 1st parameter is index and second is value to set. 376 def isIndexer(methodName as String, method as JavaMethodInfo, isSetProp) as bool is shared 377 if methodName.startsWith('is') 378 return false 379 assert methodName.startsWith('get') or methodName.startsWith('set') 380 isGetProp = not isSetProp 381 return (isGetProp and method.paramNames.count) or (isSetProp and method.paramNames.count > 1) 382 383 def _genProp(method as JavaMethodInfo, propName as String, propList as List<of JavaFieldInfo>, props as Dictionary<of String, JavaFieldInfo>) as JavaFieldInfo is shared 384 """ Create or update property fm getter/setter method and update given List and Dict. """ 385 assert method.name.startsWith('get') or method.name.startsWith('set') or method.name.startsWith('is') 386 isSetProp = method.name.startsWith('set') 387 isGetProp = not isSetProp 388 #print method.name, propName 389 if props.containsKey(propName) 390 prop = props[propName] 391 else # no existing property 392 prop = JavaFieldInfo() # JavaPropInfo 393 prop.name = propName 394 prop.isProp = true 395 prop.isIndexer = .isIndexer(method.name, method, isSetProp) 396 prop.isReadable = prop.isWritable = false 397 props[propName] = prop 398 propList.add(prop) 399 method.prop = prop 400 #print '-- new Prop' 401 if isGetProp 402 prop.isReadable = true 403 prop.getter = method 404 if not prop.typeName.length and method.returnTypeName.length, prop.typeName = method.returnTypeName 405 #prop.name0 = method.name 406 #print '-- isGetProp' 407 else #isSetProp 408 prop.isWritable = true 409 prop.setter = method 410 #print '-- isSetProp' 411 if not prop.typeName.length and method.paramNames.count, prop.typeName = method.paramNames[0] 412 if not prop.modifiers.count or not prop.modifiers[0].length, prop.modifiers = method.modifiers 413 if not prop.attributes.count, prop.attributes = method.attributes 414 assert prop.name.length 415 assert prop.typeName.length 416 return prop 417 418 cue init(name as String, pkg as String, type as JavaType, super as String, ifcs as List<of String>, modifiers as List<of String> ) 419 """Create a normal Class or GenericClass Defn. MyClass or MyClass<T>""" 420 base.init 421 assert not name.contains(".") 422 .name = name 423 .package = pkg 424 .type = type 425 .superclass = super 426 .interfaceNames = ifcs 427 .modifiers = modifiers 428 429 _isGenericDefn = name.contains('`') # Generic types have name suffix `<nGenericArgs> 430 431 #print '[type] [pkg].[name]' 432 assert .name.length 433 assert .type <> JavaType.NoType 434 if .type == JavaType.JavaClass and .canonicalName <> 'java.lang.Object' 435 assert '.' in .superclass # canonical form 436 assert .package.length 437 438 cue init(name as String, elementType as JavaClassType) 439 """Create an ArrayType.""" 440 base.init 441 .name = name 442 .package = elementType.package 443 .type = JavaType.JavaClass 444 .superclass = 'java.lang.Object' # not really - closest is javax.openmanagment.mbean.ArrayType 445 # maybe should fake up an Abstract ArrayBaseType providing methods, etc synthesized below 446 .modifiers = elementType.modifiers 447 .interfaceNames = JavaClassType._emptyStringList 448 449 _isArray = true 450 _arrayComponentType = elementType 451 _arrayDimension = name.count(c'[') 452 453 # has properties 'length' and method 'getLength' and indexer for get and set 454 methodList = List<of JavaMethodInfo>() 455 method = JavaMethodInfo() 456 method.name = 'getLength' 457 method.modifiers = ['public'] 458 method.returnTypeName = 'int' 459 method.paramNames = JavaClassType._emptyStringList 460 methodList.add(method) 461 462 propList = List<of JavaFieldInfo>() 463 prop = JavaFieldInfo() 464 prop.name = 'length' 465 prop.typeName = 'int' 466 prop.modifiers = ['public'] 467 prop.isProp = true 468 prop.isIndexer = false 469 prop.isReadable = true 470 method.prop = prop 471 prop.getter = method 472 prop.isWritable = false 473 propList.add(prop) 474 475 idxr = JavaFieldInfo() 476 idxr.name = r'[]' 477 idxr.typeName = name.replace(r'[', r'') 478 idxr.modifiers = ['public'] 479 idxr.isProp = true 480 idxr.isIndexer = true 481 idxr.isReadable = true 482 idxr.isWritable = true 483 # TODO getter return type same as typeName 484 # TODO setter params List 'int' 485 propList.add(idxr) 486 487 _props = propList 488 _methods = methodList 489 490 assert .name.length 491 assert .type <> JavaType.NoType 492 if .type == JavaType.JavaClass and .canonicalName <> 'java.lang.Object' 493 assert '.' in .superclass # canonical form 494 assert .package.length 495 496 assert _arrayDimension >0 497 assert _arrayComponentType 498 assert .name.contains(r'[') 499 500 cue init(name as String, pkg as String, paramTypes as String) 501 """Create a Generic Instantiation Type. Like MyClass<java.Lang.String>""" 502 base.init 503 print 'JavaClassType.init([name])' 504 assert not name.contains('.') 505 #assert pkg.contains('.') 506 gPart = '[pkg].[name]' 507 paramList = JavaClassType._parseList(paramTypes, [c',']) 508 print 'Looking for Generic Class [gPart]' 509 genType = JarSig.lookupClass(gPart) 510 assert genType.isGenericTypeDefinition 511 512 .name = name 513 .package = pkg # genType.package 514 .type = genType.type 515 .superclass = genType.canonicalName # not really but thats how we'll fake it 516 #.superclass = 'java.lang.Object' 517 .modifiers = genType.modifiers 518 .package = genType.package 519 _isGenericInst = true 520 521 .interfaceNames = JavaClassType._emptyStringList 522 _genParamNames= paramList 523 524 #print '[type] [pkg].[name]' 525 assert .name.length 526 assert .type <> JavaType.NoType 527 assert '`' in .superclass # fake parentage to the Generic Definition 528 assert .package.length 529 530 cue init(name as String, jType as JavaType, pkg as String) 531 """Create a Generic Parameter Type. Like the T of MyClass<T>""" 532 base.init 533 assert jType == JavaType.GenericParam 534 assert not name.contains("<") and not name.contains(">") 535 assert not name.contains(".") 536 #assert name[0].isUpper # ?? 537 538 .name = name 539 .type = jType 540 .superclass = 'java.lang.Object' # not really but thats how we'll fake it 541 .package = pkg 542 if not .package.length, .package = 'java.lang' 543 .modifiers = ['public'] 544 545 _isGenericParam = true 546 547 .interfaceNames = JavaClassType._emptyStringList 548 549 #print '[type] [pkg].[name]' 550 assert .name.length 551 assert .type <> JavaType.NoType 552 assert 'Object' in .superclass 553 assert .package.length 554 555 556 #pro name from var 557 #pro package from var 558 # ... 559 560 get canonicalName as String 561 """package and name""" 562 assert .name.length 563 return if(.package.length, '[.package].[.name]', .name) 564 565 get isClass as bool 566 return .type == JavaType.JavaClass 567 568 get isInterface as bool 569 return .type == JavaType.JavaInterface 570 571 get isEnum as bool 572 return .type == JavaType.JavaEnum 573 574 get isNested as bool 575 #return .flags.contains('N') 576 return .name.contains('$') and not .name.startsWith('$') # temporary hack 577 578 get declaringType as JavaClassType? 579 if .isNested 580 assert .name.contains('$') 581 declName = .name.beforeL('$') 582 #idx = .name.indexOf('$') 583 #declName = .name[:idx] 584 trace declName 585 # return JarSig.classByNameCache[declName] 586 return JarSig.lookupClass(declName) 587 return nil 588 589 get isPublic 590 return .modifiers.contains('public') 591 get isProtected 592 return .modifiers.contains('protected') 593 get isPrivate 594 return .modifiers.contains('private') 595 get isDefault 596 return .modifiers.contains('default') # = protected + package 597 get isStatic 598 return .modifiers.contains('static') 599 get isFinal # sealed 600 return .modifiers.contains('final') 601 get isAbstract 602 return .modifiers.contains('abstract') 603 604 def getSuperClass as JavaClassType? 605 if not .superclass.length 606 return nil 607 #return JvmNativeType(_type.getSuperClass) 608 if JarSig.classByNameCache.containsKey(.superclass) 609 return JarSig.lookupClass(.superclass) 610 #return JarSig.classByNameCache[.superclass] 611 else 612 #return JarSig.classByNameCache['java.lang.Object'] 613 return JarSig.lookupClass('java.lang.Object') 614 # e.g. Abstract base classes with default access - java.lang.AbstractStringBuilder 615 #else 616 # synth = SyntheticObject(.superclass) 617 # JarSig.classByNameCache[.superclass] = synth 618 # return synth 619 620 get isValueType as bool 621 return false # TODO true for unboxed primitives... 622 623 # TODO hops array handling 624 get isArray as bool 625 return _isArray 626 627 get arrayComponentType as JavaClassType? 628 #if not .isArray, return nil 629 assert .isArray 630 print 'JavaClassType Array support NYI [.canonicalName]' 631 return _arrayComponentType 632 633 get arrayDimension as int 634 require .isArray 635 assert _arrayDimension > 0 636 return _arrayDimension 637 638 # TODO hops Generics handling 639 # Two forms of Generic Types: Definition ( MyClass<T>) and Instantiation ( MyClass<java.lang.String>) 640 # In java with runtime generic Type instantiation all we see from the jarfile directly are definitions (:-( 641 # Walking the classes and getting the class(names) referenced (params, intefaces, returnTypes,...) 642 # gives us the names of the instantiations which we synthesize as Types or Params for our purposes... 643 644 get isGenericType as bool 645 return _isGenericDefn or _isGenericInst or _isGenericParam 646 647 get genericArgsCount as int 648 assert .isGenericType 649 #return _genArgNames.count # number of Generic args associated with this Generic Type 650 # We use dotNet naming here where generic (defn) classes are named with trailing '`<nTypeParams>' 651 if _isGenericDefn 652 parts = .name.split(c'`') 653 return int.parse(parts[1]) 654 else if _isGenericInst 655 return _genParamNames.count 656 else 657 return 0 658 659 get isGenericParameter as bool 660 """ 661 assumes generic parameters are instantiated as Types. 662 Things like T,U,E,.. - basically simple names not package specified - probably 1 Upcase char 663 """ 664 return _isGenericParam 665 666 get isGenericTypeDefinition as bool 667 """ 668 Can use this generic type to create new types if this type is a template form. 669 e.g myClass<T, U> defn allows creating new type like MyClass<String, int> 670 """ 671 assert .isGenericType 672 return _isGenericDefn 673 674 def getGenericArguments as JavaClassType* #List<of JavaClassType> 675 assert .genericArgsCount 676 if false # tmp pending jarSig gen and loading of generic args list 677 assert _genParamNames.count 678 if _genParamNames.count and not _genParams.count 679 _genParams = JavaClassType.genClassTypeList(_genParamNames) 680 return _genParams 681 682 683 def getInterfaces as JavaClassType* #List<of JavaClassType> 684 if .interfaceNames.count and not _interfaces.count 685 _interfaces = JavaClassType.genClassTypeList(.interfaceNames) 686 return _interfaces 687 688 def getFields as JavaFieldInfo* 689 return _fields 690 691 def getConstructors as JavaCtorInfo* 692 return _ctors 693 694 def getMethods as JavaMethodInfo* 695 return _methods 696 697 def getProperties as JavaFieldInfo* 698 return _props 699 700 def getAnnotations as IList<of dynamic> 701 # TODO when store annotations in .sigfile - return as a list of classes 702 #return List<of JavaClassType>() 703 return @[] to IList<of dynamic> 704 705 706 get fields from var 707 get props from var 708 get ctors from var 709 get methods from var 710 711 #dbg 712 def toMinString as String 713 return '[.type] [.canonicalName]' 714 715 def toString as String is override 716 sb = StringBuilder() 717 sb.append('[.type] [.canonicalName]') 718 if _genParamNames.count 719 sb.append('<') 720 sep = '' 721 for pName in _genParamNames 722 sb.append(sep) 723 sb.append(pName) 724 sep = ',' 725 sb.append('>') 726 sb.append(' ') 727 if .modifiers.count 728 sb.append('is ') 729 sb.append(.modifiers.join(',')) 730 sb.append(' ') 731 if .superclass.length 732 sb.append('inherits [.superclass] ') 733 if .interfaceNames.count 734 sb.append('implements ') 735 sb.append(.interfaceNames.join(',')) 736 #sb.append(String.format(' -- {0} fields {1} props {2} ctors {3} methods', _fields.count, _props.count, _ctors.count, _methods.count)) 737 return sb.toString 738 739 def dumpFields 740 for field in .getFields 741 print field 742 743 def dumpCtors 744 for ctor in .getConstructors 745 print 'ctor ', ctor.toString 746 747 def dumpMethods 748 for mthd in .getMethods 749 print mthd 750 751 def dumpProps 752 for prop in .getProperties 753 print prop 754 755 def dumpIndexers 756 assert false, 'Indexers NYI' 757 758 class JavaMemberInfo 759 var name = '' 760 var _attributes as List<of String>? 761 var modifiers = List<of String>() # public, default (=protected+pkg), protected, private 762 763 pro attributes 764 get 765 if not _attributes 766 _attributes = List<of String>() 767 return _attributes 768 set 769 _attributes = value 770 771 get isPublic 772 return .modifiers.contains('public') 773 get isProtected 774 return .modifiers.contains('protected') 775 get isPrivate 776 return .modifiers.contains('private') 777 get isDefault 778 return .modifiers.contains('default') # = protected + package 779 get isStatic 780 return .modifiers.contains('static') 781 get isFinal 782 return .modifiers.contains('final') 783 get isAbstract 784 return .modifiers.contains('abstract') 785 786 get isOverride 787 # in java this is an annotation (at best), - via pkgSig treated as strings 788 return .attributes.contains('Override') 789 790 get isNonNullable 791 return .attributes.contains('NotNull') or .attributes.contains('NonNull') or .attributes.contains('Nonnull') 792 #for name in .attributes # in java these are annotations, - via pkgSig treated as strings 793 # if name.endsWith == 'NotNull' or name.endsWith == 'NonNull' or name.endsWith == 'Nonnull' 794 # return true 795 #return false 796 797 get isVari 798 """ 799 VarArgs arglist to a a method. 800 Java sets this as a flag on the method but we convert it to a faked attribute on the methodInfo 801 """ 802 return .attributes.contains('IsVari') 803 804 class JavaFieldInfo inherits JavaMemberInfo 805 """Info for fields and properties.""" 806 var typeName = '' 807 var value = '' # pkgsig set value if final and initted 808 var isProp = false 809 var isIndexer = false 810 var isReadable = true 811 var isWritable = true 812 var getter as JavaMethodInfo? 813 var setter as JavaMethodInfo? 814 #var name0 = '' # original name before tweaked for propertyname 815 var _type as JavaClassType? 816 817 get type as JavaClassType 818 assert .typeName.length 819 if .typeName.length and not _type 820 #_type = JarSig.classByNameCache[.typeName] 821 _type = JarSig.lookupClass(.typeName) 822 return _type to ! 823 824 def getValue as Object # ?? 825 return .value 826 827 def getIndexParameters as List<of JavaClassType> 828 """ List of Types for indexes for an indexer Property.""" 829 if not .isIndexer 830 return JavaClassType.emptyClassList 831 assert .getter 832 return .getter.getParameters 833 #if .setter 834 # pars = List<of JavaClassType(.setter.getParameters) 835 # pars.removeAt(pars.count-1) # last is value to set 836 # return pars 837 838 def toString as String is override 839 prefix = 'var' 840 if .isProp 841 if .isReadable and .isWritable, prefix = 'pro' 842 else if .isReadable, prefix = 'get' 843 else if .isWritable, prefix = 'set' 844 845 sb = StringBuilder('[prefix] [.name]') 846 if .typeName.length, sb.append(' as [.type]') 847 if .modifiers.count 848 sb.append(' is ') 849 sep='' 850 for mod in .modifiers 851 sb.append(sep) 852 sep =',' 853 sb.append(mod) 854 # TODO attributes 855 if .isProp 856 sb.append(' { ') 857 if .getter 858 sb.append('getter [.getter.name], ') 859 if .setter 860 sb.append('setter [.setter.name]') 861 sb.append(' }') 862 return sb.toString 863 864 class JavaCtorInfo inherits JavaMemberInfo 865 var paramNames = List<of String>() 866 var _params = JavaClassType.emptyClassList 867 868 def getParameters as List<of JavaClassType> 869 if .paramNames.count and not _params.count 870 _params = JavaClassType.genClassTypeList(.paramNames) 871 return _params 872 873 874 def toString as String is override 875 sb = StringBuilder(.name) 876 if .paramNames.count and .paramNames[0].length 877 sb.append('(') 878 sep='' 879 for p in .paramNames 880 sb.append(sep) 881 sep =', ' 882 sb.append(p) 883 sb.append(')') 884 # TODO attributes 885 return sb.toString 886 887 class JavaMethodInfo inherits JavaCtorInfo 888 var returnTypeName = '' 889 var throwsList = List<of String>() # list of String 890 var prop as JavaFieldInfo? # if this is a get or set method for a prop refer to the property 891 892 def returnType as JavaClassType? 893 if not .returnTypeName.length 894 return nil 895 #return JarSig.classByNameCache[.returnTypeName] 896 return JarSig.lookupClass(.returnTypeName) 897 898 def getGenericArguments as List<of JavaClassType> 899 return JavaClassType.emptyClassList # TODO: support generics 900 901 def toString as String is override 902 nampar = base.toString 903 sb = StringBuilder('def [nampar] ') 904 if .returnTypeName.length 905 sb.append('as [.returnTypeName] ') 906 if .modifiers.count 907 sb.append('is ') 908 sep='' 909 for mod in .modifiers 910 sb.append(sep) 911 sep =',' 912 sb.append(mod) 913 if .prop 914 getset = .name[:3] 915 sb.append(" {[getset]ter for prop '[.prop.name]'} ") 916 if .throwsList.count 917 sb.append(' #throws') 918 sep='' 919 for thrw in .throwsList 920 sb.append(sep) 921 sep =',' 922 sb.append(thrw) 923 924 # TODO attributes 925 return sb.toString 926 927 -
Source/BackEndJvm/JvmJarSigTest.cobra
1 # standalone test for jvmJarSig class 2 3 # compile with cobra -d JvmJarSigTest.cobra JvmJarSig.cobra 4 # 5 class JvmJarSigTest 6 7 def main 8 expect InvalidOperationException 9 failPkgFile = JarSig('doWhakkaDay') 10 CobraCore.noOp(failPkgFile) 11 .simple1 12 .simple2 13 14 .pkgFile 15 .cmdline 16 17 def cmdline 18 if CobraCore.commandLineArgs.count > 1 19 pkgFile = CobraCore.commandLineArgs[1] 20 js = JarSig(pkgFile) 21 print js.toString 22 #print 'JarSig name:', js.name 23 for jc in js.getExportedTypes 24 print jc.toMinString 25 #print jc.toString 26 27 def simple1 28 #Empty class 29 # how about supporting a multiline string??? 30 simple = 'com.hops.Mpt\n Class\n com.hops\n Mpt\n com.hops.AlsoMpT\n -\npublic static\n\n' 31 jc = JavaClassType.makeFromDesc(simple.split(c'\n').toList) 32 .chkType(jc, 'com.hops.Mpt', 'Mpt', 'com.hops', 'com.hops.AlsoMpT', JavaType.JavaClass, [ 'public', 'static'], List<of String>()) 33 34 assert jc.isClass 35 assert not jc.isInterface 36 assert not jc.isEnum 37 assert jc.fields.count == 0 38 assert jc.ctors.count == 0 39 assert jc.methods.count == 0 40 assert jc.props.count == 0 41 42 def chkType(jc as JavaClassType, canonicalName as String, name as String, pkg as String, superclass as String, type as JavaType, modifiers as List<of String>, interfaces as List<of String>) 43 assert jc.canonicalName == canonicalName 44 assert jc.name == name 45 assert jc.package == pkg 46 assert jc.superclass == superclass 47 assert jc.type == type 48 assert jc.interfaces.count == interfaces.count 49 for ifc in jc.interfaces 50 assert interfaces.contains(ifc) 51 assert jc.modifiers.count == modifiers.count 52 for m in jc.modifiers 53 assert modifiers.contains(m) 54 55 def simple2 56 # how about supporting a multiline string??? 57 desc = [ 58 'com.hops.Simple', 59 ' Class', 60 ' com.hops', 61 ' Simple', 62 ' com.hops.SimpleBase', 63 ' - # no interfaces', 64 ' public', 65 ' ctor com.hops.Simple', 66 ' java.lang.String', 67 ' var count', 68 ' default', 69 ' int', 70 ' method toString', 71 ' public # modifiers', 72 ' java.lang.String # returnType', 73 ' - # no parameters', 74 ' - # no exceptions', 75 ' method getNameStr', 76 ' public # modifiers', 77 ' java.lang.String # returnType', 78 ' - # no parameters', 79 ' - # no exceptions', 80 ' method setNameStr', 81 ' public # modifiers', 82 ' void # returnType', 83 ' java.lang.String # parameters', 84 ' - # no exceptions', 85 ' method setFoo', 86 ' public # modifiers', 87 ' void # returnType', 88 ' java.lang.String # parameters', 89 ' - # no exceptions', 90 ] 91 jc = JavaClassType.makeFromDesc(desc) 92 .chkType(jc, 'com.hops.Simple', 'Simple', 'com.hops', 'com.hops.SimpleBase', JavaType.JavaClass, [ 'public'], List<of String>()) 93 94 assert jc.isClass 95 assert not jc.isInterface 96 assert not jc.isEnum 97 98 assert jc.fields.count == 1 99 assert jc.fields[0].name == 'count' 100 assert jc.fields[0].type == 'int' 101 assert jc.fields[0].modifiers.count == 1 102 assert jc.fields[0].modifiers[0] in ['default'] 103 #jc.dumpFields 104 105 assert jc.ctors.count == 1 106 assert jc.ctors[0].paramList.count == 1 107 assert jc.ctors[0].paramList[0] == 'java.lang.String' 108 #jc.dumpCtors 109 110 assert jc.methods.count == 4 111 assert jc.methods[0].name == 'toString' 112 assert jc.methods[0].returnType == 'java.lang.String' 113 assert jc.methods[0].modifiers[0] == 'public' 114 assert jc.methods[1].name == 'getNameStr' 115 assert jc.methods[2].name == 'setNameStr' 116 assert jc.methods[3].name == 'setFoo' 117 #jc.dumpMethods 118 119 assert jc.props.count == 2 120 assert jc.props[0].name =='NameStr' 121 assert jc.props[1].name =='Foo' 122 #jc.dumpProps 123 124 def pkgFile 125 expect InvalidOperationException 126 js = JarSig('noJarSigFile') 127 128 # requires file 'jarSigTestFile1.sig' 129 pkgFile = 'jarSigTestFile1' 130 js = JarSig(pkgFile) 131 assert js.name == 'jarSigTestFile1' 132 assert JarSig.sigFile(js.name) == 'jarSigTestFile1.sig' 133 134 expTypes = for jct in js.getExportedTypes get jct 135 assert expTypes.count == 3 136 137 for jct in expTypes 138 assert jct.name in ['AbstractMethodError','Appendable','Thread$State'] 139 -
Source/BackEndJvm/jarSigTestFile1.sig
1 # Class paths and boot paths being searched 2 # C:\Program Files\Java\jre6\lib\resources.jar 3 # C:\Program Files\Java\jre6\lib\rt.jar 4 # C:\Program Files\Java\jre6\lib\sunrsasign.jar 5 # C:\Program Files\Java\jre6\lib\jsse.jar 6 # C:\Program Files\Java\jre6\lib\jce.jar 7 # C:\Program Files\Java\jre6\lib\charsets.jar 8 # C:\Program Files\Java\jre6\lib\modules\jdk.boot.jar 9 # C:\Program Files\Java\jre6\classes 10 # jarfile=C:\Program Files\Java\jre6\lib\resources.jar 11 # jarfile=C:\Program Files\Java\jre6\lib\rt.jar 12 # jarfile=C:\Program Files\Java\jre6\lib\jsse.jar 13 # jarfile=C:\Program Files\Java\jre6\lib\jce.jar 14 15 java.lang.AbstractMethodError 16 class # Type 17 java.lang # package 18 AbstractMethodError # name 19 java.lang.IncompatibleClassChangeError # superclass 20 - # no interfaces 21 public # modifiers 22 ctor java.lang.AbstractMethodError 23 - # no parameters 24 ctor java.lang.AbstractMethodError 25 java.lang.String # parameters 26 27 java.lang.Appendable 28 Interface # Type 29 java.lang # package 30 Appendable # name 31 - # superclass 32 - # no interfaces 33 public # modifiers 34 method append 35 public # modifiers 36 java.lang.Appendable # returnType 37 java.lang.CharSequence # parameters 38 java.io.IOException # exceptions 39 method append 40 public # modifiers 41 java.lang.Appendable # returnType 42 java.lang.CharSequence, int, int # parameters 43 java.io.IOException # exceptions 44 method append 45 public # modifiers 46 java.lang.Appendable # returnType 47 char # parameters 48 java.io.IOException # exceptions 49 50 java.lang.Thread$State 51 Enum # Type 52 java.lang # package 53 Thread$State # name 54 java.lang.Enum # superclass 55 - # no interfaces 56 static public # modifiers 57 var NEW 58 static public # modifiers 59 java.lang.Thread$State 60 var RUNNABLE 61 static public # modifiers 62 java.lang.Thread$State 63 var BLOCKED 64 static public # modifiers 65 java.lang.Thread$State 66 var WAITING 67 static public # modifiers 68 java.lang.Thread$State 69 var TIMED_WAITING 70 static public # modifiers 71 java.lang.Thread$State 72 var TERMINATED 73 static public # modifiers 74 java.lang.Thread$State 75 method values 76 static public # modifiers 77 [Ljava.lang.Thread$State; # returnType 78 - # no parameters 79 - # no exceptions 80 method valueOf 81 static public # modifiers 82 java.lang.Thread$State # returnType 83 java.lang.String # parameters 84 - # no exceptions 85 -
Source/BackEndJvm/JvmType.cobra
1 # NativeType wrapper for Java Classes 2 3 # Eventually will use/handle java native classes but pending that and while cross compiling 4 # wrap a JavaClassType (declared in JvmJarSig.cobra) 5 6 class JvmNativeType inherits NativeType 7 8 var _type as JavaClassType 9 #var _type as java.lang.Class 10 11 #cue init(type as java.lang.Class) 12 cue init(type as JavaClassType) 13 base.init 14 _type = type 15 16 def equals(other as Object?) as bool is override 17 if other is this 18 return true 19 if other inherits JvmNativeType 20 return .backEndType == other.backEndType 21 else 22 return false 23 24 def getHashCode as int is override 25 return .backEndType.getHashCode 26 27 get backEndType as JavaClassType 28 return _type 29 30 get name as String is override 31 #return _type.getSimpleName 32 return _type.name 33 34 get fullName as String is override 35 return _type.canonicalName 36 37 get isValueType as bool is override 38 #return _type.isValueType # fix for char, int, bool, long etc vs Boxed Classes 39 return false 40 41 get baseType as NativeType? is override 42 super = _type.getSuperClass 43 if not super, return nil 44 return JvmNativeType(super) # cache? 45 #if(_type.superclass.length, JvmNativeType(_type.superclass), nil) 46 47 def customAttributes as IList<of dynamic> is override 48 return .backEndType.getAnnotations #to IList<of dynamic> 49 50 get isSystemObjectClass as bool is override 51 return /#_type and #/ .fullName == 'java.lang.Object' 52 53 get isSystemTypeClass as bool is override 54 return /# _type and #/ .fullName == 'java.lang.Class' 55 56 57 class JvmTypeProxy inherits NativeTypeProxy 58 """ 59 Acts as an ITypeProxy where the Jvm type is known. 60 Typically used when scanning DLLs. 61 """ 62 63 shared 64 var _cobraNameForJvmGenericNameCache = Dictionary<of String, String>() 65 66 def cobraNameForJvmType(jvmType as JavaClassType) as String 67 """ 68 Returns 'Foo' for 'Foo' and 'Foo<of,>' for 'Foo<T,T1>' 69 Converts generic and non-generic classes and interfaces. 70 Does *not* work for arrays, etc. 71 """ 72 name = jvmType.name 73 if not jvmType.isGenericType or jvmType.isGenericParameter 74 return name 75 if _cobraNameForJvmGenericNameCache.containsKey(name) 76 return _cobraNameForJvmGenericNameCache[name] 77 else 78 count = jvmType.genericArgsCount 79 assert count >0 80 cobraName = name + '<of' 81 for i in count-1, cobraName += ',' 82 cobraName += '>' 83 _cobraNameForJvmGenericNameCache[name] = cobraName 84 return cobraName 85 86 def cobraNameForJvmBoxName(name as String) as String 87 """ 88 Assunmed we've mangled java generics typenames a la .Net ( i.e TypeName`<nGenericTypeParams>) 89 Returns 'Foo' for 'Foo' and 'Foo<of,>' for 'Foo`2' 90 Works on generic and non-generic classes, structs and interfaces. 91 Does *not* work for arrays etc. 92 """ 93 if '`' not in name, return name 94 if _cobraNameForJvmGenericNameCache.containsKey(name) 95 return _cobraNameForJvmGenericNameCache[name] 96 else 97 parts = name.split(c'`') 98 count = int.parse(parts[1]) 99 cobraName = parts[0] + '<of' 100 for i in count-1, cobraName += ',' 101 cobraName += '>' 102 _cobraNameForJvmGenericNameCache[name] = cobraName 103 return cobraName 104 105 106 var _jvmType as JavaClassType 107 108 cue init(nativeType as NativeType) 109 .init((nativeType to JvmNativeType).backEndType) 110 111 cue init(jvmType as JavaClassType) 112 base.init 113 _jvmType = jvmType 114 115 def addMinFields 116 base.addMinFields 117 .addField('jvmType', _jvmType) 118 119 get realType as IType is override 120 return _realTypeWithCache(_jvmType) 121 122 def _realTypeWithCache(jvmType as JavaClassType) as IType 123 t = (.compiler to Compiler).typeForJvmType(jvmType) 124 if t is nil 125 t = _realTypeWithoutCache(jvmType, 0) 126 (.compiler to Compiler).addTypeForJvmType(t to !, jvmType) 127 return t to ! 128 129 def _realTypeWithoutCache(jvmType as JavaClassType, level as int) as IType 130 assert .compiler.basicTypes.count > 9 # should have bool, char, all the ints, etc. 131 132 # Must return the Cobra primitive types in place of System.Boolean, System.Char, System.Int16, etc. 133 # because it's the primitives that are used all over the compiler. 134 jvmPrimitiveToIType = .compiler.primitiveToITypeCache 135 if jvmPrimitiveToIType is nil or jvmPrimitiveToIType.count == 0 136 _initPrimToITypeCache 137 jvmPrimitiveToIType = .compiler.primitiveToITypeCache 138 assert jvmPrimitiveToIType is not nil and jvmPrimitiveToIType.count <> 0 139 basicType as IType? 140 if jvmPrimitiveToIType.tryGetValue(jvmType, out basicType) 141 return basicType to ! 142 143 # handle wrapped types, like arrays, with recursive calls 144 if jvmType.isArray 145 #assert jvmType.name.endsWith(r'[]') # could be [,] so TODO: handle multidim arrays 146 return .typeProvider.arrayType(_realTypeWithCache(jvmType.arrayComponentType to !)) 147 else if jvmType.isNested and not jvmType.isGenericParameter 148 declaringType = _realTypeWithCache(jvmType.declaringType to !) 149 potential = declaringType.memberForName(jvmType.name) 150 if potential is nil 151 .throwError('Cannot locate nested Jvm type "[jvmType]" (simple name is "[jvmType.name]").') 152 else if potential inherits IType 153 return potential 154 else 155 .throwError('Located Jvm type spec "[jvmType]" but got a [potential.englishName] instead of a type.') 156 157 # generic parameters 158 if jvmType.isGenericParameter 159 return GenericParam(JvmNativeType(jvmType)) 160 161 typeName = _computeCobraTypeName(jvmType) 162 missing = false 163 curNS = _computeNameSpace(jvmType, level, out missing) 164 if missing 165 .throwError('Cannot find Jvm type "[jvmType.canonicalName]" in package "[jvmType.package]".') 166 # since the type exists, but cannot be located in our namespaces, 167 # it must be pulled from a dependent DLL that was not directly referenced 168 # but maybe it was already attempted 169 #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/).') 170 171 #(.compiler to dynamic).jvmReadAssembly(clrType.assembly) 172 #return _realTypeWithoutCache(jvmType, level+1) # recurse. guard is just above. 173 174 # return namespace member 175 member as IMember? = curNS.declForName(typeName) 176 if member inherits IType 177 if member inherits Box 178 if jvmType.isGenericType and not jvmType.isGenericTypeDefinition 179 # So we have something like ICollection<of KeyValuePair<of TKey,TValue>> which is all Generic types. 180 # We need the Cobra types of those args so we can construct the Cobra type from the generic cobra type 181 # otherwise, we would just end up returning the generic definition. 182 print 'Dbg: JvmType.realTypeWithoutCache generic type [jvmType.canonicalName] [member.name].' 183 #.throwError('TODO support for Generic Types in JvmType _realTypeWithoutCache') 184 #member = _typeForArgsOfGeneric(jvmType, member) 185 return member 186 else 187 print '[typeName] not in [curNS.name] declsforName' 188 msg = 'Cannot locate jvm type "[jvmType]".' 189 if jvmType.package.length and jvmType.package.startsWith('java.lang') 190 if .compiler and .compiler.verbosity > 1, print msg 191 # TODO: .compiler.warning(msg) 192 return .compiler.objectType 193 else 194 .throwError(msg) 195 return .compiler.intType # CC: to make C# code gen happy. 196 197 def _initPrimToITypeCache 198 typeToIType = _makePrimitiveTypesDict 199 jvmPrimitiveToIType = Dictionary<of dynamic, IType>() 200 for key in typeToIType.keys 201 jvmPrimitiveToIType[key] = typeToIType[key] 202 (.compiler to Compiler).primitiveCache = jvmPrimitiveToIType #to ! 203 204 def _makePrimitiveTypesDict as IDictionary<of JavaClassType, IType> 205 primitiveToIType = Dictionary<of JavaClassType, IType>() 206 for bt in .compiler.basicTypes 207 if bt.systemAliasProxy 208 # lookup by qualified name (includes translation) and pull out (jvm) NativeType 209 key = (.compiler.nativeType((bt.systemAliasProxy to LibraryTypeProxy).qualifiedName) to JvmNativeType).backEndType 210 primitiveToIType[key] = bt 211 assert primitiveToIType.count == 0 or primitiveToIType.count >=8 212 return primitiveToIType 213 214 215 def _computeCobraTypeName(jvmType as JavaClassType) as String 216 typeName = jvmType.name 217 if jvmType.isGenericType 218 # generic like IComparable`1 219 assert r'[' not in typeName 220 typeName = .cobraNameForJvmType(jvmType) 221 else if not typeName[typeName.length-1].isLetterOrDigit 222 .throwError('Cannot locate JVM type "[jvmType.canonicalName]".') 223 return typeName 224 225 def _computeNameSpace(jvmType as JavaClassType, level as int, missing as out bool) as NameSpace 226 missing = false 227 if not jvmType.package.length, return .compiler.globalNS 228 nameParts = jvmType.package.split(c'.') 229 member = .compiler.globalNS.symbolForName(nameParts[0]) 230 if member inherits NameSpace, curNS = member 231 else, missing = true 232 if not missing 233 i = 1 234 while i < nameParts.length 235 namePart = nameParts[i] 236 possible = curNS.declForName(namePart) 237 if possible is nil 238 missing = true 239 break 240 else if possible inherits NameSpace 241 curNS = possible 242 else 243 .throwError('Found "[namePart]" at component [i+1] of JVM type "[jvmType.canonicalName]", but it is a [possible.englishName].') 244 i += 1 245 return curNS 246 247 /# 248 def _typeForArgsOfGeneric(jvmType as JavaClassType, member as IType) as IType 249 args = List<of IType>() 250 for genArg in jvmType.getGenericArguments 251 args.add(_realTypeWithCache(genArg)) 252 boxMember = member to Box 253 if boxMember.qualifiedName == 'System.Nullable<of>' 254 assert args.count == 1 255 member = .typeProvider.nilableType(args[0]) 256 else 257 member = boxMember.constructedTypeFor(args) 258 return member 259 #/ 260 def _typeForArgsOfGeneric(jvmType as JavaClassType, member as IType) as IType 261 args = List<of IType>() 262 for genArg in jvmType.getGenericArguments 263 args.add(_realTypeWithCache(genArg)) 264 boxMember = member to Box 265 member = boxMember.constructedTypeFor(args) 266 return member 267 -
Source/BackEndJvm/TODO
1 = Java Backend Gen TODO = 2 3 include-tests:no - remove Test invocation call 4 5 6 fixup Object namespace for X-compile so items like System.Object are rooted off 7 java.lang namespace ( rather than .Net system) 8 DONE June-2011 9 10 passthru compilation of *.java files 11 - seems to work for single files But 12 - calc of main class fm passthru *.java files 13 14 computeOutName from name of main class (or first/only) class in file rather 15 than permutation of input name 16 DONE 31-Jan-2011 17 18 19 cobra namespaces capitalized (as .Net) Java all lowercase 20 - convert namespaces in java code to lowcase 21 DONE 31-Jan-2011 22 23 24 java names lowcase 25 method Names - DONE 31-Jan-2011 26 var names - DONE 31-Jan-2011, corrected 10-Feb-2011 BoxField._backendName -> BoxField.{sharp,java}BackEndName 27 params 28 events 29 local variables 30 -> remove/reverse cobra conversion to upcase for C#/.Net 31 ( look for calls to .capitalized) 32 DONE (I think) 33 34 remove all uses of ClrNativeType in core compiler ( ->NativeType??) 35 Compiler/Enums/Types.cobra 36 DONE 37 38 properties - pro/get/set 39 - auto convert to java getters/setters and map calls 40 - Whats the equiv for indexers 41 Look at Beans spec but otherwise use/convert to {get,set}Indexer method call. 42 <indexedT> getIndexer<T, indexedT>(T) and 43 setIndexer<T, indexedT>(T, indexedT) 44 DONE 45 46 Events 47 - auto add boiler plate for listener (de)registration 48 - event firing 49 50 51 partial classes 52 Add extra phase to aggregate partial classes together into first Module 53 (Chk if cobra is doing sommat like this or relying on C# compiler) 54 55 Extensions 56 convert to static classes methods taking instance as first param 57 If lookup for name fails see if sig matches extension and remap call to extn static class method 58 59 60 Parse error lines fm java giving source line, find (trailing comment) cobra 61 line number and modify the java error msg line with the cobra lineno 62 printing that in any java error mesages so to relate the java error back 63 to the generating cobra code line. 64 - start with just spew the javac lines to output 65 - assemble into ErrorMessage Line and 'supporting lines associated with it - keeps error line count in sync 66 67 68 69 single file: 70 generate to java src files in namespace dir hier 71 compile to class file ( in class dir hier) 72 run class file 73 74 If specify multiple files 75 generate thm all to java src in in namespace dir hier 76 compile to class files ( in class dir hier) 77 generate manifest file and generate classfiles to jar file 78 Leave jar file at root of hierarchy 79 80 81 ensure support ( as builtin alternative) for jikes compiler. 82 https://sourceforge.net/projects/jikes/files/Jikes/ 83 84 85 add synonym for sharp''/sharp"" -> java''/java"" 86 or general be''/be"" (for backend) 87 88 89 see http://www.25hoursaday.com/CsharpVsJava.html 90 91 java 'synchronized' (block is exact equivalent of C# 'lock' stmt. 92 93 varargs 94 'params' keyword in C# (qualifier to the last argument to the method which should be an array). 95 In Java, the same effect is achieved by appending the string "..." to the typename of the last argument to the method. 96 97 Attributes 98 C# extend Atttribute - metainfo also ([AttributeUsage(AttributeTargets.Class)]) 99 java specify with @interface and Metainfo 100 e.g @Documented //we want the annotation to show up in the Javadocs 101 @Retention(RetentionPolicy.RUNTIME)) 102 103 Java has Set in its collections framework so use that instead of Cobra lib version. 104 105 Cobra methods nonVirtual (C# not marked virtual) in java mark as final (Cannot redefine or override). 106 107 out and inout (ref) 108 x as <Type>? = nil 109 method(...., out x) # def method(.... out x as <Type>) 110 # use X here 111 112 becomes in java 113 Type x = nil 114 Object xRef = x 115 method(..., xRef) // void method(..., xRef as Object) - inmethod xRef assigned to whatever x calculated as 116 x = xRef 117 // use x here 118 119 120 Cobra backend targetting stab language (explicitly) ?? 121 backend 'stab-jvm' 122 123 124 Decimal Type 125 Initially wrap it as new type thats is a Double with an associated DecimalFormatter 126 (giving same precision as .Net). 127 Calcs are all as doubles, toString uses formatter... 128 still get rounding error etc... 129 Decimal Type internally and emit as BigDecimal, trap math ops and map 130 131 Maybe easier to just default to Integer and ignore Decimal (initially) 132 133 134 Add convenience methods to 135 java.io.File for 136 remember 137 (Buffered)Reader(FileReader(File(path) - read text 138 (Buffered)InputStream(FileInputStream(File(path) - read bytestream 139 140 static FileInputStream/FileOutputStream openRead/openWrite(String path)- r/w bytestream 141 142 static BufferedInputStream createRead(String path) - open or create - bytes 143 static BufferedOutputStream createWrite(String path) - open+truncate or create - bytes 144 145 static BufferedWriter createText(String path) - open or create Textfile for writing 146 static BufferedReader openText(String path) - open textfile for reading 147 148 static byte[] readAllBytes(String path) 149 static String readAllText(String path) 150 static String[] readAllLines(String path) 151 static IEnumerable<of String> readLines(String path) 152 153 154 = Issues = 155 156 How support yield and conversion to enumerator/iterator? 157 ------------------------------------------------------------------------- 158 159 Checked to Unchecked exceptions 160 161 Fm http://www.mindview.net/Etc/Discussions/CheckedExceptions 162 See also ExceptionChaining since JDK1.4 163 164 ExceptionAdapter 165 166 Here's a tool that I developed with the help of Heinz Kabutz. It 167 converts any checked exception into a RuntimeException while 168 preserving all the information from the checked exception. 169 170 import java.io.*; 171 class ExceptionAdapter extends RuntimeException { 172 private final String stackTrace; 173 public Exception originalException; 174 public ExceptionAdapter(Exception e) { 175 super(e.toString()); 176 originalException = e; 177 StringWriter sw = new StringWriter(); 178 e.printStackTrace(new PrintWriter(sw)); 179 stackTrace = sw.toString(); 180 } 181 public void printStackTrace() { 182 printStackTrace(System.err); 183 } 184 public void printStackTrace(java.io.PrintStream s) { 185 synchronized(s) { 186 s.print(getClass().getName() + ": "); 187 s.print(stackTrace); 188 } 189 } 190 public void printStackTrace(java.io.PrintWriter s) { 191 synchronized(s) { 192 s.print(getClass().getName() + ": "); 193 s.print(stackTrace); 194 } 195 } 196 public void rethrow() { throw originalException; } 197 } 198 199 The original exception is stored in originalException, so you can 200 always recover it. In addition, its stack trace information is 201 extracted into the stackTrace string, which will then be printed using 202 the usual printStackTrace() if the exception gets all the way out to 203 the console. However, you can also put a catch clause at a higher 204 level in your program to catch an ExceptionAdapter and look for 205 particular types of exceptions, like this: 206 207 catch(ExceptionAdapter ea) { 208 try { 209 ea.rethrow(); 210 } catch(IllegalArgumentException e) { 211 // ... 212 } catch(FileNotFoundException e) { 213 // ... 214 } 215 // etc. 216 } 217 218 Here, you're still able to catch the specific type of exception but 219 you're not forced to put in all the exception specifications and 220 try-catch clauses everywhere between the origin of the exception and 221 the place that it's caught. An even more importantly, no one writing 222 code is tempted to swallow the exception and thus erase it. If you 223 forget to catch some exception, it will show up at the top level. If 224 you want to catch exceptions somewhere in between, you can. 225 226 Or, since originalException is public, you can also use RTTI to look 227 for particular types of exceptions. 228 229 Here's some test code, just to make sure it works (not the way I 230 suggest using it, however): 231 232 public class ExceptionAdapterTest { 233 public static void main(String[] args) { 234 try { 235 try { 236 throw new java.io.FileNotFoundException("Bla"); 237 } catch(Exception ex) { 238 ex.printStackTrace(); 239 throw new ExceptionAdapter(ex); 240 } 241 } catch(RuntimeException e) { 242 e.printStackTrace(); 243 } 244 System.out.println("That's all!"); 245 } 246 } 247 248 By using this tool you can get the benefits of the unchecked exception 249 approach (less code, cleaner code) without losing the core of the 250 information about the exception. 251 252 If you were writing code where you wanted to throw a particular type 253 of checked exception, you could use (or modify, if it isn't already 254 possible) the ExceptionAdapter like this: 255 256 if(futzedUp) 257 throw new ExceptionAdapter(new CloneNotSupportedException()); 258 259 This means you can easily use all the exceptions in their original 260 role, but with unchecked-style coding. 261 262 ------------------------------------------------------------------------- 263 I've managed to fiddle javac to not check exceptions anymore *evil 264 grin*. 265 266 Very simple really. Add a directory java/lang to your project and 267 copy into that directory Exception.java and RuntimeException.java 268 269 Change Exception to extend RuntimeException and change 270 RuntimeException to extend Throwable. 271 272 Now the compile-time exception checking is turned off. 273 274 -- hops: Doesnt work unfortunately --- 275 ------------------------------------------------------------------------- 276 277 278 279 280 281 ------------------------------------------------------------------------- 282 = Current compile cmd (X-compile) = 283 284 cobra -back-end:jvm Name.cobra 285 cobc0 -back-end:jvm -kif Name.cobra 286 287 288 = MSW Default compiler cmd = 289 File.cobra (containing class File) 290 javac -cp '[CobraCore.exePath][pathSep]CobraLang.jar File.java 291 javac -cp '../wkspace/Source/CobraLang.jar' File.java 292 293 294 = MSW run cmd = 295 java -cp ".;../wkspace/Source/CobraLang.jar" File 296 297 298 = Other back ends = 299 Fantom : compile to jvm or dotNet -
Source/BackEndJvm/ScanJvmType.cobra
1 # Load Jvm references and libraries 2 3 class Compiler is partial 4 5 #var _didLoadJars = Set<of String>() 6 7 var _didReadJars = Set<of String>() 8 9 var _jvmTypeToType = Dictionary<of JavaClassType, IType>() 10 11 var _jvmTypeCache = Dictionary<of String, JavaClassType>() 12 13 14 # Java specific Reference loading 15 def jvmLoadReference(reference as String) as bool 16 try 17 return __jvmLoadReference(reference) 18 catch fnfe as System.IO.FileNotFoundException 19 throw LoadReferenceException('FileNotFound', fnfe.fileName, fnfe.message) 20 catch fle as System.IO.FileLoadException 21 throw LoadReferenceException('FileLoadException', fle.fileName ? reference, fle.message) 22 catch fiop as InvalidOperationException 23 throw LoadReferenceException('InvalidOperationException', reference, fiop.message) 24 25 def __jvmLoadReference(reference as String) as bool 26 # uses reference parameter 27 # compiler .referenceVerbosity 28 # fills .loadedReferences 29 30 # Hopefully this is simpler than .Net case, look for reference which devolves to a pkgSig file 31 # in cwd or as abspathname or in cobra library-path settings. 32 # When running java native would probably also need to check the classpath 33 require 34 reference.endsWith('.jar') 35 reference not in ['.jar'] 36 ensure 37 result implies .loadedReferences[.loadedReferences.count-1] == reference 38 not result implies .loadedReferences.count == old.loadedReferences.count 39 body 40 jarSig as JarSig? = nil 41 rv = .referenceVerbosity 42 assert not (reference.startsWith('-r') and '-r' in reference[2:]) 43 sigFile = reference + '.sig' 44 if rv, print 'Looking for sigfile("[sigFile]").' 45 sigFilePath = _lookForSigFile(sigFile, rv, reference) 46 if not sigFilePath 47 # eventually may also search CLASSPATH 48 if rv, print 'Returning false for __jvmLoadReference("[reference]").' 49 return false 50 51 if rv, print 'Will read jarsig: [sigFilePath]' 52 try 53 jarSig = JarSig(sigFilePath) 54 catch readExc as Exception 55 if rv, print 'Caught exception during jarSig creation: [readExc]' 56 throw 57 if rv 58 print 'Did find jarSig: [jarSig]' 59 print 'Will read jarsig contents: [jarSig]' 60 try 61 .javaReadJar(jarSig to !) 62 catch readExc as Exception 63 if rv, print 'Caught exception during javaReadJar: [readExc]' 64 throw 65 if rv, print 'Did read jar signature file: [jarSig]' 66 .loadedReferences.add(reference) 67 if rv, print 'Returning true for __jvmLoadReference("[reference]").' 68 return true 69 70 def _lookForSigFile(sigFile as String, rv as int, reference as String) as String? 71 """Pathname to sigfile if found in cwd, abspath or in library-directory paths, nil otherwise.""" 72 if File.exists(sigFile) # current directory or abspathname 73 if rv, print '"[reference]" found as file in [sigFile].' 74 return sigFile 75 ccPath = Path.getDirectoryName(CobraCore.exePath) to ! 76 absSigFile = Path.combine(ccPath, sigFile) 77 if File.exists(absSigFile) 78 if rv, print '"[reference]" found as file in [absSigFile].' 79 return absSigFile 80 81 if rv, print 'File does not exist in std places. Searching library-directory setting' 82 searchPaths = .options.getDefault('library-directory', List<of String>()) to List<of String> 83 if not searchPaths.count 84 if rv, print 'No lib paths to search.' 85 return nil 86 87 found = false 88 for searchPath in searchPaths 89 if rv, print 'Checking lib path: "[searchPath]"' 90 combinedPath = Path.combine(searchPath, sigFile) 91 if File.exists(combinedPath) 92 if rv, print '"[reference]" found as file in [combinedPath].' 93 found = true 94 break 95 96 if not found 97 if rv and searchPaths.count, print 'Did not find "[reference]" in lib paths' 98 return nil 99 return combinedPath 100 101 def javaReadJar(jSig as JarSig) 102 """ 103 Reads the contents of a jar (actually JarSig) file so that they are accessible to the program. 104 """ 105 if jSig.name in _didReadJars, return 106 _didReadJars.add(jSig.name) 107 verbosity = .verbosity 108 if verbosity 109 print 'Reading jar(sig): [jSig.name]' # extra space lines up with 'Loading reference:' 110 print ' at: [jSig.location]' 111 namespaceQualNameToNameSpaceObject = Dictionary<of String, NameSpace>() 112 module = AssemblyModule(jSig.location, .globalNS) 113 saveModule, _curModule = _curModule, module 114 try 115 _modules.add(module) 116 for type in jSig.getExportedTypes 117 if type.isNested #or type.declaringType 118 # these will be scanned by Box._scanNestedTypes 119 # print '### skipping [type.name] in [type.namespace]. isNested=[type.isNested], declaringType=[type.declaringType]' 120 continue 121 typeNamespace = type.package 122 if typeNamespace.length == 0 123 # happens for classes etc. that are not declared in a namespace 124 curNameSpace = module.topNameSpace 125 else 126 namespaceName = typeNamespace 127 if namespaceQualNameToNameSpaceObject.containsKey(namespaceName) 128 curNameSpace = namespaceQualNameToNameSpaceObject[namespaceName] 129 else 130 curNameSpace = module.topNameSpace 131 for name in typeNamespace.split(c'.') 132 curNameSpace = curNameSpace.getOrMakeNameSpaceNamed(Token.empty, name) 133 assert not curNameSpace.isUnified 134 namespaceQualNameToNameSpaceObject[namespaceName] = curNameSpace 135 if verbosity >= 4 136 print ' Reading type [type.name] in namespace "[namespaceName]"' 137 jvmType = JvmNativeType(type) 138 if curNameSpace.unifiedNameSpace.declForName(jvmType.name) 139 .warning(CobraWarning('Already have declaration "[jvmType.name]" in namespace "[curNameSpace.fullName]".')) 140 else 141 if type.isClass 142 if type.name.startsWith('Extend_') and type.name.count(c'_') >= 2 143 # e.g.Extend_String - TODO 144 curNameSpace.addDecl(Extension(jvmType, .backEnd)) 145 else 146 curNameSpace.addDecl(Class(jvmType, .backEnd)) 147 else if type.isInterface 148 curNameSpace.addDecl(Interface(jvmType, .backEnd)) 149 else if type.isEnum 150 #print jvmType.name 151 curNameSpace.addDecl(EnumDecl(curNameSpace, jvmType, type.modifiers, '')) # TODO: isNames; docString? 152 else if type.isValueType 153 curNameSpace.addDecl(Struct(jvmType, .backEnd)) 154 else 155 throw FallThroughException(type) 156 finally 157 _curModule = saveModule 158 159 def jvmFixNilableMemberSigs 160 # TODO: this really needs to go in a separate file that the compiler reads each time 161 162 # fix up member sigs regarding methods returning nilable values 163 # hard coded below. TODO: read from a Cobra config file 164 # _fix is defined in ScanClrType 165 166 # These are just reflected over from the .Net ones since I dont know what the basis for inclusion is/was 167 168 _fix('java.lang.Object', 'toString getClass clone') 169 # ^ regarding .toString, not technically true, but common enough and life is too painful when the return type is nilable 170 #_fix('java.lang.System', 'out') #stdout 171 _fix('java.lang.String', 'padLeft padRight remove replace substring toLower toUpper trim') 172 #_fix('System.Type', 'assembly name toString') 173 # namespace can return nil if the Type is a generic parameter 174 #_fix('System.Environment', 'commandLine currentDirectory newLine version') 175 _fix('java.lang.Exception', 'message') 176 #_fix('System.Collections.Generic.IEnumerable<of>', r'getEnumerator') 177 #_fix('java.util.Enumeration<of>', r'getNext') 178 _fix('java.util.Iterator<of>', r'next') 179 _fix('java.util.ListIterator<of>', r'next previous') 180 _fix('java.util.Collection<of>', r'toArray') 181 182 #_fix('System.Collections.Generic.List<of>', r'[]') 183 _fix('java.util.List<of>', r'[] get set remove') 184 _fix('java.util.AbstractList<of>', r'[] get set remove') 185 _fix('java.util.AbstractSequentialList<of>', r'[] get set remove') 186 _fix('java.util.ArrayList<of>', r'[] get set remove') 187 #_fix('java.util.CopyOnWriteArrayList<of>', r'[] get set remove') 188 #_fix('java.util.LinkedList<of>', r'[] get set remove element getFirst getLast peek peekFirst peekLast poll pollFirst pollLast pop removeFirst removeLast') 189 #_fix('java.util.Vector<of>', r'[] get set elementAt firstElement lastElement remove') 190 #_fix('java.util.Stack<of>', r'[] peek pop push') 191 192 #_fix('System.Collections.Generic.IDictionary<of,>', r'[] keys values') 193 _fix('java.util.Map<of,>', r'[] get') 194 # _fix('System.Collections.Generic.Dictionary<of,>', r'[]') 195 _fix('java.util.AbstractMap<of,>', r'[] get') 196 _fix('java.util.HashMap<of,>', r'[] get') 197 #_fix('java.util.ConcurrentHashMap<of,>', r'[] get') 198 #_fix('java.util.ConcurrentSkipListHashMap<of,>', r'[] get') 199 #_fix('java.util.EnumMap<of,>', r'[] get') 200 #_fix('java.util.IdentityHash<of,>', r'[] get') 201 #_fix('java.util.TreeMap<of,>', r'[] get') 202 #_fix('java.util.WeakHashMap<of,>', r'[] get') 203 _fix('java.util.Map.Entry<of,>', r'getKey getValue') 204 #_fix('java.util.AbstractMap.SimpleEntry<of,>', r'getKey getValue') 205 #_fix('java.util.AbstractMap.SimpleImmutableEntry<of,>', r'getKey getValue') 206 207 #_fix('System.IO.File', 'create createText open openRead openText openWrite readAllBytes readAllLines readAllText') 208 #_fix('java.io.File', 'create createText open openRead openText openWrite readAllBytes readAllLines readAllText') 209 #_fix('System.IO.FileSystemInfo', 'name fullName') 210 #_fix('System.IO.TextWriter', 'newLine') 211 #_fix('System.IO.Path', 'combine getFullPath') 212 # combine = File(strA, strB).getPath(), getFullPath = File().getAbsolutePath() 213 #_fix('java.lang.StringBuilder', 'toString') # ?? 214 _fix('java.lang.Text.RegularExpressions.Regex', 'match replace') 215 _fix('System.Diagnostics.Process', 'processName') 216 217 _fix('System.Reflection.Assembly', 'getEntryAssembly getExecutingAssembly location') 218 _fix('System.Reflection.MemberInfo', 'name') 219 _fix('System.Reflection.FieldInfo', 'fieldType') 220 _fix('System.Reflection.ParameterInfo', 'parameterType') 221 _fix('System.Reflection.PropertyInfo', 'propertyType') 222 223 # TODO: shouldn't need the following. see comment in _fixSubs 224 #_fix('System.IO.StringWriter', 'toString') 225 226 227 228 # 229 # Jvm Type Cache 230 231 def typeForJvmType(jvmType as JavaClassType) as IType? 232 """ 233 Returns the Cobra type for a Java type if the Java type was previously scanned. 234 i.e this is access to the Java Type/Class cache. 235 """ 236 return if(_jvmTypeToType.containsKey(jvmType), _jvmTypeToType[jvmType], nil) 237 238 def addTypeForJvmType(type as IType, jvmType as JavaClassType) 239 require .typeForJvmType(jvmType) in [nil, type] 240 _jvmTypeToType[jvmType] = type 241 242 def jvmTypeByName(qualifiedName as String) as JavaClassType 243 """ 244 Obtain the Jvm Type given by the fully qualified (cobra) name. 245 """ 246 t as JavaClassType? 247 _jvmTypeCache.tryGetValue(qualifiedName, out t) 248 if t is nil 249 # TODO - lookup the JavaClassType by name. 250 t = JarSig.classByNameCache[qualifiedName] 251 _jvmTypeCache[qualifiedName] = t to passthrough # "to passthrough" instead of "to !" to avoid non-nil check 252 return t to passthrough 253 254 255 def installJvmNativeMethods(box as Box, nativeType as NativeType) 256 print '++ TODO scanJvmType.installJvmNativeMethods' 257 /# 258 meths = List<of Method>() 259 _installClrNativeMethodsFrom('System', nativeType, nativeType, box, meths) 260 _installClrNativeMethodsFrom('System', ClrNativeType(System.Math.getType), nativeType, box, meths) 261 262 # the next statement can be problematic in that you have to add new DecimalTools methods in Snapshot just so the compiler can see them 263 # ultimately, extensions of primitive types should be supported 264 _installClrNativeMethodsFrom('CobraLangInternal', ClrNativeType(Cobra.Lang.DecimalTools.getType), nativeType, box, meths) 265 266 _printMethods(meths, box) 267 268 def compareMethodNames(a as Method, b as Method) as int 269 return a.name.compareTo(b.name) 270 271 def _printMethods(meths as IList<of Method>, box as Box) 272 # print out the methods, useful for documentation 273 print 274 print 'type', box.name 275 sharedMeths = for meth in meths where meth.isShared 276 if sharedMeths.count 277 sharedMeths.sort(ref .compareMethodNames) 278 print ' shared' 279 for meth in sharedMeths 280 print ' [meth.cobraSourceSignature(false)]' 281 objectMeths = for meth in meths where not meth.isShared 282 if objectMeths.count 283 objectMeths.sort(ref .compareMethodNames) 284 for meth in objectMeths 285 print ' [meth.cobraSourceSignature]' 286 287 #/ 288 289 290 class Box is partial 291 292 get _jvmType as JavaClassType 293 """ 294 Returns the Jvm NativeType (System.Class eventually)) boxed in the .nativeType. 295 Throws exception rather than return nil. 296 """ 297 return (.nativeType to JvmNativeType).backEndType 298 299 def isJvmSystemExceptionClass as bool 300 return .name == 'Exception' and .parentNameSpace and .parentNameSpace.fullName == 'java.lang' 301 302 def _scanNativeTypeJvm 303 """ 304 Subclasses should invoke base and then invoke the various _scanXXX methods that are appropriate for them. 305 """ 306 ensure not .needScanNativeType 307 _needScanNativeType = false 308 # print '<> _scanNativeType for [.name] in [_parentNameSpace.fullName], class is [.getType.name]' 309 310 def _scanGenericArgsJvm 311 if _jvmType.isGenericType 312 for genArg in _jvmType.getGenericArguments 313 t = (.compiler to Compiler).typeForJvmType(genArg) 314 if t is nil 315 t = GenericParam(JvmNativeType(genArg), parentDefinition=this) 316 (.compiler to Compiler).addTypeForJvmType(t to !, genArg) 317 _genericParams.add(t) 318 319 def _prepSystemObjectClassJvm 320 # map method getType to java getClass 321 # C#'s typeof(X) is X.getType in Cobra. 322 #existing = .declForName('getClass') to BoxMember 323 #overload = MemberOverload(existing) 324 #.registerOverload(overload) 325 meth = Method(TokenFix.empty, TokenFix.empty, this, 'getType', List<of Param>(), .compiler.typeTypeProxy, nil, ['shared'], AttributeList(), 'Returns the Type instance that defines this type.') 326 meth.sharedMethodBacking = 'getClass' 327 #meth.sharedMethodBackingIsAlias = true # not static 328 #overload.addMember(meth) 329 .addDecl(meth) 330 331 def _scanJvmIsNames 332 # TODO 333 _isNames.add('extern') # to make the box like the ones that were in SystemInterfaces.cobra 334 335 def _scanJvmImplements 336 for interf in _jvmType.getInterfaces 337 if not _badJvmRelatedType(interf) 338 _baseInterfaceProxies.add(JvmTypeProxy(interf)) 339 340 /# 341 def _scanJvmNestedTypes 342 # TODO: enable and fix resulting bugs 343 # for type in .clrType.getNestedTypes(BindingFlags(Instance, Static, DeclaredOnly, Public, NonPublic)) 344 for type in _jvmType.getNestedTypes 345 _scanJvmNestedType(type) 346 #for type in _clrType.getNestedTypes(BindingFlags(Static, DeclaredOnly, NonPublic)) 347 for type in _jvmType.getNestedTypes 348 if type.isEnum and not type.isPublic 349 _scanJvmNestedType(type) 350 351 def _scanJvmNestedType(type as JavaClassType) 352 nativeType = JvmNativeType(type) 353 if type.isClass 354 .addDecl(Class(nativeType, .compiler.backEnd)) 355 else if type.isInterface 356 .addDecl(Interface(nativeType, .compiler.backEnd)) 357 else if type.isEnum 358 isNames = List<of String>() 359 docString ='' 360 .addDecl(EnumDecl(this, nativeType, isNames, docString)) # TODO: isNames; docString? 361 #else if type.isValueType 362 # .addDecl(Struct(clrType, .compiler.backEnd)) 363 #else if type.isAnsiClass 364 # # The Enum class is an example that returns false for .isClass but true for .isAnsiClass 365 # .addDecl(Class(clrType, .compiler.backEnd)) 366 else 367 throw FallThroughException(type) 368 lastDecl = .declsInOrder[.declsInOrder.count-1] to dynamic 369 if (lastDecl to Object).getType.getProperty('ParentBox') # CC: if lastDecl responds to (get parentBox as Box?) 370 lastDecl.parentBox = this 371 372 #/ 373 374 def _scanJvmFields 375 for fieldInfo in _jvmType.getFields 376 #if fieldInfo.declaringType is not _jvmType, continue 377 if fieldInfo.isDefault, continue # pkgprivate 378 if fieldInfo.isPrivate, continue 379 name = Utils.cobraNameForNativeMemberName(fieldInfo.name) 380 type = _jvmMemberTypeResultProxy(fieldInfo, fieldInfo.type) 381 attrs = AttributeList() 382 if fieldInfo.isProtected 383 isNames = ['protected'] # isNames = ['protected' 'internal'] 384 #else if fieldInfo.isDefault # pkgprivate 385 # isNames = ['internal'] # 386 else 387 isNames = ['public'] # private was guarded against above 388 389 if fieldInfo.isFinal and fieldInfo.isStatic # java static final fields are constants 390 value = if(fieldInfo.isStatic, fieldInfo.getValue, nil) 391 initExpr = SharpExpr(TokenFix.empty, if(value, .toString, 'nil')) # DocGenerator.cobra uses this 392 boxConst = BoxConst(TokenFix.empty, TokenFix.empty, this, name, type, isNames, initExpr, attrs, '') 393 boxConst.binaryName = fieldInfo.name 394 .addDecl(boxConst) 395 else 396 if fieldInfo.isStatic, isNames.add('shared') 397 if fieldInfo.isFinal, isNames.add('readonly') # final fields are readonly 398 varr = BoxVar(TokenFix.empty, TokenFix.empty, this, name, type, isNames, nil, attrs, '') 399 varr.binaryName = fieldInfo.name 400 .addDecl(varr) 401 402 def _scanJvmInitializers 403 for ctorInfo in _jvmType.getConstructors 404 if ctorInfo.isPrivate, continue 405 #if ctorInfo.declaringType is not _clrType, continue 406 skip = false 407 for paramInfo in ctorInfo.getParameters 408 if _badJvmRelatedType(paramInfo) 409 skip = true 410 break 411 if skip, continue 412 params = _scanJvmParams(ctorInfo.getParameters, ctorInfo.isVari) 413 isNames = _isNamesForJavaMemberInfo(ctorInfo) 414 attribs = _attribsForJavaMemberInfo(ctorInfo) 415 docString = '' # TODO: get doc string for class? 416 initer = Initializer(TokenFix.empty, TokenFix.empty, this, params, isNames, attribs, docString) 417 overload as MemberOverload? = nil 418 other = .declForName('cue.init') 419 if other 420 if other inherits MemberOverload 421 overload = other 422 else if other inherits AbstractMethod 423 overload = MemberOverload(other) 424 .registerOverload(overload to !) 425 else 426 throw FallThroughException([this, initer, other]) 427 if overload 428 overload.addMember(initer) 429 else 430 .addDecl(initer) 431 432 def _scanJvmProperties 433 for propInfo in _jvmType.getProperties 434 getMethod = propInfo.getter 435 setMethod = propInfo.setter 436 visible = false 437 if getMethod 438 if getMethod.isPublic or getMethod.isProtected 439 theMethod = getMethod 440 visible = true 441 if not visible and setMethod 442 if setMethod.isPublic or setMethod.isProtected 443 theMethod = setMethod to ! 444 visible = true 445 if not visible, continue 446 #if theMethod.declaringType is not _jvmType, continue 447 if propInfo.isIndexer 448 _scanJvmIndexer(propInfo) 449 continue 450 451 if _badJvmRelatedType(propInfo.type), continue 452 attribs = _attribsForJavaMemberInfo(propInfo) 453 docString = '' # TODO: get doc string 454 isNames = _isNamesForJavaMemberInfo(theMethod) 455 #print propInfo 456 propName = Utils.cobraNameForNativeMemberName(propInfo.name) 457 #if _declsByName.containsKey(propName), propName = propInfo.name0+'_prop' 458 prop = Property(TokenFix.empty, TokenFix.empty, this, propName, _jvmMemberTypeResultProxy(propInfo, propInfo.type), isNames, attribs, docString) 459 prop.binaryName = propInfo.name 460 if propInfo.isReadable 461 prop.makeGetPart(TokenFix.empty) 462 if propInfo.isWritable 463 prop.makeSetPart(TokenFix.empty) 464 if _declsByName.containsKey(prop.name) # for # Double.naN 465 print 'DUP name already exists already for property [prop.name]', _declsByName[prop.name], prop 466 return # just drop the property, field or method still available 467 .addDecl(prop) 468 469 470 def _scanJvmIndexer(propInfo as JavaFieldInfo) 471 for paramInfo in propInfo.getIndexParameters 472 if _badJvmRelatedType(paramInfo) 473 return 474 params = _scanJvmParams(propInfo.getIndexParameters, false) 475 attribs = _attribsForJavaMemberInfo(propInfo) 476 docString = '' 477 if propInfo.isReadable 478 isNames = _isNamesForJavaMemberInfo(propInfo.getter to !) 479 else if propInfo.isWritable 480 isNames = _isNamesForJavaMemberInfo(propInfo.setter to !) 481 else 482 throw FallThroughException(propInfo) 483 #name = Utils.cobraNameForNativeMemberName(propInfo.name) 484 name = r'[]' 485 indexer = Indexer(TokenFix.empty, TokenFix.empty, this, name, params, _jvmMemberTypeResultProxy(propInfo, propInfo.type), isNames, attribs, docString) 486 overload as MemberOverload? = nil 487 other = .declForName(name) 488 if other 489 if other inherits MemberOverload 490 overload = other 491 else if other inherits Indexer 492 overload = MemberOverload(other) 493 .registerOverload(overload to !) 494 else 495 throw FallThroughException([this, indexer, other]) 496 if overload 497 overload.addMember(indexer) 498 else 499 .addDecl(indexer) 500 501 # In Java properties are methods with leading is/get/set names 502 # Indexers are methods as for properties but with additional indexes in paramList. 503 def _scanJvmMethods 504 for methInfo in _jvmType.getMethods 505 if methInfo.isPrivate, continue 506 if methInfo.isDefault, continue # pkgPrivate 507 #if methInfo.declaringType is not _clrType, continue 508 skip = false 509 if _badJvmRelatedType(methInfo.returnType) 510 skip = true 511 else 512 for param in methInfo.getParameters 513 if _badJvmRelatedType(param) 514 skip = true 515 break 516 if skip, continue 517 name = Utils.cobraNameForNativeMemberName(methInfo.name) 518 genericParams = List<of IType>() 519 for genArg in methInfo.getGenericArguments 520 genericParams.add(GenericParam(JvmNativeType(genArg))) 521 params = _scanJvmParams(methInfo.getParameters, methInfo.isVari) 522 isNames = _isNamesForJavaMemberInfo(methInfo) 523 if methInfo.isOverride, isNames.add('override') # only on methods 524 attribs = _attribsForJavaMemberInfo(methInfo) 525 docString = '' 526 implementsTypeNode as ITypeProxy? # TODO: explicit interface implementation? 527 method = Method(TokenFix.empty, TokenFix.empty, this, name, genericParams, params, _jvmMemberTypeResultProxy(methInfo, methInfo.returnType), implementsTypeNode, isNames, attribs, docString) 528 method.binaryName = methInfo.name 529 overload as MemberOverload? = nil 530 other = .declForName(name) 531 if other 532 if other inherits MemberOverload 533 overload = other 534 else if other inherits AbstractMethod 535 overload = MemberOverload(other) 536 .registerOverload(overload to !) 537 else 538 print 'Unexpected overload for name:', name, other 539 throw FallThroughException([this, method, other]) 540 if overload 541 overload.addMember(method) 542 else 543 .addDecl(method) 544 545 def _scanJvmParams(jparams as List<of JavaClassType>?, isVariMethod as bool) as List<of Param> 546 """ 547 Returns a list of Cobra Params given a list of Java ClassTypes (presumably a java parameterList) 548 """ 549 params = List<of Param>() 550 if not jparams or not jparams.count 551 return params 552 553 paramN = 0 554 for javaParam in jparams 555 paramN +=1 556 isVari = paramN == jparams.count and isVariMethod #and javaParam is an array 557 # TODO support varags detection. 558 #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) 559 560 # TODO: detect nullable on paramlist types ? 561 # To support nilable on params need change representation to a javaParamType containing type + attributes (for param) ( + direction possibly) 562 # Java not support nilable directly so ignore for moment 563 #isNotNull = javaParam.isNonNullable 564 isNotNullable = false # can be null 565 parameterType = javaParam 566 type = _jvmMemberTypeProxy(parameterType, isNotNullable) 567 if isVari, type = VariTypeProxy(type) 568 name = 'unkname' # java not keep names of given formal parameters 569 param = Param(name, type) 570 param.direction = Direction.In # Java doesnt have Out or InOut equivs 571 params.add(param) 572 return params 573 574 575 def _isNamesForJavaMemberInfo(mi as JavaMemberInfo) as List<of String> 576 """ 577 Returns the Cobra "is names" such as ['public', 'static'] that correspond to the properties of the JavaMember. 578 """ 579 isNames = List<of String>(8) 580 if mi.isDefault, isNames.add('internal') # pkgPrivate/internal and protected 581 # actually 582 #if mi.isProtected 583 # isNames.add('protected') 584 # isNames.add('internal') # TODO: address this later 585 if mi.isProtected, isNames.add('protected') 586 if mi.isPrivate, isNames.add('private') 587 if mi.isPublic, isNames.add('public') 588 if mi.isStatic, isNames.add('shared') 589 if mi.isAbstract, isNames.add('abstract') 590 if mi.isFinal, isNames.add('readonly') 591 return isNames 592 593 def _attribsForJavaMemberInfo(mi as JavaMemberInfo) as AttributeList 594 return AttributeList() # TODO: 595 596 597 def _badJvmRelatedType(t as JavaClassType?) as bool 598 """ 599 Returns true if the given type, which comes from a parameter or return value, is unsupported. 600 For example, it's not public or it's nested. Members with bad types are skipped when scanning DLLs. 601 """ 602 if t is nil 603 return false 604 605 if t.isNested and not (t.isPublic or t.isProtected)and not t.isGenericParameter # TODO: need the generic param check? 606 print 'Type t.name is nested and not public,protected' 607 return true 608 609 # FYI: MS .NET 2.0 (but not Mono 1.2.6) will return true for .isNotPublic for types are "by ref" 610 #if t.isByRef # TODO: or t.isArray 611 # return _badJvmRelatedType(t.getElementType) 612 613 return false 614 615 def _jvmMemberTypeProxy(jvmType as JavaClassType?) as ITypeProxy 616 return _jvmMemberTypeProxy(jvmType, false) 617 618 def _jvmMemberTypeProxy(jvmType as JavaClassType?, notNull as bool) as ITypeProxy 619 """ 620 Returns a type proxy for a member type such as a parameter type. 621 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. 622 """ 623 if jvmType is nil 624 return .compiler.voidType 625 else if jvmType.isValueType 626 return JvmTypeProxy(jvmType) 627 else 628 # 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 629 tp = JvmTypeProxy(jvmType) to ITypeProxy 630 if not notNull 631 tp = NilableTypeProxy(tp) 632 return tp 633 634 def _jvmMemberTypeResultProxy(member as JavaMemberInfo, jvmType as JavaClassType?) as ITypeProxy 635 """ 636 Returns a type proxy for a member type such as a method return type, property or field. 637 In Java, reference types are nilable by default. 638 """ 639 if jvmType is nil 640 return .compiler.voidType 641 else if jvmType.isValueType 642 return JvmTypeProxy(jvmType) 643 else if jvmType.isValueType or jvmType.isGenericParameter 644 return JvmTypeProxy(jvmType) 645 else 646 notNull = member.isNonNullable 647 t = JvmTypeProxy(jvmType) to ITypeProxy 648 return if(notNull, t, NilableTypeProxy(t)) 649 650 651 class Class 652 is partial 653 654 def _scanNativeTypeJvm 655 base._scanNativeTypeJvm 656 print 'scanJvmNativeType ', .name 657 _scanJvmIsNames 658 _scanJvmImplements 659 #_scanJvmNestedTypes 660 _scanJvmFields 661 _scanJvmInitializers 662 _scanJvmMethods 663 _scanJvmProperties # do props last since they are synthesized 664 ##_scanJvmEvents TODO 665 # TODO: _scanJvmEnums 666 # TODO: scan all other nested types 667 668 669 class Interface 670 is partial 671 672 def _scanNativeTypeJvm 673 base._scanNativeTypeJvm 674 _scanJvmIsNames 675 _scanJvmImplements 676 #_scanJvmNestedTypes 677 _scanJvmFields 678 _scanJvmMethods 679 _scanJvmProperties 680 #_scanJvmEvents #TODO 681 682 683 class Struct 684 is partial 685 686 def _scanNativeTypeJvm 687 base._scanNativeTypeJvm 688 _scanJvmIsNames 689 _scanJvmImplements 690 #_scanJvmNestedTypes 691 _scanJvmFields 692 _scanJvmInitializers 693 _scanJvmMethods 694 _scanJvmProperties 695 #_scanJvmEvents 696 697 698 class Extension 699 is partial 700 701 def _scanNativeTypeJvm 702 # this only for Cobra specific extensions. Example: class Extend_String_1939 703 base._scanNativeTypeJvm 704 _scanJvmIsNames 705 #_scanJvmImplements 706 #_scanJvmNestedTypes 707 #_scanJvmFields 708 #_scanJvmInitializers 709 #_scanJvmProperties 710 _scanJvmMethods 711 #_scanJvmEvents 712 713 def _scanJvmParams(jparams as List<of JavaClassType>?, isVariMethod as bool) as List<of Param> is override 714 # the first argument is implicit in an Extension 715 results = base._scanJvmParams(jparams, isVariMethod) 716 return results[1:] 717 718 def jvmExtnNativeType(nativeType as NativeType) as NativeType 719 # the real extended type is the type of the first argument of any method 720 for methInfo in _jvmType.getMethods 721 nativeType = JvmNativeType(methInfo.getParameters[0]) 722 break 723 return nativeType 724 725 726 727 class EnumDecl 728 is partial 729 730 def _setUnderlyingTypeJvm 731 pass 732 733 def _scanNativeTypeJvm 734 # TODO: read attribs 735 _needScanNativeType = false 736 _storageType = .compiler.anyIntType # tmp ?? 737 738 /# Enable when have Enum and JavaEnumType in PkgSig and JarSig 739 jvmType = (_nativeType to JvmNativeType).backEndType 740 assert jvmType inherits JavaEnumType # temporary 741 for name, value in jvmType.getConstantValues # list of names and values 742 intValue = value to int 743 member = EnumMember(name, intValue) 744 member.enumDecl = this 745 .addDecl(member) 746 #/ 747 748 /# 749 isByte = Enum.getUnderlyingType(jvmType).name == 'Byte' 750 is64 = Enum.getUnderlyingType(jvmType).name == 'Int64' 751 isU32 = Enum.getUnderlyingType(jvmType).name == 'UInt32' 752 isU64 = Enum.getUnderlyingType(jvmType).name == 'UInt64' 753 values = Enum.getValues(jvmType) 754 i = 0 755 for name in Enum.getNames(jvmType) 756 value = values.getValue(i) 757 # CC: lameness follows 758 if isByte 759 intValue = int.parse((value to uint8).toString) 760 else if is64 761 try 762 intValue = int.parse((value to int64).toString) 763 catch OverflowException 764 intValue = 999 # CC: omg. but probably doesn't affect anything. we're reading the DLL here, not creating one 765 else if isU32 766 try 767 intValue = int.parse((value to uint32).toString) 768 catch OverflowException 769 intValue = 2147483647 770 else if isU64 771 try 772 intValue = int.parse((value to uint64).toString) 773 catch OverflowException 774 intValue = 2147483647 775 else 776 intValue = value to int 777 member = EnumMember(name, intValue) 778 member.enumDecl = this 779 .addDecl(member) 780 i += 1 781 #/ 782 783 784 -
Source/BackEndJvm/JvmBackEnd.cobra
1 # Backend for generating Java code to run on a JVM - Currently this is cross-compile only fm .net/mono. 2 use System.Diagnostics 3 1 4 class JvmBackEnd inherits BackEnd 2 5 6 var _objectTypeProxy as AbstractTypeProxy? 7 var _typeTypeProxy as AbstractTypeProxy? 8 3 9 cue init(compiler as Compiler) 4 10 base.init(compiler) 11 _name = 'java-jvm' 12 _rtlName = 'CobraLang.jar' 13 14 _tagToTypeName = { 15 'Object': 'java.lang.Object', 16 'Type' : 'java.lang.Class<of>', # java.lang.Type is a marker interface 17 'String' : 'java.lang.String', 18 'Exception' : 'java.lang.RuntimeException', 5 19 20 'Delegate' : 'System.Delegate', #cobra.lang.Delegate 21 'Attribute' : 'java.lang.annotation.Annotation', 22 #'ICloneable': 'System.ICloneable', #cobra.lang.ICloneable 23 'IEnumerable': 'java.lang.Iterable', 24 'IEnumerator': 'java.lang.Iterator', 25 'IEnumerable<of>' : 'java.lang.Iterable<of>', 26 'IEnumerator<of>' : 'java.lang.Iterator<of>', 27 'IDictionaryEnumerator' : 'System.Collections.IDictionaryEnumerator', 28 'ICollection': 'java.util.Collection<of Object>', # non generic collection interface 29 'ICollection<of>': 'java.util.Collection<of>', 30 'IList' : 'java.util.List<of Object>', # non generic List interface 31 'IList<of>' : 'java.util.List<of>', 32 'List<of>': 'java.util.ArrayList<of>', 33 'IDictionary': 'java.util.Map<of Object,Object>', # Non Generic Map/Dict interface 34 'IDictionary<of,>': 'java.util.Map<of,>', 35 'Dictionary<of,>' : 'java.util.HashMap<of,>', 36 'Set<of>': 'java.lang.HashSet<of>', 37 38 'bool' : 'java.lang.Boolean', # boolean 39 'char' : 'java.lang.Character',# char 40 'decimal': 'java.lang.Double', # ?? 41 'single': 'java.lang.Float', # float 42 'double': 'java.lang.Double', # double 43 'sbyte' : 'java.lang.Byte', # byte 44 'int16' : 'java.lang.Short', # short 45 'int32' : 'java.lang.Integer', # int 46 'int64' : 'java.lang.Long', # long 47 'byte' : 'java.lang.Short', # short # rest are unsigned - use next widest 48 'uint16': 'java.lang.Integer', # int 49 'uint32': 'java.lang.Long', # long 50 'uint64': 'java.lang.Long', # long 51 52 } 53 6 54 def makePhases(phases as IList<of Phase>) is override 55 # TODO 56 #phases.add(ApplyExtendedClasses(.compiler) # ?? done here or earlier 57 #phases.add(AggregatePartialClassesCodePhase(.compiler) 7 58 phases.add(GenerateJavaCodePhase(.compiler)) 8 59 phases.add(CompileJavaCodePhase(.compiler)) 9 60 10 61 def computeOutName as String is override 11 62 return .compiler.computeOutNameJava 12 63 64 def genNativeModule(filename as String, verbosity as int) as Module? is override 65 m as Module? 66 if filename.endsWith('.java') 67 if verbosity, print 'Noting [filename] as JavaModule' # extra space to line up with 'Parsing [filename]' 68 m = JavaModule(filename, verbosity) 69 return m 70 71 def setupRunProcess(baseExe as String, fullExe as String) as Process is override 72 p = Process() 73 p.startInfo.fileName = 'java' 74 clPath = Path.getDirectoryName(CobraCore.exePath) to ! 75 clPath = Path.combine(clPath, 'CobraLang.jar') 76 classpath = Environment.getEnvironmentVariable('CLASSPATH') 77 cpSep = if(CobraCore.isRunningOnUnix, ':', ';') 78 classpath = '.[cpSep][clPath][cpSep][classpath]' 79 # TODO: additional classpaths for references 80 args = '-ea -cp "[classpath]"' 81 args += ' [baseExe]' 82 83 p.startInfo.arguments = args + ' ' 84 #print p.startInfo.fileName, p.startInfo.arguments 85 return p 86 87 def setDefaultUseDirectives(ns as NameSpace) is override 88 # java packages available by default 89 useToken = Token('(implicit)', 1, 1, 1, 'USE', 'use', nil) 90 # java uses lowercase for package names - Should Cobra stay capitalised and we remap it ?? 91 ns.addUseDirective(UseDirective(useToken, ['java', 'lang'])) 92 #ns.addUseDirective(UseDirective(useToken, ['System', 'Collections', 'Generic'])) # generics built in 93 ns.addUseDirective(UseDirective(useToken, ['java', 'io'])) 94 ns.addUseDirective(UseDirective(useToken, ['java', 'util'])) 95 ns.addUseDirective(UseDirective(useToken, ['java', 'text'])) 96 ns.addUseDirective(UseDirective(useToken, ['cobra', 'lang'])) 97 98 def fixLibExtension(libRef as String) as String is override 99 """ 100 Augment given lib reference string with .jar backend extension if not already have one 101 """ 102 or require libRef.length 103 and ensure result.endsWith('.jar') 104 if not libRef.endsWith('.jar') 105 libRef += '.jar' 106 return libRef 107 108 def loadLibReference(reference as String) as bool is override 109 """ 110 Load referenced library (jar file) 111 """ 112 # Currently with cross compile fm .Net cant do this (easily) as not in a java environ 113 # (can we use Ikvm for this to bootstrap?) 114 # so what we will do is test for the existance of the jarfile in some sensible places 115 # (cwd, classpath, default install rt and extensions dir) and if it is found return true 116 # 117 #return .compiler.javaLoadReference(reference) 118 # -> reference -> jarFile -> JarSig(jarFile) -> javaReadJar 119 assert reference.endsWith('.jar') 120 return .compiler.jvmLoadReference(reference) # in ScanJvmType 121 122 def readSystemTypes is override 123 #pass # TODO 124 # Initially we will rely on a external java tool to have been run to produce a precis 125 # file in a known place (same as cobra compiler perhaps) containing exported types for 126 # items in a jar file. 127 128 # JarSig is a holder for jarfile extended with info on contained classes. 129 # javaReadJar loads info on contained classes into Cobra 130 # rt.jar is only one we need 131 .compiler.javaReadJar(JarSig('rt.jar')) 132 133 def fixNilableMemberSigs is override 134 #.compiler.javafixNilableMemberSigs 135 print '++ TODO jvmBackEnd.fixNilableMemberSigs' 136 pass # TODO 137 138 def installNativeMethods(box as Box, nativeType as NativeType) is override 139 #.compiler.installJvmNativeMethods(box, nativeType) 140 print '++ TODO jvmBackEnd.installNativeMethods' 141 pass # TODO 13 142 143 def cobraNameForNativeBoxName(nativeBoxName as String) as String is override 144 return JvmTypeProxy.cobraNameForJvmBoxName(nativeBoxName) 145 146 # Types 147 get objectTypeProxy as AbstractTypeProxy is override 148 """Type proxy for BE root of Object hierarchy.""" 149 if not _objectTypeProxy 150 _objectTypeProxy = JvmTypeProxy(JarSig.classByNameCache['java.lang.Object']) 151 return _objectTypeProxy to ! 152 153 get typeTypeProxy as AbstractTypeProxy is override 154 """Type proxy for BE notion of a class describing a Type.""" 155 if not _typeTypeProxy 156 _typeTypeProxy = JvmTypeProxy(JarSig.classByNameCache['java.lang.Class']) 157 return _typeTypeProxy to ! 158 159 def nativeTypeProxy(type as NativeType) as NativeTypeProxy is override 160 return JvmTypeProxy(type) 161 162 def nativeType(type as dynamic) as NativeType is override 163 return JvmNativeType(type) 164 165 def nativeTypeByName(qualifiedNameOrTag as String) as NativeType is override 166 #map qualified name of .net aliased types to java equivalents 167 # bool, char, decimal, single, double, sbyte, int{16,32,64}, byte, uint{16,32,64}, 168 qualifiedName = .resolveTypeTag(qualifiedNameOrTag) 169 return JvmNativeType(.compiler.jvmTypeByName(qualifiedName)) 170 /# 171 These are the type tags used directly by the compiler code. 172 173 bool 'Java.lang.Boolean' 174 char 'java.lang.Char' 175 decimal '??System.Decimal' 176 decimal 'java.lang.Float' 177 single 'java.lang.Float' 178 double 'java.lang.Double' 179 sbyte 'java.lang.Byte' 180 int16 'java.lang.Short' 181 int32 'java.lang.Int' 182 int64 'java.lang.Long' 183 # java not have unsigned types (:-( use next largest signed Type 184 byte 'java.lang.Short' #& 0x7f 185 uint16 'java.lang.Int' 186 uint32 'java.lang.Long' 187 uint64 'java.lang.Long' 188 #/ 189 190 def addArrayInterfaces(interfaces as List<of ITypeProxy>) is override 191 pass 192 #iclone = .compiler.libraryType('ICloneable') # ICloneable not supported 193 #interfaces.insert(0, iclone to ITypeProxy) 194 195 196 14 197 class GenerateJavaCodePhase inherits Phase 15 198 16 199 cue init(c as Compiler) -
Source/BackEndJvm/JavaCompilationMessage.cobra
11 11 assert msg.lineNum == 30 12 12 13 13 def willSkipMessage(msg as String) as bool is shared 14 return not '.java:' in msg 15 14 #return not '.java:' in msg 15 return false 16 16 17 var _fileName as String? 17 18 var _lineNum as int? 18 19 var _isError as bool … … 24 25 line = line.trim 25 26 _isError = true 26 27 i = line.indexOf('.java:') 27 _fileName = line[:i] 28 i += '.java:'.length 29 j = line.indexOf(':', i) 30 lineStr = line[i:j] 31 try 32 _lineNum = int.parse(lineStr) 33 catch 34 pass 35 success 36 _lineNum = compiler.cobraLineNumForCurly(.fileName, _lineNum to !) 37 if compiler.verbosity or Utils.isDevMachine, line += ' (javac)' 28 if i >= 0 29 _fileName = line[:i] 30 i += '.java:'.length 31 j = line.indexOf(':', i) 32 lineStr = line[i:j] 33 try 34 _lineNum = int.parse(lineStr) 35 catch 36 pass 37 success 38 _lineNum = compiler.cobraLineNumForCurly(.fileName, _lineNum to !) 39 if compiler.verbosity or Utils.isDevMachine, line += ' (javac)' 38 40 _message = _cleanUp(line) 39 41 40 42 def _cleanUp(line as String) as String -
Source/BackEndJvm/JavaGenerator.cobra
1 1 """ 2 Generate Java source code file for cobra AST. 3 2 4 The code in this file should not .throwError, record warnings, etc. 3 5 All of that happens during .bindFoo phases. 4 6 """ … … 10 12 11 13 class Compiler is partial 12 14 15 # run prior to compilation to determine an output filename for the java source 16 # for testing for need for compilation. 17 # Filename used may be determined later post AST generation using the first classname in file 18 # see 'fixup output filename' in compileJava below 13 19 def computeOutNameJava as String 14 20 outName ='' 15 21 if .options.boolValue('test') … … 40 46 41 47 def writeJavaTestInvocation 42 48 # TODO 43 p ass49 print 'TODO: writeJavaTestInvocation' 44 50 45 51 def compileJava 46 52 .compileJava('') … … 53 59 options = .options 54 60 55 61 # locate the Java compiler 56 compilerPath = options.getDefault('native-compiler', '') to String 57 if compilerPath <> '' 62 # TODO: This just does files compilation, augment to also generate manifest and executable jarfile 63 # TODO: augment to use Java library compiler when Java native 64 compilerPath = options.getDefault('native-compiler', 'auto') to String 65 if compilerPath <> 'auto' 58 66 if File.exists(compilerPath) 59 67 pass 60 68 else if File.exists(compilerPath+'.exe') … … 63 71 print 'Cannot find compiler specified by -native-compiler argument: [compilerPath]' 64 72 throw StopCompilation(this) 65 73 else 74 # TODO use a javatool - wrap javac and jarfile gen for multiple files 75 # javaTool -m MainClass -o outFile file-list 66 76 compilerPath = if(Utils.isRunningOnUnix, 'javac', 'javac.exe') 67 77 68 78 optChar = '-' 69 79 70 # exeNames 80 # exeNames - javaTool 71 81 outName = .computeOutNameJava 82 83 # compute backEndOptions 84 backEndOptions = '-d .' # Put namespaced classfiles in own hierarchy 72 85 73 # compute backEndOptions74 backEndOptions = ''75 86 # -optimize isn't supported by JVM, but it could potentially be used by Cobra itself 76 87 77 88 # TODO: 78 89 # for refer in .loadedReferences # don't take the library references from options, because the references can grow 79 # backEndOptions += ' "[optChar]r:[refer]"' 90 # backEndOptions += ' "[optChar]r:[refer]"') 80 91 81 92 debug = options.getDefault('debug', '') to String 82 93 if debug.length … … 87 98 # TODO: not until the java backend is more mature 88 99 # backEndOptions += ' -nowarn' 89 100 90 backEndOptions += ' ' +extraJavacOptions101 backEndOptions += extraJavacOptions 91 102 92 103 nativeArgs = .options.getDefault('native-compiler-args', '') to String 93 104 if nativeArgs.length 94 105 if nativeArgs.length > 2 and nativeArgs[0]=="'" and nativeArgs[nativeArgs.length-1]=="'" 95 # on Windows, you should really use double quotes instead of single, but 96 # we try to compensate here. 106 # on Windows, you should really use double quotes instead of single, but we try to compensate here. 97 107 nativeArgs = nativeArgs[1:-1] 98 108 backEndOptions += ' ' + nativeArgs 99 109 110 #sep = if(CobraCore.isRunningOnUnix, ':', ';') # after next snapshot 111 cpSep = ';' 112 if (Environment.osVersion.platform to int) in [4, 6, 128] # http://www.mono-project.com/FAQ:_Technical 113 cpSep = ':' 114 115 libclassPath = '' 100 116 for libPath in .options.getStringList('library-directory') 101 backEndOptions += ' ' + '-classpath "[libPath]"'117 libclassPath += '[cpSep][libPath]"' 102 118 103 # Cobra.Lang.dll is in the same directory as cobra.exe 104 libPath = Path.getDirectoryName(CobraCore.exePath) to ! 105 backEndOptions += ' ' + '-classpath "[libPath]"' 106 107 # .java files 119 # Cobra.Lang.dll is in the same directory as cobra.exe, 120 # explicitly add reference to it until we get setup to install a copy in extdirs 121 ccPath = Path.getDirectoryName(CobraCore.exePath) to ! 122 ccPath = Path.combine(ccPath, 'CobraLang.jar') 123 backEndOptions += ' -classpath "[ccPath][libclassPath]"' 124 125 # TODO: add libPaths/classpaths for referenced namespaces 126 127 # .java files fm first class name in each module 108 128 javaFileNameList = List<of String>() 109 129 for module in _modules[1:] 110 130 if module.javaFileName.length 111 131 javaFileNameList.add(module.javaFileName) 112 132 133 # fixup javaMain pkg path all lower case 134 # fixup output filename (classfile) to be in sync with Java filename 135 javaMain = _getFixedMainType 136 if outName <> javaFileNameList[0] 137 outName = javaFileNameList[0] 138 #_baseExeFileName = Path.changeExtension(outName, nil) to ! # remove any extn 139 _baseExeFileName = javaMain 140 outName = Utils.forceExtension(outName, '.class') 141 _fullExeFileName = outName 142 113 143 # compilation command 114 144 if _verbosity 115 145 print 'Compiling to produce [outName]' 146 if _verbosity >= 2 147 print 'compiler =', compilerPath 148 print ' compilerOptions =', backEndOptions 149 print ' nativeArgs =', nativeArgs 150 print ' outName =', .fullExeFileName 151 print ' baseExeFileName =', .baseExeFileName 152 print ' javaFileNameList =', javaFileNameList 116 153 117 # TODO: need to encapsulate this in CobraCore to avoid .NET dependency 118 p = System.Diagnostics.Process() 119 p.startInfo.fileName = compilerPath 120 javaFileNames = (for fileName in javaFileNameList get '"' + fileName + '"').join(' ') 121 p.startInfo.arguments = '[backEndOptions] [javaFileNames]' 122 if _verbosity >= 2 123 print '[p.startInfo.fileName] [p.startInfo.arguments]' 124 output = CobraCore.runAndCaptureAllOutput(p) 125 # TODO: check p.exitCode, especially if output is empty 154 output = _execAndCapture(compilerPath, backEndOptions, javaFileNameList) 126 155 _parseJavaCompilerOutput(output) 127 156 128 157 if .errors.count 129 158 _exitFromErrors 130 159 131 160 _deleteIntermediateFiles 132 161 162 # Better would be options as optionList as List<of String> but ftm we're stuck with space joined strings 163 # coming into caller 164 # TODO: move this to CobraCore to avoid .NET dependency 165 def _execAndCapture(binaryPath as String, options as String, fileNameList as List<of String>) as String 166 p = System.Diagnostics.Process() 167 p.startInfo.fileName = binaryPath 168 #options = optionList.join(' ') 169 fileNames = (for fileName in fileNameList get '"' + fileName + '"').join(' ') # MSW quoting 170 p.startInfo.arguments = '[options] [fileNames]' 171 if _verbosity >= 2 172 print '[p.startInfo.fileName] [p.startInfo.arguments]' 173 output = CobraCore.runAndCaptureAllOutput(p) 174 # TODO: check p.exitCode, especially if output is empty 175 return output 176 133 177 def _parseJavaCompilerOutput(output as String) 134 178 for line in output.split(c'\n') 135 179 line = line.trim … … 142 186 _addMessage(JavaCompilationMessage(line, this)) 143 187 144 188 189 def _getFixedMainType as String 190 """ 191 Fixup mainMethodType for java so that any pkg path (namespace) is all lowercase. 192 We force this in NameSpace.writeJavaDef. 193 """ 194 javaMain = .mainMethodTypeName 195 exeParts = javaMain.split('.').toList 196 if exeParts.count >1 197 javaPkg = exeParts[0:-1].join('.').toLower 198 javaMain = '[javaPkg].[exeParts.last]' 199 #trace .mainMethodTypeName, javaMain 200 return javaMain 145 201 ## 146 202 ## Node 147 203 ## … … 239 295 240 296 get javaFileName as String is override 241 297 if _javaFileName == '' and not _fileName.endsWith('SystemInterfaces.cobra') 242 _javaFileName = _fileName + '.java' 298 #java source files are persnickety about naming wrt classname contents. 299 filename = _fileName 300 if filename.endsWith('.cobra') or filename.endsWith('.COBRA'), filename = filename[:-6] 301 302 #use first className in File 303 classFileName = _firstClassName 304 if classFileName.length 305 filename = classFileName 306 _javaFileName = filename + '.java' 243 307 return _javaFileName 244 308 309 def _firstClassName as String 310 """Find first class name declared in the Module.""" 311 classFileName = '' 312 for decl in .topNameSpace.declsInOrder 313 if decl inherits Class 314 classFileName = decl.name 315 break 316 if decl inherits NameSpace 317 ns = decl 318 for decl1 in ns.declsInOrder 319 if decl1 inherits Class 320 classFileName = decl1.name 321 break 322 return classFileName 323 245 324 def writeJavaDef as Dictionary<of int, int>? is override 246 325 file = File.createText(.javaFileName) 247 326 using sw = CurlyWriter(file, CurlyLineNumberTreatment.Comment) 248 327 .compiler.addIntermediateFile(_javaFileName) 249 328 sw.start(.fileName) 250 sw.write('// [_javaFileName] \n')251 sw.write('// Generated by Cobra \n') # TODO: put version number here329 sw.write('// [_javaFileName] from [_fileName]\n') 330 sw.write('// Generated by Cobra-[CommandLine.versionString]\n') 252 331 sw.write('// on [DateTime.now]\n') 253 332 # TODO: list op sys 254 333 sw.write('\n') 255 334 256 # TODO DELME sw.write('using Cobra.Lang = Cobra.Lang[.compiler.embedRunTimeSuffix];\n')257 258 335 .topNameSpace.writeJavaDef(sw) 259 336 d = sw.curlyToCobraLineNum 260 337 return d … … 276 353 class Container<of TMember> is partial 277 354 278 355 get javaInit as String # TODO: is abstract 356 """ 357 Initial (default) value for a type (in java). 358 """ 279 359 return '' 280 360 281 361 get javaNameComponent as String … … 300 380 get _computeJavaRef as String 301 381 if .parent 302 382 s = .parent.javaRef 303 # TODO: delme304 #if s.length and not s.endsWith('::') # C# has weird "global::" name305 # s += '.'306 383 s += .javaName 307 384 else 308 385 s = .javaName 309 386 return s 310 387 311 388 def writeJavaIsNames(sw as CurlyWriter) 312 # TODO: look up Java access levels313 389 # java access levels: 390 # static, public, protected, private, (package-private), internal, abstract, final 314 391 # TODO: cache this somewhere 315 392 accessLevels = ['public', 'protected', 'internal', 'protected internal', 'private'] 316 393 # CC: accessLevels = 'public,protected,internal,protected internal,private'.split(c',') 317 # same names in both Cobra and C#318 394 319 395 # TODO: 320 396 # if isNames is nil … … 323 399 isNames.addRange(_isNames) 324 400 if .defaultAccessLevel.length 325 401 found = false 326 for level as String in accessLevels # CC: axe as402 for level in accessLevels 327 403 if level in isNames 328 404 found = true 329 405 if not found 330 406 isNames.insert(0, .defaultAccessLevel) 331 407 isNameJava = { 332 408 # only have to specify the ones that are different 333 'shared': 'static', 334 'nonvirtual': '', 409 'shared' : 'static', 410 # virtual/override, nonvirtual/new only on methods and props?? 411 #'nonvirtual': '', # n/a - final is similar but cannot override (new) 412 #'new' : '', # n/a - cant override a final 413 #'virtual' : '', # default 414 #'override' : '', # n/a - TODO mark with annotation 415 #'readonly' : 'final' # Not applicable to boxes 416 # 'public' 417 #'protected': '', 418 #'private', 419 'internal' : '', # goes to nothing which is protected+package-private which is not quite the same 420 # 'abstract' 421 # 'partial' : '??' # wot to do about this ??? 335 422 } 336 423 sep = '' 337 424 for name in isNames … … 374 461 else 375 462 return value to String 376 463 377 get javaInit as String is override # TODO: remove when not a type378 assert false379 return ''464 #get javaInit as String is override # TODO: remove when not a type 465 # assert false 466 # return '' 380 467 381 468 get javaRef as String is override 382 469 return .fullName + .javaSuffix 383 470 384 471 get javaQualifier as String 385 472 ensure result.endsWith('.') 386 return .fullName + .javaSuffix + '.' 473 # TODO : Fix this with correct Namespace setup for java 474 #if .fullName == 'System' 475 # return 'java.lang.' 476 javaName = .fullName.toLower # java idiom is all lowercase for packages 477 return javaName + .javaSuffix + '.' 387 478 388 479 def writeJavaDef(sw as CurlyWriter) is override 389 480 assert not .isUnified 390 481 base.writeJavaDef(sw) 391 # TODO: how to handle namespaces in Cobra392 #if not .isRoot393 # sw.writeAndIndent('namespace [.name][.javaSuffix] {\n\n')394 for ud in _useDirectives 482 if not .isRoot 483 javaName = .name.toLower # java idiom is all lowercase for packages 484 sw.write('package [javaName][.javaSuffix]; \n\n') 485 for ud in _useDirectives # imports 395 486 ud.writeJavaDef(sw) 396 487 for decl in _declsInOrder 397 488 if decl inherits Box … … 461 552 """ 462 553 # TODO: update doc string to reflect Java accurately 463 554 Returns a string that refers to this type including any necessary parameter declaration 464 specification such as Java'params' or 'out'. Invoked by Param.writeJavaDef.555 specification such as 'params' or 'out'. Invoked by Param.writeJavaDef. 465 556 """ 466 557 467 558 … … 482 573 return name 483 574 484 575 get javaRef as String 576 #print 'cobratype - [.javaName]' 485 577 return .javaName 486 578 487 579 get javaParamRef as String … … 496 588 get javaInit as String is override 497 589 return 'false' 498 590 591 get javaName as String is override 592 #return _nativeType.fullName 593 return 'boolean' 499 594 500 595 class CharType is partial 501 596 502 597 get javaInit as String is override 503 return '(char )0'598 return '(character)0' 504 599 505 600 506 601 class DynamicType is partial … … 515 610 class FloatType is partial 516 611 517 612 get javaName as String is override 518 return _nativeType.fullName 613 #return _nativeType.fullName 614 return 'float' 519 615 520 616 521 617 class IntType is partial 522 618 523 619 get javaName as String is override 524 return _nativeType.fullName 620 #return _nativeType.fullName 621 return 'int' # java.lang.Integer 622 # TODO byte = int8 , short = int16, int = Int32, long = int64 525 623 526 527 624 class NilableType is partial 528 625 529 626 get javaInit as String is override … … 560 657 class StreamType is partial 561 658 562 659 get javaInit as String is override 563 return 'new Cobra.Lang.EmptyStream<[.theWrappedType.javaRef]>()'660 return 'new cobra.lang.EmptyStream<[.theWrappedType.javaRef]>()' 564 661 565 662 get javaRef as String is override 566 663 assert .didBindInh and .didBindInt … … 658 755 else 659 756 java = .javaName 660 757 if .parentNameSpace and not .parentNameSpace.isRoot 758 #trace .parentNameSpace.javaQualifier 661 759 java = .parentNameSpace.javaQualifier + java 662 760 else if .parentBox 761 trace .parentBox.javaRef 663 762 java = .parentBox.javaRef + '.' + java 763 #trace java 664 764 return java 665 765 666 766 def writeJavaDef(sw as CurlyWriter) … … 769 869 expr.writeJavaDef(sw) 770 870 sw.write(')\n') 771 871 sw.indent 772 sw.write('throw new Cobra.Lang.InvariantException([expr.javaSourceSite(.name, "invariant", javaThis)], ')872 sw.write('throw new cobra.lang.InvariantException([expr.javaSourceSite(.name, "invariant", javaThis)], ') 773 873 expr.writeJavaBreakdown(sw) 774 874 sw.write('[javaThis], null);\n') 775 875 sw.dedent … … 809 909 def writeJavaInheritance(sw as CurlyWriter) is override 810 910 sw.write(' extends ') 811 911 if _baseClass 912 #trace _baseClass 812 913 sw.write(_baseClass.javaRef) 813 914 didWrite = true 814 915 if didWrite … … 872 973 873 974 874 975 class Struct is partial 875 976 # public class, public final fields, public methods? 876 977 get javaInit as String is override 877 978 return '' # blank to indicate there is no valid init 878 979 … … 975 1076 976 1077 class Param is partial 977 1078 978 def writeJav oDef(sw as CurlyWriter)1079 def writeJavaDef(sw as CurlyWriter) 979 1080 base.writeJavaDef(sw) 980 if .type.isReference and not .type inherits NilableType 981 sw.write(r'[Cobra.Lang.NotNull] ') 1081 # TODO 1082 #if .type.isReference and not .type inherits NilableType 1083 # sw.write(r'[Cobra.Lang.NotNull] ') 982 1084 branch .direction 983 1085 on Direction.In, pass 984 on Direction.InOut, sw.write(' ref ')985 on Direction.Out, sw.write(' out ')1086 on Direction.InOut, sw.write('/*inOut*/') # default 1087 on Direction.Out, sw.write('/*out*/') # TODO 986 1088 sw.write('[.type.javaParamRef] [.javaName]') 987 1089 988 1090 def writeJavaDefSansReferenceLabels(sw as CurlyWriter) … … 1021 1123 1022 1124 def writeJavaNotNull(sw as CurlyWriter) 1023 1125 if .resultType.isReference and not .resultType inherits NilableType 1024 sw.writeLine(r'[' + .javaNotNullPrefix + ' Cobra.Lang.NotNull]')1126 sw.writeLine(r'[' + .javaNotNullPrefix + 'cobra.lang.NotNull]') 1025 1127 1026 1128 get javaNotNullPrefix as String 1027 # TODO 1028 # 2007-12-22 Writing the attribute like [return: NotNull] is problematic because MemberInfo.getCustomAttributes() 1029 # will not see it. At least not on Novell Mono 1.2.4. I don't know if that is a bug or a "feature". 1030 #return 'return: ' 1129 # TODO make an annotation on BoxMember 1031 1130 return '' 1032 1131 1033 1132 def writeJavaTest(sw as CurlyWriter) … … 1058 1157 # if isNames is nil 1059 1158 # isNames = _isNames 1060 1159 1061 # TODO:1062 1160 isNameJava = { 1063 1161 # only have to specify the ones that are different 1064 1162 'shared': 'static', 1065 'nonvirtual': '', 1163 'nonvirtual': '', # n/a - final is similar but cannot override (new) 1164 'new' : '', # n/a - cant override a final 1165 'virtual' : '', # default 1166 'override' : '', # n/a - TODO mark with annotation 1167 'readonly' : 'final', 1168 # 'public', 'protected', 'private', 1169 'internal' : '' # goes to nothing which is package-private which is not quite the same 1170 # 'abstract' 1066 1171 } 1067 1172 wroteNames = Set<of String>() 1068 1173 sep = '' … … 1091 1196 # TODO: 1092 1197 1093 1198 get javaName as String is override 1094 return .name .capitalized1199 return .name #.capitalized 1095 1200 1096 1201 def writeJavaDef(sw as CurlyWriter) is override 1097 1202 base.writeJavaDef(sw) … … 1105 1210 1106 1211 class BoxField is partial 1107 1212 1108 get _backEndName as String 1109 name = .name 1110 if not name.startsWith('_') 1111 name = name.capitalized 1112 return name 1213 # java idiom uses same (sensible) naming style as cobra 1214 #get _javaBackEndName from name 1215 get _javaBackEndName as String 1216 return .name 1113 1217 1114 1218 1115 1219 class BoxConst is partial … … 1120 1224 .writeJavaIsNames(sw) 1121 1225 sw.write('const ') 1122 1226 sw.write(_type.javaRef) 1123 sw.write(' [_ backEndName] = ')1227 sw.write(' [_javaBackEndName] = ') 1124 1228 _initExpr.writeJavaDef(sw) 1125 1229 sw.write(';\n') 1126 1230 … … 1128 1232 class BoxVar is partial 1129 1233 1130 1234 get javaAssignmentNames as List<of String> 1131 return [_ backEndName]1235 return [_javaBackEndName] 1132 1236 # return List<of String>(_useBackEndNameStack) 1133 1237 1134 1238 get javaName as String is override 1135 1239 if _ifInheritsStack.count 1136 1240 if _type.isReference 1137 return '(([_ifInheritsStack.peek.javaRef])[_ backEndName])'1138 else 1241 return '(([_ifInheritsStack.peek.javaRef])[_javaBackEndName])' 1242 else # TODO fix this - .Net specific 1139 1243 # could it be a subclass? no. value types are structs and cannot be subclassed so this must be `if i` where `i` is nullable struct 1140 return '[_ backEndName].Value' # Nullable<of T>.Value1244 return '[_javaBackEndName].Value' # Nullable<of T>.Value 1141 1245 else 1142 1246 return .name 1143 1247 # return _useBackEndNameStack.peek to ! … … 1147 1251 .writeJavaAttribs(sw) 1148 1252 .writeJavaIsNames(sw) 1149 1253 sw.write(_type.javaRef) 1150 sw.write(' [_ backEndName]')1254 sw.write(' [_javaBackEndName]') 1151 1255 if _initExpr 1152 1256 sw.write(' = ') 1153 1257 _initExpr.writeJavaDef(sw) … … 1179 1283 def innerWriteJavaDef(sw as CurlyWriter) 1180 1284 pass 1181 1285 1182 def writeJavaImp(sw as CurlyWriter )1286 def writeJavaImp(sw as CurlyWriter, skipFirst as bool) 1183 1287 .compiler.codeMemberStack.push(this) 1184 1288 try 1185 1289 sw.writeAndIndent('{\n') … … 1201 1305 javaInit = param.type.javaInit 1202 1306 if not javaInit.length 1203 1307 # TODO/HACK: yes we need something like this (or a way to convice C# that the out param reference in `finally` really is okay), 1204 # but it should be something less hackish, like an attribute1205 1308 javaInit = 'DateTime.Today' 1206 1309 sw.write('[param.javaName] = [javaInit];') 1207 1310 if _backEndResultVarName.length # set in _bindImp … … 1210 1313 sw.write('= [_returnType.javaInit]') 1211 1314 sw.write(';\n') 1212 1315 sw.writeAndIndent('try {\n') 1213 for stmt in _stmts, stmt.writeJavaStmt(sw) 1316 for stmt in _stmts 1317 if skipFirst 1318 skipFirst = false 1319 continue 1320 stmt.writeJavaStmt(sw) 1214 1321 if willEnsure 1215 1322 if not stmt inherits ReturnStmt and not stmt inherits ThrowStmt 1216 1323 sw.write('_lh_canEnsure = true;\n') … … 1330 1437 if .isCompilerGenerated, return 1331 1438 if param.type.isReference and not param.type inherits NilableType and not param.isOut 1332 1439 if .compiler.options.boolValue('include-nil-checks') 1333 sw.write('if ( Cobra.Lang.CobraCore._willCheckNil && [param.javaName]==null) throw new System.ArgumentNullException("[param.name]");\n')1440 sw.write('if (cobra.lang.CobraCore._willCheckNil && [param.javaName]==null) throw new System.ArgumentNullException("[param.name]");\n') 1334 1441 1335 1442 def writeJavaDSTHead(sw as CurlyWriter) 1336 1443 if not .canHaveDetailedStackTrace 1337 1444 return 1338 1445 # could be a neat option, -trace-methods, but maybe done with events: 1339 1446 # sw.writeLine('Console.WriteLine(">> [.parentBox.name].[.name]");') 1340 sw.write(' Cobra.Lang.CobraImp.PushFrame("[.parentBox.name]", "[.name]", [Utils.javaStringLiteralFor(.token.fullPathName)], [.token.lineNum]')1447 sw.write('cobra.lang.CobraImp.pushFrame("[.parentBox.name]", "[.name]", [Utils.javaStringLiteralFor(.token.fullPathName)], [.token.lineNum]') 1341 1448 if not .isShared 1342 1449 sw.write(', "this", [.compiler.curBox.javaThis]') 1343 1450 for param in .params … … 1353 1460 # this catch all clashes with yield statements. which is why .canHaveDetailedStackTrace returns false if a method has a yield statement. 1354 1461 sw.dedentAndWrite('} catch (java.lang.Exception) {\n') 1355 1462 sw.indent 1356 sw.write(' Cobra.Lang.CobraImp.CaughtUncaughtException();\n')1463 sw.write('cobra.lang.CobraImp.CaughtUncaughtException();\n') 1357 1464 sw.write('throw;\n') 1358 1465 sw.dedentAndWrite('} finally {\n') 1359 1466 sw.indent 1360 sw.write(' Cobra.Lang.CobraImp.PopFrame();\n')1467 sw.write('cobra.lang.CobraImp.popFrame();\n') 1361 1468 sw.dedentAndWrite('}\n') 1362 1469 1363 1470 … … 1366 1473 def innerWriteJavaDef(sw as CurlyWriter) 1367 1474 base.innerWriteJavaDef(sw) 1368 1475 .writeJavaAttribs(sw) 1369 # delme first = if(_stmts.count, _stmts[0], nil) 1370 # delme callInitializer as String? = nil 1371 /# 1372 delme 1476 1477 .writeJavaIsNames(sw) 1478 sw.write(' [.parentBox.rootName]') 1479 .writeJavaParams(sw) 1480 1481 .writeJavaImp(sw, _hasCallInitializer) # Initializer Body 1482 1483 if _requirePart, _requirePart.writeJavaMethod(sw) 1484 if _ensurePart, _ensurePart.writeJavaMethod(sw) 1485 if .compiler.includeTests 1486 .writeJavaTest(sw) 1487 1488 def writeJavaImpHeader(sw as CurlyWriter) 1489 base.writeJavaImpHeader(sw) 1490 1491 first = if(_stmts.count, _stmts[0], nil) 1492 callInitializer as String? = nil 1373 1493 if first inherits DotExpr 1374 1494 if first.left inherits ThisOrBaseLit 1375 1495 if (firstRight = first.right) inherits IDotRightExpr … … 1378 1498 args = firstRight.args 1379 1499 Stmt.inInitCall = true 1380 1500 didSetInInitCall = true 1381 #/ 1382 .writeJavaIsNames(sw) 1383 sw.write(' [.parentBox.rootName]') 1384 .writeJavaParams(sw) 1385 /# 1386 delme 1387 if callInitializer 1388 sw.writeAndIndent('\n') 1389 sw.write(': [callInitializer](') 1390 sep = '' 1391 for arg in args 1392 sw.write(sep) 1393 arg.writeJavaDef(sw) 1394 sep = ', ' 1395 sw.write(') ') 1396 sw.dedent 1501 if args.count == 0 1502 sw.writeLine('//super() - default noarg initialiser call happens here') 1503 else 1504 sw.write('[callInitializer](') 1505 sep = '' 1506 for arg in args 1507 sw.write(sep) 1508 arg.writeJavaDef(sw) 1509 sep = ', ' 1510 sw.write(');') 1397 1511 if didSetInInitCall 1398 1512 assert Stmt.inInitCall # make sure it wasn't reset somewhere else 1399 1513 Stmt.inInitCall = false 1400 #/1401 .writeJavaImp(sw)1402 if _requirePart, _requirePart.writeJavaMethod(sw)1403 if _ensurePart, _ensurePart.writeJavaMethod(sw)1404 if .compiler.includeTests1405 .writeJavaTest(sw)1406 1514 1407 def writeJavaImpHeader(sw as CurlyWriter)1408 base.writeJavaImpHeader(sw)1409 1515 if .isStructMember and .compiler.options['contracts'] <> 'none' 1410 1516 sw.write('\n_ih_invariantGuard = 0;\n\n') # otherwise C# complains: Field "STRUCTNAME._ih_invariantGuard" must be fully assigned before control leaves the constructor 1411 1517 1412 1518 1519 def _hasCallInitializer as bool 1520 callInitializer as String? = nil 1521 first = if(_stmts.count, _stmts[0], nil) 1522 if first inherits DotExpr 1523 if first.left inherits ThisOrBaseLit 1524 if (firstRight = first.right) inherits IDotRightExpr 1525 if firstRight.name == 'init' 1526 callInitializer = (first.left to ThisOrBaseLit).asJava 1527 return callInitializer <> nil 1528 1529 1413 1530 class Method is partial 1414 1531 1415 1532 get javaGenericParams as String is override … … 1437 1554 name = _implementsType.javaRef + '.' + name 1438 1555 .writeJavaIsNames(sw) 1439 1556 sw.write('[returnType.javaRef] [name][.javaGenericParams]') 1440 .writeJavaParams(sw) 1557 if .isMain 1558 sw.write(r'(String[] args)') 1559 else 1560 .writeJavaParams(sw) 1441 1561 if .genericParams.count 1442 1562 sw.indent 1443 1563 for param in .genericParams … … 1448 1568 sw.write(';\n') 1449 1569 else 1450 1570 if .isAbstract, sw.writeLine(';') 1451 else, .writeJavaImp(sw )1571 else, .writeJavaImp(sw, false) 1452 1572 if _requirePart, _requirePart.writeJavaMethod(sw) 1453 1573 if _ensurePart, _ensurePart.writeJavaMethod(sw) 1454 1574 if .compiler.includeTests, .writeJavaTest(sw) … … 1457 1577 base.writeJavaImpHeader(sw) 1458 1578 if .isMain 1459 1579 if .compiler.hasExceptionReportOption 1460 sw.writeLine('try { // Exception Report') 1580 sw.writeLine('try { // Exception Report') 1461 1581 sw.indent 1462 else if .compiler.options.boolValue('debugging-tips') 1463 sw.writeLine('try { // -debugging-tips ')1582 else if .compiler.options.boolValue('debugging-tips') 1583 sw.writeLine('try { // -debugging-tips - turn off with -d/-debug (see cobra -h)') 1464 1584 sw.indent 1465 1585 if .isMain and .compiler.options.boolValue('include-tests') 1466 sw.writeLine(' Cobra.Lang.CobraCore.RunAllTests(); // turn off with -include-tests:no (see cobra -h)')1586 sw.writeLine('cobra.lang.CobraCore.runAllTests(); // turn off with -include-tests:no (see cobra -h)') 1467 1587 1468 1588 def writeJavaImpFooter(sw as CurlyWriter) 1469 1589 base.writeJavaImpFooter(sw) 1470 1590 if .isMain 1471 1591 if .compiler.hasExceptionReportOption 1472 1592 sw.dedent 1473 sw.writeLine('} catch (java.lang.Throwable _lh_exceptionReportThrowable) { Cobra.Lang.CobraCore.HandleUnhandledException(_lh_exceptionReportThrowable); }')1593 sw.writeLine('} catch (java.lang.Throwable _lh_exceptionReportThrowable) { cobra.lang.CobraCore.HandleUnhandledException(_lh_exceptionReportThrowable); }') 1474 1594 else if .compiler.options.boolValue('debugging-tips') 1475 1595 sw.dedent 1476 1596 sw.writeLine('} catch (java.lang.Throwable _lh_debuggingTipsThrowable) {') 1477 1597 sw.indent 1478 sw.writeLine('Cobra.Lang.CobraCore.PrintDebuggingTips();') 1479 sw.writeLine('throw _lh_debuggingTipsThrowable.fillInStackTrace();') 1598 sw.writeLine('cobra.lang.CobraCore.printDebuggingTips();') 1599 #sw.writeLine('throw _lh_debuggingTipsThrowable.fillInStackTrace();') 1600 sw.writeLine('_lh_debuggingTipsThrowable.printStackTrace();') 1480 1601 sw.dedent 1481 1602 sw.writeLine('}') 1482 1603 1483 1604 get javaName as String is override 1484 return .name .capitalized1605 return .name #.capitalized 1485 1606 1607 # Java, for its sins, does not have support for properties built into the language... 1608 # efforts to correct this stupidity seem to be mired in language navel gazing plus associated 1609 # belly button lint picking followed by mastubatory dick waving to find the most obscure and difficult 1610 # corner cases which then leads to it being then dropped in the 'too hard' basket 1611 # Historically and currently it instead uses a convention which leads to a whole lot of obfuscating boilerplate code 1612 # Its obviously too difficult to just copy C# (turnabout is fair play), accept and then evolve any edge misses 1486 1613 1487 1614 class ProperDexer is partial 1488 1615 … … 1579 1706 if not Path.isPathRooted(fileName) 1580 1707 fileName = Path.combine(Environment.currentDirectory, fileName) 1581 1708 fileName = Utils.javaStringLiteralFor(fileName) 1582 return 'new Cobra.Lang.SourceSite([fileName], [tok.lineNum], [boxName], [memberName], [javaThis])'1709 return 'new cobra.lang.SourceSite([fileName], [tok.lineNum], [boxName], [memberName], [javaThis])' 1583 1710 1584 1711 get javaThis as String 1585 1712 if _inInitCall # C# won't allow 'this' in a base constructor call -- TODO … … 1593 1720 1594 1721 def writeJavaSetLine(sw as CurlyWriter) 1595 1722 if _canSetLine and .token.lineNum > 0 1596 sw.write(' Cobra.Lang.CobraImp._curFrame._lineNum = [.token.lineNum];\n')1723 sw.write('cobra.lang.CobraImp._curFrame._lineNum = [.token.lineNum];\n') 1597 1724 1598 1725 def writeJavaStmt(sw as CurlyWriter) 1599 1726 assert .didBindImp … … 1608 1735 base.writeJavaDef(sw) 1609 1736 if not .compiler.options.boolValue('include-asserts') 1610 1737 return 1611 sw.write('if (Cobra.Lang.CobraCore._willCheckAssert && !') 1738 sw.write('if (cobra.lang.CobraCore._willCheckAssert') 1739 # TODO - implement cobra assertions - needs cobra assertException + Sourcesite 1740 /# 1741 sw.write(' && !') 1612 1742 _expr.writeJavaDef(sw) 1613 sw.write(') 1743 sw.write(')\n') 1614 1744 sw.indent 1615 sw.write('throw new Cobra.Lang.AssertException([.javaSourceSite], ') 1745 1746 # TODO later Implement SourceSite and CobraLang AssertException 1747 sw.write('throw new cobra.lang.AssertException([.javaSourceSite], ') 1616 1748 _expr.writeJavaBreakdown(sw) 1617 1749 sw.write('[.javaThis], ') 1618 1750 if _info … … 1621 1753 sw.write('null') 1622 1754 sw.write(');\n') 1623 1755 sw.dedent 1756 #/ 1757 1758 # use java asserts initially at least 1759 sw.write(')\n') 1760 sw.indent 1761 sw.write('assert ') 1762 _expr.writeJavaDef(sw) 1763 #_expr.writeJavaBreakdown(sw) 1764 #sw.write('[.javaThis]') 1765 if _info 1766 sw.write(' : ') 1767 _info.writeJavaDef(sw) 1768 else # Tmp till get java asserts 1769 sw.write(' : ') 1770 sw.write('" assert ') 1771 _expr.writeJavaDef(sw) 1772 sw.write(' FAILED"') 1773 1774 sw.write(';\n') 1775 sw.dedent 1624 1776 1625 1777 1626 1778 class BlockStmt is partial … … 1661 1813 def writeJavaDef(sw as CurlyWriter) 1662 1814 base.writeJavaDef(sw) 1663 1815 if _expr.type.isDynamic 1664 # if the expression is dynamic, then use an if-else ladder with CobraImp. Equals(1816 # if the expression is dynamic, then use an if-else ladder with CobraImp.equals( 1665 1817 sw.writeLine('// branch [_expr.toCobraSource]') 1666 1818 1667 1819 varName = '_lh_branch_[.serialNum]' … … 1675 1827 sep = '' 1676 1828 for e in onPart.exprs 1677 1829 sw.write(sep) 1678 sw.write(' Cobra.Lang.CobraImp.Equals([varName], ')1830 sw.write('cobra.lang.CobraImp.equals([varName], ') 1679 1831 e.writeJavaDef(sw, false) 1680 1832 sw.write(')') 1681 1833 sep = ' || ' … … 1737 1889 sw.write('// exactly what is expected\n') 1738 1890 sw.write('[gotRightExceptionVarName] = true;\n') 1739 1891 sw.dedentAndWrite('}\n') 1740 if _exceptionType inherits Box and not (_exceptionType to Box).is SystemExceptionClass1892 if _exceptionType inherits Box and not (_exceptionType to Box).isJvmSystemExceptionClass 1741 1893 wrongExceptionVarName = '_lh_expect_[_varNumber]' 1742 1894 assert gotRightExceptionVarName <> wrongExceptionVarName 1743 1895 sw.writeAndIndent('catch (java.lang.Throwable [wrongExceptionVarName]) {\n') 1744 sw.write('throw new Cobra.Lang.ExpectException(typeof([exceptionTypeRef]), [wrongExceptionVarName]);\n')1896 sw.write('throw new cobra.lang.ExpectException(typeof([exceptionTypeRef]), [wrongExceptionVarName]);\n') 1745 1897 sw.dedentAndWrite('}\n') 1746 sw.write('if (![gotRightExceptionVarName]) throw new Cobra.Lang.ExpectException([exceptionTypeRef].getClass(), null);\n')1898 sw.write('if (![gotRightExceptionVarName]) throw new cobra.lang.ExpectException([exceptionTypeRef].getClass(), null);\n') 1747 1899 1748 1900 1749 1901 class ForStmt is partial … … 1758 1910 varName = _var.javaName 1759 1911 trackLocals = .compiler.willTrackLocals 1760 1912 if trackLocals 1761 sw.write('for ( Cobra.Lang.CobraImp.SetLocal("[.var.name]", [varName]=')1913 sw.write('for (cobra.lang.CobraImp.setLocal("[.var.name]", [varName]=') 1762 1914 else 1763 1915 sw.write('for ([varName]=') 1764 1916 _start.writeJavaDef(sw) 1765 1917 if trackLocals 1766 1918 sw.write(')') 1767 1919 if _var.type.isDynamic 1768 sw.write('; Cobra.Lang.CobraImp.DynamicCompare([varName], ')1920 sw.write('; cobra.lang.CobraImp.dynamicCompare([varName], ') 1769 1921 _stop.writeJavaDef(sw, false) 1770 1922 sw.write(')[if(_dir==1, "<", ">")]0') 1771 1923 opName = if(_dir==1, 'op_Addition', 'op_Subtraction') 1772 sw.write('; [varName]= Cobra.Lang.CobraImp.DynamicOp("[opName]", [varName], ')1924 sw.write('; [varName]=cobra.lang.CobraImp.dynamicOp("[opName]", [varName], ') 1773 1925 if _step, _step.writeJavaDef(sw, false) 1774 1926 else, sw.write('1') 1775 1927 sw.write(')') … … 1800 1952 # TODO: this is the old numeric for loop behavior. 1801 1953 varName = _var.javaName 1802 1954 trackLocals = .compiler.willTrackLocals 1803 if trackLocals, sw.write('for ( Cobra.Lang.CobraImp.SetLocal("[.var.name]", [varName]=')1955 if trackLocals, sw.write('for (cobra.lang.CobraImp.setLocal("[.var.name]", [varName]=') 1804 1956 else, sw.write('for ([varName]=') 1805 1957 _start.writeJavaDef(sw) 1806 1958 if trackLocals 1807 1959 sw.write(')') 1808 sw.write('; Cobra.Lang.CobraImp.DynamicCompare([varName], ')1960 sw.write('; cobra.lang.CobraImp.dynamicCompare([varName], ') 1809 1961 _stop.writeJavaDef(sw, false) 1810 1962 sw.write(')[if(_dir==1, "<", ">")]0') 1811 1963 opName = if(_dir==1, 'op_Addition', 'op_Subtraction') 1812 sw.write('; [varName]= Cobra.Lang.CobraImp.DynamicOp("[opName]", [varName], ')1964 sw.write('; [varName]=cobra.lang.CobraImp.dynamicOp("[opName]", [varName], ') 1813 1965 if _step, _step.writeJavaDef(sw, false) 1814 1966 else, sw.write('1') 1815 1967 sw.write(')') … … 1875 2027 sw.write('int [javaDir] = [javaStep] < 0 ? -1 : +1;\n') 1876 2028 1877 2029 sw.write('for(') 1878 if trackLocals, sw.write(' Cobra.Lang.CobraImp.SetLocal("[.var.name]", [javaVar] = [javaStart])')2030 if trackLocals, sw.write('cobra.lang.CobraImp.setLocal("[.var.name]", [javaVar] = [javaStart])') 1879 2031 else, sw.write('[javaVar] = [javaStart]') 1880 2032 if isSimpleStep, sw.write('; [javaVar] < [javaStop] ; ') 1881 2033 else, sw.write('; ([javaDir]==1) ? [javaVar] < [javaStop] : [javaVar] > [javaStop]; ') 1882 if trackLocals, sw.write(' Cobra.Lang.CobraImp.SetLocal("[.var.name]", [javaVar] += [javaStep])')2034 if trackLocals, sw.write('cobra.lang.CobraImp.setLocal("[.var.name]", [javaVar] += [javaStep])') 1883 2035 else, sw.write('[javaVar] += [javaStep]') 1884 2036 sw.write(') ') 1885 2037 … … 1902 2054 # TODO: the javaRef of a type is not qualified and there is no using System.Collections; 1903 2055 # _what.writeJavaDefInContext(sw, false) 1904 2056 if _what.type.isDynamic 1905 sw.write(' Cobra.Lang.CobraImp.GetEnumerable(')2057 sw.write('cobra.lang.CobraImp.getEnumerable(') # TODO shld be getIterable ?? 1906 2058 _what.writeJavaDef(sw, false) 1907 2059 sw.write(')') 1908 2060 else … … 1911 2063 sw.write(')') 1912 2064 stmt = '[.var.javaName] = [helperName]' 1913 2065 if .compiler.willTrackLocals 1914 stmt = ' Cobra.Lang.CobraImp.SetLocal("[.var.name]", [stmt])'2066 stmt = 'cobra.lang.CobraImp.setLocal("[.var.name]", [stmt])' 1915 2067 stmt += ';\n' 1916 2068 _block.writeJavaDef(sw, stmt) 1917 2069 … … 1966 2118 1967 2119 def writeJavaDef(sw as CurlyWriter) 1968 2120 base.writeJavaDef(sw) 1969 if _destination 2121 if _destination # java Writer 1970 2122 _destination.writeJavaDef(sw, true) 1971 methodName = if(_stop, ' Write', 'WriteLine')2123 methodName = if(_stop, 'write', 'writeLine') 1972 2124 sw.write('.[methodName](') 1973 2125 else 1974 methodName = if(_stop, ' PrintStop', 'PrintLine')1975 sw.write(' Cobra.Lang.CobraImp.[methodName](')2126 methodName = if(_stop, 'printStop', 'printLine') 2127 sw.write('cobra.lang.CobraImp.[methodName](') 1976 2128 sep = '' 1977 2129 for arg in _args 1978 sw.write('[sep] Cobra.Lang.CobraImp._printStringMaker.MakeString(')2130 sw.write('[sep]cobra.lang.CobraImp._printStringMaker.makeString(') 1979 2131 arg.writeJavaDef(sw) 1980 2132 sw.write(')') 1981 2133 sep = '+" "+' … … 1986 2138 1987 2139 def writeJavaDef(sw as CurlyWriter) 1988 2140 base.writeJavaDef(sw) 1989 sw.write(' Cobra.Lang.CobraImp.PushPrintTo(')2141 sw.write('cobra.lang.CobraImp.pushPrintTo(') 1990 2142 _destination.writeJavaDef(sw, false) 1991 2143 sw.write(');\n') 1992 2144 sw.write('try') 1993 2145 _block.writeJavaDef(sw) 1994 2146 sw.write('finally {\n') 1995 2147 sw.indent 1996 sw.write(' Cobra.Lang.CobraImp.PopPrintTo();\n')2148 sw.write('cobra.lang.CobraImp.popPrintTo();\n') 1997 2149 sw.dedent 1998 2150 sw.write('}\n') 1999 2151 … … 2002 2154 2003 2155 def writeJavaDef(sw as CurlyWriter) 2004 2156 base.writeJavaDef(sw) 2005 name = .name .capitalized2157 name = .name #.capitalized 2006 2158 localName = '_lh_event_[.serialNum]' 2007 2159 sw.writeLine('// raise [.name] ...') 2008 2160 sw.write('{ [_eventType.javaRef] [localName] = this.[name]; if ([localName]!=null) [localName](') … … 2085 2237 base.writeJavaDef(sw) 2086 2238 branch .direction 2087 2239 on Direction.In, pass 2088 on Direction.Out, sw.write(' out') # TODO2089 on Direction.InOut, sw.write(' ref') # TODO2240 on Direction.Out, sw.write('/*out*/') # TODO 2241 on Direction.InOut, sw.write('/*ref*/ ') # TODO 2090 2242 .writeJavaDef(sw, true) 2091 2243 2092 2244 def writeJavaDef(sw as CurlyWriter, parens as bool) 2245 #print 'Expr.writeJavaDef', this 2093 2246 pass 2094 2247 2095 2248 def writeJavaStmt(sw as CurlyWriter) is override … … 2120 2273 class NameExpr is partial 2121 2274 2122 2275 get asJava as String 2123 return _definition.javaName 2276 #print 'Dbg: NameExpr::', _definition.javaName 2277 return _definition.javaName 2124 2278 2125 2279 2126 2280 class AsExpr is partial … … 2130 2284 sw.write('// [_name] as [_type.name]\n') 2131 2285 2132 2286 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2287 #print .asJava 2133 2288 sw.write(.asJava) 2134 2135 2289 2136 2290 class AnonymousMethodExpr is partial 2137 2291 2138 2292 # TODO … … 2152 2306 name = .name 2153 2307 if _definition inherits BoxMember and (_definition to BoxMember).binaryName 2154 2308 name = (_definition to BoxMember).binaryName to ! 2155 else 2156 name = name.capitalized 2309 # Tmp while remapping .Net libs 2310 if name.startsWithNonLowerLetter 2311 name = Utils.cobraNameForNativeMemberName(name) 2312 #else 2313 # name = name.capitalized 2314 #trace name 2157 2315 sw.write('[name]') 2158 2316 if _genericArgTypes and _genericArgTypes.count 2159 2317 sw.write('<') … … 2214 2372 # recall that this cannot be the right side of "foo.bar" since that is a MemberExpr 2215 2373 java = .javaQualification + .javaName 2216 2374 if _requiresGetClass, java = java + '.getClass()' 2375 #print 'Dbg: IdExpr::', java 2217 2376 sw.write(java) 2218 2377 2219 2378 get javaQualification as String … … 2224 2383 else 2225 2384 pn = .definition.parentNameSpace 2226 2385 if pn, qual = pn.javaQualifier 2386 #print 'Dbg: IdExpr.qual::', qual 2227 2387 return qual 2228 2388 2229 2389 get javaName as String … … 2233 2393 if .superNode inherits DotExpr 2234 2394 assert this is not (.superNode to DotExpr).right # should be a CallExpr or MemberExpr instead 2235 2395 defi = .namedDefinition 2396 #print 'Dbg: IdExpr.name::', defi.javaName 2236 2397 return defi.javaName 2237 2398 2238 2399 def _requiresGetClass as bool … … 2296 2457 2297 2458 # tpart: 2298 2459 src = Utils.javaStringLiteralFor(tpart.toCobraSource) 2299 sw.write(', [src], new Cobra.Lang.CobraDirectString(')2460 sw.write(', [src], new cobra.lang.CobraDirectString(') 2300 2461 cond.writeJavaDefForBreakdown(sw) 2301 sw.write(' ? Cobra.Lang.CobraCore.ToTechString(')2462 sw.write(' ? cobra.lang.CobraCore.toTechString(') 2302 2463 tpart.writeJavaDefForBreakdown(sw) 2303 2464 sw.write(') : "(not-evaluated)")') 2304 2465 2305 2466 # fpart: 2306 2467 src = Utils.javaStringLiteralFor(fpart.toCobraSource) 2307 sw.write(', [src], new Cobra.Lang.CobraDirectString(')2468 sw.write(', [src], new cobra.lang.CobraDirectString(') 2308 2469 cond.writeJavaDefForBreakdown(sw) 2309 sw.write(' ? "(not-evaluated)" : Cobra.Lang.CobraCore.ToTechString(')2470 sw.write(' ? "(not-evaluated)" : cobra.lang.CobraCore.toTechString(') 2310 2471 fpart.writeJavaDefForBreakdown(sw) 2311 2472 sw.write('))') 2312 2473 … … 2317 2478 2318 2479 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2319 2480 if _target.type.isDynamic 2320 sw.write(' Cobra.Lang.CobraImp.GetIndexerValue(')2481 sw.write('cobra.lang.CobraImp.getIndexerValue(') 2321 2482 _target.writeJavaDef(sw, false) 2322 2483 for expr in _args 2323 2484 sw.write(', ') … … 2380 2541 _expr.writeJavaBreakdownItems(sw) 2381 2542 2382 2543 2544 class TruthExpr 2545 is partial 2546 2547 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2548 lparen = if(parens, '(', '') 2549 rparen = if(parens, ')', '') 2550 branch _treatment 2551 on Treatment.AsIs 2552 _expr.writeJavaDef(sw, parens) 2553 on Treatment.InvokeRuntime 2554 sw.write('CobraLangInternal.CobraImp.IsTrue(') 2555 _expr.writeJavaDef(sw, false) 2556 sw.write(')') 2557 on Treatment.CompareToZero 2558 sw.write('[lparen]0!=') 2559 _expr.writeJavaDef(sw, true) 2560 sw.write(rparen) 2561 on Treatment.CompareToZeroChar 2562 sw.write("[lparen]'\\0'!=") 2563 _expr.writeJavaDef(sw, true) 2564 sw.write(rparen) 2565 on Treatment.CompareToNull 2566 sw.write('[lparen]null!=') 2567 _expr.writeJavaDef(sw, true) 2568 sw.write(rparen) 2569 2570 def writeJavaBreakdownItems(sw as CurlyWriter) is override 2571 # leaving out the base class is intentional: 2572 # base.writeJavaBreakdownItems(sw, isFirstExpr) 2573 _expr.writeJavaBreakdownItems(sw) 2574 2575 2576 class TypeExpr 2577 is partial 2578 2579 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2580 javaRef = _containedType.javaRef 2581 # handle the case of "X.X" where namespace and class are both called "X". 2582 # C# chokes on it because the first "X" is considered to be the type 2583 #if .curBox.name + '.' in javaRef 2584 # javaRef = 'global::' + javaRef 2585 if _requiresTypeOf() 2586 sw.write('typeof(') 2587 sw.write(javaRef) 2588 sw.write(')') 2589 else 2590 sw.write(javaRef) 2591 2592 /# def _requiresTypeOf as bool 2593 # Cobra never requires that you wrap a type reference in typeof(Foo). 2594 # C# requires typeof() in a variety of circumstances and won't accept it in a variety of others. 2595 superNode = .superNode 2596 if superNode is nil 2597 return false 2598 else 2599 if superNode inherits DotExpr 2600 return false 2601 if superNode inherits PostCallExpr 2602 # could be Type(foo) or _bar(Type) 2603 # in C#, the second requires `typeof` and the first won't take it 2604 if superNode.expr is this 2605 return false 2606 if superNode inherits BinaryOpExpr 2607 if this is superNode.right 2608 if superNode inherits InheritsExpr or superNode inherits AbstractToExpr 2609 return false 2610 return true 2611 #/ 2612 2613 def writeJavaDefForBreakdown(sw as CurlyWriter) is override 2614 requiresTypeOf = _requiresTypeOf # using C# version currently - chop ? 2615 if not requiresTypeOf, sw.write('typeof(') 2616 .writeSharpDef(sw) 2617 if not requiresTypeOf, sw.write(')') 2618 2619 2620 class UnaryOpExpr 2621 is partial 2622 2623 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2624 if _op == 'PLUS' 2625 if parens 2626 sw.write('(') 2627 _expr.writeJavaDef(sw, false) 2628 if parens 2629 sw.write(')') 2630 return 2631 if _expr.type.isDynamic 2632 specs = OperatorSpecs.unaryOpSpecsByCobraText 2633 assert specs.containsKey(.token.text) 2634 spec = specs[.token.text] 2635 opText = Utils.javaStringLiteralFor(spec.opMethodName) 2636 sw.write('CobraLangInternal.CobraImp.DynamicOp([opText], ') 2637 _expr.writeJavaDef(sw, false) 2638 sw.write(')') 2639 return 2640 if parens 2641 sw.write('(') 2642 branch _op 2643 on 'MINUS' 2644 sw.write('-') 2645 on 'TILDE' 2646 sw.write('~') 2647 on 'NOT' 2648 sw.write('!') 2649 else 2650 throw FallThroughException(_op) 2651 _expr.writeJavaDef(sw) 2652 if parens 2653 sw.write(')') 2654 2655 def writeJavaBreakdownItems(sw as CurlyWriter) 2656 base.writeJavaBreakdownItems(sw) 2657 sw.write(', +1') 2658 _expr.writeJavaBreakdownItems(sw) 2659 sw.write(', -1') 2660 2661 2662 2663 class Literal 2664 is partial 2665 2666 def asJava as String 2667 return '/* TODO_Literal */' 2668 2669 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2670 sw.write(.asJava) 2671 2672 2673 class AtomicLiteral 2674 is partial 2675 2676 get willWriteJavaBreakdownItems as bool is override 2677 return false 2678 2679 class IntegerLit is partial 2680 2681 def asJava as String is override 2682 s = '' 2683 if (info = .token.info) inherits int 2684 branch info 2685 on - 8, s = 'byte' # java.lang.Byte 2686 on + 8, s = 'short' # unsigned Byte uint8 2687 on -16, s = 'short' #'Int16' 2688 on +16, s = 'int' # unsigned short UInt16' 2689 on -32, s = 'int' # int32 2690 on +32, s = 'long' # unsigned int32 2691 on -64, s = 'long' 2692 on +64, s = 'long' # unsigned int64 2693 else, throw FallThroughException(info) 2694 if s.length <= 2 2695 return _value.toString + s 2696 else 2697 return '([s])[_value.toString]' 2698 2699 class BoolLit 2700 is partial 2701 2702 def asJava as String is override 2703 return if(_value, 'true', 'false') 2704 2705 2706 class CharLit 2707 is partial 2708 2709 def asJava as String is override 2710 if _value[0] to int == 39, return "'\\''" # single quote 2711 else, return "'" + _value.toString + "'" 2712 2713 2714 class NilLiteral 2715 is partial 2716 2717 def asJava as String is override 2718 return 'null' 2719 2720 class StringLit is partial 2721 2722 def asJava as String is override 2723 return Utils.javaStringLiteralFor(_string) 2724 2725 class StringSubstLit is partial 2726 2727 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2728 if _items.count>1 2729 sw.write('cobra.lang.CobraImp._printStringMaker.makeString(') 2730 sep = '' 2731 for item in _items 2732 sw.write(sep) 2733 if item inherits StringLit 2734 item.writeJavaDef(sw, true) # CC: axe the "true" when the bug about overload groups crossing inheritance is fixed 2735 else if item inherits FormattedExpr 2736 sw.write('cobra.lang.CobraImp._printStringMaker.makeString(') 2737 item.expr.writeJavaDef(sw) 2738 sw.write(',') 2739 sw.write(Utils.javaStringLiteralFor(item.format)) 2740 sw.write(')') 2741 else 2742 sw.write('cobra.lang.CobraImp._printStringMaker.makeString(') 2743 item.writeJavaDef(sw, false) 2744 sw.write(')') 2745 sep = ',' 2746 if _items.count>1 2747 sw.write(')') 2748 2749 class BaseLit is partial 2750 2751 def asJava as String is override 2752 return 'super' 2753 2754 2755 class ThisLit is partial 2756 2757 def asJava as String is override 2758 return .compiler.curBox.javaThis 2759 2760 2761 class VarLit is partial 2762 2763 def asJava as String is override 2764 return _name 2765 2766 2767 2383 2768 ## 2769 ## Binary Expressions 2770 ## 2771 2772 class BinaryOpExpr is partial 2773 2774 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2775 if parens, sw.write('(') 2776 _writeJavaDef(sw) 2777 if parens, sw.write(')') 2778 2779 def _writeJavaDef(sw as CurlyWriter) 2780 sw.write('/* TODO_BinaryOp */') 2781 # pass 2782 2783 def writeJavaBreakdownItems(sw as CurlyWriter) 2784 base.writeJavaBreakdownItems(sw) 2785 sw.write(', +1') 2786 _writeJavaBreakdownItemsLeft(sw) 2787 _writeJavaBreakdownItemsRight(sw) 2788 sw.write(', -1') 2789 2790 def _writeJavaBreakdownItemsLeft(sw as CurlyWriter) 2791 _left.writeJavaBreakdownItems(sw) 2792 2793 def _writeJavaBreakdownItemsRight(sw as CurlyWriter) 2794 _right.writeJavaBreakdownItems(sw) 2795 2796 2797 class AbstractAssignExpr is partial 2798 2799 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2800 if _trackLocal 2801 sw.write('CobraLangInternal.CobraImp.SetLocal("[_trackName]", ') 2802 else if parens 2803 sw.write('(') 2804 _writeJavaDef(sw) 2805 if _trackLocal or parens 2806 sw.write(')') 2807 2808 2809 class AssignExpr is partial 2810 2811 def _writeJavaDef(sw as CurlyWriter) is override 2812 # TODO: 2813 # if trackLocal: 2814 # out.write('CobraLangInternal.CobraImp.SetLocal("%s", ' % .left.name) 2815 if _left inherits IndexExpr 2816 if _left.target.type.isDynamic 2817 # assigning to an indexer of a dynamically typed target requires special code gen 2818 sw.write('CobraLangInternal.CobraImp.SetIndexerValue(') 2819 _left.target.writeJavaDef(sw, false) 2820 sw.write(', ') 2821 _right.writeJavaDef(sw, false) 2822 for expr in _left.args 2823 sw.write(', ') 2824 expr.writeJavaDef(sw, false) 2825 sw.write(')') 2826 return 2827 handled = false 2828 if _left inherits IdentifierExpr 2829 names = _left.javaAssignmentNames 2830 if names and names.count 2831 names.reverse 2832 for i in names.count 2833 sw.write(if(i==0, '', '=')) 2834 assert names[i].length 2835 sw.write(names[i]) 2836 else 2837 assert _left.javaName <> '' 2838 sw.write(_left.javaName) 2839 handled = true 2840 if not handled 2841 # `obj.foo = bar` where `obj` is dynamic, requires special handling 2842 if _left inherits DotExpr 2843 if _left.left.type.isDynamic 2844 assert _left.right inherits MemberExpr 2845 sw.write('CobraLangInternal.CobraImp.setPropertyValue(') 2846 _left.left.writeJavaDef(sw, false) 2847 sw.write(', ') 2848 sw.write(Utils.javaStringLiteralFor((_left.right to MemberExpr).name)) 2849 sw.write(', ') 2850 _right.writeJavaDef(sw) 2851 sw.write(')') 2852 return 2853 if not handled 2854 # for something like "p.total = 0", cannot generate "(p.Total)=0" because then C# sees 2855 # the left hand side as an r-value instead an l-value/target. hence the false below. 2856 _left.writeJavaDef(sw, false) 2857 sw.write('=') 2858 _right.writeJavaDefInContext(sw) 2859 # handle the case where a type got backed up because of assignment inside of an if-inherits 2860 if _backUpIfInheritsStack 2861 assert _left.definition inherits IVar 2862 _left.definition.ifInheritsStack = Stack<of IType>(_backUpIfInheritsStack) 2863 2864 class CompareExpr 2865 is partial 2866 2867 var _cobraToJava = { 2868 'EQ': '==', 2869 'NE': '!=', 2870 'GT': '>', 2871 'LT': '<', 2872 'GE': '>=', 2873 'LE': '<=', 2874 'IS': '==', 2875 'ISNOT': '!=', 2876 } 2877 2878 def _writeJavaDef(sw as CurlyWriter) is override 2879 left = _left 2880 right = _right 2881 op = _op 2882 # Compute the java operation which will be an operator or method call 2883 if op=='EQ' or op=='NE' 2884 if not left.type.isReference and not right.type.isReference 2885 # struct/value types 2886 #if not left.type inherits PrimitiveType and not right.type inherits PrimitiveType 2887 # # user-defined structs 2888 # op = '.Equals(' 2889 #else 2890 # # primitives like ints and decimals (even mixed like someDecimal == someInt) 2891 # op = _cobraToJava[_op] 2892 op = _cobraToJava[_op] 2893 else 2894 done = false 2895 stringType = .compiler.stringType 2896 if left.isKindOf(stringType) and right.isKindOf(stringType) # TODO: check for static comparison operations instead 2897 op = _cobraToJava[_op] 2898 done = true 2899 else if left.type inherits Box # TODO: try skipping on requiring that the type is a Box 2900 leftBox = left.type to Box 2901 compareTo = leftBox.memberForName('compareTo') 2902 if compareTo and compareTo.isMethod and compareTo.resultType.isDescendantOf(.compiler.anyIntType) and right.type.isDescendantOf(leftBox) # need last condition to prevent someString.CompareTo(someChar) 2903 op = '.compareTo(' 2904 done = true 2905 if not done 2906 assert op in ['EQ', 'NE'] 2907 assert op == .token.which 2908 op = '.equals(' 2909 else if op=='IS' or op=='ISNOT' 2910 if left.type inherits PrimitiveType and right.type inherits PrimitiveType 2911 op = _cobraToJava[_op] 2912 else if left.type.isReference and right.type.isReference 2913 op = if(op=='IS', ' instanceof ', '! instanceof ') 2914 else 2915 # non-trivial situation.. fall back to runtime support 2916 op = if(op=='IS', 'CobraLangInternal.CobraImp.Is(', 'CobraLangInternal.CobraImp.IsNot(') 2917 else 2918 if left.type.isDynamic or right.type.isDynamic 2919 sw.write('CobraLangInternal.CobraImp.DynamicCompare(') 2920 left.writeJavaDef(sw, false) 2921 sw.write(', ') 2922 right.writeJavaDef(sw, false) 2923 sw.write(')[_cobraToJava[_op]]0') 2924 return 2925 else 2926 done = false 2927 if left.type inherits Box # TODO: try skipping on requiring that the type is a Box 2928 leftBox = left.type to Box 2929 compareTo = leftBox.memberForName('compareTo') 2930 if compareTo and compareTo.isMethod and compareTo.resultType.isDescendantOf(.compiler.anyIntType) and left.type == right.type # need last condition to prevent someString.CompareTo(someChar) 2931 op = '.compareTo(' 2932 done = true 2933 if not done 2934 op = _cobraToJava[_op] 2935 # Write the Java code 2936 if op.length <= 2 2937 left.writeJavaDef(sw) 2938 sw.write(op) 2939 right.writeJavaDef(sw) 2940 else if op == '.equals(' 2941 if _op == 'NE', sw.write('!(') 2942 left.writeJavaDef(sw) 2943 sw.write(op) 2944 right.writeJavaDef(sw, false) 2945 sw.write(')') 2946 if _op == 'NE', sw.write(')') 2947 else if op == '.compareTo(' 2948 left.writeJavaDef(sw) 2949 sw.write(op) 2950 right.writeJavaDef(sw, false) 2951 sw.write(') [_cobraToJava[_op]] 0') 2952 else if op.endsWith('(') 2953 sw.write(op) 2954 left.writeJavaDef(sw) 2955 sw.write(',') 2956 right.writeJavaDef(sw) 2957 sw.write(')') 2958 else 2959 throw FallThroughException(op) 2960 2961 class ChainedCompareExpr is partial 2962 2963 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 2964 if parens, sw.write('(') 2965 .writeJavaDef(sw) 2966 if parens, sw.write(')') 2967 2968 def writeJavaDef(sw as CurlyWriter) is override 2969 sw.write('CobraLangInternal.CobraCore.ChainedComparison(') 2970 _items[0].writeJavaDef(sw) 2971 itemIndex = 1 2972 for operation in _operations 2973 sw.write(', "[operation]", ') 2974 _items[itemIndex].writeJavaDef(sw) 2975 itemIndex += 1 2976 sw.write(')') 2977 2978 2979 class DotExpr 2980 is partial 2981 2982 /# def needsContextCast as bool # in SharpGenerator 2983 r = base.needsContextCast 2984 if not r 2985 r = .left.type.isDynamic 2986 # Why isn't the base implementation sufficient? 2987 # Because for `d.getType` where `d` is dynamic, the type of `d.getType` is *not*. 2988 # It`s System.Type because `getType` is recognized as an Object method. 2989 # This would confuse the code generation into thinking that `d.getType` is a statically typed expression. 2990 return r 2991 #/ 2992 2993 def _writeJavaDef(sw as CurlyWriter) is override 2994 if _left.receiverType.isDynamic 2995 # handle dynamic typing 2996 if _dotRightExpr.definition 2997 sw.write('(' + _dotRightExpr.type.javaRef + ')') 2998 if _right inherits MemberExpr 2999 sw.write('CobraLangInternal.CobraImp.GetPropertyValue(') 3000 _left.writeJavaDef(sw, not _left inherits DotExpr) 3001 sw.write(', ') 3002 sw.write(Utils.javaStringLiteralFor(_right.name)) # was .capitalized 3003 sw.write(')') 3004 else if _right inherits CallExpr 3005 sw.write('CobraLangInternal.CobraImp.InvokeMethod(') 3006 _left.writeJavaDef(sw, not _left inherits DotExpr) 3007 sw.write(', ') 3008 sw.write(Utils.javaStringLiteralFor(_right.name)) # was .capitalized 3009 for arg in _right.args 3010 sw.write(', ') 3011 arg.writeJavaDef(sw, false) 3012 sw.write(')') 3013 else 3014 throw FallThroughException(_right) 3015 else 3016 # Given Cobra "A.B.C()" where C is a class/type/struct, then the java needs to be "new A.B.C()" 3017 # (But stuff like this makes me wonder if the ASTs should be doing some transformations, like collapsing qualified types.) 3018 if _dotRightExpr.memberDefinition inherits BoxMember 3019 backing = _dotRightExpr.definition.sharedMethodBacking 3020 if backing 3021 # example: Cobra: c.isUpper C#: char.IsUpper(c) 3022 # also used for extension methods under .NET 2.0 3023 sw.write(backing+'(') 3024 if not (_dotRightExpr.memberDefinition to BoxMember).sharedMethodBackingIsAlias # guard against Cobra "decimal.parse('5.0')" --> C# "Decimal.Parse(decimal, "5.0")" 3025 _left.writeJavaDef(sw, false) 3026 sep = ', ' 3027 else 3028 sep = '' 3029 if _right inherits CallExpr 3030 for arg in _right.args 3031 sw.write(sep) 3032 arg.writeJavaDefInContext(sw) 3033 sep = ', ' 3034 sw.write(')') 3035 return 3036 # handle static typing 3037 # don't write 'this' for shared members 3038 writeThis = true 3039 if _left inherits ThisLit 3040 writeThis = not _dotRightExpr.memberDefinition.isShared 3041 else if .curCodeMember inherits Initializer and _right inherits IDotRightExpr and (_right to IDotRightExpr).name == 'init' and _left inherits ThisOrBaseLit 3042 Stmt.inInitCall = true 3043 didSetInInitCall = true 3044 writeThis = false 3045 if writeThis 3046 if _left.needsContextCast 3047 _left.writeJavaDefInContext(sw) 3048 else 3049 _left.writeJavaDef(sw, not _left inherits DotExpr) 3050 sw.write('.') 3051 #print 'Dbg: dotExpr::', _left.toCobraSource, _right.toCobraSource 3052 _right.writeJavaDef(sw, false) 3053 if didSetInInitCall 3054 Stmt.inInitCall = false 3055 3056 def _writeJavaBreakdownItemsLeft(sw as CurlyWriter) is override 3057 _left.writeJavaBreakdownItems(sw) 3058 3059 3060 3061 class CoalesceExpr 3062 is partial 3063 3064 def _writeJavaDef(sw as CurlyWriter) is override 3065 # (L != null ? L : R ) 3066 sw.write('((') 3067 _left.writeJavaDef(sw) 3068 sw.write(') != null ? ') 3069 _left.writeJavaDef(sw) 3070 sw.write(' : ') 3071 _right.writeJavaDef(sw) 3072 3073 class CoalesceAssignExpr 3074 is partial 3075 3076 def _writeJavaDef(sw as CurlyWriter) is override 3077 # L = (L != null ? L : R ) 3078 _left.writeJavaDef(sw) 3079 sw.write(' = ') 3080 sw.write('((') 3081 _left.writeJavaDef(sw) 3082 sw.write(') != null ? ') 3083 _left.writeJavaDef(sw) 3084 sw.write(' : ') 3085 _right.writeJavaDef(sw) 3086 3087 3088 class MemberExpr 3089 is partial 3090 3091 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 3092 assert .superNode inherits DotExpr 3093 if _definition inherits BoxMember 3094 name = _definition.binaryName 3095 #if name is nil 3096 # name = _name.capitalized 3097 if name is nil 3098 name = _name 3099 #print 'Dbg: MemberExpr::', name 3100 sw.write(name) 3101 if _definition and (_definition.isMethod or _name=='toString') and not _isReference # TODO: axe the 'toString' check 3102 sw.write('()') 3103 3104 def writeJavaBreakdownItems(sw as CurlyWriter) is override 3105 pass 3106 3107 class SharpExpr 3108 is partial 3109 3110 def writeJavaDef(sw as CurlyWriter, parens as bool) is override 3111 if parens, sw.write('(') 3112 if _sharpSource 3113 sw.write(_sharpSource) 3114 else 3115 sw.write(_expr.token.value) 3116 if parens, sw.write(')') 3117 3118 ## 2384 3119 ## Temporary 2385 3120 ## 2386 3121 … … 2391 3126 def writeJavaTestInvocation(sw as CurlyWriter) 2392 3127 pass 2393 3128 2394 class IntegerLit is partial2395 2396 def asJava as String2397 return 'TODO'2398 2399 3129 class EnumMember is partial 2400 3130 2401 3131 def writeJavaTestInvocation(sw as CurlyWriter) … … 2404 3134 class Extension is partial 2405 3135 2406 3136 get javaKeyWord as String is override 2407 return ' '3137 return 'TODO_Extension' 2408 3138 2409 3139 get javaInvariantVisibility as String is override 2410 3140 return '' … … 2422 3152 shared 2423 3153 2424 3154 def javaStringLiteralFor(args as vari dynamic) as String 2425 # TODO: 2426 for arg in args, return arg 2427 return '' 3155 sb = StringBuilder() 3156 for arg in args 3157 sb.append(Utils.sharpStringLiteralFor(arg to String)) 3158 return sb.toString 2428 3159 2429 3160 class ThisOrBaseLit is partial 2430 3161 2431 def asJava as String 3162 def asJava as String is override 2432 3163 return 'this' 2433 3164 2434 3165 class ContractPart is partial 2435 3166 2436 3167 def writeJavaMethod(args as vari dynamic) 2437 3168 pass 3169 3170 3171 class JavaBackEndUtils 3172 # copied fm SharpGenerator and keywds corrected: chg entire method Vars.cobra:AbstractLocalVar,_init 3173 shared 3174 3175 var _backEndKeyWordList = 'assert boolean break byte case catch char class const continue default do double else extends false final finally float for goto if implements import instanceof int interface long native new null package private protected public return short static strictfp super switch synchronized this throw throws transient true try void volatile while'.split 3176 # C# 'abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void volatile while'.split 3177 var _backEndKeyWordSet = Set<of String>() 3178 3179 def isBackEndKeyWord(word as String) as bool 3180 """ 3181 Returns true if the given word is a keyword in Java6 3182 """ 3183 require 3184 word.length 3185 test 3186 assert .isBackEndKeyWord('byte') 3187 assert .isBackEndKeyWord('if') 3188 assert .isBackEndKeyWord('while') 3189 assert not .isBackEndKeyWord('total') 3190 body 3191 if _backEndKeyWordSet.count == 0 3192 for word in _backEndKeyWordList 3193 _backEndKeyWordSet.add(word) 3194 return word in _backEndKeyWordSet 3195 3196 def backEndNameForLocalVarName(name as String) as String 3197 if .isBackEndKeyWord(name) 3198 return '$' + name # Java supports $ as a prefix 3199 return name 3200 -
Source/Enums.cobra
1 1 2 class EnumDecl 2 3 is partial 3 4 inherits Container<of EnumMember> … … 25 26 _idToken = Token.empty 26 27 _attribs = AttributeList() 27 28 _nativeType = nativeType 28 _storageTypeNode = ClrTypeProxy(Enum.getUnderlyingType((_nativeType to ClrNativeType).clrType)) # TODO: fix native 29 #_storageTypeNode = ClrTypeProxy(Enum.getUnderlyingType((_nativeType to ClrNativeType).backEndType)) # TODO: fix native 30 _callNativeScanMethod('UnderlyingType') 29 31 _needScanNativeType = true 30 31 def _scanClrType 32 # TODO: read attribs 33 _needScanNativeType = false 34 clrType = (_nativeType to ClrNativeType).clrType # TODO: fix native 35 isByte = Enum.getUnderlyingType(clrType).name == 'Byte' 36 is64 = Enum.getUnderlyingType(clrType).name == 'Int64' 37 isU32 = Enum.getUnderlyingType(clrType).name == 'UInt32' 38 isU64 = Enum.getUnderlyingType(clrType).name == 'UInt64' 39 values = Enum.getValues(clrType) 40 i = 0 41 for name in Enum.getNames(clrType) 42 value = values.getValue(i) 43 # CC: lameness follows 44 if isByte 45 intValue = int.parse((value to uint8).toString) 46 else if is64 47 try 48 intValue = int.parse((value to int64).toString) 49 catch OverflowException 50 intValue = 999 # CC: omg. but probably doesn't affect anything. we're reading the DLL here, not creating one 51 else if isU32 52 try 53 intValue = int.parse((value to uint32).toString) 54 catch OverflowException 55 intValue = 2147483647 56 else if isU64 57 try 58 intValue = int.parse((value to uint64).toString) 59 catch OverflowException 60 intValue = 2147483647 61 else 62 intValue = value to int 63 member = EnumMember(name, intValue) 64 member.enumDecl = this 65 .addDecl(member) 66 i += 1 67 32 33 def _callNativeScanMethod(tag as String) 34 """ 35 Call a backend scan method for native type scan operation desired and backend in use. 36 """ 37 _needScanNativeType = true 38 # This is icky too - method to call needs to be set directly via backend somehow rather than this check and call code 39 # TODO: change to use strategy object set when init backend. 40 assert .compiler 41 assert tag in ['ScanNativeType', 'UnderlyingType'] 42 backEnd = .compiler.backEnd 43 branch backEnd.name 44 on 'c#-clr' 45 branch tag 46 on 'UnderlyingType', _setUnderlyingTypeClr # sets _storageTypeNode 47 on 'ScanNativeType', _scanNativeTypeClr 48 on 'java-jvm' 49 branch tag 50 on 'UnderlyingType', _setUnderlyingTypeJvm # sets _storageTypeNode 51 on 'ScanNativeType', _scanNativeTypeJvm 52 on 'objc' 53 print 'objc back end need method for [tag]' 54 assert false, 'Missing backEnd infrastructure for [backEnd.getType.name]' 55 #branch on tag 56 # on 'UnderlyingType', _setUnderlyingTypeObjc 57 # on 'ScanNativeType', _scancNativeTypeObjc 58 else 59 throw FallThroughException('No nativeScanMethod code for backend [backEnd.name] [backEnd.getType.name]') 60 #TODO: remove all direct uses of ClrNativeType, ClrTypeProxy 61 68 62 get attributes as AttributeList is override 69 63 return _attribs 70 64 … … 99 93 return base.isUsed 100 94 set 101 95 base.isUsed = value 102 if _needScanNativeType 103 _scanClrType 96 if _needScanNativeType, _callNativeScanMethod('ScanNativeType') 104 97 105 98 get nativeType from var 106 99 … … 117 110 _storageType = _storageTypeNode.realType 118 111 if not _storageType.isDescendantOf(.compiler.anyIntType) 119 112 .throwError('The enumeration storage type must be a primitive integer type such as int8, uint8, int16, uint16, int, uint, int64 or uint64.') 120 if _needScanNativeType 121 _scanClrType 113 if _needScanNativeType, _callNativeScanMethod('ScanNativeType') 122 114 123 115 def _bindImp is override 124 116 base._bindImp … … 132 124 return name 133 125 134 126 def memberForName(name as String) as IMember? 135 if _needScanNativeType 136 _scanClrType 127 if _needScanNativeType, _callNativeScanMethod('ScanNativeType') 137 128 m = base.memberForName(name) 138 129 if m is nil 139 130 objClass = .compiler.objectType -
Tests/320-misc-two/800-attributes/130-attributes-tricky-names.cobra
8 8 with no warnings or errors. 9 9 """ 10 10 use System.Xml 11 use System.Xml.Linq12 11 use System.Xml.Serialization 13 12 14 13 class Season has Serializable