github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/Reflect.pas (about) 1 namespace go.reflect; 2 3 {$IF ECHOES} 4 uses 5 System.Reflection, System.Linq; 6 {$ENDIF} 7 8 type 9 Kind = public type go.builtin.uint; 10 ChanDir = public type go.builtin.int; 11 PlatformEnumerator = {$IF ISLAND}IEnumerator<tuple of (go.reflect.Value, go.reflect.Value)>{$ELSEIF ECHOES}System.Collections.Generic.IEnumerator<tuple of (go.reflect.Value, go.reflect.Value)>{$ENDIF}; 12 13 SliceCtor = procedure(aInst: Object; aCount: Integer); 14 SliceObjectCtor = procedure(aInst: Object; aObject: Object); 15 16 ZeroFunction = method: Object; 17 18 {$IF ISLAND} 19 TEqualsMethod = public method(a: Object; b: Object): Boolean; 20 {$ENDIF} 21 22 SliceAlias = record 23 VMT: IntPtr; 24 aVal: Object; 25 end; 26 27 MemoryExt<T> = extension record(Memory<T>) 28 public 29 class method Get(aVal: Memory<T>): T; 30 begin 31 exit aVal^; 32 end; 33 end; 34 35 [ValueTypeSemantics] 36 MapIter = public class 37 private 38 fEnumerator: PlatformEnumerator; 39 public 40 constructor(aEnum: PlatformEnumerator); 41 begin 42 fEnumerator := aEnum; 43 end; 44 45 method Key: Value; 46 begin 47 result := fEnumerator.Current[0]; 48 end; 49 50 method Value: Value; 51 begin 52 result := fEnumerator.Current[1]; 53 end; 54 55 method Next: Boolean; 56 begin 57 result := fEnumerator.MoveNext; 58 end; 59 end; 60 61 const 62 Invalid: Kind = Kind(0); 63 Bool: Kind = Kind(1); 64 Int: Kind = Kind(2); 65 Int8: Kind = Kind(3); 66 Int16: Kind = Kind(4); 67 Int32: Kind = Kind(5); 68 Int64: Kind = Kind(6); 69 Uint: Kind = Kind(7); 70 Uint8: Kind = Kind(8); 71 Uint16: Kind = Kind(9); 72 Uint32: Kind = Kind(10); 73 Uint64: Kind = Kind(11); 74 Uintptr: Kind = Kind(12); 75 Float32: Kind = Kind(13); 76 Float64: Kind = Kind(14); 77 Complex64: Kind = Kind(15); 78 Complex128: Kind = Kind(16); 79 &Array: Kind = Kind(17); 80 Chan: Kind = Kind(18); 81 Func: Kind = Kind(19); 82 &Interface: Kind = Kind(20); 83 Map: Kind = Kind(21); 84 Ptr: Kind = Kind(22); 85 Slice: Kind = Kind(23); 86 String: Kind = Kind(24); 87 Struct: Kind = Kind(25); 88 UnsafePointer: Kind = Kind(26); 89 90 RecvDir: ChanDir = ChanDir(1 shl 0); 91 SendDir: ChanDir = ChanDir(1 shl 1); 92 BothDor: ChanDir = ChanDir(Integer(RecvDir) + Integer(SendDir)); 93 94 type 95 PlatformExtendedType = {$IF ISLAND}RemObjects.Elements.System.MemberInfo{$ELSEIF ECHOES}System.Reflection.MemberInfo{$ENDIF}; 96 97 ValueExtendedInfo = public (None, Slice); 98 99 [ValueTypeSemantics] 100 Value = public class 101 private 102 assembly 103 fValue: Object; 104 fType: &Type; 105 fPtr: Object; 106 fExtended: PlatformExtendedType; // basically for struct fields 107 fExtendedInfo: ValueExtendedInfo; 108 fExtendedObject: Object; 109 public 110 constructor; 111 begin 112 113 end; 114 115 constructor(aValue: Object; aType: &Type := nil); 116 begin 117 fValue := aValue; 118 if aType ≠ nil then 119 fType := aType 120 else 121 if aValue ≠ nil then 122 fType := TypeOf(aValue); 123 fPtr := aValue; 124 end; 125 126 constructor(aValue: Object; aType: &Type; aPtr: Object; aExtendedInfo: PlatformExtendedType := nil); 127 begin 128 constructor(aValue, aType); 129 fPtr := aPtr; 130 fExtended := aExtendedInfo; 131 end; 132 133 constructor(aValue: Object; aValueExtendedInfo: ValueExtendedInfo; aExtendedPtr: Object; aExtendedObject: Object); 134 begin 135 constructor(aValue); 136 fExtendedInfo := aValueExtendedInfo; 137 fExtendedObject := aExtendedObject; 138 fPtr := aExtendedPtr; 139 end; 140 141 class var fZero: Value := new Value(); 142 class property Zero: Value := fZero; published; 143 144 method String: String; 145 begin 146 exit (if fValue is IMemory then IMemory(fValue).GetValue else fValue).ToString; 147 end; 148 149 method Int: Int64; 150 begin 151 var lValue := InternalGetValue; 152 if lValue is IMemory then 153 lValue := IMemory(lValue).GetValue; 154 {$IFDEF ISLAND} 155 exit RemObjects.Elements.System.Convert.ToInt64(lValue); 156 {$ELSE} 157 if lValue is IConvertible then 158 exit System.Convert.ToInt64(lValue) 159 else 160 if lValue is System.IntPtr then 161 exit System.IntPtr(lValue).ToInt64 162 else 163 raise new Exception("Can not convert value"); 164 {$ENDIF} 165 end; 166 167 method Uint: UInt64; 168 begin 169 var lValue := InternalGetValue; 170 if lValue is IMemory then 171 lValue := IMemory(lValue).GetValue; 172 173 {$IFDEF ISLAND} 174 exit RemObjects.Elements.System.Convert.ToUInt64(lValue); 175 {$ELSE} 176 if lValue is IConvertible then 177 exit System.Convert.ToUInt64(lValue) 178 else 179 if lValue is System.UIntPtr then 180 exit System.UIntPtr(lValue).ToUInt64 181 else 182 raise new Exception("Can not convert value"); 183 {$ENDIF} 184 end; 185 method Float: Double; 186 begin 187 exit {$IFDEF ISLAND}RemObjects.Elements.System.Convert{$ELSE}System.Convert{$ENDIF}.ToDouble(if fValue is IMemory then IMemory(fValue).GetValue else fValue); 188 end; 189 190 method IsNil: Boolean; 191 begin 192 case fType.Kind of 193 Chan, Func, Map, go.reflect.Interface, UnsafePointer, __Global.Slice, go.reflect.Ptr: // missing &Interface Kind(20) --> &Interface 194 exit (if fValue is IMemory then IMemory(fValue).GetValue else fValue) = nil; 195 196 else 197 raise new Exception('Wrong value type'); 198 end; 199 end; 200 201 method Complex: go.builtin.complex128; 202 begin 203 exit go.builtin.complex128(if fValue is IMemory then IMemory(fValue).GetValue else fValue); 204 end; 205 206 method Bool: Boolean; 207 begin 208 exit {$IFDEF ISLAND}RemObjects.Elements.System.Convert{$ELSE}System.Convert{$ENDIF}.ToBoolean(if fValue is IMemory then IMemory(fValue).GetValue else fValue); 209 end; 210 211 method Convert(aTo: &Type): Value; 212 begin 213 raise new NotImplementedException; 214 end; 215 216 method IsValid: Boolean; 217 begin 218 if fValue = nil then 219 exit false; 220 221 var lValue := if fValue is IMemory then IMemory(fValue).GetValue else fValue; 222 result := lValue ≠ go.reflect.Zero(fType); 223 end; 224 225 method CanSet: Boolean; 226 begin 227 result := CanAddr; 228 end; 229 230 method Recv(): tuple of (Value, Boolean); 231 begin 232 raise new NotImplementedException(); 233 end; 234 235 method MapIndex(key: Value): Value; 236 begin 237 if fType.Kind ≠ Map then 238 raise new Exception('Wrong type, need a map'); 239 240 result := go.builtin.IMap(fValue).GetReflectValue(key); 241 end; 242 243 method MapIter: Memory<MapIter>; 244 begin 245 if fType.Kind ≠ Map then 246 raise new Exception('Wrong type, need a map'); 247 248 var lIter := new MapIter(go.builtin.IMap(fValue).GetReflectSequence().GetEnumerator()); 249 result := new Memory<MapIter>(lIter); 250 end; 251 252 method MapKeys: go.builtin.Slice<Value>; 253 begin 254 if fType.Kind ≠ Map then 255 raise new Exception('Wrong type, need a map'); 256 257 result := go.builtin.IMap(fValue).GetReflectKeys(); 258 end; 259 260 method CanInterface(): Boolean; 261 begin 262 result := true; 263 // TODO check, should be false for unexported struct fields or methods. 264 end; 265 266 method Slice(i, j: Integer): Value; 267 begin 268 case fType.Kind of 269 go.reflect.Slice: 270 exit go.builtin.ISlice(fValue).getReflectSlice(i, j); 271 272 go.reflect.String: begin 273 var lString := fValue as go.builtin.string; 274 exit new Value(new go.builtin.Slice<Byte>(lString.Value, i, j-i)); 275 end; 276 277 else 278 raise new Exception('Wrong type, need a Map or String'); 279 end; 280 end; 281 282 method Slice3(i, j, k: Integer): Value; 283 begin 284 // TODO 285 end; 286 287 method &Method(i: Int64): Value; 288 begin 289 raise new NotImplementedException; 290 end; 291 292 method Pointer(): UInt64; 293 begin 294 var lValue := InternalGetValue; 295 {$IF ISLAND} 296 exit RemObjects.Elements.System.UInt64(InternalCalls.Cast(lValue)); 297 {$ELSEIF ECHOES} 298 //exit System.Convert.ToUInt64(lValue); 299 exit 0; 300 {$ENDIF} 301 end; 302 303 method MethodByName(name: String): Value; 304 begin 305 raise new NotImplementedException; 306 end; 307 308 method OverflowFloat(x: Double): Boolean; 309 begin 310 raise new NotImplementedException; 311 end; 312 313 method OverflowInt(x: Int64): Boolean; 314 begin 315 raise new NotImplementedException; 316 end; 317 318 method OverflowUint(x: Int64): Boolean; 319 begin 320 raise new NotImplementedException; 321 end; 322 323 method FieldByIndex(idx: go.builtin.Slice<Int64>): Value; 324 begin 325 raise new NotImplementedException; 326 end; 327 328 method SetCap(n: Integer); 329 begin 330 raise new NotImplementedException; 331 end; 332 333 method SetLen(n: Integer); 334 begin 335 var lKind := Kind; 336 if (lKind <> &Array) and (lKind <> go.reflect.Slice) then 337 raise new Exception("Wrong type, need array or slice"); 338 go.builtin.ISlice(fValue).setLen(n); 339 end; 340 341 method Cap: Integer; 342 begin 343 var lKind := Kind; 344 if (lKind <> &Array) and (lKind <> go.reflect.Slice) then 345 raise new Exception("Wrong type, need array or slice"); 346 347 exit go.builtin.ISlice(fValue).getCap; 348 end; 349 350 method &Set(aVal: Value); 351 begin 352 var lValue := aVal.fValue; 353 354 if TypeImpl(aVal.fType).RealType <> TypeImpl(self.fType).RealType then 355 if not CanSet or not fType.AssignableTo(TypeOf(lValue)) then 356 raise new Exception('Can not set object'); 357 358 if fExtendedInfo = ValueExtendedInfo.Slice then begin 359 go.builtin.ISlice(fPtr).setAtIndex(Integer(fExtendedObject), lValue); 360 end 361 else begin 362 if fExtended <> nil then begin // struct field 363 //(fExtended as FieldInfo).SetValue(go.builtin.IReference(fPtr).Get, lValue); 364 if fPtr is IMemory then 365 (fExtended as FieldInfo).SetValue(IMemory(fPtr).GetValue, lValue) 366 else 367 (fExtended as FieldInfo).SetValue(fPtr, lValue); 368 fValue := lValue; 369 end 370 else begin 371 //if fPtr is go.builtin.IReference then 372 //go.builtin.IReference(fPtr).Set(lValue); 373 if fPtr is IMemory then 374 IMemory(fPtr).SetValue(lValue); 375 fValue := lValue; 376 end; 377 end; 378 end; 379 380 method InternalSet(aValue: Object); private; 381 begin 382 if fExtendedInfo = ValueExtendedInfo.Slice then begin 383 go.builtin.ISlice(fPtr).setAtIndex(Integer(fExtendedObject), aValue); 384 end 385 else begin 386 if fExtended <> nil then begin // struct field 387 //(fExtended as FieldInfo).SetValue(go.builtin.IReference(fPtr).Get, aValue); 388 if fPtr is IMemory then 389 (fExtended as FieldInfo).SetValue(IMemory(fPtr).GetValue, aValue) 390 else 391 (fExtended as FieldInfo).SetValue(fPtr, aValue); 392 end 393 else begin 394 //go.builtin.IReference(fPtr).Set(aValue); 395 IMemory(fPtr).SetValue(aValue); 396 fValue := aValue; 397 end; 398 end; 399 end; 400 401 method SetBytes(aVal: go.builtin.Slice<Byte>); 402 begin 403 var lValue := fValue as go.builtin.Slice<Byte>; 404 if lValue = nil then 405 raise new Exception('Wrong type, need a Slice of bytes'); 406 407 lValue.Assign(aVal); 408 end; 409 410 method &SetInt(aVal: Int64); 411 begin 412 if (not CanSet) or not (Integer(Kind) in [Integer(go.reflect.Int)..Integer(go.reflect.Int64)]) then 413 raise new Exception('Can not set object to integer value'); 414 415 {$IF ECHOES} 416 if (aVal ≥ :go.math.MinInt32) and (aVal ≤ :go.math.MaxInt32) then // .net runtime fails if a Int64 value try to set in a Int32 field, even if fit. 417 InternalSet(Integer(aVal)) 418 else 419 InternalSet(aVal); 420 {$ELSE} 421 InternalSet(aVal); 422 {$ENDIF} 423 end; 424 425 method &SetBool(aVal: Boolean); 426 begin 427 if (not CanSet) or (Kind ≠ go.reflect.Bool) then 428 raise new Exception('Can not set object to bool value'); 429 430 InternalSet(aVal); 431 end; 432 433 method &SetUint(aVal: UInt64); 434 begin 435 if (not CanSet) or not (Integer(Kind) in [Integer(go.reflect.Uint)..Integer(go.reflect.Uint64)]) then 436 raise new Exception('Can not set object to unsigned integer value'); 437 438 InternalSet(aVal); 439 end; 440 441 method &SetFloat(aVal: Double); 442 begin 443 if (not CanSet) or ((Kind ≠ go.reflect.Float32) and (Kind ≠ go.reflect.Float64)) then 444 raise new Exception('Can not set object to float value'); 445 446 InternalSet(aVal); 447 end; 448 449 method &SetComplex(aVal: go.builtin.complex128); 450 begin 451 raise new NotImplementedException; 452 end; 453 454 method &SetString(aVal: go.builtin.string); 455 begin 456 if (not CanSet) or (Kind ≠ go.reflect.String) then 457 raise new Exception('Can not set object to string value'); 458 459 InternalSet(aVal); 460 end; 461 462 method &Type: &Type; 463 begin 464 result := fType; 465 end; 466 467 method Bytes: go.builtin.Slice<Byte>; 468 begin 469 var lValue := InternalGetValue; 470 if lValue is go.builtin.Slice<Byte> then 471 exit lValue as go.builtin.Slice<Byte> 472 else 473 raise new Exception('Wrong type, need a Slice of bytes'); 474 end; 475 476 method Kind: Kind; 477 begin 478 if fType = nil then 479 result := go.reflect.Invalid 480 else 481 result := fType.Kind; 482 end; 483 484 method Len: Integer; 485 begin 486 var lKind := Kind(); 487 var lValue := InternalGetValue; 488 489 case lKind of 490 go.reflect.Slice: 491 exit go.builtin.ISlice(lValue).getLen(); 492 493 go.reflect.Array: 494 exit System.Array(lValue).Length; 495 496 go.reflect.Map: 497 exit go.builtin.IMap(lValue).GetLen(); 498 499 go.reflect.String: 500 exit go.builtin.string(lValue).Length; 501 502 go.reflect.Chan: 503 exit go.builtin.IChannel(lValue).Length; 504 505 else 506 raise new Exception("Wrong type calling reflect.Len method"); 507 end; 508 end; 509 510 method InternalGetValue: Object; private; 511 begin 512 var lType := TypeImpl(fType).RealType; 513 if lType.IsValueType then begin 514 {$IF ECHOES} 515 var lFieldValue := lType.GetField('Value'); 516 {$ELSE} 517 var lFieldValue := lType.Fields.FirstOrDefault(a -> a.Name = 'Value'); 518 {$ENDIF} 519 if lFieldValue = nil then 520 exit fValue; 521 var lValue: Object; 522 if fExtended <> nil then begin 523 //lValue := (fExtended as FieldInfo).GetValue(if fPtr is go.builtin.IReference then go.builtin.IReference(fPtr).Get else fPtr); 524 lValue := (fExtended as FieldInfo).GetValue(if fPtr is IMemory then IMemory(fPtr).GetValue else fPtr); 525 end 526 else 527 lValue := fValue; 528 exit lFieldValue.GetValue(lValue); 529 end 530 else 531 exit fValue; 532 end; 533 534 method &Index(i: Integer): Value; 535 begin 536 var lKind := Kind; 537 if (lKind <> &Array) and (lKind <> go.reflect.Slice) and (lKind <> go.reflect.String) then 538 raise new Exception("Wrong type, need array, slice or string"); 539 540 //var lValue := if fValue is Memory<Object> then Memory<Object>.Get(Memory<Object>(fValue)) else fValue; 541 var lValue := InternalGetValue; 542 // TODO need to create and return a reference here??? 543 case lKind of 544 go.reflect.Slice: 545 result := new Value(go.builtin.ISlice(lValue).getAtIndex(i), ValueExtendedInfo.Slice, lValue, i); 546 547 go.reflect.Array: 548 {$IF ISLAND} 549 result := new Value(System.Array(lValue).Get(i)); 550 {$ELSEIF ECHOES} 551 result := new Value(System.Array(lValue).GetValue(i)); 552 {$ENDIF} 553 554 go.reflect.String: 555 result := new Value(go.builtin.string(lValue)[i]); 556 end; 557 end; 558 559 method SetMapIndex(key: Value; val: Value); 560 begin 561 if Kind ≠ go.reflect.Map then 562 raise new Exception("Wrong type, need a map"); 563 564 go.builtin.IMap(fValue).SetReflectKeyValue(key, val); 565 end; 566 567 method NumField: Integer; 568 begin 569 result := fType.NumField; 570 end; 571 572 method NumMethod: Integer; 573 begin 574 result := fType.NumMethod; 575 end; 576 577 method Field(i: Integer): Value; 578 begin 579 {$IF ISLAND} 580 var lFields := TypeImpl(fType).fTrueType.Fields.ToArray(); 581 var lValue := InternalGetValue; 582 result := new Value(lFields[i].GetValue(lValue), new TypeImpl(lFields[i].Type), new Memory<Object>(lValue), lFields[i]); 583 {$ELSEIF ECHOES} 584 var lFields := System.Reflection.TypeInfo(TypeImpl(fType).fTrueType).DeclaredFields.ToArray(); 585 var lValue := InternalGetValue; 586 result := new Value(lFields[i].GetValue(lValue), new TypeImpl(lFields[i].FieldType), new Memory<Object>(lValue), lFields[i]); 587 {$ENDIF} 588 end; 589 590 method FieldByName(name: String): tuple of (StructField, Boolean); 591 begin 592 var lField: &PlatformField; 593 {$IF ISLAND} 594 lField := TypeImpl(fType).fTrueType.Fields.Where(a->a.Name = name).FirstOrDefault; 595 {$ELSEIF ECHOES} 596 lField := System.Reflection.TypeInfo(TypeImpl(fType).fTrueType).DeclaredFields.Where(a->a.Name = name).FirstOrDefault; 597 {$ENDIF} 598 if lField ≠ nil then 599 exit(new StructFieldImpl(lField), true) 600 else 601 exit(nil, false); 602 end; 603 604 /*method FieldByName(name: go.builtin.string): Value; 605 begin 606 raise new NotImplementedException; 607 end;*/ 608 609 method CanAddr: Boolean; 610 begin 611 result := true; 612 // TODO check when returns false 613 //raise new NotImplementedException; 614 end; 615 616 method Call(inn: go.builtin.Slice<Value>): go.builtin.Slice<Value>; 617 begin 618 raise new NotImplementedException; 619 end; 620 621 method Addr: Value; 622 begin 623 result := new Memory<Value>(fValue); 624 end; 625 626 method MapRange() :Memory<MapIter>; 627 begin 628 if fType.Kind ≠ Map then 629 raise new Exception('Wrong type, need a map'); 630 631 var lIter := new MapIter(go.builtin.IMap(fValue).GetReflectSequence().GetEnumerator()); 632 result := new Memory<MapIter>(lIter); 633 end; 634 635 method &Interface: Object; 636 begin 637 exit fValue; 638 end; 639 640 method Elem: Value; 641 begin 642 if fValue is IMemory then begin 643 var lType := TypeImpl(fType).RealType; 644 var lRealType: PlatformType; 645 {$IF ISLAND} 646 lRealType := lType.GenericArguments.FirstOrDefault; 647 {$ELSEIF ECHOES} 648 lRealType := lType.GenericTypeArguments[0]; 649 {$ENDIF} 650 //exit new Value(go.builtin.IReference(fValue).Get, new TypeImpl(lRealType), fValue); 651 exit new Value(IMemory(fValue).GetValue, new TypeImpl(lRealType), fValue); 652 end; 653 raise new NotSupportedException; 654 end; 655 656 method &Implements(u: &Type): Boolean; 657 begin 658 result := fType.Implements(u); 659 end; 660 661 method &AssignableTo(u: &Type): Boolean; 662 begin 663 result := fType.AssignableTo(u); 664 end; 665 666 method &ConvertibleTo(u: &Type): Boolean; 667 begin 668 result := fType.ConvertibleTo(u); 669 end; 670 671 end; 672 673 &Type = public interface 674 method Align: Integer; 675 method FieldAlign: Integer; 676 method &Method(i: Integer): &Method; 677 method MethodByName(s: String): tuple of (&Method, Boolean); 678 method NumMethod: Integer; 679 method Name: String; 680 method PkgPath: String; 681 method Size: UIntPtr; 682 method String: String; 683 method Kind: Kind; 684 method Implements(u: &Type): Boolean; 685 method AssignableTo(u: &Type): Boolean; 686 method ConvertibleTo(u: &Type): Boolean; 687 method Comparable: Boolean; 688 method Bits: Integer; 689 method ChanDir: ChanDir; 690 method IsVariadic: Boolean; 691 method Elem: &Type; 692 method Field(i: Integer): StructField; 693 method FieldByIndex(i: go.builtin.Slice<Int64>): StructField; 694 method FieldByName(aname: String): tuple of (StructField, Boolean); 695 method FieldByNameFunc(match: delegate(aName: String): Boolean): tuple of (StructField, Boolean); 696 method &In(i: Integer): &Type; 697 method Key: &Type; 698 method Len: Integer; 699 method NumField: Integer; 700 method NumIn: Integer; 701 method NumOut: Integer; 702 method &Out(i: Integer): &Type; 703 end; 704 705 [AliasSemantics] 706 StructTag = public record 707 public 708 Value: String; 709 710 constructor(aValue: String); 711 begin 712 Value := aValue; 713 end; 714 715 method Get(key: String): String; 716 begin 717 var lResult := Lookup(key); 718 result := lResult[0]; 719 end; 720 721 method Lookup(key: String): tuple of (String, Boolean); 722 begin 723 var lPos := Value.IndexOf(key + ':'); 724 if lPos ≥ 0 then begin 725 var lResult := Value.Substring(lPos + key.Length + 1).Trim(['"', '''', ' ']); 726 exit (lResult, true); 727 end 728 else 729 result := ('', false); 730 end; 731 end; 732 733 StructField = public interface 734 method IsValid: Boolean; 735 method &Interface: Object; 736 property Name: String read; 737 property PkgPath: String read; 738 property &Type: &Type read; 739 property Tag: StructTag read; 740 property Offset: UIntPtr read; 741 property &Index: go.builtin.Slice<Int64> read; 742 property Anonymous: Boolean read; 743 end; 744 745 PlatformField = public {$IFDEF ECHOES}System.Reflection.FieldInfo{$ELSE}RemObjects.Elements.System.FieldInfo{$ENDIF}; 746 StructFieldImpl = class(StructField) 747 private 748 fField: PlatformField; 749 public 750 constructor(aField: PlatformField); 751 begin 752 fField := aField; 753 PkgPath := ''; 754 var lTag := ''; 755 if aField ≠ nil then begin 756 {$IF ISLAND} 757 var lAttrs := aField.Attributes.Where(b->b.Type = TypeOf(go.builtin.TagAttribute)).ToList; 758 if (lAttrs ≠ nil) and (lAttrs.Count > 0) then 759 lTag := go.builtin.PlatformString(lAttrs[0].Arguments[0].Value); 760 {$ELSEIF ECHOES} 761 var lAttrs := aField.GetCustomAttributes(true); 762 if lAttrs.Length > 0 then begin 763 if lAttrs[0] is go.builtin.TagAttribute then 764 lTag := (lAttrs[0] as go.builtin.TagAttribute).Tag; 765 end; 766 {$ENDIF} 767 end; 768 Tag := new StructTag(lTag); 769 &Index := new go.builtin.Slice<Int64>(1); 770 end; 771 772 constructor(aField: PlatformField; aIndex: Integer); 773 begin 774 constructor(aField); 775 &Index[0] := aIndex; 776 end; 777 778 method IsValid: Boolean; 779 begin 780 result := (fField ≠ nil) and (fField.Name ≠ ''); 781 end; 782 783 method &Interface: Object; 784 begin 785 result := self; 786 end; 787 788 property Name: String read fField.Name; 789 property PkgPath: String read; 790 property &Type: &Type read {$IF ISLAND}new TypeImpl(fField.&Type){$ELSEIF ECHOES}new TypeImpl(fField.FieldType){$ENDIF}; 791 property Tag: StructTag read; 792 property Offset: UIntPtr read; 793 property &Index: go.builtin.Slice<Int64> read; 794 property Anonymous: Boolean read; 795 end; 796 797 &Method = public interface 798 property Name: String read; 799 property PkgPath: String read; 800 property &Type: &Type read; 801 property Func: Value read; 802 property &Index: Integer read; 803 end; 804 805 PlatformMethod = public {$IFDEF ECHOES}System.Reflection.MethodInfo{$ELSE}RemObjects.Elements.System.MethodInfo{$ENDIF}; 806 MethodImpl = class(&Method) 807 private 808 fMethod: PlatformMethod; 809 810 method get_Index: Integer; 811 begin 812 {$IF ISLAND} 813 result := fMethod.DeclaringType.Methods.ToList.IndexOf(fMethod); 814 {$ELSEIF ECHOES} 815 result := System.Array.IndexOf(fMethod.DeclaringType.GetMethods, fMethod); 816 {$ENDIF} 817 end; 818 819 public 820 constructor(aMethod: PlatformMethod); 821 begin 822 fMethod := aMethod; 823 end; 824 825 property Name: String read fMethod.Name; 826 property PkgPath: String read; 827 property &Type: &Type read {$IF ISLAND}new TypeImpl(fMethod.&Type){$ELSEIF ECHOES}new TypeImpl(fMethod.ReturnType){$ENDIF}; 828 property Func: Value read; 829 property &Index: Integer read get_Index; 830 end; 831 832 PlatformType = public {$IFDEF ECHOES}System.Type{$ELSE}RemObjects.Elements.System.Type{$ENDIF}; 833 TypeImpl = public class(&Type) 834 private 835 assembly 836 fRealType: PlatformType; 837 fTrueType: PlatformType; // used for ValueType 838 839 method IsInteger: Boolean; 840 begin 841 var lKind := self.Kind; 842 result := (Integer(lKind) ≥ Integer(go.reflect.Bool)) and (Integer(lKind) ≤ Integer(go.reflect.Uint64)); 843 end; 844 845 method IsFloatOrComplex: Boolean; 846 begin 847 var lKind := self.Kind; 848 result := (Integer(lKind) ≥ Integer(go.reflect.Float32)) and (Integer(lKind) ≤ Integer(go.reflect.Complex128)); 849 end; 850 851 public 852 853 property RealType: PlatformType read fRealType; 854 855 constructor(aType: PlatformType); 856 begin 857 fRealType := aType; 858 {$IF ISLAND} 859 var lCtors := fRealType.Methods.Where(a -> (MethodFlags.Constructor in a.Flags)).ToArray; 860 var lFields := fRealType.Fields.ToArray; 861 if fRealType.IsValueType and (lCtors.Count = 2) and (lFields.Count = 1) then 862 fTrueType := lFields[0].Type 863 else 864 fTrueType := fRealType; 865 {$ELSEIF ECHOES} 866 if fRealType.IsValueType and (fRealType.GetConstructors().Count = 2) and (fRealType.GetFields().Count = 1) then 867 fTrueType := fRealType.GetFields()[0].FieldType 868 else 869 fTrueType := fRealType; 870 {$ENDIF} 871 end; 872 873 method Align: Integer; 874 begin 875 raise new NotImplementedException; 876 end; 877 878 method FieldAlign: Integer; 879 begin 880 raise new NotImplementedException; 881 end; 882 883 method &Method(i: Integer): &Method; 884 begin 885 if (i < 0) or (i ≥ NumMethod) then 886 raise new Exception('Wrong method index'); 887 888 {$IF ISLAND} 889 result := new MethodImpl(fTrueType.Methods.ToList[i]); 890 {$ELSEIF ECHOES} 891 result := new MethodImpl(fTrueType.GetMethods[i]); 892 {$ENDIF} 893 end; 894 895 method MethodByName(s: String): tuple of (&Method, Boolean); 896 begin 897 var lMethod: &PlatformMethod; 898 {$IF ISLAND} 899 lMethod := fTrueType.Methods.Where(a->a.Name = s).FirstOrDefault; 900 {$ELSEIF ECHOES} 901 lMethod := System.Array.Find(fTrueType.GetMethods, a->a.Name = s); 902 {$ENDIF} 903 exit(new MethodImpl(lMethod), lMethod ≠ nil); 904 end; 905 906 method NumMethod: Integer; 907 begin 908 {$IF ISLAND} 909 if Kind = go.reflect.Interface then 910 exit 0 911 else 912 result := fTrueType.Methods.Count; 913 {$ELSEIF ECHOES} 914 // TODO!! do this in a better way 915 if Kind = go.reflect.Interface then 916 exit 0 917 else 918 result := fTrueType.GetMethods.Length; 919 {$ENDIF} 920 end; 921 922 method Name: String; 923 begin 924 result := fRealType.Name; 925 end; 926 927 method PkgPath: String; 928 begin 929 raise new NotImplementedException; 930 end; 931 932 method Size: UIntPtr; 933 begin 934 {$IF ISLAND} 935 result := fRealType.SizeOfType; 936 {$ELSEIF ECHOES} 937 result := System.Runtime.InteropServices.Marshal.SizeOf(fRealType); 938 {$ENDIF} 939 end; 940 941 method String: String; 942 begin 943 result := fRealType.Name; 944 end; 945 946 method Kind: Kind; 947 begin 948 if fTrueType = nil then 949 exit go.reflect.Invalid; 950 {$IF ISLAND} 951 if (fTrueType = TypeOf(go.builtin.string)) and not ((fTrueType.Flags and IslandTypeFlags.TypeKindMask) = IslandTypeFlags.Array) then 952 exit go.reflect.String; 953 954 if fTrueType.IsDelegate then 955 exit go.reflect.Func; 956 957 if fTrueType.Name.StartsWith('gt2_@') then begin 958 //if (fTrueType.Flags and IslandTypeFlags.TypeKindMask) = IslandTypeFlags.Array then begin 959 exit go.reflect.Array; 960 end; 961 962 if (fTrueType.GenericArguments <> nil) and (fTrueType.GenericArguments.Count > 0) then begin 963 if fTrueType.Name.Contains('go.builtin.Slice') then 964 exit go.reflect.Slice; 965 966 if fTrueType.Name.Contains('go.builtin.BidirectionalChannel') then 967 exit go.reflect.Map 968 else 969 exit go.reflect.Ptr; 970 end; 971 972 if fTrueType = TypeOf(Object) then 973 exit go.reflect.Interface; 974 975 case fTrueType.Code of 976 TypeCodes.Boolean: result := go.reflect.Bool; 977 TypeCodes.Char: result := go.reflect.Uint16; 978 TypeCodes.SByte: result := go.reflect.Int8; 979 TypeCodes.Byte: result := go.reflect.UInt8; 980 TypeCodes.Int16: result := go.reflect.Int16; 981 TypeCodes.UInt16: result := go.reflect.Uint16; 982 TypeCodes.Int32: result := go.reflect.Int32; 983 TypeCodes.UInt32: result := go.reflect.Uint32; 984 TypeCodes.Int64: result := go.reflect.Int64; 985 TypeCodes.UInt64: result := go.reflect.Uint64; 986 TypeCodes.Single: result := go.reflect.Float32; 987 TypeCodes.Double: result := go.reflect.Float64; 988 TypeCodes.UIntPtr: result := go.reflect.UintPtr; 989 TypeCodes.IntPtr: result := go.reflect.Ptr; 990 TypeCodes.String: result := go.reflect.String; 991 TypeCodes.Object: result := go.reflect.Struct; 992 TypeCodes.None: begin 993 case (fTrueType.Flags and IslandTypeFlags.TypeKindMask) of 994 IslandTypeFlags.Array: exit go.reflect.Array; 995 IslandTypeFlags.Struct: exit go.reflect.Struct; 996 IslandTypeFlags.Interface: exit go.reflect.Interface; 997 IslandTypeFlags.Generic: exit go.reflect.Ptr; 998 default: exit go.reflect.Struct; 999 end; 1000 end; 1001 end; 1002 {$ELSEIF ECHOES} 1003 if (fTrueType = TypeOf(go.builtin.string)) and (not fTrueType.IsArray) then 1004 exit go.reflect.String; 1005 1006 if fTrueType.IsArray then 1007 exit go.reflect.Array; 1008 1009 if fTrueType.IsInterface then 1010 exit go.reflect.Interface; 1011 1012 if fTrueType.BaseType = TypeOf(System.MulticastDelegate) then 1013 exit go.reflect.Func; 1014 1015 if fTrueType.GenericTypeArguments.Length > 0 then 1016 if fTrueType.AssemblyQualifiedName.StartsWith('go.builtin.Slice') then 1017 exit go.reflect.Slice 1018 else 1019 if fTrueType.AssemblyQualifiedName.StartsWith('go.builtin.BidirectionalChannel') then 1020 exit go.reflect.Map 1021 else 1022 exit go.reflect.Ptr; 1023 1024 if fTrueType = TypeOf(System.Object) then 1025 exit go.reflect.Interface; 1026 1027 if fTrueType = TypeOf(System.UIntPtr) then 1028 exit go.reflect.Uintptr; 1029 1030 case System.Type.GetTypeCode(fTrueType) of 1031 TypeCode.Boolean: result := go.reflect.Bool; 1032 TypeCode.Byte: result := go.reflect.UInt8; 1033 TypeCode.SByte: result := go.reflect.Int8; 1034 TypeCode.Int16: result := go.reflect.Int16; 1035 TypeCode.UInt16: result := go.reflect.Uint16; 1036 TypeCode.Int32: result := go.reflect.Int32; 1037 TypeCode.UInt32: result := go.reflect.Uint32; 1038 TypeCode.Int64: result := go.reflect.Int64; 1039 TypeCode.UInt64: result := go.reflect.Uint64; 1040 TypeCode.Single: result := go.reflect.Float32; 1041 TypeCode.Double: result := go.reflect.Float64; 1042 TypeCode.String: result := go.reflect.String; 1043 TypeCode.Char: result := go.reflect.Uint16; 1044 TypeCode.Object: 1045 begin 1046 // check ValueType 1047 var lTrueType: PlatformType; 1048 if fRealType.IsValueType {and (fRealType.GetConstructors().Count = 2)} and (fRealType.GetFields().Count = 1) then 1049 lTrueType := fRealType.GetFields()[0].FieldType 1050 else 1051 exit go.reflect.Struct; 1052 exit new &TypeImpl(lTrueType).Kind; 1053 end; 1054 TypeCode.Empty: result := go.reflect.Invalid; 1055 end; 1056 {$ENDIF} 1057 end; 1058 1059 method Implements(u: &Type): Boolean; 1060 begin 1061 result := fRealType.IsSubclassOf(TypeImpl(u).fRealType); 1062 end; 1063 1064 method AssignableTo(u: &Type): Boolean; 1065 begin 1066 if u = nil then 1067 raise new Exception('nil type in AssignableTo'); 1068 1069 if Kind = go.reflect.interface then 1070 result := true 1071 else 1072 result := TypeImpl(u).fRealType.IsAssignableFrom(self.fRealType); 1073 end; 1074 1075 method ConvertibleTo(u: &Type): Boolean; 1076 begin 1077 if u = nil then 1078 raise new Exception('nil type in ConvertibleTo'); 1079 1080 if AssignableTo(u) then 1081 exit(true); 1082 1083 // TODO Check underlying type 1084 1085 if (IsInteger or IsFloatOrComplex) and (TypeImpl(u).IsInteger or TypeImpl(u).IsFloatOrComplex) then 1086 exit(true); 1087 1088 var lUKind := u.Kind; 1089 if (IsInteger or (Kind = go.reflect.String) or (Kind = go.reflect.Slice)) and (lUKind = go.reflect.String) then 1090 exit(true); 1091 1092 if (Kind = go.reflect.String) and (TypeImpl(u).IsInteger or (lUKind = go.reflect.String) or (lUKind = go.reflect.Slice)) then 1093 exit(true); 1094 1095 exit(false); 1096 end; 1097 1098 method Comparable: Boolean; 1099 begin 1100 result := Kind <> go.reflect.Func; 1101 end; 1102 1103 method Bits: Integer; 1104 begin 1105 if IsInteger or IsFloatOrComplex then 1106 result := sizeOf(fTrueType) * 8 // size in bits... 1107 else 1108 raise new Exception("Wrong type calling Bits method"); 1109 end; 1110 1111 method ChanDir: ChanDir; 1112 begin 1113 raise new NotImplementedException; 1114 end; 1115 1116 method IsVariadic: Boolean; 1117 begin 1118 raise new NotImplementedException; 1119 end; 1120 1121 method Elem: &Type; 1122 begin 1123 //if IsMemoryType(fTrueType) then begin 1124 var lKind := Kind; 1125 if (lKind = go.reflect.ptr) or (lKind = go.reflect.slice) or (lKind = go.reflect.chan) then begin 1126 var lRealType: PlatformType; 1127 {$IF ISLAND} 1128 lRealType := fTrueType.GenericArguments.FirstOrDefault; 1129 {$ELSEIF ECHOES} 1130 lRealType := fTrueType.GenericTypeArguments[0]; 1131 {$ENDIF} 1132 exit new TypeImpl(lRealType); 1133 end; 1134 end; 1135 1136 method Field(i: Integer): StructField; 1137 begin 1138 if Kind ≠ go.reflect.Struct then 1139 raise new Exception('Wrong type, it needs to be struct'); 1140 {$IF ISLAND} 1141 var lFields := fTrueType.Fields.ToList(); 1142 if i ≥ lFields.Count then 1143 raise new IndexOutOfRangeException('Index out of range'); 1144 {$ELSEIF ECHOES} 1145 var lFields := System.Reflection.TypeInfo(fTrueType).DeclaredFields.ToArray(); 1146 if i ≥ lFields.Length then 1147 raise new IndexOutOfRangeException('Index out of range'); 1148 {$ENDIF} 1149 result := new StructFieldImpl(lFields[i], i); 1150 end; 1151 1152 method FieldByIndex(i: go.builtin.Slice<Int64>): StructField; 1153 begin 1154 if Kind ≠ go.reflect.Struct then 1155 raise new Exception('Wrong type, it needs to be struct'); 1156 1157 var lType := self; 1158 for lIndex: Integer := 0 to i.Length - 1 do begin 1159 result := lType.Field(i[lIndex]); 1160 lType := TypeImpl(result.Type); 1161 end; 1162 end; 1163 1164 method FieldByName(aname: String): tuple of (StructField, Boolean); 1165 begin 1166 var lField: &PlatformField; 1167 {$IF ISLAND} 1168 lField := fTrueType.Fields.Where(a->a.Name = aname).FirstOrDefault; 1169 {$ELSEIF ECHOES} 1170 lField := System.Reflection.TypeInfo(fTrueType).DeclaredFields.Where(a->a.Name = aname).FirstOrDefault; 1171 {$ENDIF} 1172 // TODO field index 1173 exit(new StructFieldImpl(lField), lField ≠ nil); 1174 end; 1175 1176 method FieldByNameFunc(match: delegate(aName: String): Boolean): tuple of (StructField, Boolean); 1177 begin 1178 var lField: &PlatformField; 1179 {$IF ISLAND} 1180 lField := fTrueType.Fields.Where(a -> match(a.Name)).FirstOrDefault; 1181 {$ELSEIF ECHOES} 1182 lField := TypeInfo(fTrueType).DeclaredFields.Where((a) -> match(a.Name)).FirstOrDefault; 1183 {$ENDIF} 1184 // TODO field index 1185 exit(new StructFieldImpl(lField), lField ≠ nil); 1186 end; 1187 1188 method &In(i: Integer): &Type; 1189 begin 1190 if Kind ≠ go.reflect.Func then 1191 raise new Exception('Wrong type, it needs to be Func'); 1192 {$IF ISLAND} 1193 var lMethod := fRealType.Methods.Where(a -> a.Name = 'Invoke').FirstOrDefault; 1194 var lParameters := lMethod.Arguments.ToList(); 1195 if lParameters.Count ≤ i then 1196 raise new IndexOutOfRangeException('Index out of range'); 1197 result := new TypeImpl(lParameters[i].Type); 1198 {$ELSEIF ECHOES} 1199 var lMethod := fRealType.GetMethod('Invoke'); 1200 var lParameters := lMethod.GetParameters(); 1201 if lParameters.Length ≤ i then 1202 raise new IndexOutOfRangeException('Index out of range'); 1203 result := new TypeImpl(lParameters[i].ParameterType); 1204 {$ENDIF} 1205 end; 1206 1207 method Key: &Type; 1208 begin 1209 raise new NotImplementedException; 1210 end; 1211 1212 method Len: Integer; 1213 begin 1214 raise new NotImplementedException; 1215 end; 1216 1217 method NumField: Integer; 1218 begin 1219 if Kind ≠ go.reflect.Struct then 1220 raise new Exception('Wrong type, it needs to be struct'); 1221 {$IF ISLAND} 1222 result := fTrueType.Fields.Count; 1223 {$ELSEIF ECHOES} 1224 result := System.Reflection.TypeInfo(fTrueType).DeclaredFields.ToArray().Length; 1225 {$ENDIF} 1226 end; 1227 1228 method NumIn: Integer; 1229 begin 1230 if Kind ≠ go.reflect.Func then 1231 raise new Exception('Wrong type, it needs to be Func'); 1232 {$IF ISLAND} 1233 var lMethod := fTrueType.Methods.Where(a -> a.Name = 'Invoke').FirstOrDefault; 1234 result := lMethod.Arguments.Count; 1235 {$ELSEIF ECHOES} 1236 var lMethod := fTrueType.GetMethod('Invoke'); 1237 result := lMethod.GetParameters().Length; 1238 {$ENDIF} 1239 end; 1240 1241 method NumOut: Integer; 1242 begin 1243 if Kind ≠ go.reflect.Func then 1244 raise new Exception('Wrong type, it needs to be Func'); 1245 {$IF ISLAND} 1246 var lMethod := fTrueType.Methods.Where(a -> a.Name = 'Invoke').FirstOrDefault; 1247 if lMethod.Type.GenericArguments.Count > 0 then 1248 result := lMethod.Type.Fields.Count 1249 else 1250 result := 1; 1251 {$ELSEIF ECHOES} 1252 var lMethod := fTrueType.GetMethod('Invoke'); 1253 if System.Reflection.TypeInfo(lMethod.ReturnType).IsGenericType and (System.Reflection.TypeInfo(lMethod.ReturnType).FullName.StartsWith('System.Tuple')) then 1254 result := System.Reflection.TypeInfo(lMethod.ReturnType).DeclaredFields.ToArray().Length 1255 else 1256 result := 1; 1257 {$ENDIF} 1258 end; 1259 1260 method &Out(i: Integer): &Type; 1261 begin 1262 if Kind ≠ go.reflect.Func then 1263 raise new Exception('Wrong type, it needs to be Func'); 1264 {$IF ISLAND} 1265 var lMethod := fTrueType.Methods.Where(a -> a.Name = 'Invoke').FirstOrDefault; 1266 var lParameters := lMethod.Type.Fields.ToList(); 1267 if lParameters.Count ≤ i then 1268 raise new IndexOutOfRangeException('Index out of range'); 1269 result := new TypeImpl(lParameters[i].Type); 1270 {$ELSEIF ECHOES} 1271 var lMethod := fTrueType.GetMethod('Invoke'); 1272 var lTotal := 1; 1273 if System.Reflection.TypeInfo(lMethod.ReturnType).IsGenericType and (System.Reflection.TypeInfo(lMethod.ReturnType).FullName.StartsWith('System.Tuple')) then 1274 lTotal := System.Reflection.TypeInfo(lMethod.ReturnType).DeclaredFields.ToArray().Length; 1275 1276 if lTotal < i then 1277 raise new IndexOutOfRangeException('Index out of range'); 1278 1279 if lTotal > 1 then 1280 result := new TypeImpl(System.Reflection.TypeInfo(lMethod.ReturnType).DeclaredFields.ToArray()[i].FieldType) 1281 else 1282 result := new TypeImpl(System.Reflection.TypeInfo(lMethod.ReturnType)); 1283 {$ENDIF} 1284 end; 1285 end; 1286 1287 method DeepEqual(a, b: Object): Boolean; public; 1288 begin 1289 var lAType := TypeOf(a); 1290 var lBType := TypeOf(b); 1291 1292 if (lAType = lBType) and (lAType.Kind = go.reflect.Struct) then begin 1293 {$IF ISLAND} 1294 var lAFields := TypeImpl(lAType).fTrueType.Fields.ToArray(); 1295 var lBFields := TypeImpl(lBType).fTrueType.Fields.ToArray(); 1296 {$ELSEIF ECHOES} 1297 var lAFields := System.Reflection.TypeInfo(TypeImpl(lAType).fTrueType).DeclaredFields.ToArray(); 1298 var lBFields := System.Reflection.TypeInfo(TypeImpl(lBType).fTrueType).DeclaredFields.ToArray(); 1299 {$ENDIF} 1300 if lAFields.Length ≠ lBFields.Length then 1301 exit false; 1302 for i: Integer := 0 to lAFields.Length - 1 do begin 1303 var lAValue := lAFields[i].GetValue(a); 1304 var lBValue := lBFields[i].GetValue(b); 1305 result := DeepEqual(lAValue, lBValue); 1306 if not result then 1307 exit; 1308 end; 1309 end 1310 else begin 1311 var lRealAType := TypeImpl(lAType).fTrueType; 1312 {$IF ISLAND} 1313 var lMethod := lRealAType.Methods.Where(m -> m.Name = 'op_Equality').FirstOrDefault; 1314 if lMethod ≠ nil then begin 1315 //result := lMethod.Invoke(lRealAType, [a, b]) as Boolean 1316 var lCaller := TEqualsMethod(lMethod.Pointer); 1317 result := lCaller(a, b); 1318 end 1319 else 1320 result := a.Equals(b); 1321 {$ELSEIF ECHOES} 1322 var lMethod := System.Array.Find(lRealAType.GetMethods, m -> m.Name = 'op_Equality'); 1323 if lMethod ≠ nil then 1324 result := lMethod.Invoke(lRealAType, [a, b]) as Boolean 1325 else 1326 result := Object.Equals(a, b); 1327 {$ENDIF} 1328 end; 1329 end; 1330 1331 Method &New(aType: &Type): Value;public; 1332 begin 1333 exit new Value(new Memory<Object>(Zero(aType)), aType); 1334 end; 1335 1336 method Zero(aType: &Type): Value;public; 1337 begin 1338 {$IFDEF ISLAND} 1339 if aType.Kind = go.reflect.string then 1340 exit new Value(go.builtin.string.Zero); 1341 1342 var lZero := TypeImpl(aType).fRealType.Properties.Where(a->a.Name = 'Zero').FirstOrDefault; 1343 if lZero <> nil then 1344 exit new Value(ZeroFunction(lZero.Read.Pointer)()); 1345 1346 if not TypeImpl(aType).RealType.IsValueType and (TypeImpl(aType).RealType.Methods.Any(a -> a.Name = '__Set')) then 1347 exit new Value(TypeImpl(aType).RealType.Instantiate()) 1348 else begin 1349 if TypeImpl(aType).fRealType.IsValueType then 1350 exit new Value(InternalCalls.Cast<Object>(DefaultGC.New(TypeImpl(aType).RealType.RTTI, sizeOf(^Void) + TypeImpl(aType).RealType.SizeOfType))) 1351 else 1352 exit new Value(nil); 1353 end; 1354 {$ELSE} 1355 if TypeImpl(aType).fRealType = System.Type.GetType('go.builtin.string') then 1356 exit new Value(go.builtin.string.Zero) // String .net does not have a constructor with no arguments. 1357 else begin 1358 var lZero := TypeImpl(aType).fRealType.GetProperty('Zero'); 1359 if lZero <> nil then 1360 exit new Value(lZero.GetValue(nil)); 1361 end; 1362 1363 if not TypeImpl(aType).RealType.IsValueType and (TypeImpl(aType).RealType.GetMethods.Any(a -> a.Name = '__Set')) then 1364 exit new Value(Activator.CreateInstance(TypeImpl(aType).RealType)) 1365 else 1366 if TypeImpl(aType).fRealType.IsValueType then 1367 exit new Value(Activator.CreateInstance(TypeImpl(aType).fRealType)) 1368 else 1369 exit new Value(nil); 1370 {$ENDIF} 1371 end; 1372 1373 method PtrTo(t: &Type): Memory<&Type>; public; 1374 begin 1375 result := new Memory<&Type>(t); 1376 end; 1377 1378 method ValueOf(i: Object): Value;public; 1379 begin 1380 exit new Value(i); 1381 end; 1382 1383 method Indirect(v: Value): Value;public; 1384 begin 1385 exit new Value(new Memory<Object>(v.fValue), v.fType); 1386 end; 1387 1388 method TypeOf(v: Object): &Type;public; 1389 begin 1390 result := new TypeImpl(v.GetType()); 1391 end; 1392 1393 method Swapper(aslice: Object): delegate(arg0: go.builtin.int; arg1: go.builtin.int); public; 1394 begin 1395 exit @go.sort.Interface(aslice).Swap; 1396 end; 1397 1398 method MakeMap(t: &Type): Value; public; 1399 begin 1400 raise new NotImplementedException; 1401 end; 1402 1403 method MakeMapWithSize(t: &Type;n: Integer): Value; public; 1404 begin 1405 raise new NotImplementedException; 1406 end; 1407 1408 method InternalGetValue(aVal: Value): Object; 1409 begin 1410 var lType := TypeImpl(aVal.fType).RealType; 1411 if lType.IsValueType then begin 1412 {$IF ECHOES} 1413 var lFieldValue := lType.GetField('Value'); 1414 {$ELSE} 1415 var lFieldValue := lType.Fields.FirstOrDefault(a -> a.Name = 'Value'); 1416 {$ENDIF} 1417 var lValue: Object; 1418 if aVal.fExtended <> nil then begin 1419 //lValue := (aVal.fExtended as FieldInfo).GetValue(if aVal.fPtr is go.builtin.IReference then go.builtin.IReference(aVal.fPtr).Get else aVal.fPtr); 1420 lValue := (aVal.fExtended as FieldInfo).GetValue(if aVal.fPtr is IMemory then IMemory(aVal.fPtr).GetValue else aVal.fPtr); 1421 end 1422 else 1423 lValue := aVal.fValue; 1424 exit lFieldValue.GetValue(lValue); 1425 end 1426 else 1427 exit aVal.fValue; 1428 end; 1429 1430 method Copy(dst: Value; src: Value): Integer; 1431 begin 1432 var lDstKind := dst.Kind; 1433 var lSrcKind := src.Kind; 1434 if not (((lDstKind = go.reflect.Slice) and (lSrcKind = go.reflect.Slice)) or ((lDstKind = go.reflect.Array) and (lSrcKind = go.reflect.Array)) 1435 or ((lDstKind = go.reflect.Slice) and (lSrcKind = go.reflect.String))) then 1436 raise new Exception("Wrong type on reflect.copy method"); 1437 1438 var lDst: go.builtin.ISlice; 1439 if dst.fExtendedInfo = ValueExtendedInfo.Slice then begin 1440 var lTmp := go.builtin.ISlice(dst.fPtr).getAtIndex(Integer(dst.fExtendedObject)); 1441 lDst := go.builtin.ISlice(InternalGetValue(new Value(lTmp))); 1442 end 1443 else 1444 lDst := go.builtin.ISlice(InternalGetValue(dst)); 1445 var lSrc := go.builtin.ISlice(InternalGetValue(src)); 1446 1447 result := Math.Min(if lSrc = nil then 0 else lSrc.getLen, if lDst = nil then 0 else lDst.getLen); 1448 for i: Integer := 0 to result -1 do 1449 lDst.setAtIndex(i, lSrc.getAtIndex(i)); 1450 end; 1451 1452 method InstantiateSlice(aType: PlatformType; aCount: Integer): Object; private; 1453 begin 1454 {$IF ISLAND} 1455 if aType.IsValueType then begin 1456 var lCtors := aType.Methods.Where(a -> (MethodFlags.Constructor in a.Flags)).ToArray; 1457 var lFields := aType.Fields.ToArray; 1458 if (lCtors.Count = 2) and (lFields.Count = 1) then begin 1459 //var lCtorType: MethodInfo := aType.Methods.where(a -> (MethodFlags.Constructor in a.Flags) and (a.Arguments.Count = 1) and (a.Arguments.ToArray[0].Type = lFields[0].Type)).FirstOrDefault; 1460 var lNewType := DefaultGC.New(aType.RTTI, aType.SizeOfType); 1461 result := InternalCalls.Cast<Object>(lNewType); 1462 ^SliceAlias(lNewType)^.aVal := InstantiateSlice(lFields[0].Type, aCount); 1463 exit; 1464 end; 1465 end; 1466 1467 var lCtor: MethodInfo := aType.Methods.FirstOrDefault(a -> (MethodFlags.Constructor in a.Flags) and (a.Arguments.Count = 1) and (a.Arguments.ToArray[0].Type.IsInteger)); 1468 var lRealCtor := SliceCtor(lCtor.Pointer); 1469 var lNew := DefaultGC.New(aType.RTTI, aType.SizeOfType); 1470 result := InternalCalls.Cast<Object>(lNew); 1471 lRealCtor(result, aCount); 1472 {$ELSEIF ECHOES} 1473 if aType.IsValueType and (aType.GetConstructors().Count = 2) and (aType.GetFields().Count = 1) then begin 1474 exit Activator.CreateInstance(aType, [InstantiateSlice(aType.GetFields()[0].FieldType, aCount)]); 1475 end; 1476 exit Activator.CreateInstance(aType, [aCount]); 1477 {$ENDIF} 1478 end; 1479 1480 method MakeSlice(t: &Type; len, cap: Integer): Value; 1481 begin 1482 result := new Value(InstantiateSlice(TypeImpl(t).fRealType, cap), new TypeImpl(TypeImpl(t).fRealType)); 1483 end; 1484 1485 method MakeFunc(typ: &Type; fn: delegate(args: go.builtin.Slice<Value>): go.builtin.Slice<Value>): Value; 1486 begin 1487 raise new NotImplementedException; 1488 end; 1489 1490 operator Equal(a, b: &Type): Boolean; public; 1491 begin 1492 if (a is TypeImpl) and (b is TypeImpl) then exit (TypeImpl(a).fRealType = TypeImpl(b).fRealType); 1493 exit Object.ReferenceEquals(a, b); 1494 end; 1495 1496 operator NotEqual(a, b: &Type): Boolean;public; 1497 begin 1498 exit not (a = b); 1499 end; 1500 1501 operator Equal(a: &Type; b: TypeImpl): Boolean;public; 1502 begin 1503 if not assigned(a) and not assigned(b) then 1504 exit true; 1505 1506 if not assigned(a) or not assigned(b) then 1507 exit false; 1508 1509 if (a is TypeImpl) then exit (TypeImpl(a).fRealType = b.fRealType); 1510 exit Object.ReferenceEquals(a, b); 1511 end; 1512 1513 operator Equal(a: TypeImpl; b: &Type): Boolean;public; 1514 begin 1515 if (b is TypeImpl) then exit (a.fRealType = TypeImpl(b).fRealType); 1516 exit Object.ReferenceEquals(a, b); 1517 end; 1518 1519 operator Equal(a: TypeImpl; b: TypeImpl): Boolean;public; 1520 begin 1521 exit (a.fRealType = b.fRealType); 1522 exit Object.ReferenceEquals(a, b); 1523 end; 1524 1525 method Append(s: Value; params x: array of Value): Value; 1526 begin 1527 var lSlice := go.builtin.ISlice(s.fValue); 1528 var lNewValue: go.reflect.Value; 1529 for each lValue in x do 1530 lNewValue := lSlice.AppendObject(lValue.fValue); 1531 1532 exit lNewValue; 1533 end; 1534 1535 method Append(s: Value; x: go.builtin.Slice<Value>): Value; 1536 begin 1537 raise new NotImplementedException; 1538 end; 1539 1540 method AppendSlice(s: Value; x: Value): Value; 1541 begin 1542 raise new NotImplementedException; 1543 end; 1544 1545 method SliceOf(t: &Type): &Type; 1546 begin 1547 raise new NotImplementedException; 1548 end; 1549 1550 method NewAt(t: &Type; p: go.unsafe.Pointer): Value; 1551 begin 1552 raise new NotImplementedException; 1553 end; 1554 1555 method IsMemoryType(aType: PlatformType): Boolean; assembly; 1556 begin 1557 {$IF ECHOES} 1558 if aType.FullName.StartsWith('RemObjects.Elements.System.Memory') then 1559 exit true; 1560 {$ELSE} 1561 if aType.Name.StartsWith('RemObjects.Elements.System.Memory`1') then 1562 exit true; 1563 {$ENDIF} 1564 result := false; 1565 end; 1566 1567 end.