{$MODE OBJFPC} { -*- delphi -*- }
{$INCLUDE settings.inc}
{$WARNINGS OFF}
{$HINTS OFF}
program test;
uses
   variants, sysutils;

type
   TInvokableVariant = class
     protected
      constructor Create(); virtual; abstract; overload;
      constructor Copy(Previous: TInvokableVariant); virtual; abstract; overload;
      function AsString(): UTF8String; virtual;
      function AsDouble(): Double; virtual;
      function AsInteger(): Integer; virtual;
      function AsBoolean(): Boolean; virtual;
      function Call(const Name: ShortString; const Arguments: array of const): TInvokableVariant; virtual;
      function GetProperty(const Name: ShortString): TInvokableVariant; virtual;
      function SetProperty(const Name: ShortString; const Value: TInvokableVariant): Boolean; virtual;
   end;

// implementation

type
   TInvokableVariantManager = class(TInvokeableVariantType)
    private
     class var Singleton: TInvokableVariantManager;
     class constructor Init();
     class destructor Done();
    public
     type
      TCastVarData = packed record
        public
         VarType: TVarType;
        private
         Res1, Res2, Res3: Word;
        public
         Value: TInvokableVariant;
        private
         {$ifdef FPC_HASFIXED64BITVARIANT}
           Res4: Pointer;
         {$endif FPC_HASFIXED64BITVARIANT}
      end;
     procedure Clear(var V: TVarData); override;
     procedure Cast(var Dest: TVarData; const Source: TVarData); override;
     procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override;
     procedure CastToOle(var Dest: TVarData; const Source: TVarData); override;
     procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
     procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); override;
     procedure UnaryOp(var Right: TVarData; const Operation: TVarOp); override;
     function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; override;
     // Compare() is never invoked by FreePascal
     function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; override;
     function DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; override;
     function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; override;
     function SetProperty(var V: TVarData; const Name: string; const Value: TVarData): Boolean; override;
   end;

class constructor TInvokableVariantManager.Init();
begin
   Singleton := TInvokableVariantManager.Create();
end;

class destructor TInvokableVariantManager.Done();
begin
   FreeAndNil(Singleton);
end;

procedure TInvokableVariantManager.Clear(var V: TVarData);
begin
   FreeAndNil(TCastVarData(V).Value);
   V.VType := varEmpty;
end;

procedure TInvokableVariantManager.Cast(var Dest: TVarData; const Source: TVarData);
begin
   
end;

procedure TInvokableVariantManager.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
begin
end;

procedure TInvokableVariantManager.CastToOle(var Dest: TVarData; const Source: TVarData);
begin
end;

procedure TInvokableVariantManager.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
begin
   Assert(Indirect = False); // Indirect is never set to True by FreePascal
end;

procedure TInvokableVariantManager.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
begin
end;

procedure TInvokableVariantManager.UnaryOp(var Right: TVarData; const Operation: TVarOp);
begin
end;

function TInvokableVariantManager.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean;
begin
end;

function TInvokableVariantManager.DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
begin
end;

function TInvokableVariantManager.DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
begin
end;

function TInvokableVariantManager.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
begin
end;

function TInvokableVariantManager.SetProperty(var V: TVarData; const Name: string; const Value: TVarData): Boolean;
begin
end;

operator := (Value: TInvokableVariant): Variant;
var
   CastResult: TInvokableVariantManager.TCastVarData absolute Result;
begin
   if (not Assigned(Value)) then
   begin
      Result := nil;
   end
   else
   begin
      VarClear(Result);
      CastResult.VarType := TInvokableVariantManager.Singleton.VarType;
      CastResult.Value := Value;
   end;
end;

// program

type
   TJSON = class(TInvokableVariant)
     public
      constructor Create(); override;
      constructor Copy(Previous: TInvokableVariant); override;
     protected
   end;

constructor TJSON.Create();
begin
end;

constructor TJSON.Copy(Previous: TInvokableVariant);
begin
   Assert(Previous is ClassType);
end;

procedure RunTest();
var
   J: TJSON;
   V: Variant;
begin
   J := nil;
   V := J;
end;

begin
   RunTest();
end.