Wiki

Ticket #52: percent-internal-macro.patch

File percent-internal-macro.patch, 9.2 KB (added by hopscc, 9 years ago)
  • Source/CobraTokenizer.cobra

     
    9494            r'AMBIGUOUS_COMMENT     \/\#.*', 
    9595            r'SPACE                 [ \t]+', 
    9696 
     97            r'MACRO_STR             @[A-Za-z][A-Za-z0-9_]*', 
    9798            r'OPEN_GENERIC          [A-Za-z_][A-Za-z0-9_]*<of[ \n\r\t]', 
    9899            r'OPEN_IF               if\(', 
    99100            r'OPEN_CALL             [A-Za-z_][A-Za-z0-9_]*\(', 
     
    240241         
    241242    def makeSTRING_STOP_DOUBLE(definition as String) as TokenDef? 
    242243        return StringStopTokenDef('STRING_STOP_DOUBLE', definition[0]) 
    243  
     244             
     245    def makeMACRO_STR(definition as String) as TokenDef? 
     246        return StringNamedExprTokenDef('MACRO_STR', definition, definition[0])  
     247             
     248             
    244249    def afterStart is override 
    245250        base.afterStart 
    246251        # CC: 
     
    439444        tok.value = s[:-3] 
    440445        return tok 
    441446 
     447    # subst "expr=[CobraCore.toTechString([expr])" back into source line 
     448    def onMACRO_STR(tok as IToken) as IToken? 
     449        .checkForMacro(tok) 
     450        return nil 
     451         
    442452    def onID(tok as IToken) as IToken? 
    443453        tok = .keywordOrWhich(tok, 'ID') 
    444454        if tok.which<>'ID' 
     
    842852                on 'warning', pass 
    843853                else, .throwError('Unrecognized compiler directive "[name]".') 
    844854 
     855    var _macroTable = {  
     856        'debug' : r"'{0}=[CobraCore.toTechString({0})]'", 
     857        'dts'   : r"'{0}=[CobraCore.toTechString({0})]'",   # descriptive-tech-string 
     858        'toTS'  : r"'[CobraCore.toTechString({0})]'",       # to-TechString  
     859    } 
    845860 
     861    def checkForMacro(tok as IToken) 
     862        # breakout macro of form '@' name or '@' name '(' expr ')',  
     863        #  expand and substitute back into parse stream 
     864        i = tok.text.indexOf('(') 
     865        if i<0  
     866            name = tok.text[1:] 
     867            exprStr = '' 
     868        else 
     869            name = tok.text[1:i]        # '@|name|(' 
     870            exprStr = tok.text[i+1:-1]  # 'name(|expr|)' 
     871        #print name, exprStr 
     872        if _macroTable.containsKey(name) 
     873            mac = _macroTable[name] 
     874            subst = String.format(mac, "[exprStr]") to !    #"'[exprStr]=\[CobraCore.toTechString([exprStr])]'" 
     875            #print subst 
     876            _pushString(subst) 
     877        else 
     878            .throwError('Unrecognized macro "[name]".') 
     879 
     880 
    846881    ## 
    847882    ## Deprecated 
    848883    ## 
     
    10071042            assert x._match(r"]foo\\[foo]") is nil 
    10081043        body 
    10091044            return _matchBetween(input, c']', _quote, c'[' ) 
     1045             
     1046class StringNamedExprTokenDef 
     1047    inherits StringTokenDef 
     1048    """ 
     1049    Match name and expression of form '@name(expr)' 
     1050    """ 
     1051    var _name as String 
     1052    #var _exprStr as String='' 
     1053    var _re as Regex 
     1054     
     1055    def init(which as String, regex as String, firstCh as char) 
     1056        base.init(which, firstCh) 
     1057        _name = regex 
     1058        _re = Regex(regex, RegexOptions.Compiled) 
     1059         
     1060    get firstChars as List<of char> is override 
     1061        return [_quote] 
     1062 
     1063    def _match(input as String) as String? is override 
     1064        test 
     1065            x = StringNamedExprTokenDef('A_FOO', r'@[f][a-z]*', c'@') 
     1066            # normal: 
     1067            assert x._match('aoeu') is nil 
     1068            assert x._match(r"@foo(bar) ") == r"@foo(bar)" 
     1069            # miss: 
     1070            assert x._match(r"@goo(a+33)") == nil 
     1071            # escaped: 
     1072            assert x._match(r"@foo(wokka\n") == nil 
     1073            assert x._match(r"@foo\(wx1)") == r'@foo' 
     1074            assert x._match(r"@foo(wx1\)") == nil 
     1075            assert x._match(r"@foo()") == r'@foo()' 
     1076            assert x._match(r'@foo(1+(2+3)-a) no more' ) == r'@foo(1+(2+3)-a)' 
     1077            assert x._match(r'@foo((1)-1()) no more' ) == r'@foo((1)-1())' 
     1078            assert x._match("(@foo)") is nil 
     1079            # not this token def: 
     1080            assert x._match("(@gfoo)") is nil 
     1081             
     1082            assert x._match(r"@foo(\)")is nil 
     1083            assert x._match(r"@foo(foo(foo))asas") == r'@foo(foo(foo))' 
     1084        body 
     1085            #if not input.startsWith(_name) 
     1086            #   return nil 
     1087            if not input[0] == _quote # '@' 
     1088                return nil 
     1089            if not _reMatch(input) 
     1090                return nil 
     1091            sb = StringBuilder(_name) 
     1092            # match from '(' to terminating ')' handling escapes and nested () 
     1093            #  could become matchEnclosed(input, c'(', c')' ) 
     1094            startch = c'(' 
     1095            stopch  = c')' 
     1096            l = _name.length 
     1097            if input[l] <> startch, return _name    # nil  
     1098            nestCount = 0 
     1099            isEscaped = false 
     1100            for i in l : input.length 
     1101                c = input[i] 
     1102                if c == startch and not isEscaped, nestCount += 1 
     1103                if c == c'\n', return nil 
     1104                sb.append(c) 
     1105                if isEscaped 
     1106                    isEscaped = false 
     1107                    continue 
     1108                if c == stopch 
     1109                    nestCount -= 1 
     1110                    if nestCount == 0 
     1111                        #_exprStr= input[l+1:i-1] 
     1112                        return sb.toString 
     1113                if c == c'\\', isEscaped = true 
     1114            return nil 
     1115         
     1116    def _reMatch(input as String) as bool 
     1117        reMatch = _re.match(input) 
     1118        if not reMatch.success 
     1119            return false 
     1120        assert reMatch.index == 0 
     1121        assert reMatch.value 
     1122        _name = reMatch.value to ! 
     1123        return true 
  • Source/Tokenizer.cobra

     
    269269    get token from var 
    270270 
    271271    get tokenizer from var 
     272     
     273class SourceLineState 
     274    
     275    var sourceLine as String? 
     276    var sourceLineIndex as int 
     277    var colNum as int 
     278    var charNum as int 
     279    var fileName as String? 
    272280 
     281    def init(srcLine as String?, srcLnIdx as int, colNum as int, charNum as int, fileName as String?) 
     282        .sourceLine = srcLine 
     283        .sourceLineIndex = srcLnIdx 
     284        .colNum  = colNum 
     285        .charNum = charNum 
     286        .fileName = fileName 
    273287 
    274288class Tokenizer 
    275289    """ 
     
    582596            _colNum = 1 
    583597            return true 
    584598 
     599    var _sourceLineStack = Stack<of SourceLineState>() #is private 
     600    def _pushString(s as String) 
     601        """  
     602        Push string of source into parse stream at current point 
     603        """ 
     604        #_sourceLine = _sourceLine.insert(0, s) 
     605        sli = SourceLineState(_sourceLine, _sourceLineIndex, _colNum, _charNum, _fileName) 
     606        _sourceLineStack.push(sli) 
     607        _sourceLine=s 
     608        _colNum=1 
     609        _charNum=1 
     610        _fileName='(Internally pushed String [s])' 
     611         
     612    def _sourceLinePushActive as bool 
     613        return _sourceLineStack.count >0     
     614 
     615    def _sourceLinePop 
     616        assert _sourceLineStack.count >0 
     617        sli = _sourceLineStack.pop 
     618        _sourceLine       = sli.sourceLine 
     619        _sourceLineIndex  = sli.sourceLineIndex 
     620        _colNum           = sli.colNum 
     621        _charNum          = sli.charNum 
     622        _fileName         = sli.fileName 
     623     
    585624    var _narrowTokenDefs = true 
    586625    var _minNumTokenDefsToNarrow = 4 
    587626 
     
    596635                # eat up queue first 
    597636                return _tokenQueue.dequeue 
    598637            if not _sourceLine or not _sourceLine.length 
    599                 if not _obtainSource() 
     638                if _sourceLinePushActive() 
     639                    _sourceLinePop 
     640                else if not _obtainSource() 
    600641                    return nil 
    601642            try 
    602643                assert _tokenDefs 
     
    670711            assert _tokenDefsByFirstChar 
    671712            assert _sourceLine.length 
    672713            if _tokenDefsByFirstChar.containsKey(_sourceLine[0]) 
    673                 # print 'Using short list for char: [_sourceLine[0]], [_sourceLine[0] to int]' 
     714                #print 'Using short list for char: [_sourceLine[0]], [_sourceLine[0] to int]' 
    674715                return _tokenDefsByFirstChar[_sourceLine[0]] 
    675716        return _tokenDefs to ! 
    676717 
  • Tests/200-misc/290-internal-macro.cobra

     
     1# test for built in macro %debug taking an expression   
     2# expanding to 'expr=[CobraCore.toTechString(expr)]' 
     3 
     4# if user definitions supported could be done something like this 
     5#%subst @debug(a)   '{0}=[CobraCore.toTechString({0})]' 
     6# better name - todts = to-descriptive-tech-string 
     7#%subst @todts(a)   '{0}=[CobraCore.toTechString({0})]' 
     8#   these could be useful additions 
     9#%subst @CLCC       'Comp.Lang.CobraCore' 
     10#%subst @toTS       'Comp.Lang.CobraCore.toTechString' 
     11 
     12class MacroStr 
     13    var xy is shared 
     14 
     15    def main is shared 
     16        .xy='zz zz zzz zzzz z zzzzzzz' 
     17        a = 47 
     18        b = [1,2,3,4,5] 
     19        c={'a':'b', 'b':'c', 'c':'d'} 
     20        x=@['Haere','Mae'] 
     21         
     22        assert @debug(a) == r'a=47' 
     23        assert @debug(b) == r'b=List<of int>[1, 2, 3, 4, 5]' 
     24 
     25        s = @debug(x) 
     26        assert s == r"x=String[]['Haere', 'Mae']" 
     27 
     28        sx = .xx(@debug(c)) 
     29        assert sx == r"xx:: c=Dictionary<of String, String>{'a': 'b', 'b': 'c', 'c': 'd'}" 
     30 
     31        sx = @debug(.xy) 
     32        assert sx == ".xy='zz zz zzz zzzz z zzzzzzz'" 
     33         
     34        #hidden gotcha: string has to be "" delimited since macro defn is '' delimited 
     35        assert  "xxxx[@debug(a)]yyy" == "xxxxa=47yyy" 
     36         
     37    def xx(s as String) as String is shared 
     38        return "xx:: [s]"    
     39         
     40         
  • Developer/IntermediateReleaseNotes.text

     
    8383  
    8484* Added a new built-in doc tool accessible via "cobra -doc ...". The documentation is generated to local HTML files using your declarations, doc strings, contracts, etc. 
    8585 
     86* Added additional tracing convenience - %debug(expr) generates String 'expr=[CobraCore.toTechString(expr)' 
     87 for use where want trace like info without using trace statement (hopscc) 
     88 
    8689* Added support for declaring and raising events. When raising events, passing "this" is implied (e.g., not required) since that is the normal behavior for events. Also, if the events argument has a default constructor, it too can be omitted. 
    8790 
    8891* Add support for specifying unsigned integers as Hex literals