Ticket #111: utilsToExtns.patch
File utilsToExtns.patch, 34.6 KB (added by hopscc, 16 years ago) |
---|
-
Source/TypeProxies.cobra
380 380 Also, implements -correct-source:case or suggests it if it is off, but would have resolved. 381 381 """ 382 382 # don't need to check "basic types" like int, bool, etc. here. the parser does those. 383 if Utils.isCapped(name)383 if name.isCapped 384 384 symbol = .compiler.symbolForName(name, true, false) # nested enum and class types are capped and can be members of the current class 385 385 else 386 386 symbol = nil 387 387 if symbol is nil 388 388 correctCase = 'case' in .compiler.options.setValue('correct-source') 389 389 if correctCase 390 if not Utils.isCapped(name)390 if not name.isCapped 391 391 # not very sophisticated, but catches 'string', 'object', etc. 392 392 name = name.capped 393 393 symbol = .compiler.symbolForName(name, true, false) … … 399 399 .compiler.correctSource(.token, name) 400 400 if symbol is nil 401 401 sugg = Compiler.suggestionFor(name) ? '' 402 if sugg == '' and not Utils.isCapped(name)402 if sugg == '' and not name.isCapped 403 403 other = .compiler.symbolForName(name.capped, true, false) 404 404 if other, sugg = name.capped 405 405 if sugg <> '', sugg = ' Try "[sugg]". Also, consider the -correct-source option (see cobra -h for details).' -
Source/Expr.cobra
860 860 """ 861 861 862 862 cue init(token as IToken, name as String, args as List<of Expr>, definition as EnumDecl) 863 require Utils.isCapped(name)863 require name.isCapped 864 864 base.init(token) 865 865 _name = name 866 866 _args = args -
Source/Parser.cobra
145 145 if _willShowTokens 146 146 print 'expect([whatTypes]) --> [t]' 147 147 if t is nil 148 .throwError('Expecting [ Utils.join(" or ",whatTypes)], but source ended suddenly.')148 .throwError('Expecting [" or ".join(whatTypes)], but source ended suddenly.') 149 149 if t.which not in whatTypes 150 .throwError('Expecting [ Utils.join(" or ",whatTypes)], but got [t] instead.')150 .throwError('Expecting [" or ".join(whatTypes)], but got [t] instead.') 151 151 return t to ! 152 152 153 153 def optional(whatTypes as vari String) as IToken? -
Source/BackEndClr/SharpGenerator.cobra
145 145 backEndOptions += ' [optChar]target:[target]' 146 146 # TODO: what is the output for a module? 147 147 branch target 148 on 'exe' or 'winexe', outName = Utils. forceExtension(outName, '.exe')149 on 'library', outName = Utils. forceExtension(outName, '.dll')150 on 'module', outName = Utils. forceExtension(outName, '.netmodule') # http://msdn2.microsoft.com/en-us/library/58scf68s(VS.80).aspx148 on 'exe' or 'winexe', outName = Utils.pathForceExtension(outName, '.exe') 149 on 'library', outName = Utils.pathForceExtension(outName, '.dll') 150 on 'module', outName = Utils.pathForceExtension(outName, '.netmodule') # http://msdn2.microsoft.com/en-us/library/58scf68s(VS.80).aspx 151 151 else, throw FallThroughException(target) 152 152 else 153 outName = Utils. forceExtension(outName, '.exe')153 outName = Utils.pathForceExtension(outName, '.exe') 154 154 _fullExeFileName = outName 155 155 156 156 delaySign = options.boolValue('delay-sign') … … 233 233 # use Process class instead of CSharpCodeProvider because the user specified a path to a C# compiler 234 234 p = System.Diagnostics.Process() 235 235 p.startInfo.fileName = cscPath 236 sharpFileNames = Utils.join(' ',for fileName in sharpFileNameList get '"' + fileName + '"')236 sharpFileNames = ' '.join( for fileName in sharpFileNameList get '"' + fileName + '"') 237 237 p.startInfo.arguments = '[backEndOptions] [sharpFileNames]' 238 238 if _verbosity >= 2 239 239 print '[p.startInfo.fileName] [p.startInfo.arguments]' … … 281 281 # otherwise, the first element is the C# compilation line 282 282 if _verbosity >= 2 and cr.output.count > 0 283 283 print '>>', cr.output[0], '<<' 284 output = if(cr.output.count==0, '', Utils.join('\n',cr.output[1:]).trim)284 output = if(cr.output.count==0, '', '\n'.join(cr.output[1:]).trim) 285 285 # trace output 286 286 _parseSharpCompilerOutput(output) 287 287 … … 396 396 if false 397 397 # kind of silly, but it works: 398 398 d = Dictionary<of int, int>() 399 for i = 1 .. Utils.countChars(File.readAllText(_sharpFileName),c'\n')+1399 for i in 1 : File.readAllText(_sharpFileName).countChars(c'\n')+1 400 400 d[i] = i 401 401 return d 402 402 return nil … … 508 508 } 509 509 sep = '' 510 510 for name in isNames 511 name = Utils. getSS(isNameCS to passthrough, name, name) to !511 name = Utils.dictGetVOD<of String>(isNameCS to passthrough, name, name) 512 512 sw.write(sep) 513 513 sw.write(name) 514 514 sep = ' ' … … 1432 1432 wroteNames = Set<of String>() 1433 1433 sep = '' 1434 1434 for name in _isNames 1435 name = Utils. getSS(isNameCS, name, name)to !1435 name = Utils.dictGetVOD<of String>(isNameCS, name, name)# to ! 1436 1436 sw.write(sep) 1437 1437 sw.write(name) 1438 1438 sep = ' ' -
Source/BackEndClr/ScanClrType.cobra
54 54 .warning(CobraWarning('Already have declaration "[clrType.name]" in namespace "[curNameSpace.fullName]".')) 55 55 else 56 56 if type.isClass 57 if type.name.startsWith('Extend_') and Utils.countChars(type.name,c'_') >= 257 if type.name.startsWith('Extend_') and type.name.countChars(c'_') >= 2 58 58 curNameSpace.addDecl(Extension(clrType)) 59 59 else 60 60 curNameSpace.addDecl(Class(clrType)) -
Source/BackEndJvm/JavaGenerator.cobra
114 114 if false 115 115 # kind of silly, but it works: 116 116 d = Dictionary<of int, int>() 117 for i in 1 : Utils.countChars(File.readAllText(_javaFileName),c'\n')+1117 for i in 1 : File.readAllText(_javaFileName).countChars(c'\n')+1 118 118 d[i] = i 119 119 return d 120 120 return nil … … 229 229 } 230 230 sep = '' 231 231 for name in isNames 232 name = Utils. getSS(isNameJava to passthrough, name, name) to !232 name = Utils.dictGetVOD<of String>(isNameJava to passthrough, name, name) 233 233 sw.write(sep) 234 234 sw.write(name) 235 235 sep = ' ' -
Source/CobraTokenizer.cobra
354 354 assert tok.text.endsWith(' ') 355 355 # this is okay on continued lines 356 356 if .justDidLineContinuation 357 indentLevel = Utils.countChars(tok.text, c'\t') + Utils.countChars(tok.text,c' ') // 4357 indentLevel = tok.text.countChars(c'\t') + tok.text.countChars(c' ') // 4 358 358 return _processNumIndentLevels(indentLevel) # will check continuation indentation rules 359 359 else 360 360 return .onINDENT_MIXED_TS(tok) … … 375 375 return .onINDENT_MIXED_TS(tok) 376 376 377 377 def onINDENT_ALL_TABS(tok as IToken) as IToken? 378 numTabs = Utils.countChars(tok.text,c'\t')378 numTabs = tok.text.countChars(c'\t') 379 379 return _processNumIndentLevels(numTabs) 380 380 381 381 def onINDENT_ALL_SPACES(tok as IToken) as IToken? 382 numSpaces = Utils.countChars(tok.text,c' ')382 numSpaces = tok.text.countChars(c' ') 383 383 if numSpaces % 4 and not .justDidLineContinuation # yes, 4. hard coded, intentionally. 384 384 # TODO: should really just record an error and take (numSpaces/4).round as the indent 385 385 .throwError('Space-based indentation must be a multiple of 4. This line has a remainder of [numSpaces%4].') -
Source/Compiler.cobra
567 567 hasSpaces = any for a in argList where ' ' in a 568 568 if hasSpaces 569 569 argList = for arg in argList get if(' ' in arg, '"[arg]"', arg) 570 args += Utils.join(' ',argList)570 args += ' '.join(argList) 571 571 p.startInfo.arguments = args 572 572 return p 573 573 -
Source/Tokenizer.cobra
585 585 if _sourceLine is nil 586 586 # end of source 587 587 return false 588 numLines = Utils.countChars(_sourceLine to !,c'\n')588 numLines = (_sourceLine to !).countChars( c'\n') 589 589 if numLines == 0 and _willAlwaysEndWithNewLine 590 590 _sourceLine += "\n" 591 591 #trace sourceLine -
Source/Boxes.cobra
232 232 assert ns is not ns.superNameSpace 233 233 ns = ns.superNameSpace 234 234 nameSpaces.reverse 235 prefix = Utils.join('.',for ns in nameSpaces get ns.name)235 prefix = '.'.join( for ns in nameSpaces get ns.name) 236 236 if prefix.length 237 237 prefix += '.' 238 238 return prefix … … 533 533 def _checkForInheritanceCycles(originalBox as Box, bases as Stack<of Box>) 534 534 if this in bases 535 535 names = for aBase in List<of Box>(Stack<of Box>(bases))[1:] get aBase.name 536 .throwError('Cyclical inheritance for "[.name]" with ancestor types [ Utils.join(", ",names)] and back to [.name].')536 .throwError('Cyclical inheritance for "[.name]" with ancestor types [", ".join(names)] and back to [.name].') 537 537 else 538 538 bases.push(this) 539 539 if .baseClass, .baseClass._checkForInheritanceCycles(originalBox, bases) … … 861 861 t = .memberwiseClone to Box 862 862 assert t is not this 863 863 genericDef._constructedTypes[key] = t 864 argNames = Utils.join(',',for type in typeArgs get type.name)864 argNames = ','.join(for type in typeArgs get type.name) 865 865 t._name = '[.rootName]<of [argNames]>' 866 866 t._genericDef = this 867 867 t._nativeType = nil # The constructed type is really sourced from the generic def. Don't foster confusion with a reference to the original generic def's clr type (if there is one). -
Source/Cobra.Lang/Extensions.cobra
27 27 for i in chars.count, charsArray[i] = chars[i] 28 28 return List<of String>(.split(charsArray)) 29 29 30 # library String class join() only works on arrays of strings 31 def join(parts as System.Collections.IEnumerable) as String # TODO: given that this seems necessary, should Cobra add "use System.Collections" to all programs? 32 """ 33 Join the items in an IEnumerable collection separated by this string 34 """ 35 test 36 assert '.'.join(['a', 'b'])=='a.b' 37 assert ' and '.join(['a', 'b'])=='a and b' 38 body 39 sep = this 40 sb = StringBuilder() 41 s = '' 42 for part in parts 43 sb.append(s) 44 sb.append(part.toString) 45 s = sep 46 return sb.toString 47 48 def join(lastSep as String, parts as System.Collections.IEnumerable) as String 49 """ 50 Join the items of an IEnumerable collection with this string except for the last 51 two items; join them with the lastSep string 52 """ 53 test 54 assert ', '.join(' and ', ['a', 'b'])=='a and b' 55 assert ', '.join(' and ', ['a', 'b', 'c'])=='a, b and c' 56 assert ', '.join(' and ', ['a', 'b', 'c', 'd'])=='a, b, c and d' 57 body 58 sep = this 59 sb = StringBuilder() 60 s = '' 61 partsList = [] 62 for part in parts, partsList.add(part) 63 count = partsList.count 64 for i in count 65 sb.append(s) 66 sb.append(partsList[i].toString) 67 s = if(i==count-2, lastSep, sep) 68 return sb.toString 69 70 # def join(sep as String, parts as vari String) as String # CC: shouldn't need this because vari should implement IEnumerable 71 # return .join(sep, parts to System.Collections.IEnumerable) 72 73 74 def md5HashInHex as String 75 ensure 76 result.length == 32 77 test 78 assert 'Black holes and revelations.'.md5HashInHex == '95b141d670c19f2f20a820751897b9c6' 79 body 80 md5 = System.Security.Cryptography.MD5CryptoServiceProvider() 81 data = System.Text.Encoding.ascii.getBytes(this) # why ASCII? why not utf8 or something? 82 data = md5.computeHash(data) 83 ret = '' 84 for i in data.length 85 ret += data[i].toString('x2') 86 return ret 87 88 def countChars(c as char) as int 89 test 90 assert ''.countChars(c'x')==0 91 assert 'x'.countChars(c'x')==1 92 assert 'X'.countChars(c'x')==0 # case sensitive 93 assert ' ! ! '.countChars(c'!')==2 94 body 95 count = 0 96 for ch in this 97 if c==ch 98 count += 1 99 return count 100 101 def isCapped as bool 102 test 103 assert 'Aoeu'.isCapped 104 assert 'Zaoeu'.isCapped 105 assert not 'aoeu'.isCapped 106 assert not ''.isCapped 107 assert not '1234'.isCapped 108 body 109 return .length and this[0].isUpper 110 111 def capped as String 112 """ 113 Returns the string with the first character capitalized. 114 Returns a blank string for a blank string. 115 """ 116 ensure 117 result.length == .length 118 result.length implies result[0] == result[0].toUpper 119 test 120 assert 'chuck'.capped == 'Chuck' 121 assert 'Chuck'.capped == 'Chuck' 122 assert ''.capped == '' 123 assert ' foo'.capped == ' foo' 124 assert 'f'.capped == 'F' 125 assert '1aoeu'.capped == '1aoeu' 126 body 127 if .length == 0, return this 128 return this[0:1].toUpper + this[1:] 129 130 def startsIsLower as bool 131 require 132 .length 133 test 134 assert 'a'.startsIsLower 135 assert 'z'.startsIsLower 136 assert not 'A'.startsIsLower 137 assert not '1'.startsIsLower 138 assert not '_'.startsIsLower 139 body 140 return this[0].isLower 141 142 def startsIsNonLower as bool 143 require 144 .length 145 test 146 assert not 'a'.startsIsNonLower 147 assert not 'z'.startsIsNonLower 148 assert not '1'.startsIsNonLower 149 assert 'A'.startsIsNonLower 150 body 151 return this[0] <> this[0].toLower 152 153 30 154 31 155 class DecimalTools 32 156 -
Source/CommandLine.cobra
446 446 """ 447 447 448 448 get versionString as String is shared 449 ensure Utils.countChars(result,c'.') == 2449 ensure result.countChars(c'.') == 2 450 450 451 451 # Can't just take CobraCore.versionDescription as is, because that will be the one from Snapshot, 452 452 # not the current Source directory. And Snapshot can be a final release such as '0.7.4' for a … … 858 858 reMatch = Regex(r'\d+\.\d+\.\d+').match(.versionString) 859 859 assert reMatch.success 860 860 version = reMatch.value to ! 861 assert Utils.countChars(version,c'.') == 2 # ex: '0.8.0'861 assert version.countChars(c'.') == 2 # ex: '0.8.0' 862 862 if ' ' in .versionString or 'post' in .versionString # ex: '0.8.0 post' 863 863 # 'post' versions have a fourth version component of 1, as opposed to 0 864 864 version += '.1' 865 assert Utils.countChars(version,c'.') == 3865 assert version.countChars(c'.') == 3 866 866 _options.addExtraUse('use System.Reflection') 867 867 _options.addExtraSource("assembly\n\thas AssemblyVersion('[version]')\n") 868 868 .doCompile(List<of String>(), true, false, false) … … 988 988 errMsg = 'Cannot parse value "[valueStr]" for option "[name]".' 989 989 branch spec.type 990 990 on 'bool', errMsg += ' Possible values include yes, no, y, n, true, false, t, f, 1, 0, + and -.' 991 on 'menu', errMsg += ' Possible values are [ Utils.join(", "," and ", spec.choices)].'991 on 'menu', errMsg += ' Possible values are [", ".join(" and ", spec.choices)].' 992 992 _error(errMsg) 993 993 valueDict[name] = value to ! 994 994 didSpecify[name] = true … … 1007 1007 # TODO: make the option names case-insensitive 1008 1008 1009 1009 if mainOptions.count > 1 1010 _error('Cannot have these main options at the same time: [ Utils.join(", ",mainOptions)]')1010 _error('Cannot have these main options at the same time: [", ".join(mainOptions)]') 1011 1011 1012 1012 _unpackOptions(valueDict, fileList) 1013 1013 … … 1082 1082 """ 1083 1083 require name.trim <> '' 1084 1084 ensure result.trim <> '' 1085 name = Utils. getSS(_synToName to passthrough, name, name) to !1085 name = Utils.dictGetVOD<of String>(_synToName to passthrough, name, name) 1086 1086 assert name.trim <> '' 1087 1087 if not _specDict.containsKey(name) 1088 1088 msg = 'No such option "[name]".' -
Source/NameSpace.cobra
114 114 t.add(ns.name) 115 115 ns = ns._superNameSpace 116 116 t.reverse 117 _fullName = Utils.join('.',t)117 _fullName = '.'.join(t) 118 118 return _fullName to ! 119 119 120 120 def getOrMakeNameSpaceNamed(token as IToken, name as String) as NameSpace # CC: same … … 195 195 for ns in _subNameSpacesList, ns.bindInh 196 196 197 197 def _checkCase 198 if Utils.startsWithLowerLetter(.name)and not .token.isEmpty198 if .name.startsIsLower and not .token.isEmpty 199 199 # TODO: make this an error eventually. warning added 2009-01-04 200 200 .compiler.warning(this, 'Namespace names should start with an uppercase letter in order to avoid collisions with other identifiers such as arguments and local variables.') 201 201 … … 212 212 for n in sameNames, remainingNames.remove(n) 213 213 # at this point we have, for example, ['Foo', 'foo', 'FOO'] 214 214 215 namesMsgPart = Utils.join(' ',for n in sameNames get '"[n]"') + '.'215 namesMsgPart = ' '.join(for n in sameNames get '"[n]"') + '.' 216 216 if all for n in sameNames get _declsByName[n] inherits NameSpace 217 217 # namespaces can be spread across DLLs and source files in any combination, so they only get a warning 218 218 .compiler.warning(this, 'Multiple namespaces in "[.fullName]" differ only by case: ' + namesMsgPart) … … 289 289 membersList = List<of IMember>(members) 290 290 membersList.sort(do(a as IMember, b as IMember)) 291 291 return a.parentNameSpace.fullName.compareTo(b.parentNameSpace.fullName) 292 spaces = Utils.join(', ',' and ', for m in membersList get '"[m.parentNameSpace.fullName]"')292 spaces = ', '.join(' and ', for m in membersList get '"[m.parentNameSpace.fullName]"') 293 293 if .compiler and .compiler.nodeStack.peek inherits ISyntaxNode 294 294 node = .compiler.nodeStack.peek 295 295 else … … 395 395 cue init(token as IToken, nameParts as List<of String>, fileName as String?) 396 396 base.init(token) 397 397 _nameParts = nameParts 398 _fullName = Utils.join('.',nameParts)398 _fullName = '.'.join(nameParts) 399 399 _fileName = fileName ? '' 400 400 401 401 def addMinFields -
Source/Utils.cobra
8 8 9 9 extend String 10 10 11 def capped as String12 """13 Returns the string with the first character capitalized.14 Returns a blank string for a blank string.15 """16 ensure17 result.length == .length18 result.length implies result[0] == result[0].toUpper19 test20 assert 'chuck'.capped == 'Chuck'21 assert 'Chuck'.capped == 'Chuck'22 assert ''.capped == ''23 assert ' foo'.capped == ' foo'24 assert 'f'.capped == 'F'25 assert '1aoeu'.capped == '1aoeu'26 body27 if .length == 0, return this28 return this[0:1].toUpper + this[1:]29 30 def md5HashInHex as String31 ensure32 result.length == 3233 test34 assert 'Black holes and revelations.'.md5HashInHex == '95b141d670c19f2f20a820751897b9c6'35 body36 md5 = System.Security.Cryptography.MD5CryptoServiceProvider()37 data = System.Text.Encoding.ascii.getBytes(this) # why ASCII? why not utf8 or something?38 data = md5.computeHash(data)39 ret = ''40 for i in data.length41 ret += data[i].toString('x2')42 return ret43 44 11 ## Language specific 45 12 46 13 def canBeUndottedMemberName as bool … … 52 19 names are typically protected data fields or methods while the uppercase names would be 53 20 enums or (in the future) nested boxes. 54 21 """ 55 return .startsWith('_') or Utils.isCapped(this)22 return .startsWith('_') or .isCapped 56 23 57 24 58 25 class Utils 59 26 60 27 shared 61 28 62 def combinePaths(a as String, b as String) as String63 """64 Same as Path.combine() but leaves no '\.\' or '/./' in the result.65 """66 p = Path.combine(a, b)67 good = Path.directorySeparatorChar.toString68 bad = '[good].[good]'69 p = p.replace(bad, good)70 return p71 72 def normalizePath(path as String) as String73 while path.startsWith('.\\'), path = path[2:]74 while path.startsWith('./'), path = path[2:]75 return path76 77 29 def plural(items as System.Collections.ICollection) as String 78 30 ensure 79 31 result == '' or result == 's' … … 88 40 # Could be made more sophisitcated in the future 89 41 return name + 's' 90 42 91 def isCapped(s as String) as bool92 test93 assert Utils.isCapped('Aoeu')94 assert Utils.isCapped('Zaoeu')95 assert not Utils.isCapped('aoeu')96 assert not Utils.isCapped('')97 assert not Utils.isCapped('1234')98 body99 return s.length and s[0].isUpper100 101 def startsWithLowerLetter(s as String) as bool102 require103 s.length104 test105 assert Utils.startsWithLowerLetter('a')106 assert Utils.startsWithLowerLetter('z')107 assert not Utils.startsWithLowerLetter('A')108 assert not Utils.startsWithLowerLetter('1')109 assert not Utils.startsWithLowerLetter('_')110 body111 return s[0].isLower112 113 def startsNonLower(s as String) as bool114 require115 s.length116 test117 assert not Utils.startsNonLower('a')118 assert not Utils.startsNonLower('z')119 assert not Utils.startsNonLower('1')120 assert Utils.startsNonLower('A')121 body122 return s[0] <> s[0].toLower123 124 43 def toIdentifier(s as String) as String 125 44 test 126 45 cases = [ … … 140 59 sb.append(c'_') 141 60 return sb.toString 142 61 143 # TODO: count should be a CobraCore util method 144 # TODO: count should be an extension method of String 145 def countChars(s as String, c as char) as int 146 test 147 assert Utils.countChars('', c'x')==0 148 assert Utils.countChars('x', c'x')==1 149 assert Utils.countChars('X', c'x')==0 # case sensitive 150 assert Utils.countChars(' ! ! ', c'!')==2 151 body 152 count = 0 153 for ch in s 154 if c==ch 155 count += 1 156 return count 157 158 # CC: the getXX() methods should be one generic method 159 160 def getSB(d as Dictionary<of String, dynamic>, key as String, defaultValue as bool) as bool 62 # this should probably be an extension on Dictionary?? 63 def dictGetVOD<of T>(d as Dictionary<of String, T>, key as String, defaultValue as T) as T 64 """ 65 GetValueOrDefault genericised for return type. 66 Return the value for String key from Dictionary d or if none return provided 67 default value 68 """ 161 69 if d.containsKey(key) 162 70 return d[key] 163 71 else 164 72 return defaultValue 165 166 def getSI(d as Dictionary<of String, int>, key as String, defaultValue as int) as int 167 if d.containsKey(key) 168 return d[key] 169 else 170 return defaultValue 171 172 def getSS(d as Dictionary<of String, String?>, key as String, defaultValue as String?) as String? 173 if d.containsKey(key) 174 return d[key] 175 else 176 return defaultValue 177 178 def getSO(d as Dictionary<of String, Object>, key as String, defaultValue as Object?) as Object? 179 if d.containsKey(key) 180 return d[key] 181 else 182 return defaultValue 183 184 # CC: make join an extension method of String which already has a join() except that it only works on arrays of strings 185 def join(sep as String, parts as System.Collections.IEnumerable) as String # TODO: given that this seems necessary, should Cobra add "use System.Collections" to all programs? 186 test 187 assert Utils.join('.', ['a', 'b'])=='a.b' 188 body 189 sb = StringBuilder() 190 s = '' 191 for part in parts 192 sb.append(s) 193 sb.append(part.toString) 194 s = sep 195 return sb.toString 196 197 # CC: make join an extension method of String which already has a join() except that it only works on arrays of strings 198 def join(sep as String, lastSep as String, parts as System.Collections.IEnumerable) as String 199 test 200 assert Utils.join(', ', ' and ', ['a', 'b'])=='a and b' 201 assert Utils.join(', ', ' and ', ['a', 'b', 'c'])=='a, b and c' 202 assert Utils.join(', ', ' and ', ['a', 'b', 'c', 'd'])=='a, b, c and d' 203 body 204 sb = StringBuilder() 205 s = '' 206 partsList = [] 207 for part in parts, partsList.add(part) 208 count = partsList.count 209 for i in count 210 sb.append(s) 211 sb.append(partsList[i].toString) 212 s = if(i==count-2, lastSep, sep) 213 return sb.toString 214 215 def join(sep as String, parts as vari String) as String # CC: shouldn't need this because vari should implement IEnumerable 216 return .join(sep, parts to System.Collections.IEnumerable) 217 218 73 219 74 ## C# 220 75 221 76 def cobraNameForSharpMemberName(name as String) as String … … 291 146 print '[lineNum]|[line]' # CC: right align and pad 0 the lineNum 292 147 lineNum += 1 293 148 294 def forceExtension(fileName as String, extension as String) as String 149 # These (next 3 methods) would be better as static extension methods on the Path class 150 # but MS/C#/.Net doesnt support extending existing classes with *static* extension methods 151 # so they remain util methods albeit renamed. 152 def pathCombine(a as String, b as String) as String 153 """ 154 Same as Path.combine() but normalized such that it leaves no '\.\' or '/./' in the result. 155 """ 156 p = Path.combine(a, b) 157 good = Path.directorySeparatorChar.toString 158 bad = '[good].[good]' 159 p = p.replace(bad, good) 160 return p 161 162 def pathNormalizeLeading( path as String) as String 163 """ 164 Normalise this string as a path string removing any leading './' or '.\' 165 """ 166 while path.startsWith('.\\'), path = path[2:] 167 while path.startsWith('./'), path = path[2:] 168 return path 169 170 def pathForceExtension(fileName as String, extension as String) as String 295 171 require 296 172 fileName.length 297 173 extension.length 298 174 ensure 299 175 result.endsWith(extension) 300 176 test 301 assert Utils. forceExtension('foo.csv', '.exe') == 'foo.exe'302 assert Utils. forceExtension('foo.csv', 'exe') == 'foo.exe'303 assert Utils. forceExtension('foo', '.exe') == 'foo.exe'304 assert Utils. forceExtension('foo', 'exe') == 'foo.exe'305 assert Utils. forceExtension('foo.bar.csv', '.exe') == 'foo.bar.exe'177 assert Utils.pathForceExtension('foo.csv', '.exe') == 'foo.exe' 178 assert Utils.pathForceExtension('foo.csv', 'exe') == 'foo.exe' 179 assert Utils.pathForceExtension('foo', '.exe') == 'foo.exe' 180 assert Utils.pathForceExtension('foo', 'exe') == 'foo.exe' 181 assert Utils.pathForceExtension('foo.bar.csv', '.exe') == 'foo.bar.exe' 306 182 body 307 183 if not extension.startsWith('.') 308 184 extension = '.' + extension … … 323 199 require path.length 324 200 return .readKeyValues(path, File.openText(path), Console.out) 325 201 326 def readKeyValues(sr as StreamReader, warnings as TextWriter) as Dictionary<of String, String>327 return .readKeyValues(sr, Console.out)328 329 202 def readKeyValues(path as String, tw as TextReader, warnings as TextWriter) as Dictionary<of String, String> 330 203 test 331 204 nl = Environment.newLine -
Source/CobraParser.cobra
242 242 textParts.add(tok.text) 243 243 else 244 244 .throwError('Expecting more doc string contents or the end of the doc string instead of [tok].') 245 text = Utils.join('',textParts)245 text = ''.join(textParts) 246 246 return text 247 247 else if .optional('DOC_STRING_LINE') 248 248 return .last.value to String … … 472 472 fileNameParts.add(id.text) 473 473 dot = .optional('DOT') 474 474 if not dot, break 475 fileName = Utils.join('.',fileNameParts)475 fileName = '.'.join(fileNameParts) 476 476 else 477 477 .throwError('Expecting a file name (sans extension, with or without quotes) after "from".') 478 478 if fileName.endsWith('.dll') or fileName.endsWith('.exe') … … 780 780 if expectComma 781 781 .expect('COMMA') 782 782 ident = .expect('ID').text 783 if Utils.startsWithLowerLetter(ident)783 if ident.startsIsLower 784 784 .throwError('Generic parameter names must start with an uppercase letter in order to avoid collisions with other identifiers such as arguments and local variables.') 785 785 params.add(GenericParam(ident)) 786 786 expectComma = true … … 2595 2595 else if peek=='NOT' and .peek(+1).which=='IN' 2596 2596 op = 'NOTIN' 2597 2597 # handle precedence (and detect non-binary operators) 2598 binaryOpPrec = Utils. getSI(_binaryOpPrec, op ? peek, -1)2598 binaryOpPrec = Utils.dictGetVOD<of int>(_binaryOpPrec, op ? peek, -1) 2599 2599 if binaryOpPrec==-1 or binaryOpPrec<precedence 2600 2600 break 2601 2601 # continue... … … 2878 2878 _spaceAgnostic 2879 2879 if .peek is nil 2880 2880 literal = {'RPAREN': ')', 'RBRACKET': ']'} 2881 what = Utils.join(" or ",for t in terminators get '"[if(literal.containsKey(t), literal[t], t)]"')2881 what = " or ".join(for t in terminators get '"[if(literal.containsKey(t), literal[t], t)]"') 2882 2882 .throwError('Expecting "," or [what].') 2883 2883 if .peek.which in terminators 2884 2884 .grab … … 2975 2975 if .opStack.count and .opStack.peek=='DOT' 2976 2976 return MemberExpr(nameToken) 2977 2977 if .peek.which=='AS' 2978 if not Utils.startsWithLowerLetter(name)2978 if not name.startsIsLower 2979 2979 .throwError('Local variable declarations must start with a lowercase letter. This avoids collisions with other identifiers such as classes and enums.') 2980 2980 return AsExpr(.grab, nameToken, .typeId) 2981 2981 else … … 3017 3017 sep = which 3018 3018 break 3019 3019 if sep is nil 3020 .throwError('Expecting one of: [ Utils.join(", ",separators)], but encountered [.peek.which]')3020 .throwError('Expecting one of: [", ".join(separators)], but encountered [.peek.which]') 3021 3021 if sep=='COLON' 3022 3022 lastThingWasColon = true 3023 3023 if .peek.which=='RBRACKET' … … 3157 3157 nameToken = .expect('ID') 3158 3158 name = nameToken.text 3159 3159 if .peek.which=='AS' 3160 if not Utils.startsWithLowerLetter(name)3160 if not name.startsIsLower 3161 3161 .throwError('Local variable declarations must start with a lowercase letter. This avoids collisions with other identifiers such as classes and enums.') 3162 3162 return AsExpr(.grab, nameToken, .typeId) 3163 3163 else … … 3372 3372 other = box.declForNameCI(name) 3373 3373 if other 3374 3374 .throwError('There is already another class member with the name "[other.name]". You must differentiate member names by more than just case.') 3375 if Utils.startsNonLower(name)3375 if name.startsIsNonLower 3376 3376 .throwError('Property names must start with lowercase letters. ([name])') 3377 3377 3378 3378 def checkStartsLowercase(identifier as String, whatName as String) … … 3392 3392 sugg = sugg[0].toString.toLower + sugg[1:] 3393 3393 sugg = ' Try "[sugg]".' 3394 3394 .recordError('[whatName] declarations cannot start with an underscore. Those are reserved for class variables.[sugg]') 3395 if Utils.startsNonLower(identifier)3395 if identifier.startsIsNonLower 3396 3396 sugg = identifier[0].toString.toLower + identifier[1:] 3397 3397 .recordError('[whatName] declarations must start with a lowercase letter to distinguish them from other types of identifiers. Try "[sugg]".') 3398 3398 … … 3413 3413 """ 3414 3414 token = .peek(peekAhead) 3415 3415 if token.which == 'ID' 3416 return Utils.startsNonLower(token.value to String)3416 return (token.value to String).startsIsNonLower 3417 3417 return .isOneOfKeywords(token, ['bool', 'char', 'decimal', 'int', 'uint', 'float', 'number']) 3418 3418 3419 3419 def looksLikeVarNameIsNext(peekAhead as int) as bool 3420 3420 token = .peek(peekAhead) 3421 return token is not nil and token.which=='ID' and Utils.startsWithLowerLetter(token.text)3421 return token is not nil and token.which=='ID' and token.text.startsIsLower 3422 3422 3423 3423 def isOneOfKeywords(nToken as IToken?, keywords as List<of String>) as bool 3424 3424 token = nToken to ! -
Source/TestifyRunner.cobra
195 195 paths.addRange(Directory.getDirectories('.') to passthrough) 196 196 paths.sort 197 197 for baseName in paths 198 baseName = Utils. normalizePath(baseName)198 baseName = Utils.pathNormalizeLeading(baseName) 199 199 if baseName.startsWith('_'), continue 200 200 if baseName.endsWith('.cobra') or baseName.endsWith('.COBRA') 201 201 _testifyCount += .testifyFile(baseName) … … 245 245 print 246 246 print 247 247 print 'RUN [baseName]' 248 print ' [Utils. combinePaths(Environment.currentDirectory, baseName)]'248 print ' [Utils.pathCombine(Environment.currentDirectory, baseName)]' 249 249 print ' Test #[_testifyCount+1]' 250 250 print bar 251 251 print bar … … 266 266 print 'Running multiple files.' 267 267 for fileName in firstLine.substring(firstLine.indexOf('.multi.')+8).split 268 268 if fileName.length 269 fileNames.add(Utils. combinePaths(Path.getDirectoryName(baseName) to !, fileName))270 print 'Multiple filenames:', Utils.join(', ',fileNames)269 fileNames.add(Utils.pathCombine(Path.getDirectoryName(baseName) to !, fileName)) 270 print 'Multiple filenames:', ', '.join(fileNames) 271 271 # enable having another directive on the next line, such as .error. 272 272 lines = lines[1:] 273 273 firstLine = lines[0] -
Developer/IntermediateReleaseNotes.text
34 34 35 35 * Added extension methods to List<of T>. @@ expand on this 36 36 37 * Moved useful Utils methods to extension methods. ticket 111 38 37 39 ================================================================================ 38 40 Command Line 39 41 ================================================================================