Ticket #37: noWarn.patch

File noWarn.patch, 11.8 kB (added by hopscc, 5 months ago)
  • Source/Tokenizer.cobra

     
    300300        var _tokenDefs as List<of TokenDef>? 
    301301        var _tokenDefsByFirstChar as Dictionary<of char, List<of TokenDef>>? 
    302302        var _tokenDefsByWhich as Dictionary<of String, TokenDef>? 
     303        var _noWarnLines as ISet<of String> 
    303304        var _curTokenDef as TokenDef? 
    304305        var _lastTokenDef as TokenDef? 
    305306        var _avgCount = 0 
     
    314315        var _charNum as int 
    315316 
    316317        def init 
     318                _noWarnLines = Set<of String>() 
    317319                _didReset = false 
    318320                _reset() 
    319321 
     
    368370 
    369371        get tokenDefsByWhich from var 
    370372         
     373        get noWarnLines from var 
    371374 
    372375        ## Other 
    373376 
     
    436439                Returns all remaining tokens as a list. 
    437440                """ 
    438441                tokens = List<of IToken>() 
     442                #st = DateTime.now 
    439443                while true 
    440444                        t = .nextToken 
    441445                        if t 
    442446                                tokens.add(t) 
    443447                        else 
    444448                                break 
     449                # determine timings for various Tokeniser lexing changes 
     450                #duration = DateTime.now.subtract(st) 
     451                #if  tokens.count > 100 and duration > TimeSpan(0) 
     452                #       avt = (duration.ticks to int) / (tokens.count to int) 
     453                #       ms = avt/10000 
     454                #       fnm = _fileName 
     455                #       if _fileName.startsWith("(") 
     456                #               fnm = '(None)' 
     457                #       lastsl =_fileName.lastIndexOf("\\") 
     458                #       if lastsl > 0 
     459                #               fnm = _fileName[lastsl+1:] to ! 
     460                #       print "[fnm.padRight(20)]\t[duration]\t[tokens.count]\t" stop 
     461                #       print " [ms:N3] ms/Token av ([ms/1000:N3]sec)" 
    445462                return tokens 
    446463 
    447464        def restart 
     
    591608                                        return nil 
    592609                        try 
    593610                                assert _tokenDefs 
    594                                 if _narrowTokenDefs and _tokenDefs.count >= _minNumTokenDefsToNarrow 
    595                                         assert _tokenDefsByFirstChar 
    596                                         assert _sourceLine.length 
    597                                         if _tokenDefsByFirstChar.containsKey(_sourceLine[0]) 
    598                                                 # print 'Using short list for char: [_sourceLine[0]], [_sourceLine[0] to int]' 
    599                                                 tokenDefs = _tokenDefsByFirstChar[_sourceLine[0]] 
    600                                         else 
    601                                                 tokenDefs = _tokenDefs to ! 
    602                                 else 
    603                                         tokenDefs = _tokenDefs to ! 
     611                                tokenDefs = _getCandidateTokenDefs(_sourceLine) 
    604612                                for tokenDef in tokenDefs 
    605613                                        count += 1 
    606                                         if tokenDef.ignoreCount 
    607                                                 tokenDef.ignoreCount -= 1 
     614                                        if _skipMatchAttempt(tokenDef, _sourceLineIndex) 
    608615                                                continue 
    609                                         if not tokenDef.isActive 
    610                                                 continue 
    611                                         if _sourceLineIndex>0 and tokenDef.requiresBOL 
    612                                                 continue 
    613                                         if not .isActiveCall(tokenDef) 
    614                                                 continue 
    615616                                        #print '<> Trying to match [tokenDef]' 
    616617                                        sourceLine = _sourceLine to ! 
    617618                                        #print '_sourceLineIndex=[_sourceLineIndex]' 
     
    634635 
    635636                                        # enable methods to customize handling of tokens 
    636637                                        reinvoke = false 
    637  
    638                                         which = tok.which 
    639                                         if _onTokenTypeCache.containsKey(which) 
    640                                                 meth = _onTokenTypeCache[which] 
    641                                         else 
    642                                                 methName = 'On' + which 
    643                                                 meth = .getType.getMethod(methName) 
    644                                                 _onTokenTypeCache[which] = meth 
    645                                                  
     638                                        meth = _getTokenMethod(tok.which) 
    646639                                        if meth 
    647                                                 try 
    648                                                         tok = meth.invoke(this, @[tok]) to IToken? 
    649                                                 catch tie as TargetInvocationException 
    650                                                         throw tie.innerException 
    651                                                 if tok is nil 
    652                                                         # skip token, so go to the next one 
    653                                                         reinvoke = true 
    654                                                 else 
    655                                                         # TODO: could probably make this more efficient by axing the queue and just checking for nextToken in this method 
    656                                                         while tok 
    657                                                                 _tokenQueue.enqueue(tok) 
    658                                                                 tok = tok.nextToken 
    659                                                         reinvoke = true  # to pick up the queue 
     640                                                tok = _tokenPostProcess(meth, tok ) 
     641                                                # nil indicates skipped token - will re call this method 
     642                                                if not tok  
     643                                                        reinvoke = true  # to pick up next token after skipped 
    660644 
    661645                                        # finished with current line? 
    662646                                        if _sourceLine.length==0 
     
    689673                        _avgCount += count 
    690674                        _avgCountNum += 1 
    691675 
     676        def _getCandidateTokenDefs(sourceLine as String?) as List<of TokenDef> 
     677                if _narrowTokenDefs and _tokenDefs.count >= _minNumTokenDefsToNarrow 
     678                        assert _tokenDefsByFirstChar 
     679                        assert _sourceLine.length 
     680                        if _tokenDefsByFirstChar.containsKey(_sourceLine[0]) 
     681                                # print 'Using short list for char: [_sourceLine[0]], [_sourceLine[0] to int]' 
     682                                return _tokenDefsByFirstChar[_sourceLine[0]] 
     683                return _tokenDefs to ! 
     684 
     685        def _skipMatchAttempt(tokenDef as TokenDef, sourceLineIndex as int) as bool 
     686                if tokenDef.ignoreCount 
     687                        tokenDef.ignoreCount -= 1 
     688                        return true 
     689                if not tokenDef.isActive 
     690                        return true 
     691                if sourceLineIndex>0 and tokenDef.requiresBOL 
     692                        return true 
     693                if not .isActiveCall(tokenDef) 
     694                        return true 
     695                return false     
     696 
     697        # get method for token (On<which>)  from cache if there else from reflection and cache it 
     698        def _getTokenMethod(which as String) as  MethodInfo?  
     699                if not _onTokenTypeCache.containsKey(which) # not already in methods cache 
     700                        methName = 'On' + which                                  
     701                        meth = .getType.getMethod(methName)      
     702                        _onTokenTypeCache[which] = meth                  
     703                else 
     704                        meth = _onTokenTypeCache[which] 
     705                return meth 
     706                 
     707        # invoke any tokenMethod and return adjusted token or first token in any returned 
     708        # token chain (rest of chain queued) 
     709        # nil token returned indicates token is skipped. 
     710        def _tokenPostProcess(meth as MethodInfo,  tok as IToken?) as IToken? 
     711                try 
     712                        tok = meth.invoke(this, @[tok]) to IToken? 
     713                catch tie as TargetInvocationException 
     714                        throw tie.innerException 
     715                if not tok 
     716                        return nil      # token is to be skipped 
     717                retTok = tok 
     718                tok = tok.nextToken 
     719                while tok 
     720                # TODO: could probably make this more efficient by axing the queue and just checking for nextToken in this method 
     721                        _tokenQueue.enqueue(tok)  # store any token chain returned by method call 
     722                        tok = tok.nextToken 
     723                return retTok    
     724 
    692725        def pushTokenDefs(defs as List<of TokenDef>) 
    693726                ensure 
    694727                        _tokenDefs is defs 
     
    762795                # TODO: like parser, this should probably not be recorded unless it "makes it out". see comment in CobraParser.throwError 
    763796                throw .recordError(msg) 
    764797 
     798        def addNoWarn(token as IToken) 
     799                entry='[token.fileName]:[token.lineNum]' 
     800                _noWarnLines.add(entry) 
     801                 
    765802        def checkTokens(tokens as List<of IToken>, expected as String) 
    766803                is shared 
    767804                """ 
  • Source/Compiler.cobra

     
    7474        var _warnings as List<of SourceException> 
    7575        var _messages as List<of SourceException>  # all errors and warnings 
    7676        var _messagesPerSourceLine as IDictionary<of String, List<of SourceException>>  # key is 'filename:lineNum' 
     77        var _warningSuppressBySourceLine as ISet<of String>     # key is 'filename:lineNum' 
    7778 
    7879        var _intermediateFileNames as List<of String> 
    7980        var _baseExeFileName as String = '' 
     
    104105                _codeMemberStack = Stack<of AbstractMethod>() 
    105106                _messages = List<of SourceException>() 
    106107                _messagesPerSourceLine = Dictionary<of String, List<of SourceException>>() 
     108                _warningSuppressBySourceLine = Set<of String>() 
    107109                _errors = List<of SourceException>() 
    108110                _warnings = List<of SourceException>() 
    109111                _intermediateFileNames = List<of String>() 
     
    181183        get warnings from var 
    182184 
    183185        get messages from var 
     186         
     187        set warningSuppressLines as ISet<of String> 
     188                _warningSuppressBySourceLine = value 
    184189 
    185190        pro htmlWriter from var 
    186191                """ 
     
    11531158 
    11541159        def warning(cw as CobraWarning) 
    11551160                require not cw.isError 
     1161                if _suppressWarning(cw), return 
    11561162                _addMessage(cw) 
    1157                  
     1163         
     1164        def _suppressWarning(cw as CobraWarning) as bool 
     1165                # TODO: add suppress all warnings (cmdline sw) - maybe? 
     1166                # TODO: add suppress by error tag - maybe? 
     1167                entry = if(cw.hasSourceSite, '[cw.fileName]:[cw.lineNum]', '') 
     1168                return _warningSuppressBySourceLine.contains(entry) 
     1169                         
    11581170        def augmentWarning(node as ISyntaxNode, lookFor as String, search as String, augment as String) as bool 
    11591171                require  
    11601172                        lookFor.length 
  • Source/CobraParser.cobra

     
    219219                                msg = 'Token error: ' + msg 
    220220                        .throwError(te.token, msg) 
    221221 
     222                #TODO: fold all occcurrences of this lookup to a helper 
     223                compiler = .typeProvider to? Compiler 
     224                if compiler, compiler.warningSuppressLines = tokenizer.noWarnLines 
     225 
    222226                if tokenizer.errors.count 
    223227                        for error in tokenizer.errors 
    224228                                .recordError(error.token, error.message) 
    225                          
     229 
    226230                _nextTokenIndex = 0 
    227231 
    228232 
     
    548552                                if typeName.text not in ['decimal', 'float', 'float32', 'float64'] 
    549553                                        .throwError('Compiler directive "number": unrecognized type "[typeName.text]". Must be one of "decimal", "float", "float32" or "float64".') 
    550554                                .expect('EOL') 
    551                                 comp = .typeProvider to Compiler? 
     555                                comp = .typeProvider to? Compiler 
    552556                                if comp, comp.numberTypeName = typeName.text 
    553557                        else 
    554558                                .throwError('Unknown compiler directive.') 
  • Source/CobraTokenizer.cobra

     
    389389        def onWHITESPACE_COMMENT_2(tok as IToken) as IToken? 
    390390                #print '<> onWHITESPACE_COMMENT_2' 
    391391                return nil 
    392  
     392         
    393393        ## 
    394394        ## Comment out block 
    395395        ## 
     
    506506 
    507507        def onSINGLE_LINE_COMMENT(tok as IToken) as IToken? 
    508508                # eat these 
     509                .chkForLeadingCommentToken(tok) 
    509510                return nil 
    510511 
     512        def chkForLeadingCommentToken(tok as IToken) 
     513                insens = tok.text.trimStart.toLower 
     514                # nowarn is only one to date 
     515                if insens.startsWith('#.nowarn.') or insens.startsWith('#.no-warn.') 
     516                        .addNoWarn(tok) 
     517                         
    511518        def onSPACE(tok as IToken) as IToken? 
    512519                # eat these 
    513520                return nil 
  • Tests/800-warnings/400-no-warn.cobra

     
     1# test use of various forms of .noWarn comment token to suppress warnings 
     2# probably should stick to either       #.nowarn.  #.noWarn. or #.no-warn. 
     3class E 
     4        var _count =0    
     5        var rCount =0 
     6         
     7        sig BumpEventHandler(sender as Object, args as EventArgs)  
     8        event bumpEvent as BumpEventHandler      
     9 
     10 
     11        # (protected) method to raise/fire the event for this class 
     12        def _onBumpEvent(args as EventArgs) 
     13                raise .bumpEvent, this, args    #.noWarn. warning:implied this 
     14                 
     15        def bump 
     16                _count += 1      
     17                if _count % 10 == 0 
     18                        ev = EventArgs() 
     19                        _onBumpEvent(ev)         
     20                        assert this.rCount  #.NoWarn. warning:unnecessary this literal   
     21                         
     22                         
     23        def doBump(source as Object, eArgs as EventArgs) 
     24                .rCount += 1 
     25 
     26#class Driver            
     27        def main is shared, shared #.No-WARN. warning:duplicate modifier 
     28                e = E() 
     29                listen e.bumpEvent, ref e.doBump 
     30                for i in 20 
     31                        e.bump 
     32                assert e.rCount == 2 
     33 
     34                j=99            #.no-warn.  warning: never used 
     35                a = 99 
     36                if (a < 10) #.noWarn.  warning: Unnecessary parens 
     37                        a=10 
     38                assert a is 99          #.NoWaRn.  warning:value Types   
     39                assert a is not 100     #.nOwArN.  warning:value Types   
     40 
     41                s='string' 
     42                t = s to String         #.no-Warn. warning:redundant typecast 
     43                t1 = s to String?       #.NOWARN.  warning:just use to ? 
  • Developer/IntermediateReleaseNotes.text

     
    11Post 0.8 
    22 
     3* Add support for warning suppression on arbitrary lines by placing a trailing 
     4    comment containing .nowarn. or .no-warn. immediately after the # 
     5    e.g.   this.call()  #.nowarn.  
     6 
    37* Add support for commenting full blocks of lines using /# and #/. Block comments can be nested. 
    48        '/#' block comment start and  '#/' block comment end as initial chars on line 
    59