github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/string/string.go (about) 1 package string 2 3 import ( 4 "bytes" 5 "strings" 6 7 "github.com/hirochachacha/plua/compiler/dump" 8 "github.com/hirochachacha/plua/internal/pattern" 9 "github.com/hirochachacha/plua/object" 10 "github.com/hirochachacha/plua/object/fnutil" 11 ) 12 13 func _byte(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 14 ap := fnutil.NewArgParser(th, args) 15 16 s, err := ap.ToGoString(0) 17 if err != nil { 18 return nil, err 19 } 20 21 i, err := ap.OptGoInt(1, 1) 22 if err != nil { 23 return nil, err 24 } 25 if i < 0 { 26 i = len(s) + 1 + i 27 } 28 if i < 1 { 29 i = 1 30 } 31 32 j, err := ap.OptGoInt(2, i) 33 if err != nil { 34 return nil, err 35 } 36 if j < 0 { 37 j = len(s) + 1 + j 38 } 39 if j > len(s) { 40 j = len(s) 41 } 42 43 if i > j { 44 return nil, nil 45 } 46 47 rets := make([]object.Value, j-i+1) 48 for k := range rets { 49 rets[k] = object.Integer(s[k+i-1]) 50 } 51 52 return rets, nil 53 } 54 55 func char(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 56 ap := fnutil.NewArgParser(th, args) 57 58 bs := make([]byte, len(args)) 59 60 for i := range args { 61 i64, err := ap.ToGoInt64(i) 62 if err != nil { 63 return nil, err 64 } 65 66 if i64 < 0 || i64 > 255 { 67 return nil, ap.ArgError(i, "(value out of range)") 68 } 69 70 bs[i] = byte(i64) 71 } 72 73 return []object.Value{object.String(bs)}, nil 74 } 75 76 func _dump(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 77 ap := fnutil.NewArgParser(th, args) 78 79 cl, err := ap.ToClosure(0) 80 if err != nil { 81 return nil, err 82 } 83 84 strip := ap.OptGoBool(1, false) 85 86 var mode dump.Mode 87 if strip { 88 mode |= dump.StripDebugInfo 89 } 90 91 buf := new(bytes.Buffer) 92 93 e := dump.DumpTo(buf, cl.Prototype(), mode) 94 if e != nil { 95 return nil, object.NewRuntimeError(e.Error()) 96 } 97 98 return []object.Value{object.String(buf.String())}, nil 99 } 100 101 func find(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 102 ap := fnutil.NewArgParser(th, args) 103 104 s, err := ap.ToGoString(0) 105 if err != nil { 106 return nil, err 107 } 108 109 pat, err := ap.ToGoString(1) 110 if err != nil { 111 return nil, err 112 } 113 114 init, err := ap.OptGoInt(2, 1) 115 if err != nil { 116 return nil, err 117 } 118 if init < 0 { 119 init = len(s) + 1 + init 120 } 121 if init < 0 { 122 init = 1 123 } 124 if init-1 > len(s) { 125 return nil, nil 126 } 127 128 isPlain := ap.OptGoBool(3, false) 129 130 if isPlain { 131 s = s[init-1:] 132 133 idx := strings.Index(s, pat) 134 if idx == -1 { 135 return nil, nil 136 } 137 138 return []object.Value{object.Integer(idx + init), object.Integer(idx + init + len(pat) - 1)}, nil 139 } 140 141 captures, e := pattern.FindIndex(s, pat, init-1) 142 if e != nil { 143 return nil, object.NewRuntimeError(e.Error()) 144 } 145 146 if captures == nil { 147 return nil, nil 148 } 149 150 rets := make([]object.Value, len(captures)+1) 151 152 loc := captures[0] 153 154 rets[0] = object.Integer(loc.Begin + 1) 155 rets[1] = object.Integer(loc.End) 156 157 for i, cap := range captures[1:] { 158 rets[i+2] = cap.Value(s) 159 } 160 161 return rets, nil 162 } 163 164 // gmatch(s, patter) 165 func gmatch(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 166 ap := fnutil.NewArgParser(th, args) 167 168 s, err := ap.ToGoString(0) 169 if err != nil { 170 return nil, err 171 } 172 173 pat, err := ap.ToGoString(1) 174 if err != nil { 175 return nil, err 176 } 177 178 allCaptures, e := pattern.FindAllIndex(s, pat, -1) 179 if e != nil { 180 return nil, object.NewRuntimeError(e.Error()) 181 } 182 183 i := 0 184 185 fn := func(object.Thread, ...object.Value) ([]object.Value, *object.RuntimeError) { 186 if i == len(allCaptures) { 187 return nil, nil 188 } 189 190 caps := allCaptures[i] 191 192 i++ 193 194 loc := caps[0] 195 196 if len(caps) == 1 { 197 return []object.Value{loc.Value(s)}, nil 198 } 199 200 rets := make([]object.Value, len(caps)-1) 201 for i, cap := range caps[1:] { 202 rets[i] = cap.Value(s) 203 } 204 205 return rets, nil 206 } 207 208 return []object.Value{object.GoFunction(fn)}, nil 209 } 210 211 func _len(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 212 ap := fnutil.NewArgParser(th, args) 213 214 s, err := ap.ToGoString(0) 215 if err != nil { 216 return nil, err 217 } 218 219 return []object.Value{object.Integer(len(s))}, nil 220 } 221 222 func lower(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 223 ap := fnutil.NewArgParser(th, args) 224 225 s, err := ap.ToGoString(0) 226 if err != nil { 227 return nil, err 228 } 229 230 s = strings.ToLower(s) 231 232 return []object.Value{object.String(s)}, nil 233 } 234 235 func match(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 236 ap := fnutil.NewArgParser(th, args) 237 238 s, err := ap.ToGoString(0) 239 if err != nil { 240 return nil, err 241 } 242 243 pat, err := ap.ToGoString(1) 244 if err != nil { 245 return nil, err 246 } 247 248 init, err := ap.OptGoInt(2, 1) 249 if err != nil { 250 return nil, err 251 } 252 if init < 0 { 253 init = len(s) + 1 + init 254 } 255 if init < 0 { 256 init = 1 257 } 258 259 captures, e := pattern.FindIndex(s, pat, init-1) 260 if e != nil { 261 return nil, object.NewRuntimeError(e.Error()) 262 } 263 264 if captures == nil { 265 return nil, nil 266 } 267 268 loc := captures[0] 269 270 if len(captures) == 1 { 271 return []object.Value{loc.Value(s)}, nil 272 } 273 274 rets := make([]object.Value, len(captures)-1) 275 for i, cap := range captures[1:] { 276 rets[i] = cap.Value(s) 277 } 278 279 return rets, nil 280 } 281 282 func rep(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 283 ap := fnutil.NewArgParser(th, args) 284 285 s, err := ap.ToGoString(0) 286 if err != nil { 287 return nil, err 288 } 289 290 n, err := ap.ToGoInt(1) 291 if err != nil { 292 return nil, err 293 } 294 295 sep, err := ap.OptGoString(2, "") 296 if err != nil { 297 return nil, err 298 } 299 300 if n <= 0 { 301 return []object.Value{object.String("")}, nil 302 } 303 304 size := len(s)*n + len(sep)*(n-1) 305 if size < 0 { 306 return nil, object.NewRuntimeError("result is overflowed") 307 } 308 309 buf := make([]byte, size) 310 311 bp := copy(buf, s+sep) 312 for bp < len(buf) { 313 copy(buf[bp:], buf[:bp]) 314 bp *= 2 315 } 316 317 return []object.Value{object.String(buf)}, nil 318 } 319 320 func reverse(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 321 ap := fnutil.NewArgParser(th, args) 322 323 s, err := ap.ToGoString(0) 324 if err != nil { 325 return nil, err 326 } 327 328 b := make([]byte, len(s)) 329 for i := 0; i < len(s); i++ { 330 b[i] = s[len(s)-1-i] 331 } 332 333 return []object.Value{object.String(b)}, nil 334 } 335 336 func sub(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 337 ap := fnutil.NewArgParser(th, args) 338 339 s, err := ap.ToGoString(0) 340 if err != nil { 341 return nil, err 342 } 343 344 i, err := ap.ToGoInt(1) 345 if err != nil { 346 return nil, err 347 } 348 if i < 0 { 349 i = len(s) + 1 + i 350 } 351 if i < 1 { 352 i = 1 353 } 354 355 j, err := ap.OptGoInt(2, -1) 356 if err != nil { 357 return nil, err 358 } 359 if j < 0 { 360 j = len(s) + 1 + j 361 } 362 if j > len(s) { 363 j = len(s) 364 } 365 366 if i > j { 367 return []object.Value{object.String("")}, nil 368 } 369 370 return []object.Value{object.String(s[i-1 : j])}, nil 371 } 372 373 func upper(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 374 ap := fnutil.NewArgParser(th, args) 375 376 s, err := ap.ToGoString(0) 377 if err != nil { 378 return nil, err 379 } 380 381 s = strings.ToUpper(s) 382 383 return []object.Value{object.String(s)}, nil 384 } 385 386 func Open(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 387 m := th.NewTableSize(0, 17) 388 389 m.Set(object.String("byte"), object.GoFunction(_byte)) 390 m.Set(object.String("char"), object.GoFunction(char)) 391 m.Set(object.String("dump"), object.GoFunction(_dump)) 392 m.Set(object.String("find"), object.GoFunction(find)) 393 m.Set(object.String("format"), object.GoFunction(format)) 394 m.Set(object.String("gmatch"), object.GoFunction(gmatch)) 395 m.Set(object.String("gsub"), object.GoFunction(gsub)) 396 m.Set(object.String("len"), object.GoFunction(_len)) 397 m.Set(object.String("lower"), object.GoFunction(lower)) 398 m.Set(object.String("match"), object.GoFunction(match)) 399 m.Set(object.String("pack"), object.GoFunction(pack)) 400 m.Set(object.String("packsize"), object.GoFunction(packsize)) 401 m.Set(object.String("rep"), object.GoFunction(rep)) 402 m.Set(object.String("reverse"), object.GoFunction(reverse)) 403 m.Set(object.String("sub"), object.GoFunction(sub)) 404 m.Set(object.String("unpack"), object.GoFunction(unpack)) 405 m.Set(object.String("upper"), object.GoFunction(upper)) 406 407 mt := th.NewTableSize(0, 1) 408 409 mt.Set(object.String("__index"), m) 410 411 th.SetMetatable(object.String(""), mt) 412 413 return []object.Value{m}, nil 414 }