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 sfIncludeSelf, // add item to search results where search has started sfSearchPrevOnly, // search in previous items only sfSearchInherited, // search in inherited sfSearchChildren, // search in children sfSearchChildrenLazy, // set sfSearchChildren in next recursion level sfChildrenOnlyFile, // do not leave current file when searching for children sfChildrenOnlyClass, // do not leave current class when searching for children sfChildrenOnlyGenerator, // do not leave current generator when searching for children sfChildrenOnlyScope, // do not leave current scope when searching for children sfChildrenForceFile, // overwrite sfChildrenOnlyXXX flag when item is a file sfChildrenForceClass, // overwrite sfChildrenOnlyXXX flag when item is a class sfChildrenForceGenerator, // overwrite sfChildrenOnlyXXX flag when item is a generator sfChildrenForceScope, // overwrite sfChildrenOnlyXXX flag when item is a scope sfSearchParents, // search in Parents sfParentsOnlyFile, // do not leave current file when searching in parents sfParentsOnlyClass, // do not leave current class when searching in parents sfParentsOnlyGenerator, // do not leave current generator when searching in parents sfParentsOnlyScope, // do not leave current scope when searching in parents sfParentsForceFile, // overwrite sfParentsOnlyXXX flag when item is a file sfParentsForceClass, // overwrite sfParentsOnlyXXX flag when item is a class sfParentsForceGenerator, // overwrite sfParentsOnlyXXX flag when item is a generator sfParentsForceScope // overwrite sfParentsOnlyXXX flag when item is a scope ); TengSearchFlags = set of TengSearchFlag; const SEARCH_FLAG_CURRENT_SCOPE = [ sfSearchPrevOnly, sfSearchInherited, // search in inherited sfSearchChildrenLazy, // set sfSearchChildren in next recursion level sfChildrenOnlyScope, // do not leave current scope when searching for children sfChildrenForceFile, // overwrite sfChildrenOnlyXXX flag when item is a file sfSearchParents, // search in Parents sfParentsOnlyFile // do not leave current file when searching in parents ]; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderPart = class; CengShaderPart = class of TengShaderPart; TengShaderPartList = specialize TutlSimpleList; TengSearchResults = 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; 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 function FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TengSearchResults): Boolean; virtual; 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 Find(const aFlags: TengSearchFlags; const aResults: TengSearchResults); 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; 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, uengShaderPartClass, 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengSearchResults///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengSearchResults.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 TengSearchResults.Add(const aPart: TengShaderPart): Boolean; begin result := true; if result and CheckObj(aPart, result) then inherited Add(aPart); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengSearchResults.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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TengSearchResults): Boolean; function VisitChild(const aItem: TengShaderPart): Boolean; begin result := (sfSearchChildren in aFlags); if not result then exit; result := result and Assigned(aItem) and (not (sfChildrenOnlyFile in aFlags) or not (self is TengShaderFile)) and (not (sfChildrenOnlyClass in aFlags) or not (self is TengShaderPartClass)) and (not (sfChildrenOnlyGenerator in aFlags) or not (self is TengShaderCodeGenerator)) and (not (sfChildrenOnlyScope in aFlags) or not (self is TengShaderPartScope)); result := result or ((sfChildrenForceFile in aFlags) and (self is TengShaderFile)) or ((sfChildrenForceClass in aFlags) and (self is TengShaderPartClass)) or ((sfChildrenForceGenerator in aFlags) and (self is TengShaderCodeGenerator)) or ((sfChildrenForceScope in aFlags) and (self is TengShaderPartScope)); end; function VisitParent(const aItem: TengShaderPart): Boolean; begin result := (sfSearchParents in aFlags); if not result then exit; result := result and Assigned(aItem) and (not (sfParentsOnlyFile in aFlags) or not (self is TengShaderFile)) and (not (sfParentsOnlyClass in aFlags) or not (self is TengShaderPartClass)) and (not (sfParentsOnlyGenerator in aFlags) or not (self is TengShaderCodeGenerator)) and (not (sfParentsOnlyScope in aFlags) or not (self is TengShaderPartScope)); result := result or ((sfParentsForceFile in aFlags) and (self is TengShaderFile)) or ((sfParentsForceClass in aFlags) and (self is TengShaderPartClass)) or ((sfParentsForceGenerator in aFlags) and (self is TengShaderCodeGenerator)) or ((sfParentsForceScope in aFlags) and (self is TengShaderPartScope)); end; 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 VisitChild(c) then result := result and c.FindIntern(aFlags - [sfSearchParents] + [sfIncludeSelf], nil, aResults); if not result then exit; end; end; if (sfIncludeSelf in aFlags) then result := result and aResults.Add(self); if (sfSearchChildrenLazy in aFlags) then aFlags := aFlags + [sfSearchChildren] - [sfSearchChildrenLazy]; if VisitParent(Parent) then result := result and Parent.FindIntern(aFlags + [sfIncludeSelf], self, aResults); 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 + ' ha sno parent of type ' + aType.GetTokenName, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPart.Find(const aFlags: TengSearchFlags; const aResults: TengSearchResults); begin FindIntern(aFlags, nil, aResults); 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //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.