1 #!/usr/bin/env python 2 3 """ 4 String objects. 5 6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from __builtins__.int import maxint 23 from __builtins__.operator import _negate 24 from __builtins__.sequence import itemaccess 25 from __builtins__.types import check_int 26 from native import str_add, str_lt, str_gt, str_eq, str_len, str_nonempty, \ 27 str_substr 28 29 class basestring(itemaccess): 30 31 "The base class for all strings." 32 33 _p = maxint / 32 34 _a = 31 35 36 def __init__(self, other=None): 37 38 "Initialise the string, perhaps from 'other'." 39 40 # Note the __data__ member. Since strings are either initialised from 41 # literals or converted using routines defined for other types, no form 42 # of actual initialisation is performed here. 43 44 # NOTE: Cannot perform "other and other.__data__ or None" since the 45 # NOTE: __data__ attribute is not a normal attribute. 46 47 if other: 48 self.__data__ = other.__data__ 49 else: 50 self.__data__ = None 51 52 # Note the __key__ member. This is also initialised statically. Where 53 # a string is the same as an attribute name, the __key__ member contains 54 # attribute position and code details. 55 56 if other: 57 self.__key__ = other.__key__ 58 else: 59 self.__key__ = None 60 61 def __hash__(self): 62 63 "Return a value for hashing purposes." 64 65 result = 0 66 l = self.__len__() 67 i = 0 68 69 while i < l: 70 result = (result * self._a + ord(self.__get_single_item__(i))) % self._p 71 i += 1 72 73 return result 74 75 def _binary_op(self, op, other): 76 77 "Perform 'op' on this object and 'other' if appropriate." 78 79 # Refuse to operate on specialisations of this class. 80 81 if self.__class__ is not other.__class__: 82 return NotImplemented 83 84 # Otherwise, perform the operation on the operands' data. 85 86 else: 87 return op(self.__data__, other.__data__) 88 89 def _binary_op_rev(self, op, other): 90 91 "Perform 'op' on 'other' and this object if appropriate." 92 93 # Refuse to operate on specialisations of this class. 94 95 if self.__class__ is not other.__class__: 96 return NotImplemented 97 98 # Otherwise, perform the operation on the operands' data. 99 100 else: 101 return op(other.__data__, self.__data__) 102 103 def __iadd__(self, other): 104 105 "Return a string combining this string with 'other'." 106 107 return self._binary_op(str_add, other) 108 109 __add__ = __iadd__ 110 111 def __radd__(self, other): 112 113 "Return a string combining this string with 'other'." 114 115 return self._binary_op_rev(str_add, other) 116 117 def __mul__(self, other): pass 118 def __rmul__(self, other): pass 119 def __mod__(self, other): pass 120 def __rmod__(self, other): pass 121 122 def __lt__(self, other): 123 124 "Return whether this string is less than 'other'." 125 126 return self._binary_op(str_lt, other) 127 128 def __gt__(self, other): 129 130 "Return whether this string is greater than 'other'." 131 132 return self._binary_op(str_gt, other) 133 134 def __le__(self, other): 135 136 "Return whether this string is less than or equal to 'other'." 137 138 return _negate(self.__gt__(other)) 139 140 def __ge__(self, other): 141 142 "Return whether this string is greater than or equal to 'other'." 143 144 return _negate(self.__lt__(other)) 145 146 def __eq__(self, other): 147 148 "Return whether this string is equal to 'other'." 149 150 return self._binary_op(str_eq, other) 151 152 def __ne__(self, other): 153 154 "Return whether this string is not equal to 'other'." 155 156 return _negate(self.__eq__(other)) 157 158 def bytelength(self): 159 160 "Return the number of bytes in this string." 161 162 return str_len(self.__data__) 163 164 __len__ = bytelength 165 166 def __str__(self): 167 168 "Return a string representation." 169 170 return self 171 172 def __repr__(self): 173 174 "Return a program representation." 175 176 # NOTE: To be implemented with proper quoting. 177 b = buffer(['"', self, '"']) 178 return str(b) 179 180 def __bool__(self): 181 return str_nonempty(self.__data__) 182 183 def endswith(self, s): 184 185 "Return whether this string ends with 's'." 186 187 return self[-s.__len__():] == s 188 189 def find(self, sub, start=None, end=None): 190 191 """ 192 Find 'sub' in the string, starting at 'start' (or 0, if omitted), ending 193 at 'end' (or the end of the string, if omitted), returning -1 if 'sub' 194 is not present. 195 """ 196 197 sublen = sub.__len__() 198 199 i = start or 0 200 end = end or self.__len__() 201 202 while i < end - sublen: 203 if sub == self[i:i+sublen]: 204 return i 205 i += 1 206 207 return -1 208 209 def index(self, sub, start=None, end=None): 210 211 """ 212 Find 'sub' in the string, starting at 'start' (or 0, if omitted), ending 213 at 'end' (or the end of the string, if omitted), raising ValueError if 214 'sub' is not present. 215 """ 216 217 i = self.find(sub, start, end) 218 219 if i == -1: 220 raise ValueError(sub) 221 else: 222 return i 223 224 def join(self, l): 225 226 "Join the elements in 'l' with this string." 227 228 # Empty strings just cause the list elements to be concatenated. 229 230 if not self.__bool__(): 231 return str(buffer(l)) 232 233 # Non-empty strings join the elements together in a buffer. 234 235 b = buffer() 236 first = True 237 238 for s in l: 239 if first: 240 first = False 241 else: 242 b.append(self) 243 b.append(s) 244 245 return str(b) 246 247 def lower(self): pass 248 def lstrip(self, chars=None): pass 249 def replace(self, old, new, count=None): pass 250 def rfind(self, sub, start=None, end=None): pass 251 def rsplit(self, sep=None, maxsplit=None): pass 252 def rstrip(self, chars=None): pass 253 def split(self, sep=None, maxsplit=None): pass 254 def splitlines(self, keepends=False): pass 255 256 def startswith(self, s): 257 258 "Return whether this string starts with 's'." 259 260 return self[:s.__len__()] == s 261 262 def strip(self, chars=None): pass 263 def upper(self): pass 264 265 # Special implementation methods. 266 267 def __get_single_item__(self, index): 268 269 "Return the item at the normalised (positive) 'index'." 270 271 self._check_index(index) 272 return str_substr(self.__data__, index, index + 1, 1) 273 274 def __get_multiple_items__(self, start, end, step): 275 276 """ 277 Return items from 'start' until (but excluding) 'end', at 'step' 278 intervals. 279 """ 280 281 self._check_index(start) 282 self._check_end_index(end) 283 check_int(step) 284 285 if step == 0: 286 raise ValueError(step) 287 288 if start == end: 289 return "" 290 291 return str_substr(self.__data__, start, end, step) 292 293 class string(basestring): 294 295 "A plain string of bytes." 296 297 pass 298 299 def str(obj): 300 301 "Return the string representation of 'obj'." 302 303 # Class attributes of instances provide __str__. 304 305 return obj.__str__() 306 307 # vim: tabstop=4 expandtab shiftwidth=4