unit srNode;

{$mode objfpc}{$H+}

interface

type
 PsrNode=^TsrNode;
 PPsrNode=^PsrNode;

 PPrepTypeNode=^TPrepTypeNode;
 TPrepTypeNode=record
  dnode:PsrNode;
  rtype:Integer;
 end;

 TsrNodeVmt=class
   class Procedure add_read    (node,src:PsrNode);             virtual;
   class Procedure rem_read    (node,src:PsrNode);             virtual;
   //
   class Procedure add_write   (node,src:PsrNode);             virtual;
   class Procedure rem_write   (node,src:PsrNode);             virtual;
   //
   class Procedure mark_read   (node,src:PsrNode);             virtual;
   class Procedure mark_unread (node,src:PsrNode);             virtual;
   //
   class Procedure zero_read   (node:PsrNode);                 virtual;
   class Procedure zero_unread (node:PsrNode);                 virtual;
   //
   class Procedure mark_write  (node,src:PsrNode);             virtual;
   class Procedure mark_unwrite(node,src:PsrNode);             virtual;
   //
   class Function  pwrite_count(node:PsrNode):PDWORD           virtual;
   class Procedure SetWriter(node,w,line:PsrNode);             virtual;
   class Procedure ResetWriter(node,w:PsrNode);                virtual;
   class Function  is_used(node:PsrNode):Boolean               virtual;
   class Function  GetPtype(node:PsrNode):PsrNode;             virtual;
   class Function  GetStorageClass(node:PsrNode):DWORD;        virtual;
   class function  GetStorageName(node:PsrNode):RawByteString; virtual;
   class function  GetPrintName(node:PsrNode):RawByteString;   virtual;
   class function  GetPrintData(node:PsrNode):RawByteString;   virtual;
   class function  Down(node:PsrNode):Pointer;                 virtual;
   class function  Next(node:PsrNode):Pointer;                 virtual;
   class function  Prev(node:PsrNode):Pointer;                 virtual;
   class function  Parent(node:PsrNode):Pointer;               virtual;
   class function  First(node:PsrNode):Pointer;                virtual;
   class function  Last(node:PsrNode):Pointer;                 virtual;
   class Procedure PrepType(node:PPrepTypeNode);               virtual;
   //
   class function  GetIndexCount(node:PsrNode):DWORD;          virtual;
   //
   class function  GetRef(node:PsrNode):Pointer;               virtual;
   //
   class function  GetData(node:PsrNode;data:Pointer):Ptruint; virtual;
 end;

 TsrNodeType=class of TsrNodeVmt;

 TsrNode=packed object
  protected
   fntype:TsrNodeType;
  private
   fread_count:DWORD;
  public
   property    ntype:TsrNodeType read fntype;
   property    read_count:DWORD  read fread_count;
   function    IsType(t:TsrNodeType):Boolean;
   function    AsType(t:TsrNodeType):Pointer;
   Procedure   mark_read   (src:PsrNode);
   Procedure   mark_unread (src:PsrNode);
   Procedure   mark_write  (src:PsrNode);
   Procedure   mark_unwrite(src:PsrNode);
   function    write_count:DWORD;
   Procedure   SetWriter(w,line:PsrNode);
   Procedure   ResetWriter(w:PsrNode);
   function    IsUsed:Boolean;
   Function    pType:Pointer;
   Function    GetStorageClass:DWORD;
   function    GetStorageName:RawByteString;
   function    GetPrintName:RawByteString;
   function    GetPrintData:RawByteString;
   function    Next:Pointer;
   function    Prev:Pointer;
   function    Parent:Pointer;
   function    First:Pointer;
   function    Last:Pointer;
   procedure   PrepType(rtype:Integer);
   function    GetIndexCount:DWORD;
   function    GetRef:Pointer;
   function    GetData(data:Pointer):Ptruint;
 end;

 TCustomEmit=class
  Function  Alloc(Size:ptruint):Pointer;                   virtual abstract;
  Function  GetExecutionModel  :Word;                      virtual abstract;
  Function  GetConfig          :Pointer;                   virtual abstract;
  Function  GetCodeHeap        :Pointer;                   virtual abstract;
  Function  GetLiteralList     :Pointer;                   virtual abstract;
  Function  GetTypeList        :Pointer;                   virtual abstract;
  Function  GetConstList       :Pointer;                   virtual abstract;
  Function  GetRegsStory       :Pointer;                   virtual abstract;
  Function  GetCapabilityList  :Pointer;                   virtual abstract;
  Function  GetHeaderList      :Pointer;                   virtual abstract;
  Function  GetDecorateList    :Pointer;                   virtual abstract;
  Function  GetDebugInfoList   :Pointer;                   virtual abstract;
  Function  GetVariableList    :Pointer;                   virtual abstract;
  Function  GetInputList       :Pointer;                   virtual abstract;
  Function  GetOutputList      :Pointer;                   virtual abstract;
  Function  GetDataLayoutList  :Pointer;                   virtual abstract;
  Function  GetVertLayoutList  :Pointer;                   virtual abstract;
  Function  GetFragLayoutList  :Pointer;                   virtual abstract;
  Function  GetBufferList      :Pointer;                   virtual abstract;
  Function  GetUniformList     :Pointer;                   virtual abstract;
  Function  GetBitcastList     :Pointer;                   virtual abstract;
  Function  GetCacheOpList     :Pointer;                   virtual abstract;
  Function  GetFuncList        :Pointer;                   virtual abstract;
  Function  GetCursor          :Pointer;                   virtual abstract;
  function  curr_line          :Pointer;                   virtual abstract;
  function  init_line          :Pointer;                   virtual abstract;
  function  NewRefNode         :PsrNode;                   virtual abstract;
  function  OpCast  (pLine,      dst,src:PsrNode):PsrNode; virtual abstract;
  function  OpLoad  (pLine,dtype,dst,src:PsrNode):PsrNode; virtual abstract;
  function  OpStore (pLine,      dst,src:PsrNode):PsrNode; virtual abstract;
  procedure PostLink(pLine,      dst:PsrNode);             virtual abstract;
  procedure emit_spi;                                      virtual abstract;
 end;

implementation

class Procedure TsrNodeVmt.add_read(node,src:PsrNode);
begin
 Inc(node^.fread_count);
end;

class Procedure TsrNodeVmt.rem_read(node,src:PsrNode);
begin
 Assert(node^.fread_count<>0,node^.ntype.ClassName);
 if (node^.fread_count=0) then Exit;
 Dec(node^.fread_count);
end;

class Procedure TsrNodeVmt.add_write(node,src:PsrNode);
var
 p:PDWORD;
begin
 p:=node^.fntype.pwrite_count(node);
 if (p<>nil) then
 begin
  Inc(p^);
 end;
end;

class Procedure TsrNodeVmt.rem_write(node,src:PsrNode);
var
 p:PDWORD;
begin
 p:=node^.fntype.pwrite_count(node);
 if (p<>nil) then
 begin
  Assert(p^<>0);
  if (p^=0) then Exit;
  Dec(p^);
 end;
end;

class Procedure TsrNodeVmt.mark_read(node,src:PsrNode);
var
 prv:Boolean;
begin
 repeat
  Assert(node^.fntype<>nil);

  prv:=node^.IsUsed;

  node^.fntype.add_read(node,src);

  if (prv=node^.IsUsed) then Exit;

  node^.fntype.zero_read(node);

  src :=node;
  node:=node^.fntype.Down(node);
 until (node=nil);
end;

class Procedure TsrNodeVmt.mark_unread(node,src:PsrNode);
var
 prv:Boolean;
begin
 repeat
  Assert(node^.fntype<>nil);

  prv:=node^.IsUsed;

  node^.fntype.rem_read(node,src);

  if (prv=node^.IsUsed) then Exit;

  node^.fntype.zero_unread(node);

  src :=node;
  node:=node^.fntype.Down(node);
 until (node=nil);
end;

class Procedure TsrNodeVmt.zero_read(node:PsrNode);
begin
 //
end;

class Procedure TsrNodeVmt.zero_unread(node:PsrNode);
begin
 //
end;

class Procedure TsrNodeVmt.mark_write(node,src:PsrNode);
var
 prv:Boolean;
begin
 repeat
  Assert(node^.fntype<>nil);

  prv:=node^.IsUsed;

  node^.fntype.add_write(node,src);

  if (prv=node^.IsUsed) then Exit;

  node^.fntype.zero_read(node);

  src :=node;
  node:=node^.fntype.Down(node);
 until (node=nil);
end;

class Procedure TsrNodeVmt.mark_unwrite(node,src:PsrNode);
var
 prv:Boolean;
begin
 repeat
  Assert(node^.fntype<>nil);

  prv:=node^.IsUsed;

  node^.fntype.rem_write(node,src);

  if (prv=node^.IsUsed) then Exit;

  node^.fntype.zero_unread(node);

  src :=node;
  node:=node^.fntype.Down(node);
 until (node=nil);
end;

class Function TsrNodeVmt.pwrite_count(node:PsrNode):PDWORD;
begin
 Result:=nil;
end;

class Procedure TsrNodeVmt.SetWriter(node,w,line:PsrNode);
begin
 w^.mark_read(node);
end;

class Procedure TsrNodeVmt.ResetWriter(node,w:PsrNode);
begin
 w^.mark_unread(node);
end;

class Function TsrNodeVmt.is_used(node:PsrNode):Boolean;
begin
 Result:=(node^.read_count<>0) or (node^.write_count<>0);
end;

class Function TsrNodeVmt.GetPtype(node:PsrNode):PsrNode;
begin
 Result:=nil;
end;

class Function TsrNodeVmt.GetStorageClass(node:PsrNode):DWORD;
begin
 Result:=6;
end;

class function TsrNodeVmt.GetStorageName(node:PsrNode):RawByteString;
begin
 Result:='';
end;

class function TsrNodeVmt.GetPrintName(node:PsrNode):RawByteString;
begin
 Result:='';
end;

class function TsrNodeVmt.GetPrintData(node:PsrNode):RawByteString;
begin
 Result:='';
end;

class function TsrNodeVmt.Down(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.Next(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.Prev(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.Parent(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.First(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.Last(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class Procedure TsrNodeVmt.PrepType(node:PPrepTypeNode);
begin
 node^.dnode:=nil;
end;

class function TsrNodeVmt.GetIndexCount(node:PsrNode):DWORD;
begin
 Result:=0;
end;

class function TsrNodeVmt.GetRef(node:PsrNode):Pointer;
begin
 Result:=nil;
end;

class function TsrNodeVmt.GetData(node:PsrNode;data:Pointer):Ptruint;
begin
 Result:=0;
end;

//

function TsrNode.IsType(t:TsrNodeType):Boolean;
begin
 Result:=False;
 if (@Self=nil) then Exit;
 Result:=fntype.InheritsFrom(t);
end;

function TsrNode.AsType(t:TsrNodeType):Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 if not fntype.InheritsFrom(t) then Exit;
 Result:=@Self;
end;

Procedure TsrNode.mark_read(src:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.mark_read(@Self,src);
end;

Procedure TsrNode.mark_unread(src:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.mark_unread(@Self,src);
end;

Procedure TsrNode.mark_write(src:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.mark_write(@Self,src);
end;

Procedure TsrNode.mark_unwrite(src:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.mark_unwrite(@Self,src);
end;

function TsrNode.write_count:DWORD;
var
 p:PDWORD;
begin
 Result:=0;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 p:=fntype.pwrite_count(@Self);
 if (p=nil) then Exit;
 Result:=p^;
end;

Procedure TsrNode.SetWriter(w,line:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.SetWriter(@Self,w,line);
end;

Procedure TsrNode.ResetWriter(w:PsrNode);
begin
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 fntype.ResetWriter(@Self,w);
end;

function TsrNode.IsUsed:Boolean;
begin
 Result:=False;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.is_used(@Self);
end;

Function TsrNode.pType:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetPtype(@Self);
end;

Function TsrNode.GetStorageClass:DWORD;
begin
 Result:=6;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetStorageClass(@Self);
end;

function TsrNode.GetStorageName:RawByteString;
begin
 Result:='';
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetStorageName(@Self);
end;

function TsrNode.GetPrintName:RawByteString;
begin
 Result:='';
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetPrintName(@Self);
end;

function TsrNode.GetPrintData:RawByteString;
begin
 Result:='';
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetPrintData(@Self);
end;

function TsrNode.Next:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.Next(@Self);
end;

function TsrNode.Prev:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.Prev(@Self);
end;

function TsrNode.Parent:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.Parent(@Self);
end;

function TsrNode.First:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.First(@Self);
end;

function TsrNode.Last:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.Last(@Self);
end;

procedure TsrNode.PrepType(rtype:Integer);
var
 node:TPrepTypeNode;
begin
 node:=Default(TPrepTypeNode);
 node.dnode:=@Self;
 node.rtype:=rtype;
 While (node.dnode<>nil) do
 begin
  Assert(node.dnode^.fntype<>nil);
  node.dnode^.fntype.PrepType(@node);
 end;
end;

function TsrNode.GetIndexCount:DWORD;
begin
 Result:=0;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetIndexCount(@Self);
end;

function TsrNode.GetRef:Pointer;
begin
 Result:=nil;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetRef(@Self);
end;

function TsrNode.GetData(data:Pointer):Ptruint;
begin
 Result:=0;
 if (@Self=nil) then Exit;
 Assert(fntype<>nil);
 Result:=fntype.GetData(@Self,data);
end;

end.

