github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/bas/value_util.go (about) 1 package bas 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "reflect" 9 "runtime" 10 "runtime/debug" 11 "strconv" 12 "strings" 13 "sync" 14 15 "github.com/coyove/nj/internal" 16 "github.com/coyove/nj/typ" 17 ) 18 19 var ( 20 ioWriterType = reflect.TypeOf((*io.Writer)(nil)).Elem() 21 ioReaderType = reflect.TypeOf((*io.Reader)(nil)).Elem() 22 ioCloserType = reflect.TypeOf((*io.Closer)(nil)).Elem() 23 errType = reflect.TypeOf((*error)(nil)).Elem() 24 valueType = reflect.TypeOf(Value{}) 25 ) 26 27 func (v Value) Error() *ExecError { 28 return v.Native().Unwrap().(*ExecError) 29 } 30 31 func (v Value) Bytes() []byte { 32 return v.Native().Unwrap().([]byte) 33 } 34 35 func Write(w io.Writer, v Value) (int, error) { 36 switch v.Type() { 37 case typ.Nil: 38 return 0, nil 39 case typ.Native: 40 if v.IsBytes() { 41 return w.Write(v.Bytes()) 42 } 43 case typ.String: 44 return internal.WriteString(w, v.Str()) 45 } 46 v.Stringify(w, typ.MarshalToString) 47 return 1, nil 48 } 49 50 func (v Value) IsBytes() bool { 51 return v.Type() == typ.Native && v.Native().meta.Proto.HasPrototype(&Proto.Bytes) 52 } 53 54 func (v Value) IsError() bool { 55 return v.Type() == typ.Native && v.Native().meta.Proto.HasPrototype(&Proto.Error) 56 } 57 58 func (v Value) IsPanic() bool { 59 return v.Type() == typ.Native && v.Native().meta.Proto.HasPrototype(&Proto.Panic) 60 } 61 62 func DeepEqual(a, b Value) bool { 63 if a.Equal(b) { 64 return true 65 } 66 if at, bt := a.Type(), b.Type(); at == bt { 67 switch at { 68 case typ.Native: 69 if a.IsArray() && b.IsArray() { 70 flag := a.Native().Len() == b.Native().Len() 71 if !flag { 72 return false 73 } 74 for i := 0; flag && i < a.Native().Len(); i++ { 75 flag = DeepEqual(b.Native().Get(i), a.Native().Get(i)) 76 } 77 return flag 78 } 79 case typ.Object: 80 flag := a.Object().Len() == b.Object().Len() 81 if !flag { 82 return false 83 } 84 a.Object().Foreach(func(k Value, v *Value) bool { 85 flag = DeepEqual(b.Object().Get(k), *v) 86 return flag 87 }) 88 return flag 89 } 90 } 91 return false 92 } 93 94 func lessStr(a, b Value) bool { 95 if a.isSmallString() && b.isSmallString() { 96 al := (a.unsafeAddr() - uintptr(smallStrMarker)) / 8 * 8 97 bl := (b.unsafeAddr() - uintptr(smallStrMarker)) / 8 * 8 98 av := a.v >> (64 - al) 99 bv := b.v >> (64 - bl) 100 return av < bv 101 } 102 return a.Str() < b.Str() 103 } 104 105 func (a Value) Less(b Value) bool { 106 at, bt := a.Type(), b.Type() 107 if at != bt { 108 return at < bt 109 } 110 switch at { 111 case typ.Number: 112 if a.IsInt64() && b.IsInt64() { 113 return a.UnsafeInt64() < b.UnsafeInt64() 114 } 115 return a.Float64() < b.Float64() 116 case typ.String: 117 return lessStr(a, b) 118 } 119 return a.unsafeAddr() < b.unsafeAddr() 120 } 121 122 func (a Value) HasPrototype(p *Object) bool { 123 switch a.Type() { 124 case typ.Nil: 125 return p == nil 126 case typ.Object: 127 return a.Object().HasPrototype(p) 128 case typ.Bool: 129 return p == &Proto.Bool 130 case typ.Number: 131 return p == &Proto.Float || (a.IsInt64() && p == &Proto.Int) 132 case typ.String: 133 return p == &Proto.Str 134 case typ.Native: 135 return a.Native().HasPrototype(p) 136 } 137 return false 138 } 139 140 // ToType converts value to reflect.Value based on reflect.Type. 141 // The result, even not being Zero, may be illegal to use in certain calls. 142 func (v Value) ToType(t reflect.Type) reflect.Value { 143 if t == valueType { 144 return reflect.ValueOf(v) 145 } 146 if t == nil { 147 return reflect.ValueOf(v.Interface()) 148 } 149 150 switch vt := v.Type(); vt { 151 case typ.Nil: 152 if t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface { 153 return reflect.Zero(t) 154 } 155 case typ.Object: 156 if t.Kind() == reflect.Func { 157 return reflect.MakeFunc(t, func(args []reflect.Value) (results []reflect.Value) { 158 var a []Value 159 for i := range args { 160 if i == len(args)-1 && t.IsVariadic() { 161 // TODO: performance 162 for j := 0; j < args[i].Len(); j++ { 163 a = append(a, ValueOf(args[i].Index(j).Interface())) 164 } 165 } else { 166 a = append(a, ValueOf(args[i].Interface())) 167 } 168 } 169 out := v.Object().Call(nil, a...) 170 if to := t.NumOut(); to == 1 { 171 results = []reflect.Value{out.ToType(t.Out(0))} 172 } else if to > 1 { 173 if !out.IsArray() { 174 internal.Panic("ToType: function should return %d values (sig: %v)", to, t) 175 } 176 results = make([]reflect.Value, t.NumOut()) 177 for i := range results { 178 results[i] = out.Native().Get(i).ToType(t.Out(i)) 179 } 180 } 181 return 182 }) 183 } 184 if t.Kind() == reflect.Map { 185 s := reflect.MakeMap(t) 186 kt, vt := t.Key(), t.Elem() 187 v.Object().Foreach(func(k Value, v *Value) bool { 188 s.SetMapIndex(k.ToType(kt), v.ToType(vt)) 189 return true 190 }) 191 return s 192 } 193 if t.Implements(ioWriterType) || t.Implements(ioReaderType) || t.Implements(ioCloserType) { 194 return reflect.ValueOf(valueIO(v)) 195 } 196 case typ.Native: 197 a := v.Native().Unwrap() 198 if t.Implements(ioWriterType) || t.Implements(ioReaderType) || t.Implements(ioCloserType) { 199 return reflect.ValueOf(a) 200 } 201 if t.Implements(errType) { 202 return reflect.ValueOf(v.Error()) 203 } 204 if t == reflect.TypeOf(a) { 205 return reflect.ValueOf(a) 206 } 207 if v.IsArray() { 208 switch a := v.Native(); t.Kind() { 209 case reflect.Slice: 210 s := reflect.MakeSlice(t, a.Len(), a.Len()) 211 for i := 0; i < a.Len(); i++ { 212 s.Index(i).Set(a.Get(i).ToType(t.Elem())) 213 } 214 return s 215 case reflect.Array: 216 s := reflect.New(t).Elem() 217 for i := 0; i < a.Len(); i++ { 218 s.Index(i).Set(a.Get(i).ToType(t.Elem())) 219 } 220 return s 221 } 222 } 223 case typ.Number: 224 if t.Kind() >= reflect.Int && t.Kind() <= reflect.Float64 { 225 return reflect.ValueOf(v.Interface()).Convert(t) 226 } 227 case typ.Bool: 228 if t.Kind() == reflect.Bool { 229 return reflect.ValueOf(v.Bool()) 230 } 231 case typ.String: 232 if t.Kind() == reflect.String { 233 return reflect.ValueOf(v.Str()) 234 } 235 } 236 if t.Kind() == reflect.Interface { 237 return reflect.ValueOf(v.Interface()) 238 } 239 panic("ToType: failed to convert " + v.simple() + " to " + t.String()) 240 } 241 242 func (v Value) Len() int { 243 switch v.Type() { 244 case typ.String: 245 if v.isSmallString() { 246 return int(uintptr(v.p)-uintptr(smallStrMarker)) / 8 247 } 248 return len(*(*string)(v.p)) 249 case typ.Native: 250 return v.Native().Len() 251 case typ.Object: 252 return v.Object().Len() 253 case typ.Nil: 254 return 0 255 } 256 panic("can't measure length of " + v.simple()) 257 } 258 259 func setObjectRecv(v, r Value) Value { 260 if v.IsObject() { 261 o := v.Object().Copy() 262 o.this = r 263 v = o.ToValue() 264 } 265 return v 266 } 267 268 func (v Value) simple() string { 269 switch vt := v.Type(); vt { 270 case typ.Object: 271 if f := v.Object().fun; f != nil && f != objDefaultFun { 272 return v.Object().funcSig() 273 } 274 return fmt.Sprintf("%s{%d}", v.Object().Name(), v.Object().Len()) 275 case typ.Native: 276 a := v.Native() 277 if v.IsArray() { 278 return fmt.Sprintf("%s[%d]", a.meta.Name, a.Len()) 279 } 280 return a.meta.Name 281 case typ.Number, typ.Bool: 282 return v.String() 283 case typ.String: 284 ln := (v).Len() 285 if ln < 16 { 286 return strconv.Quote(v.Str()) 287 } 288 return fmt.Sprintf("string(%db)", ln) 289 default: 290 return v.Type().String() 291 } 292 } 293 294 func multiMap(e *Env, fun *Object, t Value, n int) Value { 295 if n < 1 || n > runtime.NumCPU()*1e3 { 296 internal.Panic("invalid number of goroutines: %v", n) 297 } 298 299 type payload struct { 300 i int 301 k Value 302 v *Value 303 } 304 305 var outError Value 306 work := func(e *Env, fun *Object, p payload) { 307 defer catchPanicError(e, &outError) 308 if p.i == -1 { 309 *p.v = fun.Call(e, p.k, *p.v) 310 } else { 311 t.Native().Set(p.i, fun.Call(e, Int(p.i), p.k)) 312 } 313 } 314 315 if n == 1 { 316 if t.IsArray() { 317 for i := 0; outError == Nil && i < t.Native().Len(); i++ { 318 work(e, fun, payload{i, t.Native().Get(i), nil}) 319 } 320 } else { 321 t.Object().Foreach(func(k Value, v *Value) bool { 322 work(e, fun, payload{-1, k, v}) 323 return outError == Nil 324 }) 325 } 326 } else { 327 var in = make(chan payload, t.Len()) 328 var wg sync.WaitGroup 329 wg.Add(n) 330 for i := 0; i < n; i++ { 331 go func(e *Env) { 332 defer wg.Done() 333 for p := range in { 334 if outError != Nil { 335 break 336 } 337 work(e, fun, p) 338 } 339 }(e.Copy()) 340 } 341 342 if t.IsArray() { 343 for i := 0; i < t.Native().Len(); i++ { 344 in <- payload{i, t.Native().Get(i), nil} 345 } 346 } else { 347 t.Object().Foreach(func(k Value, v *Value) bool { 348 in <- payload{-1, k, v} 349 return true 350 }) 351 } 352 close(in) 353 354 wg.Wait() 355 } 356 if outError != Nil { 357 return outError 358 } 359 return t 360 } 361 362 func Fprintf(w io.Writer, format string, args ...Value) { 363 tmp := bytes.Buffer{} 364 ai := 0 365 NEXT: 366 for len(format) > 0 { 367 idx := strings.Index(format, "%") 368 if idx == -1 { 369 internal.WriteString(w, format) 370 break 371 } 372 if idx == len(format)-1 { 373 internal.WriteString(w, "%?(NOVERB)") 374 break 375 } 376 internal.WriteString(w, format[:idx]) 377 if format[idx+1] == '%' { 378 internal.WriteString(w, "%") 379 format = format[idx+2:] 380 continue 381 } 382 383 tmp.Reset() 384 tmp.WriteByte('%') 385 format = format[idx+1:] 386 387 preferNumber := ' ' 388 for found := false; len(format) > 0 && !found; { 389 head := format[0] 390 tmp.WriteByte(head) 391 format = format[1:] 392 switch head { 393 case 'b', 'd', 'o', 'O', 'c', 'U': 394 preferNumber = 'i' 395 found = true 396 case 'f', 'F', 'g', 'G', 'e', 'E': 397 preferNumber = 'f' 398 found = true 399 case 's', 'q', 'x', 'X', 'v', 't', 'p': 400 found = true 401 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', '+', '#', ' ': 402 default: 403 internal.WriteString(w, tmp.String()+"(BAD)") 404 goto NEXT 405 } 406 } 407 if ai >= len(args) { 408 internal.WriteString(w, tmp.String()+"(MISSING)") 409 } else { 410 v := args[ai].Interface() 411 if a := args[ai]; a.IsNumber() { 412 if preferNumber == 'i' { 413 v = a.Int64() 414 } else if preferNumber == 'f' { 415 v = a.Float64() 416 } else if a.IsInt64() { 417 v = a.Int64() 418 } else { 419 v = a.Float64() 420 } 421 } 422 fmt.Fprintf(w, tmp.String(), v) 423 } 424 ai++ 425 } 426 } 427 428 func Fprint(w io.Writer, values ...Value) { 429 for _, v := range values { 430 v.Stringify(w, typ.MarshalToString) 431 } 432 } 433 434 func Fprintln(w io.Writer, values ...Value) { 435 for _, v := range values { 436 v.Stringify(w, typ.MarshalToString) 437 internal.WriteString(w, " ") 438 } 439 internal.WriteString(w, "\n") 440 } 441 442 func bassertTwoInts(op string, va, vb *Value) { 443 if !va.IsInt64() || !vb.IsInt64() { 444 internal.Panic("bitwise "+op+" requires integer numbers, got %v and %v", va.simple(), vb.simple()) 445 } 446 } 447 448 func bassertOneInt(op string, va Value) { 449 if !va.IsInt64() { 450 internal.Panic("bitwise "+op+" requires integer numbers, got %v", va.simple()) 451 } 452 } 453 454 func panicNotEnoughArgs(a *Object) { 455 panic("not enough arguments to call " + a.Name()) 456 } 457 458 func catchPanicError(e *Env, err *Value) { 459 if r := recover(); r != nil { 460 if internal.IsDebug() { 461 log.Println(string(debug.Stack())) 462 } 463 rv, ok := r.(Value) 464 if ok { 465 r = rv.Interface() 466 } 467 er, _ := r.(*ExecError) 468 if er != nil { 469 er.fatal = true 470 *err = NewNativeWithMeta(er, &Proto.PanicMeta).ToValue() 471 } else { 472 er, _ := r.(error) 473 if er == nil { 474 er = fmt.Errorf("%v", r) 475 } 476 477 ee := &ExecError{ 478 root: er, 479 stacks: e.runtime.Stacktrace(true), 480 fatal: true, 481 } 482 *err = NewNativeWithMeta(ee, &Proto.PanicMeta).ToValue() 483 } 484 } 485 }