Wiki

Ticket #108: modifier-sections.patch

File modifier-sections.patch, 14.3 KB (added by hopscc, 4 years ago)
  • Source/CobraParser.cobra

     
    100100    var _lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz' 
    101101    var _uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 
    102102 
    103     var _isNamesStack as Stack<of String>? 
     103    var _modifierNamesStack as Stack<of String>? 
    104104        """ Stack for recording modifier for items in modifier sections (e.g.shared). """ 
    105105 
    106106    var _boxStack as Stack<of Box>? 
     
    231231        tokVerbosity = _verbosity - 4  # in order words, tokenizer does not spew unless our verbosity is 5 or greater 
    232232        if tokVerbosity < 0, tokVerbosity = 0 
    233233 
    234         _isNamesStack = Stack<of String>()  # for `shared` for example 
     234        _modifierNamesStack = Stack<of String>()  # for `shared` for example 
    235235        _leftStack = Stack<of Expr>() 
    236236        _opStackStack = Stack<of Stack<of String>>() 
    237237        .newOpStack 
     
    697697                .throwError('Cannot nest a type underneath a [parentBox.englishName]')  # TODO: needs a test case 
    698698 
    699699        _boxStack.push(theClass) 
    700 #       .isNamesStack = Stack<of String>() 
     700#       .modifierNamesStack = Stack<of String>() 
    701701        .bodiedBoxMemberDecls(theClass) 
    702702        _boxStack.pop 
    703703 
     
    780780 
    781781    def _isDeclNamesNoEOL(hasIsNames as out bool) as List<of String> 
    782782        """ Parse for possible stream of isNames without terminating EOL. """ 
    783         names = List<of String>(_isNamesStack) 
     783        names = List<of String>(_modifierNamesStack) 
    784784        hasIsNames = false 
    785785        if .optional('IS') is nil 
    786786            return names 
    787787        hasIsNames = true 
     788        return _commaSepDeclNames(names) 
     789 
     790    def _commaSepDeclNames(names as List<of String>) as List<of String> 
     791        """ 
     792        Grab one or a comma separated sequence of declNames/isNames. 
     793        Verify that the modifier names are valid and internally consistant 
     794        Returns 
     795            A string list of the modifierNames/isNames 
     796        """ 
    788797        while true 
    789798            what = .grab.text 
    790799            if what in .validIsNames 
     
    801810                if .peek.text in .validIsNames 
    802811                    .throwError(.peek, 'Multiple access modifiers should be separated by commas such as "[what], [.peek.text]".') 
    803812                break 
    804         # TODO: error on virtual and shared 
     813        # error on virtual and shared 
     814        if 'virtual' in names and 'shared' in names 
     815            .recordError(.last, 'Cannot specify both "virtual" and "shared".') 
    805816        # to-do: move these to _bindInt 
    806817        # error on non virtual and override 
    807818        if 'nonvirtual' in names and 'override' in names 
    808819            .recordError(.last, 'Cannot specify both "nonvirtual" and "override".') 
    809         # to-do: cannot specify 'new' and 'override' 
     820        # Cannot specify 'new' and 'override' 
     821        if 'new' in names and 'override' in names 
     822            .recordError(.last, 'Cannot specify both "new" and "override".') 
    810823        # error if 2 or more of 'public', 'protected', 'private', 'internal' 
    811824        accessModifierCount = 0 
    812825        for vam in _validAccessModifiers 
     
    819832    var _validAccessModifiers = ['public', 'protected', 'private', 'internal'] 
    820833 
    821834    get validIsNames as List<of String> 
     835        """ 
     836        All the valid isNames/DeclNames or modifiers. 
     837        Some of these are specific to clauses - i.e partial on Types/Class..., readonly on vars 
     838        """ 
    822839        if _validIsNames is nil 
    823840            _validIsNames = [ 
    824841                'fake', 'extern', 'shared', 'virtual', 'nonvirtual', 'override', 'new', 
     
    897914 
    898915        # TODO when supporting nested classes, look at the _boxStack and set a back pointer here 
    899916        _boxStack.push(theMixin) 
    900 #       .isNamesStack = Stack<of String>() 
     917#       .modifierNamesStack = Stack<of String>() 
    901918        .bodiedBoxMemberDecls(theMixin) 
    902919        _boxStack.pop 
    903920 
     
    936953        theInterface = Interface(wordToken, idToken, name, .makeList<of IType>(genericParams), typeSpecs.isNames, typeSpecs.attributes, typeSpecs.inheritsProxies, docString) 
    937954 
    938955        _boxStack.push(theInterface) 
    939 #       .isNamesStack = Stack<of String>() 
     956#       .modifierNamesStack = Stack<of String>() 
    940957        .bodiedBoxMemberDecls(theInterface)  # TODO: this shouldn't be bodiedBoxMemberDecls, right? 
    941958        _boxStack.pop 
    942959 
     
    974991                .throwError('Cannot nest a type underneath a [parentBox.englishName]')  # TODO: needs a test case 
    975992 
    976993        _boxStack.push(theStruct) 
    977 #       .isNamesStack = Stack<of String>() 
     994#       .modifierNamesStack = Stack<of String>() 
    978995        .bodiedBoxMemberDecls(theStruct) 
    979996        _boxStack.pop 
    980997 
     
    9881005        handlerType = .typeId 
    9891006        # ahem, duplicated from .boxVarDecl 
    9901007        docString = '' to ? 
    991         isNames = List<of String>(_isNamesStack) 
     1008        isNames = List<of String>(_modifierNamesStack) 
    9921009        if .peek.which=='IS' 
    9931010            isNames = .isDeclNames 
    9941011            attribs = .hasAttribs 
     
    12191236            breakLoop = false  # cannot use 'break' to stop a 'while' loop in a branch statement. CC? 
    12201237            while not breakLoop 
    12211238                _isTraceOn = true 
    1222                 branch .peek.which 
     1239                nextWhich = .peek.which  
     1240                if .peek.text in .validIsNames # shared, protected, etc - lower case not tokenNames 
     1241                    .bodiedBoxMemberDeclNames(box) 
     1242                    continue 
     1243                branch nextWhich 
    12231244                    on 'PASS' 
    12241245                        .classPass 
    12251246                        breakLoop = true 
     
    12321253                    on 'VAR', .addDecl(box, .boxFieldDecl(true)) 
    12331254                    on 'CONST', .addDecl(box, .boxFieldDecl(false)) 
    12341255                    on 'INVARIANT', .declareInvariant 
    1235                     on 'EOL', .endOfLine 
     1256                    on 'EOL',  .endOfLine 
    12361257                    on 'ENUM', .addDecl(box, .enumDecl) 
    1237                     on 'EVENT', .addDecl(box, .eventDecl) 
    1238                     on 'SIG', .addDecl(box, .declareMethodSig) 
    1239                     on 'SHARED', .bodiedBoxMemberDeclsShared(box) 
    1240                     on 'TEST', .testSection(box) 
     1258                    on 'EVENT',.addDecl(box, .eventDecl) 
     1259                    on 'SIG',  .addDecl(box, .declareMethodSig) 
     1260                    on 'TEST',   .testSection(box) 
    12411261                    on 'CLASS',  .addDecl(box, .classDecl)  # nested types 
    12421262                    on 'STRUCT', .addDecl(box, .structDecl) # nested types 
    12431263                    else 
    1244                         branch .peek.text 
     1264                        branch .peek.text  
    12451265                            on 'ensure', sugg = 'invariant' 
    12461266                            on 'void', sugg = 'def' 
    12471267                            else, sugg = '' 
    1248                         if sugg <> '' 
    1249                             sugg = ' Instead of "[.peek.text]", try "[sugg]".' 
     1268                        if sugg <> '', sugg = ' Instead of "[.peek.text]", try "[sugg]".' 
    12501269                        .throwError('Got [.peek] when expecting class, def, enum, get, invariant, pro, set, shared, sig, struct, test or var.[sugg]') 
    12511270            .dedent 
    12521271 
     
    12581277                # TODO: Give another error with the line number of the other definition (and then change message above) 
    12591278            box.addDecl(member) 
    12601279 
    1261     def bodiedBoxMemberDeclsShared(box as Box) 
    1262         .expect('SHARED') 
     1280    def bodiedBoxMemberDeclNames(box as Box) 
     1281        """ Section for block of common decl/modifier isnames.""" 
     1282        declModifierNames = _commaSepDeclNames(List<of String>()) 
     1283        if 'fake' in declModifierNames or 'partial' in declModifierNames 
     1284            .recordError(.last, 'Cannot have "fake" or "partial" in a modifier block.') 
     1285 
     1286        for modName in declModifierNames 
     1287            _modifierNamesStack.push(modName) 
    12631288        .indent 
    1264         _isNamesStack.push('shared') 
    12651289        try 
    12661290            .bodiedBoxMemberDecls(box) 
    12671291        finally 
    1268             _isNamesStack.pop 
    1269  
     1292            for modName in declModifierNames 
     1293                _modifierNamesStack.pop 
     1294                 
    12701295    def classPass 
    12711296        if .curBox.declsInOrder.count 
    12721297            _warning('Encountered "pass" in a class that already has declared members.')  # TODO: change to an error 
     
    12991324            if type is nil 
    13001325                type = .typeProvider.defaultType 
    13011326        docString = '' to ? 
    1302         isNames = List<of String>(_isNamesStack) 
     1327        isNames = List<of String>(_modifierNamesStack) 
    13031328        if .peek.which=='IS' 
    13041329            isNames = .isDeclNames 
    13051330            attribs = .hasAttribs 
     
    13701395        params = _methodParams(opener) 
    13711396        returnType = _methodReturnType 
    13721397 
    1373         isNames = List<of String>(_isNamesStack) 
     1398        isNames = List<of String>(_modifierNamesStack) 
    13741399        attribs = AttributeList() 
    13751400        implementsType = nil to ITypeProxy? 
    13761401 
     
    15511576        if not .optional('INDENT') 
    15521577            # with no indent there can be no additional specs like attributes, contracts or body 
    15531578            if not hasIsNames 
    1554                 isNames = List<of String>(_isNamesStack) 
     1579                isNames = List<of String>(_modifierNamesStack) 
    15551580            attribs = AttributeList() 
    15561581            docString = '' to ? 
    15571582        else 
     
    16251650            if not isAbstract and curBox.canHaveStatements 
    16261651                .throwError('Missing body for property.') 
    16271652            if not hasIsNames 
    1628                 isNames = List<of String>(_isNamesStack) 
     1653                isNames = List<of String>(_modifierNamesStack) 
    16291654            attribs = AttributeList() 
    16301655            docString = '' 
    16311656        if params.count 
     
    16931718            docString = .docString 
    16941719            .dedent 
    16951720        else 
    1696             if not hasIsNames, isNames = List<of String>(_isNamesStack) 
     1721            if not hasIsNames, isNames = List<of String>(_modifierNamesStack) 
    16971722            attribs = AttributeList() 
    16981723            docString = '' 
    16991724        varDef = _genVarDef(declVarType, token, name, varName, initExpr) 
     
    17061731        possibleVarDef = .curBox.declForName(varName) 
    17071732        if not possibleVarDef 
    17081733            if initExpr or declVarType 
    1709                 varDef = BoxVar(token, token, .curBox, varName, declVarType, List<of String>(_isNamesStack), initExpr, nil, 'Automatic backing var for property "[name]".') 
     1734                varDef = BoxVar(token, token, .curBox, varName, declVarType, List<of String>(_modifierNamesStack), initExpr, nil, 'Automatic backing var for property "[name]".') 
    17101735                .curBox.addDecl(varDef) 
    17111736                return varDef 
    17121737            if not varName.startsWith('_') or varName.startsWith('__') 
     
    17821807            if not isAbstract and curBox.canHaveStatements 
    17831808                .throwError('Missing body for property.') 
    17841809            if not hasIsNames 
    1785                 isNames = List<of String>(_isNamesStack) 
     1810                isNames = List<of String>(_modifierNamesStack) 
    17861811            attribs = AttributeList() 
    17871812            docString = '' 
    17881813        if params.count 
  • Tests/120-classes/450-isnames/502-bad-combo-new-override.cobra

     
     1class Test 
     2    def xyzzy is new, override #.error. Cannot specify both 
     3        pass 
     4         
     5    def xyzzy is override, new #.error. Cannot specify both 
     6        pass 
     7         
     8    def main is shared 
     9        Test().xyzzy     
  • Tests/120-classes/450-isnames/100-isnames.cobra

     
     1class Base 
     2    def foo is shared 
     3        pass 
     4 
     5    def bar is shared 
     6        .foo 
     7             
     8class Derived inherits Base 
     9    def main is shared 
     10        .bar 
     11        .foo 
  • Tests/120-classes/450-isnames/500-bad-combo-shared-virtual.cobra

     
     1class Test 
     2    def xyzzy is virtual, shared #.error. Cannot specify both 
     3        pass 
     4     
     5    def xyzzy is shared, virtual #.error. Cannot specify both 
     6        pass 
     7         
     8    def main is shared 
     9        Test().xyzzy     
  • Tests/120-classes/450-isnames/200-modifier-section.cobra

     
     1class Base 
     2    shared 
     3        def foo 
     4            pass 
     5 
     6        def bar 
     7            .foo 
     8             
     9class Derived inherits Base 
     10    def main is shared 
     11        .bar 
     12        .foo 
  • Tests/120-classes/450-isnames/202-modifier-section.cobra

     
     1class Base 
     2    private 
     3        def foo 
     4            pass 
     5 
     6    shared 
     7        def bar 
     8            .foo #.error. cannot access instance member "foo" 
     9             
     10class Derived inherits Base 
     11    def main is shared 
     12        .bar 
     13        .foo  # .error. Cannot access private "foo" 
     14 
  • Tests/120-classes/450-isnames/204-modifier-section.cobra

     
     1class Base 
     2    private, shared 
     3        def foo 
     4            pass 
     5 
     6    shared 
     7        def bar 
     8            .foo 
     9             
     10class Derived inherits Base 
     11    def main is shared 
     12        .bar 
     13        .foo  # .error. Cannot access private "foo" 
     14 
  • Tests/120-classes/450-isnames/206-modifier-section.cobra

     
     1class Base is abstract 
     2    private, shared 
     3        def foo 
     4            pass 
     5 
     6    shared 
     7        def bar 
     8            .foo 
     9         
     10    abstract, protected 
     11        def brazil 
     12 
     13class Derived inherits Base 
     14     
     15    def brazil is override, protected 
     16        pass 
     17 
     18    def main is shared 
     19        .bar 
     20         
     21        d = Derived() 
     22        d.brazil 
  • Tests/120-classes/450-isnames/504-bad-combo-access-modifiers.cobra

     
     1class Test 
     2    def xyzzy is private, protected #.error. Can only specify one of 
     3        pass 
     4     
     5    def xyzzy1 is private, public #.error. Can only specify one of 
     6        pass 
     7     
     8    def xyzzy2 is protected, public #.error. Can only specify one of 
     9        pass 
     10         
     11    def xyzzy3 is protected, private #.error. Can only specify one of 
     12        pass 
     13         
     14    def xyzzy4 is public, internal #.error. Can only specify one of 
     15        pass 
     16         
     17    def xyzzy5 is private, internal #.error. Can only specify one of 
     18        pass 
     19         
     20    def xyzzy6 is protected, internal #.error. Can only specify one of 
     21        pass 
     22         
     23    def xyzzyAll is internal, protected, private #.error. Can only specify one of 
     24        pass 
     25    def xyzzyAll is private, protected, public, internal #.error. Can only specify one of 
     26        pass 
     27         
     28         
     29    def main is shared 
     30        Test().xyzzy