Ticket #52: percent-internal-macro.patch
File percent-internal-macro.patch, 9.2 KB (added by hopscc, 16 years ago) |
---|
-
Source/CobraTokenizer.cobra
94 94 r'AMBIGUOUS_COMMENT \/\#.*', 95 95 r'SPACE [ \t]+', 96 96 97 r'MACRO_STR @[A-Za-z][A-Za-z0-9_]*', 97 98 r'OPEN_GENERIC [A-Za-z_][A-Za-z0-9_]*<of[ \n\r\t]', 98 99 r'OPEN_IF if\(', 99 100 r'OPEN_CALL [A-Za-z_][A-Za-z0-9_]*\(', … … 240 241 241 242 def makeSTRING_STOP_DOUBLE(definition as String) as TokenDef? 242 243 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 244 249 def afterStart is override 245 250 base.afterStart 246 251 # CC: … … 439 444 tok.value = s[:-3] 440 445 return tok 441 446 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 442 452 def onID(tok as IToken) as IToken? 443 453 tok = .keywordOrWhich(tok, 'ID') 444 454 if tok.which<>'ID' … … 842 852 on 'warning', pass 843 853 else, .throwError('Unrecognized compiler directive "[name]".') 844 854 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 } 845 860 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 846 881 ## 847 882 ## Deprecated 848 883 ## … … 1007 1042 assert x._match(r"]foo\\[foo]") is nil 1008 1043 body 1009 1044 return _matchBetween(input, c']', _quote, c'[' ) 1045 1046 class 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
269 269 get token from var 270 270 271 271 get tokenizer from var 272 273 class 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? 272 280 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 273 287 274 288 class Tokenizer 275 289 """ … … 582 596 _colNum = 1 583 597 return true 584 598 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 585 624 var _narrowTokenDefs = true 586 625 var _minNumTokenDefsToNarrow = 4 587 626 … … 596 635 # eat up queue first 597 636 return _tokenQueue.dequeue 598 637 if not _sourceLine or not _sourceLine.length 599 if not _obtainSource() 638 if _sourceLinePushActive() 639 _sourceLinePop 640 else if not _obtainSource() 600 641 return nil 601 642 try 602 643 assert _tokenDefs … … 670 711 assert _tokenDefsByFirstChar 671 712 assert _sourceLine.length 672 713 if _tokenDefsByFirstChar.containsKey(_sourceLine[0]) 673 # 714 #print 'Using short list for char: [_sourceLine[0]], [_sourceLine[0] to int]' 674 715 return _tokenDefsByFirstChar[_sourceLine[0]] 675 716 return _tokenDefs to ! 676 717 -
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 12 class 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
83 83 84 84 * 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. 85 85 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 86 89 * 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. 87 90 88 91 * Add support for specifying unsigned integers as Hex literals