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 class string(basestring): 266 267 "A plain string of bytes." 268 269 # Special implementation methods. 270 271 def __get_single_item__(self, index): 272 273 "Return the item at the normalised (positive) 'index'." 274 275 self._check_index(index) 276 return str_substr(self.__data__, index, index + 1, 1) 277 278 def __get_multiple_items__(self, start, end, step): 279 280 """ 281 Return items from 'start' until (but excluding) 'end', at 'step' 282 intervals. 283 """ 284 285 self._check_index(start) 286 self._check_end_index(end) 287 check_int(step) 288 289 if step == 0: 290 raise ValueError(step) 291 292 if start == end: 293 return "" 294 295 return str_substr(self.__data__, start, end, step) 296 297 def str(obj): 298 299 "Return the string representation of 'obj'." 300 301 # Class attributes of instances provide __str__. 302 303 return obj.__str__() 304 305 # vim: tabstop=4 expandtab shiftwidth=4