""" Objective-C Code Generator The code in this file should not .throwError, record warnings, etc. All of that happens during .bindFoo phases. cobra -back-end:objc hello Check-in comment: ObjC back-end progress. to-do: write headers to-do: appkit example to-do: self compile """ ## ## Compiler ## class Compiler is partial var _objcSource = Dictionary() def createObjcFile(fileName as String, content as String) """ Creates a new TextWriter for writing sharp source code. Will create a physical file or string writer as appropriate. """ File.writeAllText(fileName, content) .addIntermediateFile(fileName) def computeOutNameObjc as String outName ='' if .options.boolValue('test') outName = _modules.last.fileName else if .options.containsKey('out') outName = .options.getDefault('out', '') if outName == '', outName = .defaultOutName to ! if outName.endsWith('.objc') or outName.endsWith('.OBJC'), outName = outName[:-5] if outName.endsWith('.cobra') or outName.endsWith('.COBRA'), outName = outName[:-6] _baseExeFileName = outName # outName = Utils.forceExtension(outName, '....') # No extension for ObjC on Mac & Linux _fullExeFileName = outName return outName def writeObjc Node.setCompiler(this) try _moduleFileName_to_curlyToCobraLineNum = Dictionary>() for _curModule in _modules if not _curModule.fileName.endsWith('SystemInterfaces.cobra') objcToCobraLineNum = _curModule.writeObjcDef _moduleFileName_to_curlyToCobraLineNum[_curModule.fileName] = objcToCobraLineNum _moduleFileName_to_curlyToCobraLineNum[Path.getFullPath(_curModule.fileName)] = objcToCobraLineNum finally Node.setCompiler(nil) def writeObjcTestInvocation pass # to-do def compileObjc .compileObjc('') def compileObjc(extraNativeOptions as String) require .modules.count body .options['keep-intermediate-files'] = true # to-do: remove this much later. need to look at generated objc quite often right now if .verbosity >= 2, print 'Compiling generated code' options = .options # locate the native compiler compilerPath = options.getDefault('native-compiler', '') to String if compilerPath == 'auto', compilerPath = '' if compilerPath <> '' if File.exists(compilerPath) pass else if File.exists(compilerPath+'.exe') compilerPath += '.exe' else # to-do: change print statement to an error print 'Cannot find compiler specified by -native-compiler argument: [compilerPath]' throw StopCompilation(this) else compilerPath = if(Utils.isRunningOnUnix, 'gcc', 'gcc.exe') # to-do: use or axe: optChar = '-' # exeNames outName = .computeOutNameObjc # compute backEndOptions backEndOptions = '' backEndOptions += ' -O3' # to-do: make conditional on Cobra's -o option. backEndOptions += ' -fobjc-gc-only' backEndOptions += ' -framework Foundation' # to-do: debug flag # to-do: respect -native-compiler compilerPath = 'gcc' backEndOptions += ' ' + extraNativeOptions nativeArgs = .options.getDefault('native-compiler-args', '') to String if nativeArgs.length if nativeArgs.length > 2 and nativeArgs[0]=="'" and nativeArgs[nativeArgs.length-1]=="'" # on Windows, you should really use double quotes instead of single, but # we try to compensate here. nativeArgs = nativeArgs[1:-1] backEndOptions += ' ' + nativeArgs # to-do: framework and library references # source files sourceFileNameList = List() for module in _modules[1:] if module.objcFileName.length sourceFileNameList.add(module.objcFileName) # compilation command if _verbosity print 'Compiling to produce [outName]' # TODO: need to encapsulate this in CobraCore to avoid .NET dependency p = System.Diagnostics.Process() p.startInfo.fileName = compilerPath sourceFileNames = (for fileName in sourceFileNameList get '"' + fileName + '"').join(' ') p.startInfo.arguments = '[backEndOptions] [sourceFileNames]' if true or _verbosity >= 2 # to-do: remove 'true' print '[p.startInfo.fileName] [p.startInfo.arguments]' output = p.runAndCaptureAllOutput # TODO: check p.exitCode, especially if output is empty _parseObjcCompilerOutput(output) if .errors.count _exitFromErrors _deleteIntermediateFiles def _parseObjcCompilerOutput(output as String) for line in output.split(c'\n') line = line.trim if not line.length, continue if ObjcCompilationMessage.willSkipMessage(line) continue else if _verbosity >= 3 print 'objc message: [line]' _addMessage(ObjcCompilationMessage(line, this)) class ObjcCompilationMessage inherits SourceException # to-do: break out to separate file and complete def willSkipMessage(line as String) as bool is shared return false cue init(line as String, compiler as Compiler) base.init(line) ## ## Node ## class Node is partial def writeObjcDef(sw as CurlyWriter) require .didBindInt or .didBindImp pass class SyntaxNode is partial def writeObjcDef(sw as CurlyWriter) base.writeSharpDef(sw) sw.node(this) interface INamedNode is partial get objcName as String """ Return the name that should be used in Obj-C source code. """ class NamedNode is partial get objcName as String return _name get objcRef as String return .sharpName ## ## Module ## class Module is partial var _objcSource as String? var _objcFileName = '' get objcFileName from var get objcSource as String if _objcSource, return _objcSource if _objcFileName.length return File.readAllText(_objcFileName) else throw FallThroughException('No objc source or filename.') def writeObjcDef as Dictionary? is abstract def writeObjcTestInvocation(sw as CurlyWriter) pass # to-do class JavaModule is partial def writeObjcDef as Dictionary? is override assert false return nil class SharpModule is partial def writeObjcDef as Dictionary? is override assert false return nil class AssemblyModule is partial get objcSource as String is override return '(no objc source for [this])' def writeObjcDef as Dictionary? is override return nil sig WriteObjcMethod(cw as CurlyWriter) class CobraModule is partial get objcFileName as String is override if _objcFileName == '' and not _fileName.endsWith('SystemInterfaces.cobra') _objcFileName = _fileName + '.m' return _objcFileName def writeObjcHeader as Dictionary? return _writeObjcFile(ref .topNameSpace.writeObjcHeader) def writeObjcDef as Dictionary? is override return _writeObjcFile(ref .topNameSpace.writeObjcDef) def _writeObjcFile(writeObjc as WriteObjcMethod) as Dictionary? sw = CodePoundLineWriter() .compiler.addIntermediateFile(_objcFileName) sw.start(.fileName) sw.write('// [_objcFileName]\n') sw.write('// Generated by Cobra\n') # TODO: put version number here sw.write('// on [DateTime.now]\n') # TODO: list op sys sw.write('\n') # to-do: axe or change: sw.write('using CobraCoreInternal = Cobra.Core[.compiler.embedRunTimeSuffix];\n') writeObjc(sw) (.compiler to Compiler).createObjcFile(.objcFileName, sw.output) d = sw.curlyToCobraLineNum if false bar = '----------------------------------------------' print bar print sw.output print bar return d def writeObjcTestInvocation(sw as CurlyWriter) is override .topNameSpace.writeObjcTestInvocation(sw) ## ## Container and friends ## interface IParentSpace is partial get objcRef as String class Container is partial get objcInit as String is abstract get objcNameComponent as String """ Returns a string that can be used in a Obj-C identifier. That means it cannot have special symbols such as period or left bracket. """ ensure result.length > 0 # TODO? Move to interface return .objcRef var _objcRef as String? get objcRef as String is override if _objcRef is nil and .didBindImp _objcRef = _computeObjcRef return _objcRef to ! else return _computeObjcRef get objcParamRef as String return .objcRef def _computeObjcRef as String if .parent s = .parent.objcRef if s.length and not s.endsWith('::') # Obj-C has weird "global::" name # to-do: not an obj-c thing s += '.' s += .objcName else s = .objcName return s def writeObjcIsNames(sw as CurlyWriter) # TODO: cache this somewhere accessLevels = ['public', 'protected', 'internal', 'protected internal', 'private'] # CC: accessLevels = 'public,protected,internal,protected internal,private'.split(c',') # same names in both Cobra and Obj-C # TODO: # if isNames is nil # isNames = _isNames isNames = List() isNames.addRange(_isNames) if .defaultAccessLevel.length found = false for level as String in accessLevels # CC: axe as if level in isNames found = true if not found isNames.insert(0, .defaultAccessLevel) isNameCS = { # only have to specify the ones that are different 'shared': 'static', 'nonvirtual': '', } sep = '' for name in isNames name = isNameCS.get(name, name) sw.write(sep) sw.write(name) sep = ' ' if sep.length sw.write(' ') def writeObjcTestInvocation(sw as CurlyWriter) pass # to-do interface IMember is partial def writeObjcDef(sw as CurlyWriter) """ Write the Obj-C code for this member declaration to the given CurlyWriter. """ def writeObjcTestInvocation(sw as CurlyWriter) """ Write the Obj-C call to the test method for this member. """ ## ## Namespace ## class NameSpace is partial get objcFullName as String value as Object? if not .addOnValues.tryGetValue('objcFullName', out value) fullName = .fullName if fullName == 'Cobra.Core' name = 'Cobra.Core' + .compiler.embedRunTimeSuffix else if fullName.startsWith('Cobra.Core.') name = 'Cobra.Core[.compiler.embedRunTimeSuffix].' + fullName['Cobra.Core.'.length:] else name = fullName name = name.replace('.', '_x_') # no real namespaces in ObjC .addOnValues['objcFullName'] = name return name else return value to String get objcInit as String is override # TODO: remove when not a type assert false return '' get objcRef as String is override if _superNameSpace is nil return 'global::' else return .objcFullName get objcQualifier as String ensure result.endsWith('.') or result == 'global::' if _superNameSpace is nil return 'global::' else return .objcFullName + '.' def writeObjcHeader(sw as CurlyWriter) pass # to-do def writeObjcDef(sw as CurlyWriter) is override assert not .isUnified base.writeObjcDef(sw) if not .isRoot suffix = if(.fullName == 'Cobra.Core', .compiler.embedRunTimeSuffix, '') sw.writeAndIndent('namespace [.name][suffix] {\n\n') for ud in _useDirectives ud.writeObjcDef(sw) for decl in _declsInOrder if decl inherits Box .compiler.boxStack.push(decl) decl.writeObjcDef(sw) if decl inherits Box .compiler.boxStack.pop if not .isRoot sw.dedentAndWrite('} // namespace [.name]\n') def writeObjcTestInvocation(sw as CurlyWriter) is override for decl in _declsInOrder decl.writeObjcTestInvocation(sw) class UseDirective is partial pass ## ## Types ## class FakeLibraryType is partial get objcInit as String throw NoSourceGenerationException(this) get objcName as String throw NoSourceGenerationException(this) get objcNameComponent as String throw NoSourceGenerationException(this) get objcParamRef as String throw NoSourceGenerationException(this) get objcRef as String throw NoSourceGenerationException(this) def writeObjcDef(sw as CurlyWriter) throw NoSourceGenerationException(this) def writeObjcTestInvocation(sw as CurlyWriter) throw NoSourceGenerationException(this) interface IType is partial get objcInit as String get objcNameComponent as String """ Returns a string that refers to this type and is suitable for embedding in a larger identifier (meaning there will be no punction, spaces or comments). """ get objcRef as String """ Returns a string that refers to this type. Examples: 'int' 'NSMutableArray' 'object' """ get objcParamRef as String """ Returns a string that refers to this type including any necessary parameter declaration specification such as C# 'params' or 'out'. Invoked by Param.writeObjcDef. to-do """ class CobraType is partial get objcInit as String is abstract get objcName as String return .name get objcNameComponent as String name = .name i = name.indexOf('/*') # form: /*foo*/bar if i <> -1 j = name.indexOf('*/', i) name = name[:i] + name[j+2:] name = name.replace('.', '_').replace('<', '_').replace('>', '_').replace(', ', '_') return name get objcRef as String return .objcName get objcParamRef as String return .objcRef def writeObjcTestInvocation(sw as CurlyWriter) pass class BoolType is partial get objcInit as String is override return 'NO' class CharType is partial get objcInit as String is override return '(char)0' class DynamicType is partial get objcInit as String is override return 'nil' get objcName as String is override return 'id' class FloatType is partial get objcName as String is override return _nativeType.fullName class IntType is partial get objcName as String is override return _nativeType.fullName class NilableType is partial get objcInit as String is override return 'null' get objcRef as String is override # to-do: how to handle nullable value types? return _wrappedType.objcRef + if(not _wrappedType.isReference, '?', '') class NilType is partial get objcInit as String is override return 'nil' get objcRef as String is override return '/*nil*/id' class AbstractNumberType is partial get objcInit as String is override return '0' class PassThroughType is partial get objcInit as String is override return 'nil' get objcRef as String is override return '/*passthrough*/id' class StreamType is partial get objcInit as String is override return 'new CobraCoreInternal.EmptyStream<[.theWrappedType.objcRef]>()' # to-do get objcRef as String is override assert .didBindInh and .didBindInt return '/*[.name]*/[.box.objcRef]' class VoidType is partial get objcInit as String is override throw Exception('Cannot init a void type.') class WrappedType is partial get objcInit as String is override return _wrappedType.objcInit class ArrayType is partial get objcRef as String is override return '[_wrappedType.objcRef]' + r'[]' # to-do? get objcInit as String is override return 'nil' class VariType is partial get objcRef as String is override return '[_wrappedType.objcRef]' + r'[]' # to-do get objcParamRef as String is override return 'params ' + .objcRef # to-do class UnspecifiedType is partial get objcInit as String is override # to-do: throw Exception('Not expecting code gen for unspecified types.') return '!UnspecifiedType!' ## ## Enums ## class EnumDecl is partial def writeObjcHeader(sw as CurlyWriter) pass # to-do def writeObjcTestInvocation(cw as CurlyWriter) is override pass get objcInit as String is override return '' class EnumMember is partial def writeObjcTestInvocation(cw as CurlyWriter) pass ## ## Boxes ## class Box is partial get objcNameComponent as String is override name = .objcName i = name.indexOf('/*') # form: /*foo*/bar if i <> -1 j = name.indexOf('*/', i) name = name[:i] + name[j+2:] # qualified types and generics need cleanup for ch in '.<>, ' name = name.replace(ch, c'_') return name get objcThis as String """ Returns 'this' as you would expect. Overridden by Extension. """ return 'this' get objcKeyWord as String is abstract get objcName as String is override return _name.replace('') source = sb.toString else source = .objcName if .parentNameSpace and not .parentNameSpace.isRoot source = .parentNameSpace.objcQualifier + source else if .parentBox source = .parentBox.objcRef + '.' + source return source def writeObjcHeader(sw as CurlyWriter) if .isExtern, return .compiler.boxStack.push(this) try assert not .isConstructed # to-do .writeObjcAttribs(sw) # to-do .writeObjcIsNames(sw) sw.write('@interface') # to-do: not valid for interface or struct .writeObjcDefName(sw) .writeObjcInheritance(sw) sep = '' for inter in _baseInterfaces sw.write(sep) sw.write(inter.objcRef) sep = ', ' if _genericParams.count sw.indent for param in _genericParams if param inherits GenericParam param.writeObjcConstraint(sw) sw.dedent sw.writeAndIndent('{\n') for decl in _declsInOrder if not .willWriteDeclObjcDef(decl), continue .compiler.boxMemberStack.push(decl) try decl.writeObjcHeader(sw) finally .compiler.boxMemberStack.pop sw.dedentAndWrite('} // [.objcKeyWord] [.name]\n') sw.write('\n') finally .compiler.boxStack.pop # uu def writeObjcDef(sw as CurlyWriter) base.writeObjcDef(sw) if .isExtern, return .compiler.boxStack.push(this) try assert not .isConstructed sw.write('[.objcKeyWord] ') .writeObjcDefName(sw) sw.writeAndIndent('{\n') .writeObjcInvariantMethod(sw) for tm in _testMethods .compiler.boxMemberStack.push(tm) try, tm.writeObjcDef(sw) finally, .compiler.boxMemberStack.pop for decl in _declsInOrder if not .willWriteDeclObjcDef(decl), continue .compiler.boxMemberStack.push(decl) try decl.writeObjcDef(sw) finally .compiler.boxMemberStack.pop if .compiler.includeTests .writeObjcTest(sw) sw.dedentAndWrite('} // [.objcKeyWord] [.name]\n') sw.write('\n') finally .compiler.boxStack.pop def willWriteDeclObjcDef(decl) as bool return true def writeObjcAttribs(sw as CurlyWriter) for attrib in _attribs attrib.writeObjcDef(sw) def writeObjcDefName(sw as CurlyWriter) sw.write('[.rootName]') if _genericParams.count sw.write('<') sep = '' for param in _genericParams sw.write(sep) param.writeObjcDef(sw) sep = ', ' sw.write('>') def writeObjcInheritance(sw as CurlyWriter) """ Class uses this to write its base class declaration. No box uses this to write interface implementation--that's handled in the Box class. """ pass get objcInvariantVisibility as String is abstract def writeObjcInvariantMethod(sw as CurlyWriter) if .compiler.options['contracts'] <> 'none' sw.write('\nint _ih_invariantGuard;\n\n') if .compiler.options['contracts'] <> 'methods' return sw.write('\n[.objcInvariantVisibility] void invariant_[.rootName]() {\n') sw.indent if _baseClass and (not _baseClass.isFromBinaryLibrary or _baseClass.declForName('invariant_[_baseClass.rootName]')) sw.write('invariant_[_baseClass.rootName]();\n') .writeObjcInvariantChecks(sw) sw.dedent sw.write('}\n\n') def writeAllObjcInvariantChecks(sw as CurlyWriter) """ Writes all Objc invariant checks including inherited. In support of -contracts:inline """ _writeAllObjcInvariantChecks(sw, this) def _writeAllObjcInvariantChecks(sw as CurlyWriter, box as Box) if box.baseClass and not box.baseClass.isFromBinaryLibrary _writeAllObjcInvariantChecks(sw, box.baseClass to !) box.writeObjcInvariantChecks(sw) def writeObjcInvariantChecks(sw as CurlyWriter) """ Writes the Objc invariant checks just for this class. """ for expr in _invariants objcThis = '[.objcName].class' sw.write('if (!') expr.writeObjcDef(sw) sw.write(')\n') sw.indent sw.write('throw new Cobra.Core.InvariantException([expr.objcSourceSite(.name, "invariant", objcThis)], ') # to-do expr.writeObjcBreakdown(sw) sw.write('[objcThis], null);\n') sw.dedent def writeObjcTest(sw as CurlyWriter) pass var _didWriteObjcTestInvocation = false def writeObjcTestInvocation(sw as CurlyWriter) is override # used by the test option if _didWriteObjcTestInvocation return if .isExtern return if .isGenericDef # sorry, but static methods always require a type arg even if you don't need it. workaround. make another class with a 'test' section that tests the generic class TODO: make Cobra do this, but then watch for use of the generic param! return assert .parentNameSpace sw.write('\t\t[.objcRef].RunTestsIfNeeded();\n') _didWriteObjcTestInvocation = true get newForObjcTest as String return '' class ClassOrStruct is partial get objcRef as String if .isGeneric and .isGenericDef return .qualifiedRootName + '<' + String(c',',.genericParams.count-1) + '>' else return base.objcRef class Class is partial get objcInit as String is override return 'nil' get objcInvariantVisibility as String is override return 'protected' get objcKeyWord as String is override return '@implementation' def writeObjcInheritance(sw as CurlyWriter) is override sw.write(' : ') if _baseClass sw.write(_baseClass.objcRef) didWrite = true if didWrite if _baseInterfaces.count sw.write(', ') else sw.write(' ') get newForObjcTest as String is override return if(not _baseClass.isExtern, ' new', '') class Interface is partial get objcInit as String is override return '' get objcInvariantVisibility as String is override return 'to-do' get objcKeyWord as String is override return 'to-do' class Mixin is partial pass # to-do class Struct is partial get objcInit as String is override return '' get objcInvariantVisibility as String is override return 'to-do' get objcKeyWord as String is override return 'to-do' class MethodSig is partial pass # to-do class GenericParam is partial # to-do def writeObjcConstraint(sw as CurlyWriter) pass get objcInit as String is override return '' class GenericClassConstraint is partial pass # to-do class GenericStructConstraint is partial pass # to-do class GenericCallableConstraint is partial pass # to-do class GenericTypeConstraint is partial pass # to-do class Extension is partial get objcInit as String is override return '' get objcInvariantVisibility as String is override return 'to-do' get objcKeyWord as String is override return 'to-do' ## ## Vars ## interface IVar is partial pass # to-do class AbstractLocalVar is partial pass # to-do class Param is partial pass # to-do class LocalVar is partial pass # to-do class ResultVar is partial pass # to-do ## ## Members ## interface IBoxMember is partial def writeObjcHeader(sw as CurlyWriter) class BoxMember is partial def writeObjcHeader(sw as CurlyWriter) pass # to-do def writeObjcTestInvocation(cw as CurlyWriter) pass # to-do class BoxEvent is partial pass # to-do class BoxConst is partial pass # to-do class BoxVar is partial pass # to-do class AbstractMethod is partial pass # to-do class Initializer is partial pass # to-do class Method is partial pass # to-do class ProperDexer is partial pass # to-do class ProperDexerXetter is partial pass # to-do class Property is partial pass # to-do class Indexer is partial pass # to-do class MemberOverload is partial pass # to-do class TestMethod is partial pass # to-do class ContractPart is partial pass # to-do class RequirePart is partial pass # to-do class EnsurePart is partial pass # to-do ## ## Statements ## class Stmt is partial pass # to-do class AssertStmt is partial pass # to-do class BranchStmt is partial pass # to-do class BlockStmt is partial pass # to-do class BreakStmt is partial pass # to-do class ContinueStmt is partial pass # to-do class ExpectStmt is partial pass # to-do class ForStmt is partial pass # to-do class OldForNumericStmt is partial pass # to-do class ForNumericStmt is partial pass # to-do class ForEnumerableStmt is partial pass # to-do class IfStmt is partial pass # to-do class ListenOrIgnoreStmt is partial pass # to-do class ListenStmt is partial pass # to-do class IgnoreStmt is partial pass # to-do class LockStmt is partial pass # to-do class PassStmt is partial pass # to-do class PrintStmt is partial pass # to-do class RaiseStmt is partial pass # to-do class ReturnStmt is partial pass # to-do class TraceStmt is partial pass # to-do class TraceLocationStmt is partial pass # to-do class TraceAllStmt is partial pass # to-do class TraceExprsStmt is partial pass # to-do class TryStmt is partial pass # to-do class CatchBlock is partial pass # to-do class ThrowStmt is partial pass # to-do class UsingStmt is partial pass # to-do class WhileStmt is partial pass # to-do class PostWhileStmt is partial pass # to-do class YieldStmt is partial pass # to-do class YieldBreakStmt is partial pass # to-do class YieldReturnStmt is partial pass # to-do class MultiTargetAssignStatement is partial pass # to-do ## ## Expressions ## class Expr is partial # to-do def objcSourceSite(args as vari dynamic) as String return '' def writeObjcBreakdown(sw as CurlyWriter) pass class NameExpr is partial pass # to-do class AsExpr is partial pass # to-do class AnonymousMethodExpr is partial pass # to-do class LambdaExpr is partial pass # to-do class CallExpr is partial pass # to-do class EnumCallExpr is partial pass # to-do class ForExpr is partial pass # to-do class IdentifierExpr is partial pass # to-do class IfExpr is partial pass # to-do class IndexExpr is partial pass # to-do class IsNilExpr is partial pass # to-do class IsNotNilExpr is partial pass # to-do class MemberExpr is partial pass # to-do class OldExpr is partial pass # to-do class PostCallExpr is partial pass # to-do class RefExpr is partial pass # to-do class SharpExpr is partial pass # to-do class SliceExpr is partial pass # to-do class TypeExpr is partial pass # to-do class AllOrAnyExpr is partial pass # to-do class UnaryOpExpr is partial pass # to-do class Literal is partial pass # to-do class AtomicLiteral is partial pass # to-do class BoolLit is partial pass # to-do class CharLit is partial pass # to-do class DecimalLit is partial pass # to-do class FractionalLit is partial pass # to-do class FloatLit is partial pass # to-do class IntegerLit is partial pass # to-do class NilLiteral is partial pass # to-do class StringLit is partial pass # to-do class StringSubstLit is partial pass # to-do class BaseLit is partial pass # to-do class ThisLit is partial pass # to-do class VarLit is partial pass # to-do class SequenceLit is partial pass # to-do class ListLit is partial pass # to-do class ArrayLit is partial pass # to-do class SetLit is partial pass # to-do class DictLit is partial pass # to-do class ToNilableOrNotExpr is partial pass # to-do class ToNilableExpr is partial pass # to-do class ToNonNilableExpr is partial pass # to-do ## ## Binary Expressions ## class BinaryOpExpr is partial pass # to-do class AssignExpr is partial pass # to-do class NumericPromoExpr is partial pass # to-do class AugAssignMathExpr is partial pass # to-do class AugAssignBitwiseExpr is partial pass # to-do class BinaryBoolExpr is partial pass # to-do class BinaryBitwiseExpr is partial pass # to-do class BinaryMathExpr is partial pass # to-do class CompareExpr is partial pass # to-do class ChainedCompareExpr is partial pass # to-do class DotExpr is partial pass # to-do class InExpr is partial pass # to-do class InheritsExpr is partial pass # to-do class ToExpr is partial pass # to-do class ToQExpr is partial pass # to-do class CoalesceExpr is partial pass # to-do class InverseCoalesceExpr is partial pass # to-do class CoalesceAssignExpr is partial pass # to-do class InverseCoalesceAssignExpr is partial pass # to-do ## ## Attributes ## class AttributeDecl is partial pass # to-do class AssemblyDecl is partial def writeObjcTestInvocation(cw as CurlyWriter) pass ## ## Misc items ## class ObjcBackEndUtils shared # to-do: update these var _backEndKeyWordList = '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 var _backEndKeyWordSet = Set() def isBackEndKeyWord(word as String) as bool """ Returns true if the given word is a keyword in C# 2.0. """ require word.length test assert .isBackEndKeyWord('object') assert .isBackEndKeyWord('if') assert not .isBackEndKeyWord('total') body if _backEndKeyWordSet.count == 0 for word in _backEndKeyWordList _backEndKeyWordSet.add(word) return word in _backEndKeyWordSet # to-do: use a different technique def backEndNameForLocalVarName(name as String) as String if .isBackEndKeyWord(name) return '@' + name # C# supports @ as a prefix to escape identifiers else return name