unit uengShaderPart; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, uengShaderFileParser, uengShaderFileTypes {$IFDEF SHADER_FILE_USE_BITSPACE_UTILS} , uutlGenerics {$ELSE} , uengShaderFileGenerics {$ENDIF} ; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderPart = class; CengShaderPart = class of TengShaderPart; CengShaderPartArr = array of CengShaderPart; TengShaderPartList = specialize TutlSimpleList; TengShaderPartWalker = class(TObject) protected procedure Visit(const aPart, aCaller: TengShaderPart; const aArgs: Pointer); virtual; public procedure Run(const aPart: TengShaderPart); end; TengShaderPart = class(TIntfObjNoRefCount) { Nested Types } public type TEnumerator = class(TObject) private fOwner: TengShaderPart; fPosition: Integer; fReverse: Boolean; function GetCurrent: TengShaderPart; public property Current: TengShaderPart read GetCurrent; function GetEnumerator: TEnumerator; function MoveNext: Boolean; constructor Create(const aOwner: TengShaderPart; const aReverse: Boolean = false); end; { Code Loading & Storage } protected { members } fRoot: TengShaderPart; fParent: TengShaderPart; fLine: Integer; fCol: Integer; protected { virtual getter } function GetCount: Integer; virtual; function GetChild(const aIndex: Integer): TengShaderPart; virtual; function GetText: String; virtual; function GetFilename: String; virtual; function GetFileReader: IengShaderFileReader; virtual; function GetFileWriter: IengShaderFileWriter; virtual; { General } protected procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); virtual; public { general methods } property Root: TengShaderPart read fRoot; property Parent: TengShaderPart read fParent; property Line: Integer read fLine; property Col: Integer read fCol; property Filename: String read GetFilename; property Text: String read GetText; property Count: Integer read GetCount; property FileReader: IengShaderFileReader read GetFileReader; property FileWriter: IengShaderFileWriter read GetFileWriter; property Children[const aIndex: Integer]: TengShaderPart read GetChild; default; function HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean; function GetParent(const aType: CengShaderPart; out aPart): Boolean; function GetParent(const aType: CengShaderPart): TengShaderPart; procedure PrintTrace(const aPrefix: String; const aLines: TStrings); procedure LogMsg(const aLogLevel: TengShaderPartLogLevel; const aMsg: String); function GetEnumerator: TEnumerator; function GetReverseEnumerator: TEnumerator; constructor Create(const aParent: TengShaderPart); virtual; { Class Methods } public class function GetTokenName: String; virtual; class function CheckToken(const aToken: String): Boolean; virtual; class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); virtual; end; implementation uses uengShaderFileConstants; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TEnumerator.GetCurrent: TengShaderPart; begin result := fOwner[fPosition]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TEnumerator.GetEnumerator: TEnumerator; begin result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TEnumerator.MoveNext: Boolean; begin if not fReverse then inc(fPosition) else dec(fPosition); result := (0 <= fPosition) and (fPosition < fOwner.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderPart.TEnumerator.Create(const aOwner: TengShaderPart; const aReverse: Boolean); begin inherited Create; fOwner := aOwner; fReverse := aReverse; if not fReverse then fPosition := -1 else fPosition := aOwner.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPartWalker////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPartWalker.Visit(const aPart, aCaller: TengShaderPart; const aArgs: Pointer); begin // DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPartWalker.Run(const aPart: TengShaderPart); begin Visit(aPart, nil, nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetCount: Integer; begin result := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart; begin result := nil; EengShaderPartInternal.Create('this part does not have any children'); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetText: String; begin result := ''; //DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetFilename: String; begin if Assigned(fParent) then result := fParent.Filename else result := UNKNOWN_FILENAME; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetFileReader: IengShaderFileReader; begin if Assigned(fParent) then result := fParent.GetFileReader else result := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetFileWriter: IengShaderFileWriter; begin if Assigned(fParent) then result := fParent.GetFileWriter else result := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPart.LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); begin if Assigned(Parent) then Parent.LogMsgIntern(aSender, aLogLevel, aMsg); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean): Boolean; var p: TengShaderPart; begin result := (aIncludeSelf and (self is aType)) or GetParent(aType, p); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetParent(const aType: CengShaderPart; out aPart): Boolean; begin result := true; TengShaderPart(aPart) := nil; if (fParent is aType) then TengShaderPart(aPart) := fParent else if Assigned(fParent) then result := fParent.GetParent(aType, aPart) else result := false; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetParent(const aType: CengShaderPart): TengShaderPart; begin if not GetParent(aType, result) then raise EengShaderPartInternal.Create(GetTokenName + ' has no parent of type ' + aType.GetTokenName, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPart.PrintTrace(const aPrefix: String; const aLines: TStrings); function GetName(const aPart: TengShaderPart): String; begin result := aPart.GetTokenName; if (result = '') then result := aPart.ClassName else result := result + ' (' + aPart.ClassName + ')'; end; var p: TengShaderPart; begin p := self; while Assigned(p) do begin aLines.Add(Format('%s%s (%d:%d): %s', [aPrefix, p.Filename, p.Line+1, p.Col, GetName(p)])); p := p.Parent; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPart.LogMsg(const aLogLevel: TengShaderPartLogLevel; const aMsg: String); begin LogMsgIntern(self, aLogLevel, aMsg); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetEnumerator: TEnumerator; begin result := TEnumerator.Create(self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetReverseEnumerator: TEnumerator; begin result := TEnumerator.Create(self, true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderPart.Create(const aParent: TengShaderPart); begin inherited Create; fParent := aParent; if Assigned(fParent) then fRoot := fParent.Root else fRoot := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TengShaderPart.GetTokenName: String; begin result := ''; // DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TengShaderPart.CheckToken(const aToken: String): Boolean; begin result := (aToken = GetTokenName); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class procedure TengShaderPart.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); begin // DUMMY end; end.