unit uengShaderPartClass; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, uengShaderPart, uengShaderCodeGenerator, uengShaderFileParser {$IFDEF USE_BITSPACE_UTILS} , uutlGenerics {$ENDIF} ; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderPartClass = class(TengShaderCodeGenerator) { Code Loading & Storage } private { member } fName: String; fExtends: TStringList; private { getter } function GetExtends: TStrings; protected { virtual getter } function GetText: String; override; function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; { General } protected procedure UpdateInherited; override; public property Name: String read fName; property Extends: TStrings read GetExtends; constructor Create(const aParent: TengShaderPart); override; destructor Destroy; override; { Class Methods } public class function GetTokenName: String; override; class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override; end; TengShaderPartClassMap = specialize TutlMap; implementation uses uengShaderFile, uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartIf; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPartClass/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartClass.GetExtends: TStrings; begin result := fExtends; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartClass.GetText: String; var s: String; begin result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName; if (fExtends.Count > 0) then begin result := result + ' ' + TOKEN_EXTENDS; for s in fExtends do result := result + ' ' + s; end; result := result + TOKEN_CHAR_END + inherited GetText + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartClass.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; var i: Integer; begin if (aParams[0].Name <> GetTokenName) then with aParams[0] do raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self); if (aParams.Count < 2) then raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, self); with aParams[1] do begin if not IsValidIdentifier(Name) then raise EengInvalidIdentifier.Create(Name, self); fName := Name; end; if (aParams.Count > 2) then begin if (aParams.Count < 4) then raise EengInvalidParamterCount.Create(GetTokenName, 4, -1, self); if (aParams[2].Name <> TOKEN_EXTENDS) then with aParams[2] do raise EengInvalidParamter.Create(aParams[2].Name, TOKEN_EXTENDS, Line, Col, Filename, self); fExtends.Clear; for i := 3 to aParams.Count-1 do fExtends.Add(aParams[i].Name); end; result := inherited ParseIntern(aArgs, aParams); result := CheckEndToken(aArgs, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderPartClass.UpdateInherited; var sr: TengShaderPart.TSearchResults; i: Integer; s: String; begin inherited UpdateInherited; fInherited.Clear; sr := TengShaderPart.TSearchResults.Create([TengShaderPartClass]); try sr.Ignore := self; Find([sfSearchChildrenLazy, sfSearchParents, sfParentsFileOnly, sfSearchPrevOnly], sr); for s in fExtends do begin i := 0; while (i >= 0) and (i < sr.Count) do begin if ((sr[i] as TengShaderPartClass).Name = s) then begin fInherited.Add(sr[i]); i := -1; end; inc(i); end; if (i > 0) or (sr.Count = 0) then raise EengUnknownIdentifier.Create(s, self); end; finally FreeAndNil(sr); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderPartClass.Create(const aParent: TengShaderPart); begin inherited Create(aParent); fExtends := TStringList.Create; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengShaderPartClass.Destroy; begin FreeAndNil(fExtends); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TengShaderPartClass.GetTokenName: String; begin result := TOKEN_CLASS; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class procedure TengShaderPartClass.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); procedure RaiseEx(const aToken: String); begin with aArgs do raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in ' + aToken, Line, Col, Filename, aParent); end; begin inherited Validate(aArgs, aParent); if aParent.HasParent(TengShaderPartElIf, true) then RaiseEx(TengShaderPartElIf.GetTokenName); if aParent.HasParent(TengShaderPartElse, true) then RaiseEx(TengShaderPartElse.GetTokenName); if aParent.HasParent(TengShaderPartIf, true) then RaiseEx(TengShaderPartIf.GetTokenName); if aParent.HasParent(TengShaderPartClass, true) then RaiseEx(TengShaderPartClass.GetTokenName); end; end.