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