unit uengShaderPart; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, uengShaderFileParser, uengShaderFileTypes {$IFDEF USE_BITSPACE_UTILS} , uutlGenerics {$ELSE} , fgl {$ENDIF} ; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengSearchFlag = ( sfEvaluateIf, // evaluate if statements before search and process with suitable subtree sfSearchAllIf, // search in all if sub trees sfSearchPrevOnly, // search in previous items only sfSearchInherited, // search in inherited sfSearchChildren, // search in children sfSearchChildrenLazy, // set sfSearchChildren in next recursion level sfChildrenFileOnly, // do not leave current file when searching for children sfChildrenGeneratorOnly, // do not leave current generator when searching for children sfChildrenScopeOnly, // do not leave current scope when searching for children sfSearchParents, // search in Parents sfParentsFileOnly, // do not leave current file when searching in parents sfParentsGeneratorOnly, // do not leave current generator when searching in parents sfParentsScopeOnly // do not leave current scope when searching in parents ); TengSearchFlags = set of TengSearchFlag; TengShaderPart = class; CengShaderPart = class of TengShaderPart; TengShaderPartList = specialize TutlSimpleList; 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; TSearchResults = class(specialize TutlList) private fFirstOnly: Boolean; fIgnore: TengShaderPart; fTypes: array of CengShaderPart; protected function CheckObj(const aPart: TengShaderPart; var aContinue: Boolean): Boolean; virtual; public property FirstOnly: Boolean read fFirstOnly write fFirstOnly; property Ignore: TengShaderPart read fIgnore write fIgnore; function Add(const aPart: TengShaderPart): Boolean; reintroduce; constructor Create(const aTypes: array of CengShaderPart); end; { Code Loading & Storage } protected { members } fParent: TengShaderPart; fLine: Integer; fCol: Integer; fRoot: TengShaderPart; 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 UpdateCache; virtual; function FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TSearchResults): Boolean; 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 Find(const aFlags: TengSearchFlags; const aResults: TSearchResults); 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; TengShaderCodePart = class(TengShaderPart) { Code Loading & Storage } protected function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; virtual; public function ParseText(const aArgs: TengParseArgs): String; end; CengShaderCodePart = class of TengShaderCodePart; implementation uses uengShaderPartScope, uengShaderCodeGenerator, uengShaderFile, 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart.TSearchResults///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TSearchResults.CheckObj(const aPart: TengShaderPart; var aContinue: Boolean): Boolean; var c: CengShaderPart; begin aContinue := not fFirstOnly or (Count = 0);; if aContinue then begin result := (Length(fTypes) = 0); for c in fTypes do result := result or (aPart is c); result := result and (aPart <> fIgnore); end else result := false; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TSearchResults.Add(const aPart: TengShaderPart): Boolean; begin result := true; if result and CheckObj(aPart, result) then inherited Add(aPart); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderPart.TSearchResults.Create(const aTypes: array of CengShaderPart); var i: Integer; begin inherited Create(false); fFirstOnly := false; SetLength(fTypes, Length(aTypes)); for i := Low(fTypes) to High(fTypes) do fTypes[i] := aTypes[i]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetCount: Integer; begin result := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart; begin 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.UpdateCache; var p: TengShaderPart; begin for p in self do p.UpdateCache; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TSearchResults): Boolean; var c: TengShaderPart; b: Boolean; begin b := false; result := true; if (sfSearchChildren in aFlags) then begin for c in self.GetReverseEnumerator do begin b := b or (c = aChild); if (sfSearchPrevOnly in aFlags) and not b then continue; if (c <> aChild) and (not (sfChildrenScopeOnly in aFlags) or not (c is TengShaderPartScope)) and (not (sfChildrenGeneratorOnly in aFlags) or not (c is TengShaderCodeGenerator)) and (not (sfChildrenFileOnly in aFlags) or not (c is TengShaderFile)) then result := result and c.FindIntern(aFlags - [sfSearchParents], nil, aResults); if not result then exit; end; end; result := result and aResults.Add(self); if (sfSearchChildrenLazy in aFlags) then aFlags := aFlags + [sfSearchChildren] - [sfSearchChildrenLazy]; if (sfSearchParents in aFlags) and Assigned(Parent) and (not (sfParentsScopeOnly in aFlags) or not (self is TengShaderPartScope)) and (not (sfParentsGeneratorOnly in aFlags) or not (self is TengShaderCodeGenerator)) and (not (sfParentsFileOnly in aFlags) or not (self is TengShaderFile)) then result := result and Parent.FindIntern(aFlags, self, aResults); 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; 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 + ' ha sno parent of type ' + aType.GetTokenName, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPart.Find(const aFlags: TengSearchFlags; const aResults: TSearchResults); begin FindIntern(aFlags, nil, aResults); 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderCodePart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderCodePart.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; begin result := ''; // DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderCodePart.ParseText(const aArgs: TengParseArgs): String; var params: TengTokenParameterList; begin params := TengTokenParameterList.Create(Filename); try fCol := aArgs.Col; fLine := aArgs.Line; if (GetTokenName <> '') then aArgs.ExtractToken(self, params); result := ParseIntern(aArgs, params); finally FreeAndNil(params); end; end; end.