Wiki

root/cobra/trunk/Source/Compiler.cobra

Revision 2636, 49.7 KB (checked in by Charles.Esterbrook, 7 weeks ago)

JVM back-end progress.
credit:hopscc

  • Property svn:eol-style set to native
Line 
1use System.Reflection
2use System.Diagnostics
3
4
5class StopCompilation
6    inherits Exception
7    """
8    Thrown by the compiler when it must stop compilation due to errors. This can happen at the end
9    of the phases:
10        * parsing
11        * bind interface
12        * bind implementation
13        * code gen
14    """
15
16    var _comp as Compiler
17
18    cue init(comp as Compiler)
19        base.init
20        _comp = comp
21
22
23class UnexpectedInvocationException
24    inherits SystemException
25    """
26    Throw this when a class is not expecting a particular method to be invoked at runtime
27    (even though it inherits it or must implement it for an interface).
28    """
29
30    cue init(obj as Object)
31        base.init('Not expecting invocation.')
32       
33class LoadReferenceException inherits Exception
34    """
35    Thrown when Loading a reference fails for some reason.
36        FileNotFoundException, FileLoadException
37    """
38    var fileName =''
39    var tag=''
40   
41    cue init(tag as String, fileName as String, msg as String)
42        base.init(msg)
43        .tag = tag
44        .fileName = fileName
45       
46    def toString as String is override
47        return '[.tag] [.fileName] [.message]' 
48
49enum PlatformEnum
50    Microsoft
51    Novell
52
53
54class BackEnd is abstract 
55    """
56    Holder for items specific to the backEnd implementation
57    """
58   
59    var _tagToTypeName = Dictionary<of String, String>()
60        """ Map from Typename tags used in compiler to backend specific qualified Type name"""
61   
62    cue init(compiler as Compiler)
63        base.init
64        _name = ''
65        _runTimeLibFileName = 'rtl'
66        _runTimeLibNativeSourceFileName = 'rtlSrc.ext'
67        __compiler = compiler
68
69    get name from var as String
70   
71    get cobraRuntimeLibFileName from _runTimeLibFileName as String 
72        """Name of the Cobra RunTime Library file for this backend."""
73
74    get runTimeLibNativeSourceFileName from _runTimeLibNativeSourceFileName as String
75        """Name of the backEnd source file containing any native code support for Cobra.Lang."""
76
77    get compiler from __compiler as Compiler
78   
79    get tagToTypeName from var
80        """ Map from TypeName tags used in compiler to backend specific qualified TypeName"""
81   
82    def resolveTypeTag(qualifiedNameOrTag as String) as String
83        if qualifiedNameOrTag.contains('.')         
84            qualifiedName = qualifiedNameOrTag
85        else   
86            qualifiedName = .tagToTypeName[qualifiedNameOrTag]  # type tag to backend qualifiedName
87        return qualifiedName
88       
89    def makePhases(phases as IList<of Phase>) is abstract
90        """
91        Given a list of core phases for compilation complete it with additions (or even removals and
92        rearrangements if necessary) for this given backend.
93        """
94       
95    def getRecommendedBuiltInType(parentNameSpace as NameSpace?, name as String) as String? is abstract
96        """
97        If parentNameSpace is the main system namespace and name is a backEnd builtin type
98        return the Cobra equivalent language type name (or nil).
99        """
100       
101    def computeOutName as String is abstract
102        """
103        Return the binary file output name for compilation of files for this backend.
104        """
105       
106    def genNativeModule(filename as String, verbosity as int) as Module? is abstract   
107        """
108        Check if a filename is a Native module and if so generate and return the Native module type for it
109        otherwise return nil.
110        """
111   
112    def setupRunProcess(baseExe as String, fullExe as String) as Process is abstract
113        """
114        Create and initialise the process to run the compiled program post compilation
115        setup varies on the backend (.Clr/Jvm) and platform.
116        """
117   
118    def setDefaultUseDirectives(ns as NameSpace) is abstract
119        """
120        Set the default Use directives into the given Namespace (usually topNamespace) for this backend.
121        """
122   
123    def fixLibExtension(libRef as String) as String is abstract
124        """
125        Augment given lib reference string with backend extension if not already have one.
126        """
127   
128    def loadLibReference(reference as String) as bool is abstract
129        """
130        Load the given library reference file  using the current backend paradigms.
131        Return true if reference found and loaded correctly, false otherwise
132        """
133   
134    def readSystemTypes is abstract
135        """ Read and Load System Types for backend for Compiler to make available"""
136       
137    def fixMemberSigs is abstract
138        """         
139        Most backends dont natively support nilablility, this marks/fixes the common backend
140        class signatures that should be marked nilable.
141        """
142   
143    def installNativeMethods(box as Box, nativeType as NativeType) is abstract
144        """
145        Setup so that static methods (on Primitives and some others) get installed/treated as normal methods
146        on the instance.
147        """
148           
149    def isRunnableFile( fullExeFileName as String) as bool is abstract
150        """Test if given filename is an executable ( vs a library or something else) """
151
152    # Native Types access
153    def cobraNameForNativeBoxName(name as String) as String is abstract
154        """
155        Returns name from backend library entries converted to cobra naming form.
156        """
157   
158    get objectTypeProxy as AbstractTypeProxy is abstract
159        """BE TypeProxy for root of back end Object hierarchy."""
160
161    get typeTypeProxy as AbstractTypeProxy is abstract
162        """BE TypeProxy for BE notion of a class describing a Type."""
163
164    def nativeTypeProxy(type as NativeType) as NativeTypeProxy  is abstract
165        """
166        Return a Proxy placeHolder for a BackEnd Native Type.
167        """
168       
169    def nativeType(type as dynamic) as NativeType is abstract
170        """
171        Return a Native Type wrapped so we can use it without explicitly knowing what it is anywhere
172        else but the providing back end. Used by the backends to generate Types from Libraries.
173        """
174   
175    def nativeTypeByName(qualifiedName as String) as NativeType is abstract
176        """
177        Return a Native Type corresponding to the fully qualified name.
178        Abstract Type Literal tags used in the compiler directly can also be obtained through this
179        otherwise the qualified names are expected to conform to the platform back end naming.
180        """
181   
182    def prepSystemObjectClass(box as Box) is abstract
183        """Setup additional or convenience members on the System Object class. """
184       
185    def scanGenericArgs(box as Box) is abstract
186        """Scan a loaded Dll (generic) type and translate from native any generic Args."""
187       
188    def scanNativeType(box as Box) is abstract
189        """Scan a loaded Dll type and convert its native Type info to Cobras form """
190       
191    def scanNativeType(edcl as EnumDecl) is abstract
192        """Scan a loaded Dll Enum type and convert its native info to Cobras form """
193       
194    def setUnderlyingType(edcl as EnumDecl)  is abstract
195        """Set underlying Storage Type of the value of an Enum."""
196       
197    def determineExtnNativeType(extn as Extension, nativeType as NativeType) as NativeType
198        """
199        The real extended type is the type of the first argument of any method.
200        Find and make that type from the param list.
201        """
202        throw Exception('Need implementation of determineExtnNativeType for backend to determine type for an extension')
203
204    def handleNameSpaceNameCollision(ns as NameSpace, token as IToken, name as String) as NameSpace
205        """ 
206            What to do if a namespace name collides with an existing symbol.
207            Some backends disallow this situation so its an error.
208            Others keep namespace and symbol tables separate so its perfectly
209            allowable.
210        """
211        throw Exception('In [ns.name] there is a already non-namespace declaration named "[name]".')
212   
213class BasicBackEnd inherits BackEnd
214    """ Stub BackEnd for tests. """
215   
216    cue init(compiler as Compiler)
217        base.init(compiler)
218        _name = 'c#-clr(basic)'
219        _runTimeLibFileName = 'cobraRTL.libext'
220        _runTimeLibNativeSourceFileName = 'cobraRTL.ext'
221       
222        _tagToTypeName = {
223            'Object': 'System.Object',
224            'Type'  : 'System.Type',
225        }
226       
227    def makePhases(phases as IList<of Phase>) is override
228        pass
229       
230    def getRecommendedBuiltInType(parentNameSpace as NameSpace?, name as String) as String? is override
231        return nil
232
233    def computeOutName as String  is override
234        return 'BasicOut'
235       
236    def genNativeModule(filename as String, verbosity as int) as Module?  is override
237        return nil
238   
239    def setupRunProcess(baseExe as String, fullExe as String) as Process  is override
240        p = Process()
241        p.startInfo.fileName = 'echo' 
242        p.startInfo.arguments = 'basic BackEnd process - [baseExe]'
243        return p       
244   
245    def setDefaultUseDirectives(ns as NameSpace)  is override
246        pass
247   
248    def fixLibExtension(libRef as String) as String is override
249        if not libRef.endsWith('.libext')
250            libRef += '.libext'
251        return libRef   
252   
253    def loadLibReference(reference as String) as bool is override
254        return true
255   
256    def readSystemTypes is override
257        pass
258   
259    def fixMemberSigs is override
260        pass
261   
262    def installNativeMethods(box as Box, nativeType as NativeType) is override
263        pass
264       
265    def isRunnableFile(fullExeFileName as String) as bool is override
266        return true
267       
268    # Native Type access
269    def cobraNameForNativeBoxName(name as String) as String is override
270        return name + '_BBE'
271   
272    def prepSystemObjectClass(box as Box) is override
273        pass
274       
275    def scanGenericArgs(box as Box) is override
276        pass
277       
278    def scanNativeType(box as Box) is override
279        pass
280       
281    def scanNativeType(edcl as EnumDecl) is override
282        pass
283       
284    def setUnderlyingType(edcl as EnumDecl)  is override
285        pass
286
287    # Types
288    get objectTypeProxy as AbstractTypeProxy is override
289        return ClrTypeProxy(Object) # for testing
290           
291    get typeTypeProxy  as AbstractTypeProxy is override
292        return ClrTypeProxy(Type )# for testing
293
294    def nativeTypeProxy(type as NativeType) as NativeTypeProxy is override
295        return ClrTypeProxy(type) #TODO: fix this to something non BE specific Tmp
296       
297    def nativeType(type) as NativeType is override
298        return ClrNativeType(type) #TODO: fix this to something non BE specific Tmp
299   
300    def nativeTypeByName(qualifiedName as String) as NativeType is override
301        return ClrNativeType(System.Object) #TODO: fix this to something non BE specific Tmp
302   
303class Compiler implements ITypeProvider, IWarningRecorder, IErrorRecorder, ICompilerForNodes is partial
304    """
305    General notes:
306
307    To cope with nesting, the compiler keeps a stack of the three types of things that can be nested. Items are pushed and popped off these stacks during each of the "bind interface" and "bind implementation" phases. The three stacks are:
308        * nameSpaceStack - namespaces
309        * boxStack - boxes are classes, structs and interfaces
310        * codeMemberStack - methods, properties and inits
311    """
312
313    var _backEnd as BackEnd?
314   
315    var _nextSerialNum as int is shared
316    var _serialNum as int
317    var _verbosity as int
318    var _options as OptionValues
319    var _commandLineArgParser as ArgParser?
320    var _willPrintSuccessMsg = true
321    var _willWriteTestInvocation = false
322    var _htmlWriter as HtmlWriter?
323
324    var _globalNS as NameSpace
325    var _modules as List<of Module>
326
327    var _curModule as Module?  # set during bindInt and bindImp
328    var _nodeStack as Stack<of INode>
329    var _nameSpaceStack as Stack<of NameSpace>
330    var _boxStack as Stack<of Box>
331    var _boxMemberStack as Stack<of IBoxMember>
332    var _codeMemberStack as Stack<of AbstractMethod>
333
334    var _errors as List<of SourceException>
335    var _warnings as List<of SourceException>
336    var _messages as List<of SourceException>  # all errors and warnings
337    var _messagesPerSourceLine as IDictionary<of String, List<of SourceException>>  # key is 'filename:lineNum'
338    var _noWarningLines as Cobra.Lang.ISet<of String>   # key is 'filename:lineNum'
339
340    var _intermediateFileNames as List<of String>
341    var _loadedReferences as List<of String>
342
343
344    # caches
345    var _primitiveToITypeCache as IDictionary<of dynamic, IType>? # Key is backend type for a Type ( e.g System.Type)
346
347    cue init
348        .init(0, nil)
349
350    cue init(verbosity as int)
351        .init(verbosity, nil)
352
353    cue init(verbosity as int, initialModules as IList<of Module>?)
354        base.init
355        Node.reset
356        _nextSerialNum += 1
357        _serialNum = _nextSerialNum
358        _verbosity = verbosity
359        _modules = List<of Module>()
360        _options = OptionValues()
361        _pathsToCompile = List<of String>()
362        _globalNS = NameSpace(Token.empty, '(global)')
363        _nodeStack = Stack<of INode>()
364        _nameSpaceStack = Stack<of NameSpace>()
365        _boxStack = Stack<of Box>()
366        _boxMemberStack = Stack<of IBoxMember>()
367        _codeMemberStack = Stack<of AbstractMethod>()
368        _messages = List<of SourceException>()
369        _messagesPerSourceLine = Dictionary<of String, List<of SourceException>>()
370        _noWarningLines = Set<of String>()
371        _errors = List<of SourceException>()
372        _warnings = List<of SourceException>()
373        _intermediateFileNames = List<of String>()
374        _loadedReferences = List<of String>()
375        if initialModules
376            if false # TODO: not working yet
377                for mod in initialModules
378                    if mod inherits AssemblyModule
379                        ns = mod.topNameSpace
380                        assert not ns.superNameSpace
381                        ns.unifyInto(_globalNS)
382                    # TODO: handle CobraModule too
383                    _modules.add(mod)
384
385    def toString as String is override
386        return '[.getType.name]([_serialNum])'
387
388    get backEnd from var
389
390    pro defaultOutName from var as String?
391
392    pro verbosity from var
393
394    get includeTests as bool
395        return .options.boolValue('include-tests')
396
397    get primitiveToITypeCache from var
398        """
399        Returns a cache mapping BackEnd types to their corresponding ITypes.
400        Populated and used by the backend TypeProxy implementations ( {Clr,Jvm,...}TypeProxy)
401        """
402    set primitiveCache as IDictionary<of dynamic, IType>
403        assert value.count <> 0
404        _primitiveToITypeCache = value
405
406    get globalNS from var
407        """
408        Holds all topLevel decls including refs to Namespaces used and referenced.
409        """
410
411    pro mainMethodTypeName from var as String = ''
412
413    get modules from var
414
415    pro options from var
416
417    get pathsToCompile from var as IList<of String>
418        """
419        Phases are free to modify this list (usually by adding new paths to include in compilation).
420        """
421
422    pro commandLineArgParser from var
423
424    pro willPrintSuccessMsg from var
425
426    pro willWriteTestInvocation from var
427   
428    get curPhase from var as Phase?
429   
430    pro curModule from var
431
432    get lastPhase from var as Phase?
433   
434    get nodeStack from var
435
436    get nameSpaceStack from var
437
438    get curNameSpace as NameSpace
439        require .nameSpaceStack.count
440        return _nameSpaceStack.peek
441
442    get boxStack from var
443
444    get curBox as Box
445        require .boxStack.count
446        return _boxStack.peek
447
448    get curBoxMember as IBoxMember
449        require .boxMemberStack.count
450        return _boxMemberStack.peek
451
452    get boxMemberStack from var
453
454    get curCodeMember as AbstractMethod
455        require .codeMemberStack.count
456        return _codeMemberStack.peek
457
458    get codeMemberStack from var
459
460    get errors from var
461
462    get warnings from var
463
464    get messages from var
465
466    get noWarningLines from var
467
468    get loadedReferences from var
469        """
470        Returns the list of library references that were loaded.
471        This could be more than what's specified on the command line due to UseDirective.
472        And it could be less due to failures to load.
473        """
474
475    pro htmlWriter from var
476        """
477        Set this to support the output-html command line option.
478        """
479
480    get hasDetailedStackTraceOption as bool
481        return _options.boolValue('detailed-stack-trace')
482
483    get willTrackLocals as bool
484        # the box stack can be empty because of assembly; has SomeAttr
485        if .boxStack.count
486            # the code member stack can be empty due to class variables (ex: var _x = 1)
487            return .hasDetailedStackTraceOption and (.codeMemberStack.count == 0 or .curCodeMember.parentBox.canHaveDetailedStackTrace)
488        else
489            return false
490
491    pro refExprLevel from var as int
492   
493    get hasExceptionReportOption as bool
494        return .options.boolValue('exception-report')
495       
496    pro linesCompiled from var as int 
497    pro nodesCompiled from var as int 
498    pro tokensCompiled from var as int 
499
500    def recordError(error as SourceException)
501        """
502        Node calls this to record errors.
503        """
504        if error inherits NodeMultiException
505            for exc in error.exceptions
506                _addMessage(exc)
507        else
508            _addMessage(error)
509
510    def addIntermediateFile(path as String)
511        _intermediateFileNames.add(path)
512
513
514    ## Phases
515
516    def phaseClasses as List<of Type>
517        """
518        Returns a list of phase classes in the order they should be run.
519        Note that the back-ends also add their own phases.
520        """
521        return [
522            BindRunTimeLibraryPhase,
523            ReadLibrariesPhase,
524            ParsePhase,
525            BindUsePhase,
526            BindInheritancePhase,
527            BindInterfacePhase,
528            ComputeMatchingBaseMembersPhase,
529            BindImplementationPhase,
530            IdentifyMainPhase,
531            SuggestDefaultNumberPhase,
532        ]
533
534    def makePhases as List<of Phase>
535        """
536        Returns a list of phase instances in the order they should be run.
537        Consults the back-end.
538        """
539        phases = for phaseClass in .phaseClasses get phaseClass(this) to Phase
540        .backEnd.makePhases(phases)
541        if .options.boolValue('timeit')
542            phases.add(CountNodesPhase(this))
543        for i, phase in phases.numbered, phase.stableOrder = i
544        phases.sort  # see Phase.order and .compareTo
545        return phases
546
547    def runPhase(phaseType as Type) as bool
548        require phaseType.isSubclassOf(Phase)
549        ensure result implies .errors.count > old .errors.count
550        return .runPhase(phaseType(this) to Phase)
551
552    def runPhase(phase as Phase) as bool
553        require
554            phase.compiler is this
555            not phase.isRunning
556        ensure
557            phase.didRun
558            not phase.isRunning
559            .lastPhase is phase
560            result implies .errors.count > old .errors.count
561        body
562            oldErrorCount = .errors.count
563            _curPhase = phase
564            try
565                phase.run
566                .writeSourceCodeCorrections
567                return .errors.count > oldErrorCount
568            finally
569                _curPhase = nil
570                _lastPhase = phase
571
572
573    ## Compiler
574   
575    def compileFilesNamed(paths as IList<of String>)
576        .compileFilesNamed(paths, false, nil)
577
578    def compileFilesNamed(paths as IList<of String>, writeTestInvocation as bool, stopCompilation as Predicate<of Compiler>?)
579        .initBackEnd
580        .defaultOutName = if(.options.buildStandardLibrary, 'Cobra.Lang.dll', paths[0])
581        if .options.boolValue('compile-if-needed')
582            outName = .backEnd.computeOutName   
583            if not .isCompilationNeeded(outName, paths)
584                return
585               
586        if .options.boolValue('reveal-internal-exceptions')
587            _compileFilesNamed(paths, writeTestInvocation, stopCompilation)
588            .printMessages
589            return
590
591        try
592            _compileFilesNamed(paths, writeTestInvocation, stopCompilation)
593        catch StopCompilation
594            throw
595        catch exc as Exception
596            # unexpected exception -- only StopCompilation should be thrown
597            if exc inherits SourceException
598                if exc.hasSourceSite
599                    .recordError(InternalError(exc.fileName, exc.lineNum, exc.message, exc))
600                else
601                    .recordError(InternalError(exc.message, exc))
602            else if exc inherits AssertException
603                sn as SyntaxNode?
604                if exc.this inherits SyntaxNode
605                    sn = exc.this to SyntaxNode
606                else if exc.info inherits SyntaxNode
607                    sn = exc.info to SyntaxNode
608                if sn
609                    .recordError(InternalError(sn.token.fileName, sn.token.lineNum, exc.message, exc))
610                else
611                    .recordError(InternalError(exc.message, exc))
612            else
613                .recordError(InternalError(exc.message, exc))
614            .printMessages
615            throw StopCompilation(this)
616        success
617            .printMessages
618
619    def _compileFilesNamed(paths as IList<of String>, writeTestInvocation as bool, stopCompilation as Predicate<of Compiler>?)
620        timeit = .options.boolValue('timeit') and .verbosity
621        timings, totalElapsed = [], 0.0f
622        .willWriteTestInvocation = writeTestInvocation
623        _pathsToCompile = paths
624        # now, essentially, do this:
625        #     for phase in .makePhases, runPhase(phase)
626        # but pay attention to things like errors and stopCompilation
627        hasErrors = false
628        for phase in .makePhases
629            if stopCompilation and stopCompilation(this), break
630            if not hasErrors or phase.willRunWithErrors
631                sw = System.Diagnostics.Stopwatch()
632                sw.start
633                if .runPhase(phase), hasErrors = true
634                sw.stop
635                if timeit
636                    totalElapsed += sw.elapsed.totalSeconds
637                    timings.add([sw.elapsed, phase.description])
638                sw.reset
639        if timeit
640            # to see timings try:
641            # cobra -c -v -timeit hello.cobra
642#           timings.sort(do(a, b)=b[0].compareTo(a[0]))
643            sharp'timings.Sort(delegate(object a, object b) { return ((System.TimeSpan)((System.Collections.Generic.List<object>)b)[0]).CompareTo((System.TimeSpan)((System.Collections.Generic.List<object>)a)[0]); })'
644            print
645            print 'Phase timings:'
646            for timing in timings
647                elapsed, description = timing[0].totalSeconds to float, timing[1] to String
648                percent = 100 * elapsed / totalElapsed
649                print '   [percent:00.00][elapsed:00.00]secs  [description]'
650            print '  100.00%  [totalElapsed:00.00]secs  Total for all phases'
651            print
652
653        if hasErrors, _exitFromErrors
654
655    def testifyFilesNamed(fileNames as IList<of String>, options as OptionValues, resultsWriter as IndentedWriter, verbose as bool)
656        """
657        Compiles the given fileNames in support of "testify".
658        Sets .options to the options arg.
659        Will raise StopCompilation when an error occurs.
660        """
661        saveError = Console.error
662        Console.setError(CobraCore.printDestination)
663        try
664            .options = options
665            bar = '----------------------------------------------------------------------------------------------------'
666            .initBackEnd
667            .defaultOutName = if(.options.buildStandardLibrary, 'Cobra.Lang.dll', fileNames[0])
668            _pathsToCompile = fileNames
669            hasErrors = false
670            for phase in .makePhases
671                if verbose, print 'Testify phase:', phase.description
672                if not hasErrors or phase.willRunWithErrors
673                    if .runPhase(phase), hasErrors = true
674                if verbose
675                    .dumpModulesForTestify(resultsWriter, 'Modules after: [phase.description]')
676                    print bar
677            .printMessages
678            print bar
679            if hasErrors, throw StopCompilation(this# testify runner wants this
680            # TODO: to display the intermediate source:
681            #   for module in .modules
682            #       if not module.isCobraLibrary
683            #           Utils.printSource(module.sharpSource)
684            #   print bar
685        finally
686            Console.setError(saveError)
687
688    def isCompilationNeeded(outName as String, paths as IList<of String>) as bool
689        """
690        Returns true if compilation is needed because the output file does not exist
691        or a source file is newer than it.
692        """
693        v = .verbosity
694        if v, print 'Checking timestamps for -compile-if-needed'
695        if not File.exists(outName)
696            if v, print '    "[outName]" does not exist.'
697            return true
698        targetTime = File.getLastWriteTime(outName)
699        if v >= 2, print '    "[outName]" last write time: [targetTime].'
700        for path in paths
701            srcTime = File.getLastWriteTime(path)
702            if v >= 2, print '    "[path]" last write time: [srcTime].'
703            if srcTime.compareTo(targetTime) >= 0
704                if v, print '    "[path]" is newer than "[outName]"; will compile.'
705                return true
706        if v, print '    No source file is newer than "[outName]"; skipping compile.'
707        return false
708   
709    def addRunTimeRef(opts as OptionValues)
710        if not opts.containsKey('reference')
711            opts['reference'] = List<of String>()
712        refs = opts['reference'] to List<of String>
713        libName = .backEnd.cobraRuntimeLibFileName
714        if libName not in refs
715            if .verbosity, print 'Adding reference to [libName]'
716            refs.add(libName)
717
718    def runProcess as Process
719        return .runProcess(nil, nil)
720       
721    def runProcess(exeName as String?, argList as List<of String>?) as Process
722        """
723        Returns a new Process with startInfo.fileName and p.startInfo.arguments set appropriately
724        for the produced executable and the current options and any provided argsList.
725        """
726        baseExeFileName = exeName ? .baseExeFileName
727        fullExeFileName = exeName ? .fullExeFileName
728        p = .backEnd.setupRunProcess(baseExeFileName, fullExeFileName)
729
730        if argList and argList.count
731            args = p.startInfo.arguments ? ''
732            if args <> '', args += ' '
733            hasSpaces = any for a in argList where ' ' in a
734            if hasSpaces
735                argList = for arg in argList get if(' ' in arg, '"[arg]"', arg)
736            args += argList.join(' ')
737            p.startInfo.arguments = args
738        return p
739
740    ##
741    ## ITypeProvider
742    ##
743
744    var _anyFloatType as AnyFloatType?
745    var _anyIntType as AnyIntType?
746    var _arrayTypes as Dictionary<of IType, ArrayType>?
747    var _boolType as BoolType?
748    var _charType as CharType?
749    var _decimalType as DecimalType?
750    var _dynamicType as DynamicType?
751    var _floatTypes = Dictionary<of int, FloatType>()
752    var _intTypes = Dictionary<of int, IntType>()
753    var _nilType as NilType?
754    var _numberType as AbstractNumberType?
755    var _passThroughType as PassThroughType?
756    var _unspecifiedType as UnspecifiedType?
757    var _voidType as VoidType?
758    var _nilableTypes as Dictionary<of INode, NilableType>?
759    var _variTypes as Dictionary<of INode, VariType>?
760    var _nilableDynamicType as NilableType?
761
762    def typeForName(name as String) as IType
763        assert false, 'TODO'
764        return .intType
765
766    def typeOrNilForName(name as String) as IType?
767        assert false, 'TODO'
768        return nil
769
770    get anyFloatType as AnyFloatType
771        if _anyFloatType is nil
772            _anyFloatType = AnyFloatType()
773        return _anyFloatType to !
774
775    get anyIntType as AnyIntType
776        if _anyIntType is nil
777            _anyIntType = AnyIntType()
778        return _anyIntType to !
779
780    def arrayType(type as IType) as ArrayType
781        if _arrayTypes is nil, _arrayTypes = Dictionary<of IType, ArrayType>()
782        if _arrayTypes.containsKey(type)
783            return _arrayTypes[type]
784        else
785            _arrayTypes[type] = at = ArrayType(type)
786            at.bindInh
787            at.bindInt
788            return at
789
790    get boolType as BoolType
791        if _boolType is nil
792            _boolType = BoolType()
793        return _boolType to !
794
795    get charType as CharType
796        if _charType is nil
797            _charType = CharType()
798        return _charType to !
799
800    get decimalType as DecimalType
801        if _decimalType is nil
802            _decimalType = DecimalType()
803        return _decimalType to !
804
805    get dynamicType as DynamicType
806        if _dynamicType is nil
807            _dynamicType = DynamicType()
808        return _dynamicType to !
809
810    def floatType as FloatType
811        return .floatType(64)
812   
813    def floatType(size as int) as FloatType
814        require size in [32, 64]
815        type as FloatType?
816        if _floatTypes.tryGetValue(size, out type)
817            return type to !
818        else
819            type = _floatTypes[size] = FloatType(size, .anyFloatType)
820            return type to !
821
822    def intType as IntType
823        return .intType(true, 32)
824
825    def uintType as IntType
826        return .intType(false, 32)
827
828    def intType(signed as bool, size as int) as IntType
829        require size in [8, 16, 32, 64] # CC: inherit from interface
830        key = if(signed, -1, +1) * size
831        type as IntType?
832        if _intTypes.tryGetValue(key, out type)
833            return type to !
834        else
835            type = _intTypes[key] = IntType(signed, size, .anyIntType)
836            return type to !
837
838    get nilType as NilType
839        if _nilType is nil
840            _nilType = NilType()
841        return _nilType to !
842
843    get numberType as AbstractNumberType
844        if _numberType is nil
845            branch .options['number'] to String
846                on 'decimal', _numberType = .decimalType
847                on 'float',   _numberType = .floatType
848                on 'float32', _numberType = .floatType(32)
849                on 'float64', _numberType = .floatType(64)
850                else, throw FallThroughException(.options['number'])
851        return _numberType to !
852
853    set numberTypeName as String
854        """
855        Set `number` type from a string/name.
856        """
857        require value in ['decimal', 'float', 'float32', 'float64']
858        branch value
859            on 'decimal', _numberType = .decimalType
860            on 'float',   _numberType = .floatType
861            on 'float32', _numberType = .floatType(32)
862            on 'float64', _numberType = .floatType(64)
863            else, throw FallThroughException(value)
864
865    get passThroughType as PassThroughType
866        if _passThroughType is nil
867            _passThroughType = PassThroughType()
868        return _passThroughType to !
869
870    get unspecifiedType as UnspecifiedType
871        if _unspecifiedType is nil
872            _unspecifiedType = UnspecifiedType()
873        return _unspecifiedType to !
874
875    get voidType as VoidType
876        if _voidType is nil
877            _voidType = VoidType()
878        return _voidType to !
879
880    def nilableType(type as IType) as NilableType
881        if type inherits NilableType, return type
882        if _nilableTypes is nil
883            _nilableTypes = Dictionary<of INode, NilableType>()
884        if _nilableTypes.containsKey(type)
885            return _nilableTypes[type]
886        else
887            _nilableTypes[type] = nt = NilableType(type)
888            nt.bindInh
889            if not .isBindingInh, nt.bindInt
890            return nt
891
892    def variType(type as IType) as VariType
893        if _variTypes is nil
894            _variTypes = Dictionary<of INode, VariType>()
895        else if _variTypes.containsKey(type)
896            return _variTypes[type]
897        _variTypes[type] = vt = VariType(type)
898        return vt
899
900    def defaultType as IType
901        return .nilableDynamicType
902
903    def nilableDynamicType as NilableType
904        if _nilableDynamicType is nil
905            _nilableDynamicType = .nilableType(.dynamicType)
906        return _nilableDynamicType to !
907# -- end of ITypeProvider
908
909
910
911    get typeType as IType
912        return .libraryType('Type')
913
914    ## More type stuff
915
916    def readSystemTypes
917        .backEnd.readSystemTypes
918
919    def fixLibExtensions(references as List<of String>)
920        i = 0
921        for reference in List<of String>(references)
922            references[i] = .backEnd.fixLibExtension(references[i])
923            i += 1
924           
925    def printRefs(references as List<of String>)
926        if references.count == 0
927            print 'No additional assembly references.'
928        else
929            print 'Final assembly reference list:'
930            i = 0
931            for refPath in references
932                print '[i]. [refPath]'
933                i += 1
934           
935    def readAssemblyTypes(options as OptionValues)
936        references = options.getStringList('reference')
937
938        # Excluding the extension can be problematic
939        .fixLibExtensions(references)
940
941        # now that references are fixed, make a copy so that .options['references'] is not modified further
942        references = List<of String>(references)
943
944        if options.containsKey('pkg')
945            for pkgName in options['pkg'] to List<of String>
946                references.addRange(.refsForPackage(pkgName))
947
948        if .verbosity > 1
949            .printRefs(references)
950
951        # Here be "reflectionOnlyLoad" code... which does not work on Mono 1.2.4
952        # The run-time error message says:
953        #   ** (./cobra.exe:24284): WARNING **: Cannot resolve dependency to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.
954        # But hooking ReflectionOnlyAssemblyResolve has no effect as it never gets called.
955        # Looks like others are having problems too:
956        #   http://csammisrun.net/shaim/viewtopic.php?t=29&sid=e46dc962b1e4d14a5210ae2852ac7d87
957        # General references:
958        # * "Reflection Only Assembly Loading" blog entry by Junfeng Zhang
959        #   http://blogs.msdn.com/junfeng/archive/2004/08/24/219691.aspx
960        # * http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2485940&SiteID=1
961        #   Justin Pinnix from MSFT says "Once our assembly resolver finds your DLL, it calls
962        #   Assembly.LoadFrom().  So, even though your code calls Assembly.Load, we still
963        #   call Assembly.LoadFrom"
964        # TODO: try this out on MS .NET and if it works there, use it there
965        # TODO: file a Mono bug report (or ping an existing one)
966        # curDomain = AppDomain.currentDomain
967        # sharp'curDomain.ReflectionOnlyAssemblyResolve += _resolveEvent'
968
969        for reference in references
970            if not .loadReference(reference, false)
971                _addMessage(SourceException('Cannot locate assembly reference "[reference]".'))
972
973    def refsForPackage(pkgName as String) as List<of String>
974        """
975        Returns the library/DLL refs for the give package name.
976        Runs pkg-config to get that list.
977        See HowTo/GTK.cobra
978        """
979        refs = List<of String>()
980
981        # example: pkg-config --libs gtk-sharp-2.0
982        p = Process()
983        macMonoPkgConfig = '/Library/Frameworks/Mono.framework/Commands/pkg-config'
984        if File.exists(macMonoPkgConfig)
985            # avoid conflict with MacPorts whose pkg-config in '/opt/local/bin/pkg-config' will not pick up on Mono packages
986            p.startInfo.fileName = macMonoPkgConfig
987        else
988            p.startInfo.fileName = 'pkg-config'
989        p.startInfo.arguments = '--libs [pkgName]'
990        if .verbosity > 1
991            print 'Running: [p.startInfo.fileName] [p.startInfo.arguments]'
992        output = CobraCore.runAndCaptureAllOutput(p).trim
993        if p.exitCode
994            _addMessage(SourceException('Cannot locate package "[pkgName]"'))
995            print ' $ [p.startInfo.fileName] [p.startInfo.arguments]'
996            for line in output.split(c'\n')
997                print ' |', line
998            return refs
999
1000        parts = output.replace('-r:', '\0').split(c'\0')  # while Cobra uses -ref:, pkg-config outputs -r:
1001        for part in parts
1002            if part.trim <> '', refs.add(part.trim)
1003       
1004        return refs
1005
1006    def _resolveEvent(sender as Object, args as ResolveEventArgs) as Assembly?
1007        return nil
1008
1009    var _referenceVerbosity = -1
1010   
1011    get referenceVerbosity as int
1012        if _referenceVerbosity == -1
1013            _referenceVerbosity = .options.getDefault('verbosity-ref', 0)
1014        return _referenceVerbosity
1015
1016    var _willReadDependencies = false
1017
1018    def indentPrint
1019        # see .loadReference which sets up the indented writer
1020        (CobraCore.printDestination to IndentedWriter).indent
1021
1022    def outdentPrint
1023        # see .loadReference which sets up the indented writer
1024        (CobraCore.printDestination to IndentedWriter).dedent
1025
1026    def loadReference(reference as String, addExtn as bool) as bool
1027        """
1028        Attempts to load the given library reference.
1029        On success, adds reference to .loadedReferences and returns true.
1030        On failure, returns false, but does not add any warnings or errors.
1031        This method is used by Compiler and UseDirective.
1032        """
1033        if addExtn
1034            reference = .backEnd.fixLibExtension(reference)
1035        v, rv = .verbosity, .referenceVerbosity
1036        if v, print 'Loading reference:', reference
1037        if rv
1038            print to IndentedWriter(CobraCore.printDestination, indentString=' : ')
1039                print '>> .loadReference("[reference]")'
1040                .indentPrint
1041                try
1042                    r = _loadReference(reference)
1043                finally
1044                    print 'Returning [r]'
1045                    .outdentPrint
1046                print '<< .loadReference("[reference]")'
1047        else
1048            r = _loadReference(reference)
1049        if v and not r, print 'Could not load:   ', reference
1050        return r
1051
1052    def _loadReference(reference as String) as bool
1053        try
1054            return .backEnd.loadLibReference(reference)
1055        catch lre as LoadReferenceException
1056            # example: 'FileNotFoundException fileName Could not load file or assembly 'NHibernate, Version=2.1.0.1001,
1057            # Culture=neutral, PublcKeyToken=aa95f207798dfdb4' or one of its dependencies. The
1058            # system cannot find the file specified.
1059            if .referenceVerbosity, print '[lre] in _loadReference("[reference]")'
1060            return false
1061
1062    def fixMemberSigs
1063        .backEnd.fixMemberSigs
1064   
1065    def installNativeMethods(box as Box, nativeType as NativeType) 
1066        .backEnd.installNativeMethods(box, nativeType)
1067       
1068    ##
1069    ## Binding
1070    ##
1071
1072    var _basicTypes as List<of PrimitiveType>?
1073
1074    get basicTypes as IList<of PrimitiveType>
1075        if _basicTypes is nil
1076            _basicTypes = List<of PrimitiveType>()
1077            _basicTypes.addRange([.anyFloatType, .anyIntType, .boolType, .charType, .decimalType, .floatType])
1078            for size in [32, 64]
1079                _basicTypes.add(.floatType(size))
1080            for signed in [true, false]
1081                for size in [8, 16, 32, 64]
1082                    _basicTypes.add(.intType(signed, size))
1083        return _basicTypes to !
1084
1085    def symbolForName(name as String, haveThis as bool) as IMember?
1086        return .symbolForName(name, haveThis, false)
1087
1088    def symbolForName(name as String, haveThis as bool, isLowerOkay as bool) as IMember?
1089        """
1090        name - obvious.
1091        haveThis - if false, symbols like methods, properties, etc. will not be returned while enums, nested classes, etc. could be.
1092        isLowerOkay - true if a lowercase name (non capCased) is allowed.   
1093        """
1094        require
1095            name.length
1096        body
1097            # TODO: remove canBeMember arg
1098            assert _curModule
1099
1100            # check for generic parameters in methods
1101            if not haveThis and not name[0].isLower
1102                if _codeMemberStack.count and _codeMemberStack.peek inherits Method
1103                    m = (_codeMemberStack.peek to Method).genericParamForName(name) to IMember?
1104                    if m, return m
1105
1106            # check the current box which will ask its namespace which will ask its `use` directives
1107            if _boxStack.count
1108                #print '>> .compiler.symbolForName([name], [haveThis])'
1109                if not isLowerOkay and name[0].isLower
1110                    assert false, 'use findLocal instead. [name]'
1111                    return nil
1112                m = _boxStack.peek.symbolForName(name, haveThis)
1113                #print '<< .compiler.symbolForName returning', m
1114                #print
1115
1116            if m is nil
1117                # global namespace of the current module
1118                m = ((_curModule to dynamic).topNameSpace).symbolForName(name)
1119                # TODO: cast above is kind of weird, but SharpModule has no .topNameSpace
1120
1121            return m
1122
1123    def dumpModulesForTestify(output as IndentedWriter)
1124        .dumpModulesForTestify(output, 'Modules')
1125
1126    def dumpModulesForTestify(output as IndentedWriter, title as String)
1127        print '[title]:'
1128        output.indent
1129        try
1130            print to output
1131                i = 1
1132                for module in _modules
1133                    print '[i]. ' stop
1134                    if module.isCobraLibrary
1135                        print to output, module
1136                    else
1137                        module.writeDeepString(output)
1138                    i += 1
1139        finally
1140            output.dedent
1141
1142    def _exitFromErrors
1143        # TODO 2009-12 Having problems with this requirement in same cases. Not important to enforce right now.
1144        # require .errors.count
1145        """
1146        This method should not be invoked from partial classes found in phases or back-ends. Some
1147        phases want to run even when there are errors from previous phases. This is managed by
1148        the compiler's execution of the phases.
1149        """
1150        .printMessages
1151        _deleteIntermediateFiles
1152        throw StopCompilation(this)
1153
1154    def printMessages
1155        if .htmlWriter
1156            .printHtmlMessages
1157        else
1158            .printConsoleMessages
1159        Environment.exitCode = if(.errors.count, 1, 0)
1160
1161    def printHtmlMessages
1162        require .htmlWriter
1163        dest = .htmlWriter to !
1164        dest.writeHtml('<table class=messages cellpadding=2 cellspacing=2>[dest.newLine]\n')
1165        dest.writeHtml('<tr class=headings> <td class=heading> File </td> <td class=heading> Line </td> <td class=heading> Type </td> <td class=heading> Message </td> </tr>\n')
1166        for msg in _messages
1167            msg.writeHtmlTo(dest)
1168        dest.writeHtml('</table>[dest.newLine]')
1169        if _errors.count
1170            dest.writeHtml('<span class=compilationFailed>[_compilationFailedMessage()]</span><br>\n')  # CC: axe ()s
1171        else
1172            dest.writeHtml('<span class=compilationSucceeded>Compilation succeeded - [_warnings.count] warning[if(_warnings.count==1,'','s')]</span><br>\n')
1173
1174    def printConsoleMessages
1175        willColor = .options.boolValue('color')
1176        savedColor = Console.foregroundColor
1177        if CobraCore.isRunningOnMono  # bug on mono: the initial Console.foregroundColor is not necessarily accurate (at least in bash on Terminal.app on Mac OS X 10.4.10 on Mono 1.2.4)
1178            savedColor = ConsoleColor.Black  # this is really just a guess and possibly a bad one. should be controllable via a cmd line option or argument
1179        dest = if(Console.error, Console.error, Console.out) to !  # some IDEs prefer errors and warnings to go to stderr
1180        for obj in _messages
1181            if willColor and obj.isError
1182                Console.foregroundColor = ConsoleColor.Red
1183                restoreColor = true
1184            print to dest, obj.consoleString
1185            if restoreColor
1186                Console.foregroundColor = savedColor
1187                restoreColor = false
1188        if _errors.count
1189            if willColor, Console.foregroundColor = ConsoleColor.Red
1190            print _compilationFailedMessage()  # CC: axe ()s
1191            if willColor, Console.foregroundColor = savedColor
1192        else
1193            didPrint = false
1194            if willColor, Console.foregroundColor = ConsoleColor.Blue
1195            if _willPrintSuccessMsg or _warnings.count
1196                print 'Compilation succeeded' stop
1197                didPrint = true
1198            if _warnings.count
1199                print ' - [_warnings.count] warning[if(_warnings.count==1,'','s')]'
1200            else
1201                if didPrint, print
1202            if willColor, Console.foregroundColor = savedColor
1203
1204    def _compilationFailedMessage as String
1205        return 'Compilation failed - [_errors.count] error[if(_errors.count==1,'','s')], [_warnings.count] warning[if(_warnings.count==1,'','s')]'
1206
1207    def printTimingStats(elapsed as TimeSpan)
1208        secs = elapsed.totalMilliseconds / 1_000
1209        if .linesCompiled
1210            lps = .linesCompiled / secs
1211            print '[.linesCompiled] lines compiled at [lps:F1] lines/sec'
1212        if .nodesCompiled
1213            nps = .nodesCompiled / secs
1214            print '[.nodesCompiled] nodes compiled at [nps:F1] nodes/sec'
1215        if .tokensCompiled
1216            tps = .tokensCompiled / secs
1217            print '[.tokensCompiled] tokens compiled at [tps:F1] tokens/sec'
1218
1219    ##
1220    ## Source Code Corrections
1221    ##
1222
1223    var _sourceCorrections = Dictionary<of String, Dictionary<of int, List<of Replacement>>>()
1224        """
1225        The first key of type String is filename.
1226        The second key of type int is line number.
1227        """
1228
1229    def correctSource(token as IToken, replace as String)
1230        if not _sourceCorrections.containsKey(token.fileName)
1231            _sourceCorrections[token.fileName] = Dictionary<of int, List<of Replacement>>()
1232        file = _sourceCorrections[token.fileName]
1233        if not file.containsKey(token.lineNum)
1234            file[token.lineNum] = List<of Replacement>()
1235        file[token.lineNum].add(Replacement(token.colNum, token.text, replace))
1236
1237    def writeSourceCodeCorrections
1238        # TODO: this doesn't properly handle when the replacements are a different length than the
1239        # original next, but then this isn't needed right now since the only type of correction
1240        # being done is case correction
1241        if _sourceCorrections.count == 0, return
1242        v = .verbosity
1243        for fileName, lineToReplacements in _sourceCorrections
1244            if v, print 'Correcting source:', fileName
1245            lineNums = List<of int>(lineToReplacements.keys)
1246            lineNums.sort
1247            lines = File.readAllLines(fileName)
1248            for lineNum in lineNums
1249                for rep in lineToReplacements[lineNum]
1250                    assert rep.oldText.length == rep.newText.length  # see TODO above
1251                    if v >= 2, print 'Correct: Line [lineNum], Column [rep.colNum], Old "[rep.oldText]", New "[rep.newText]"'
1252                    i = lineNum - 1
1253                    line = lines[i]
1254                    # print line
1255                    oldLen = line.length
1256                    col = rep.colNum - 1
1257                    lines[i] = line[:col] + rep.newText + line[col+rep.oldText.length:]
1258                    # print lines[i]
1259                    assert lines[i].length == oldLen
1260            try
1261                File.writeAllLines(fileName, lines)
1262            catch exc as Exception
1263                .warning(CobraWarning(fileName, nil, 'Cannot write source code corrections due to: [exc.message] ([exc.getType.name]).'))
1264        _sourceCorrections.clear
1265
1266    ##
1267    ## Important system library types
1268    ##
1269    # ILibTypeProvider
1270   
1271    get objectType as IType
1272        # for ITypeProvider
1273        return _libraryClass('Object')
1274
1275    def objectClass as Class
1276        # for stronger typing
1277        return _libraryClass('Object')
1278
1279    def stringType as Class
1280        return _libraryClass('String')
1281
1282    def exceptionType as Class
1283        return _libraryClass('Exception')
1284
1285    def delegateType as Class
1286        return _libraryClass('Delegate')
1287
1288    def attributeType as Box
1289        return _libraryBox('Attribute')
1290
1291    def enumerableType as Box
1292        return _libraryBox('IEnumerable')
1293
1294    def enumeratorType as Box
1295        return _libraryBox('IEnumerator')
1296
1297    def enumerableOfType as Box
1298        return _libraryBox('IEnumerable<of>')
1299
1300    def enumeratorOfType as Box
1301        return _libraryBox('IEnumerator<of>')
1302
1303    def dictEnumeratorType as Box
1304        return _libraryBox('IDictionaryEnumerator')
1305       
1306    def collectionType as Box
1307        return _libraryBox('ICollection')
1308
1309    def collectionOfType as Box
1310        return _libraryBox('ICollection<of>')
1311
1312    def ilistType as Box
1313        return _libraryBox('IList')
1314       
1315    def ilistOfType as Box
1316        return _libraryBox('IList<of>')
1317       
1318    def listOfType as Class
1319        return _libraryClass('List<of>')
1320
1321    def idictionaryType as Box
1322        return _libraryBox('IDictionary')
1323       
1324    def idictionaryOfType as Box
1325        return _libraryBox('IDictionary<of,>')
1326
1327    def dictionaryOfType as Class
1328        return _libraryClass('Dictionary<of,>')
1329
1330    def setOfType as Class
1331        return _libraryClass('Set<of>')
1332
1333    def libraryType(qualifiedNameOrTag as String) as IType
1334        """
1335        Implemented for ITypeProvider, but use the more specific methods such as .stringType instead.
1336        """
1337        return _libraryType(.backEnd.resolveTypeTag(qualifiedNameOrTag))
1338
1339    var _libraryTypeCache = Dictionary<of String, IType>()
1340
1341    def _libraryType(qualifiedName as String) as IType
1342        """
1343        find qualified Type name in (cache or) Library/namespace Decls structures.
1344        Used to retrieve types such as System.String.
1345        Example:
1346            _libraryType('System.String')
1347        """
1348        assert qualifiedName.length
1349        type as IType?
1350        if _libraryTypeCache.tryGetValue(qualifiedName, out type)
1351            return type to !
1352        names = qualifiedName.split(c'.')
1353        type = _libraryType(names to passthrough)
1354        _libraryTypeCache[qualifiedName] = type to !
1355        return type to !
1356
1357    def _libraryType(names as vari String) as IType
1358        #trace names
1359        ns as IContainer = _globalNS
1360        thing as IContainer? = nil
1361        for name in names
1362            possible = (thing ? ns).declForName(name)
1363            #print name
1364            # dbg
1365            #if not possible
1366            #   trace thing ? ns
1367            #   ((thing ? ns) to NameSpace).dumpDeclsNameKeys
1368            assert possible, name
1369            if possible inherits IContainer
1370                thing = possible
1371            else
1372                assert false, [name, possible.getType.name, possible]
1373        if thing inherits IType
1374            if thing.name<>names[names.length-1] # TODO: add this as an ensure as well
1375                print 'names=' stop
1376                print CobraCore.toTechString(names)
1377                print 'thing=[thing]'
1378                assert false
1379            return thing
1380        else
1381            throw FallThroughException('found [name], but it is not an IType. it is [thing]')
1382
1383    def _libraryBox(qualifiedNameOrTag as String) as Box
1384        """
1385        Returns a box from the standard library such as 'System.Object' or 'System.Collections.Generic.IEnumerable<of>'.
1386        """
1387        return _libraryType(.backEnd.resolveTypeTag(qualifiedNameOrTag)) to Box
1388
1389    def _libraryClass(qualifiedNameOrTag as String) as Class
1390        """
1391        Returns a class from the standard library such as 'System.Object' or 'System.Collections.Generic.Dictionary<of,>'.
1392        """
1393        return _libraryType(.backEnd.resolveTypeTag(qualifiedNameOrTag)) to Class
1394
1395
1396    ##
1397    ## Services to nodes
1398    ##
1399
1400    def embedRunTimeSuffix as String
1401        return .options.embedRunTimeSuffix
1402
1403    #special type proxies for common Types -  Object and Type
1404    def objectTypeProxy as AbstractTypeProxy 
1405        """
1406        Type proxy for BE notion of a class for the root of Object hierarchy
1407            e.g. Object in dotNet
1408        """
1409        #return ClrTypeProxy(Object)
1410        return .backEnd.objectTypeProxy
1411
1412    def typeTypeProxy as AbstractTypeProxy 
1413        """
1414        Type proxy for BE notion of a class for a Type
1415            e.g. System.Type in dotNet, java.lang.class in Java
1416        """
1417        #return ClrTypeProxy(Type)
1418        return .backEnd.typeTypeProxy
1419       
1420    def nativeType(qualifiedName as String) as NativeType
1421        return .backEnd.nativeTypeByName(qualifiedName)
1422
1423    def suggestionFor(name as String) as String? is shared
1424        require name.length
1425        # CC: return _unknownSuggestions.getDefault(name, nil)
1426        if _unknownSuggestions.containsKey(name)
1427            return _unknownSuggestions[name]
1428        else if _unknownSuggestions.containsKey(name.toLower)
1429            return _unknownSuggestions[name.toLower]
1430        else
1431            return nil
1432
1433    def warning(node as ISyntaxNode, msg as String)
1434        require msg.length
1435        .warning(CobraWarning(node.token, msg))
1436
1437    def warning(cw as CobraWarning)
1438        require not cw.isError
1439        if _suppressWarning(cw), return
1440        _addMessage(cw)
1441   
1442    def _suppressWarning(cw as CobraWarning) as bool
1443        # TODO: add suppress all warnings (cmdline sw) - maybe?
1444        # TODO: add suppress by error tag - maybe?
1445        entry = if(cw.hasSourceSite, '[cw.fileName]:[cw.lineNum]', '')
1446        return _noWarningLines.contains(entry)
1447           
1448    def augmentWarning(node as ISyntaxNode, lookFor as String, search as String, augment as String) as bool
1449        require 
1450            lookFor.length
1451            augment.length
1452        body
1453            message = CobraWarning(node.token, lookFor)
1454            key = if(message.hasSourceSite, '[message.fileName]:[message.lineNum]', '')
1455            if not _messagesPerSourceLine.containsKey(key)
1456                return false
1457            lowerToMatch = message.message.toLower
1458            lowerSearch = if(search.length > 0, search.toLower, '')
1459            for se in _messagesPerSourceLine[key]
1460                lowerMsg = se.message.toLower
1461                if lowerMsg.contains(lowerToMatch)  # matched
1462                    if search.length == 0 or lowerMsg.contains(lowerSearch)
1463                        se.appendToMessage(augment)
1464                        return true
1465            return false
1466
1467    shared
1468        var _unknownSuggestions = {
1469        # literals
1470        'null':     'nil',
1471        'none':     'nil',
1472        'nothing':  'nil',
1473        'True':     'true',
1474        'False':    'false',
1475
1476        # Python
1477        'self':     'this',
1478        'super':    'base',
1479        'elif':     'else if',
1480
1481        # Ruby
1482        'puts':     'print',
1483       
1484        # C#
1485        'using':    'use',
1486        'foreach':  'for',
1487
1488        # VisualBasic
1489        'imports':  'use',
1490        'sub':      'def',
1491
1492        # operators (word ones anyway)
1493        'isa':      'inherits',
1494        'new':      'SomeClass() or SomeClass(arg1,arg2) without new',
1495
1496        # constructs
1497        #'lambda':  'def(args) ...',  # TODO
1498
1499        # statements
1500        'do':       'post while <condition>',
1501        'elseif':   'else if',
1502
1503        # types
1504        'boolean':      'bool',
1505        'character':    'char',
1506        'byte':         'uint8',
1507        'sbyte':        'int8',
1508        'short':        'int16',
1509        'ushort':       'uint16',
1510        'integer':      'int',
1511        'long':         'int64',
1512        'ulong':        'uint64',
1513        'single':       'float32',
1514        'double':       'float',
1515        'str':          'String',
1516        'string':       'String',
1517        'object':       'Object',
1518        }
1519
1520    get unknownSuggestions from var
1521
1522    def suggestionForUnknown(word as String) as String?
1523        if _unknownSuggestions.tryGetValue(word, out word), return word
1524        else, return nil
1525
1526
1527    ##
1528    ## Services to this
1529    ##
1530
1531    def _addMessage(message as SourceException)
1532        # Cobra can sometimes generate duplicate messages. Specifically, a constructed type might generate a message that its generic def did.
1533        # Also, assert statements whose conditions cause C# warnings will get duplicate warnings because of the expression breakdown.
1534        # Yeah, ideally, this would be fixed, but sometimes that's harder than just removing the duplicates:
1535        key = if(message.hasSourceSite, '[message.fileName]:[message.lineNum]', '')
1536        if _messagesPerSourceLine.containsKey(key)
1537            for se in _messagesPerSourceLine[key]
1538                if se.message.toLower == message.message.toLower
1539                    if Utils.isDevMachine or .verbosity >= 3
1540                        print 'Skipping duplicate message:', message.consoleString
1541                    return
1542        else
1543            _messagesPerSourceLine[key] = List<of SourceException>()
1544        _messagesPerSourceLine[key].add(message)
1545        _messages.add(message)
1546        if message.isError
1547            _errors.add(message)
1548        else
1549            _warnings.add(message)
1550
1551    def initBackEnd
1552        require .backEnd is nil
1553        ensure .backEnd
1554        branch .options.get('back-end')
1555            on 'none', _backEnd = ClrBackEnd(this# TODO-SELFHOST
1556            on 'clr',  _backEnd = ClrBackEnd(this)
1557            on 'jvm'
1558                _backEnd = JvmBackEnd(this)
1559                if .options['number'] == 'decimal', .options['number'] = 'float'
1560            on 'objc', _backEnd = ObjcBackEnd(this)
1561            else, throw FallThroughException(.options.get('back-end'))
1562           
1563
1564class InternalError
1565    inherits SourceException
1566    """
1567    Represents cases where the Cobra compiler itself has experienced an internal exception.
1568    """
1569
1570    var _fileName as String?
1571    var _lineNum as int?
1572    var _internalException as Exception
1573
1574    cue init(fileName as String, lineNum as int, message as String, internalException as Exception)
1575        .init(message, internalException)
1576        _fileName = fileName
1577        _lineNum = lineNum
1578
1579    cue init(message as String, internalException as Exception)
1580        base.init(('COBRA INTERNAL ERROR / ' + internalException.getType.name + ' / ' + message.replace('\r','').replace('\n','; ').trim)[:1024])
1581        _internalException = internalException
1582
1583    get isError as bool is override
1584        return true
1585
1586    get hasSourceSite as bool is override
1587        return _fileName is not nil
1588
1589    get fileName as String is override
1590        return _fileName to !
1591
1592    get lineNum as int is override
1593        return _lineNum to !
1594
1595
1596class Replacement
1597
1598    cue init(colNum as int, oldText as String, newText as String)
1599        base.init
1600        _colNum = colNum
1601        _oldText = oldText
1602        _newText = newText
1603   
1604    get colNum from var as int
1605   
1606    get oldText from var as String
1607   
1608    get newText from var as String
1609
1610
1611class TestCompiler inherits Compiler
1612    """
1613    Used by SharpCompilationMessage.test
1614    CC: should be inside the test or easy to remove via a test attribute
1615    TODO: should inherit an AbstractCompiler
1616    """
1617
1618    cue init
1619        base.init(0)
1620        _backEnd = BasicBackEnd(this)
1621       
1622    pro verbosity as int is override
1623        get
1624            return 0
1625        set
1626            pass
1627   
1628    def cobraLineNumForCurly(fileName as String, lineNum as int) as int is override
1629        return lineNum
1630
1631
Note: See TracBrowser for help on using the browser.