From 756fd412a455dc29e03cf07a392bbf407c4d4a68 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Fri, 21 Aug 2015 23:48:04 +0200 Subject: [PATCH] * reimplemented experssion parser --- uengShaderCodeGenerator.pas | 13 +- uengShaderFile.pas | 73 ++-- uengShaderFileExpression.pas | 620 +++++++++++++++++++-------------- uengShaderFileTypes.pas | 47 ++- uengShaderPart.pas | 264 ++++++++------ uengShaderPartCall.pas | 2 +- uengShaderPartClass.pas | 32 ++ uengShaderPartCntr.pas | 8 +- uengShaderPartComment.pas | 2 +- uengShaderPartEcho.pas | 2 +- uengShaderPartIf.pas | 38 +- uengShaderPartInclude.pas | 2 +- uengShaderPartKeyValuePair.pas | 22 +- uengShaderPartMessage.pas | 2 +- uengShaderPartMeta.pas | 2 +- uengShaderPartParameter.pas | 2 +- uengShaderPartProc.pas | 9 - uengShaderPartText.pas | 6 +- 18 files changed, 668 insertions(+), 478 deletions(-) diff --git a/uengShaderCodeGenerator.pas b/uengShaderCodeGenerator.pas index 5daa624..58dcd3c 100644 --- a/uengShaderCodeGenerator.pas +++ b/uengShaderCodeGenerator.pas @@ -12,16 +12,13 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderCodeGenerator = class(TengShaderPartScope) - { Code Loading & Storage } + { General } private fProperties: TengShaderPartPropertyMap; - protected fInherited: TengShaderPartList; procedure UpdateInherited; virtual; - function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; - - { General } + procedure UpdateCache; override; public constructor Create(const aParent: TengShaderPart); override; destructor Destroy; override; @@ -34,13 +31,13 @@ implementation //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderCodeGenerator.UpdateInherited; begin - // TODO + // DUMMY end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderCodeGenerator.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +procedure TengShaderCodeGenerator.UpdateCache; begin - result := inherited ParseIntern(aArgs, aParams); + inherited UpdateCache; UpdateInherited; end; diff --git a/uengShaderFile.pas b/uengShaderFile.pas index 12355ff..5e41945 100644 --- a/uengShaderFile.pas +++ b/uengShaderFile.pas @@ -32,13 +32,16 @@ type function GetGenerator(const aName: String): TengShaderCodeGenerator; function GetGeneratorCount: Integer; function GetGeneratorNames(const aIndex: Integer): String; - procedure UpdateClasses; protected function GetFilename: String; override; function GetFileReader: IengShaderFileReader; override; function GetFileWriter: IengShaderFileWriter; override; { General } + private + procedure UpdateClasses; + protected + procedure UpdateCache; override; public property Generator [const aName: String]: TengShaderCodeGenerator read GetGenerator; property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames; @@ -82,30 +85,6 @@ begin else result := fClasses.Keys[aIndex-1]; end; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TengShaderFile.UpdateClasses; -var - l: TengShaderPart.TSearchResults; - p: TengShaderPart; - new, old: TengShaderPartClass; - -begin - l := TengShaderPart.TSearchResults.Create; - try - fClasses.Clear; - FindAll([sfSearchChildren], [TengShaderPartClass], l); - for p in l do begin - new := (p as TengShaderPartClass); - old := fClasses[new.Name]; - if Assigned(old) then - raise EengDuplicateIdentifier.Create(new.Name, new, old, self); - fClasses.Add(new.Name, new); - end; - finally - FreeAndNil(l); - end; -end; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderFile.GetFilename: String; begin @@ -128,6 +107,36 @@ begin result := Parent.FileWriter; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.UpdateClasses; +var + sr: TengShaderPart.TSearchResults; + p: TengShaderPart; + new, old: TengShaderPartClass; +begin + sr := TengShaderPart.TSearchResults.Create([TengShaderPartClass]); + try + fClasses.Clear; + Find([sfSearchChildren], sr); + for p in sr do begin + new := (p as TengShaderPartClass); + old := fClasses[new.Name]; + if Assigned(old) then + raise EengDuplicateIdentifier.Create(new.Name, new, old, self); + fClasses.Add(new.Name, new); + end; + finally + FreeAndNil(sr); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.UpdateCache; +begin + inherited UpdateCache; + UpdateClasses; +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader); var @@ -153,7 +162,7 @@ begin if (token <> '') then with args do raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename, self); if (Root = self) then - UpdateClasses; + UpdateCache; finally FreeAndNil(args); end; @@ -165,7 +174,7 @@ end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter); var - l: TengShaderPart.TSearchResults; + sr: TengShaderPart.TSearchResults; i: Integer; sl: TStringList; ms: TMemoryStream; @@ -176,19 +185,19 @@ begin if not Assigned(fFileWriter) then fFileWriter := TengShaderFileWriter.Create; - l := TengShaderPart.TSearchResults.Create; + sr := TengShaderPart.TSearchResults.Create([TengShaderPartInclude]); sl := TStringList.Create; ms := TMemoryStream.Create; try - FindAll([sfSearchChildren, sfCurrentFileOnly], [TengShaderPartInclude], l); - for i := 0 to l.Count-1 do - (l[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter); + Find([sfSearchChildren, sfChildrenFileOnly], sr); + for i := 0 to sr.Count-1 do + (sr[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter); sl.Text := Text; sl.SaveToStream(ms); ms.Position := 0; fFileWriter.SaveStream(aFilename, ms); finally - FreeAndNil(l); + FreeAndNil(sr); FreeAndNil(sl); FreeAndNil(ms); fFileWriter := nil; diff --git a/uengShaderFileExpression.pas b/uengShaderFileExpression.pas index 018cd63..bc788db 100644 --- a/uengShaderFileExpression.pas +++ b/uengShaderFileExpression.pas @@ -7,25 +7,14 @@ interface uses Classes, SysUtils, variants, - uengShaderFileParser; + uengShaderPart, uengShaderFileParser; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengExpressionItem = class(TObject) - private - fOwner: TObject; - fLine: Integer; - fCol: Integer; - fFilename: String; + TengExpressionItem = class(TengShaderPart) public - property Owner: TObject read fOwner; - property Line: Integer read fLine; - property Col: Integer read fCol; - property Filename: String read fFilename; - - function GetText: String; virtual; function GetValue: Variant; virtual; - constructor Create(const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + constructor Create(const aLine, aCol: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -33,9 +22,12 @@ type private fValue: Variant; public + property Value: Variant read fValue; + function GetText: String; override; function GetValue: Variant; override; - constructor Create(const aValue: Variant; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + + constructor Create(const aValue: Variant; const aLine, aCol: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -43,9 +35,12 @@ type private fName: String; public + property Name: String read fName; + function GetText: String; override; function GetValue: Variant; override; - constructor Create(const aName: String; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + + constructor Create(const aName: String; const aLine, aCol: Integer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -53,13 +48,25 @@ type private fChild: TengExpressionItem; public - property Child: TengExpressionItem read fChild write fChild; + property Child: TengExpressionItem read fChild; + function GetText: String; override; function GetValue: Variant; override; - constructor Create(const aChild: TengExpressionItem; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + + constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionOperation = class(TengExpressionItem) + protected + function GetWeight: Integer; virtual; + public + property Weight: Integer read GetWeight; + function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; virtual; + function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; virtual; + end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengExpressionUnaryOperator = ( opBinaryNot, @@ -67,18 +74,22 @@ type opDefined, opSet ); - TengExpressionUnaryOperation = class(TengExpressionItem) + TengExpressionUnaryOperation = class(TengExpressionOperation) private fChild: TengExpressionItem; fUnaryOp: TengExpressionUnaryOperator; + protected + function GetWeight: Integer; override; public - property Child: TengExpressionItem read fChild write fChild; + property Child: TengExpressionItem read fChild; property UnaryOp: TengExpressionUnaryOperator read fUnaryOp; function GetText: String; override; function GetValue: Variant; override; + function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; override; + function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; override; - constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aChild: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; @@ -89,11 +100,13 @@ type opLogicalOr, opLogicalAnd, opLogicalXor, // logical opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison ); - TengExpressionBinaryOperation = class(TengExpressionItem) + TengExpressionBinaryOperation = class(TengExpressionOperation) private fFirst: TengExpressionItem; fSecond: TengExpressionItem; fBinaryOp: TengExpressionBinaryOperator; + protected + function GetWeight: Integer; override; public property First: TengExpressionItem read fFirst write fFirst; property Second: TengExpressionItem read fSecond write fSecond; @@ -101,12 +114,14 @@ type function GetText: String; override; function GetValue: Variant; override; + function ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; override; + function ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; override; - constructor Create(const aOperator: TengExpressionBinaryOperator; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); + constructor Create(const aOperator: TengExpressionBinaryOperator; const aFirst, aSecond: TengExpressionItem; const aLine, aCol: Integer); destructor Destroy; override; end; - function ParseExpression(const aOwner: TObject; const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem; + function ParseExpression(const aParent: TengShaderPart; const aParams: TengTokenParameterList; aIndex: Integer): TengExpressionItem; implementation @@ -126,7 +141,6 @@ const TOKEN_OP_DEFINED, //opDefined TOKEN_OP_SET //opSet ); - EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = ( TOKEN_OP_BINARY_OR, //opBinaryOr TOKEN_OP_BINARY_AND, //opBinaryAnd @@ -146,17 +160,39 @@ const TOKEN_OP_GREATER, //opGreater TOKEN_OP_LEQUALS, //opLEquals TOKEN_OP_GEQUALS, //opGEquals - TOKEN_OP_UNEQUALS //opUnequals, + TOKEN_OP_UNEQUALS //opUnequals + ); + + UNARY_OPERATION_WEIGHTS: array[TengExpressionUnaryOperator] of Integer = ( + 00, //opBinaryNot + 00, //opLogicalNot + 00, //opDefined + 00 //opSet + ); + BINARY_OPERATION_WEIGHTS: array[TengExpressionBinaryOperator] of Integer = ( + 01, //opBinaryOr + 02, //opBinaryAnd + 03, //opBinaryXor + + 04, //opMultiply + 05, //opDivide + 06, //opAdd + 07, //opSubtract + + 14, //opLogicalOr + 15, //opLogicalAnd + 16, //opLogicalXor + + 08, //opEquals + 09, //opLesser + 10, //opGreater + 11, //opLEquals + 12, //opGEquals + 13 //opUnequals ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengExpressionItem.GetText: String; -begin - result := ''; // DUMMY -end; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionItem.GetValue: Variant; begin @@ -164,13 +200,11 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionItem.Create(const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +constructor TengExpressionItem.Create(const aLine, aCol: Integer); begin - inherited Create; - fOwner := aOwner; - fLine := aLine; - fCol := aCol; - fFilename := aFilename; + inherited Create(nil); + fLine := aLine; + fCol := aCol; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -188,9 +222,9 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionValue.Create(const aValue: Variant; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer); begin - inherited Create(aOwner, aLine, aCol, aFilename); + inherited Create(aLine, aCol); fValue := aValue; end; @@ -209,9 +243,9 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionVariable.Create(const aName: String; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +constructor TengExpressionVariable.Create(const aName: String; const aLine, aCol: Integer); begin - inherited Create(aOwner, aLine, aCol, aFilename); + inherited Create(aLine, aCol); fName := aName; end; @@ -234,9 +268,9 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer); begin - inherited Create(aOwner, aLine, aCol, aFilename); + inherited Create(aLine, aCol); fChild := aChild; end; @@ -247,8 +281,34 @@ begin inherited Destroy; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionOperation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionOperation.GetWeight: Integer; +begin + result := -1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; +begin + result := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; +begin + result := nil; +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionUnaryOperation////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.GetWeight: Integer; +begin + result := UNARY_OPERATION_WEIGHTS[fUnaryOp]; +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionUnaryOperation.GetText: String; begin @@ -296,15 +356,29 @@ begin raise EengInvalidParamter.Create( ex.Message + '("' + GetText + '" ==> ' + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")', - Line, Col, Filename, Owner); + Line, Col, Filename, self); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +function TengExpressionUnaryOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; +begin + result := fChild; + fChild := aItem; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; +begin + result := fChild; + fChild := aItem; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aChild: TengExpressionItem; const aLine, aCol: Integer); begin - inherited Create(aOwner, aLine, aCol, aFilename); - fChild := nil; + inherited Create(aLine, aCol); + fChild := aChild; fUnaryOp := aUnaryOp; end; @@ -317,6 +391,12 @@ end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengExpressionBinaryOperation///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.GetWeight: Integer; +begin + result := BINARY_OPERATION_WEIGHTS[fBinaryOp]; +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengExpressionBinaryOperation.GetText: String; begin @@ -367,17 +447,32 @@ begin raise EengInvalidParamter.Create( ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")', - fLine, fCol, fFilename, fOwner); + self); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aOwner: TObject; const aLine, aCol: Integer; const aFilename: String); +function TengExpressionBinaryOperation.ExchangeFirst(const aItem: TengExpressionItem): TengExpressionItem; +begin + result := fFirst; + fFirst := aItem; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.ExchangeLast(const aItem: TengExpressionItem): TengExpressionItem; begin - inherited Create(aOwner, aLine, aCol, aFilename); + result := fSecond; + fSecond := aItem; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; + const aFirst, aSecond: TengExpressionItem; const aLine, aCol: Integer); +begin + inherited Create(aLine, aCol); fBinaryOp := aOperator; - fFirst := nil; - fSecond := nil; + fFirst := aFirst; + fSecond := aSecond; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -394,240 +489,225 @@ end; type TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation); TExpectedParams = set of TExpectedParam; -{$IFDEF USE_BITSPACE_UTILS} - TExpressionItemStack = specialize TutlSimpleList; -{$ELSE} - TExpressionItemStack = class(specialize TFPList) - public - + TExpressionParser = class(TObject) + private + fParent: TengShaderPart; + fParamPos: Integer; + fParams: TengTokenParameterList; + private + function NextParam(var aParam: TengTokenParameter): Boolean; + function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; + function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; + procedure RaiseEx(const aMsg: String; const aParam: TengTokenParameter; aName: String = ''); + function Move(var aItem: TengExpressionItem): TengExpressionItem; + function Merge(aOld, aNew: TengExpressionItem): TengExpressionItem; + function GetExpr(const aExpected: TExpectedParams): TengExpressionItem; + private + function GetGroup: TengExpressionItem; + constructor Create(const aParent: TengShaderPart; const aParams: TengTokenParameterList; const aIndex: Integer); end; -{$ENDIF} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function ParseExpression(const aOwner: TObject; const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem; -var - p: TengTokenParameter; +//TExpressionParser///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.NextParam(var aParam: TengTokenParameter): Boolean; +begin + inc(fParamPos); + result := (fParamPos < fParams.Count); + if result then + aParam := fParams[fParamPos]; +end; - procedure RaiseEx(const aMsg: String); - begin - raise EengExpression.Create(aMsg, p.Line, p.Col, aParam.Filename, aOwner); - end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; +begin + result := true; + for aOperator in TengExpressionUnaryOperator do + if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then + exit; + result := false; +end; - function NextParam: Boolean; - begin - inc(aIndex); - result := (aIndex < aParam.Count); - if result then - p := aParam[aIndex]; - end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; +begin + result := true; + for aOperator in TengExpressionBinaryOperator do + if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then + exit; + result := false; +end; - function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; - begin - result := true; - for aOperator in TengExpressionUnaryOperator do - if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then - exit; - result := false; - end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TExpressionParser.RaiseEx(const aMsg: String; const aParam: TengTokenParameter; aName: String = ''); +begin + if (aName = '') then + aName := aParam.Name; + raise EengExpression.Create(aMsg + ' ' + aParam.Name, aParam.Line, aParam.Col, fParent.Filename, fParent); +end; - function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; - begin - result := true; - for aOperator in TengExpressionBinaryOperator do - if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then - exit; - result := false; - end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.Move(var aItem: TengExpressionItem): TengExpressionItem; +begin + result := aItem; + aItem := nil; +end; - procedure MergeItems(const aStack: TExpressionItemStack; var aNew: TengExpressionItem); - var - item: TengExpressionItem; - begin - try - if (aStack.Count = 0) then begin - aStack.PushLast(aNew); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.Merge(aOld, aNew: TengExpressionItem): TengExpressionItem; +var + o, n: TengExpressionOperation; + tmp: TengExpressionItem; +begin + result := nil; + try + if not Assigned(aOld) then begin + result := aNew; + exit; + end else if not Assigned(aNew) then begin + result := aOld; + exit; + end else if (aOld is TengExpressionOperation) and (aNew is TengExpressionOperation) then begin + o := (aOld as TengExpressionOperation); + n := (aNew as TengExpressionOperation); + if (n.Weight < o.Weight) then begin + tmp := n.ExchangeFirst(o.ExchangeLast(n)); aNew := nil; - exit; - end; - - item := aStack.Last; - if (item is TengExpressionBinaryOperation) then begin - if (aNew is TengExpressionBinaryOperation) then begin - //both are binary operators, new is weaker then existing - if ((aNew as TengExpressionBinaryOperation).BinaryOp < - (item as TengExpressionBinaryOperation).BinaryOp) then - begin - (aNew as TengExpressionBinaryOperation).First := item; - aStack.PopLast; - aStack.PushLast(aNew); - aNew := nil; - - //both are binary operators, new is stronger than existing - end else begin - if not Assigned((item as TengExpressionBinaryOperation).Second) then - RaiseEx('inconsistent state'); - (aNew as TengExpressionBinaryOperation).First := (item as TengExpressionBinaryOperation).Second; - (item as TengExpressionBinaryOperation).Second := aNew; - aStack.PushLast(aNew); - aNew := nil; - end; - - //existing is binary operator, new is normal - end else begin - if Assigned((item as TengExpressionBinaryOperation).Second) then - RaiseEx('inconsistent state'); - (item as TengExpressionBinaryOperation).Second := aNew; - aNew := nil; - while (aStack.Count > 1) do - aStack.PopLast; //remove all but first - end; + result := aOld; end else begin - //existing is normal item, new is binary operation - if (aNew is TengExpressionBinaryOperation) then begin - aStack.PopLast; - (aNew as TengExpressionBinaryOperation).First := item; - aStack.PushLast(aNew); - aNew := nil; - - //existing is unary operation, new is normal item or unary operation - end else if (item is TengExpressionUnaryOperation) then begin - if Assigned((item as TengExpressionUnaryOperation).Child) then - RaiseEx('inconsistent state'); - (item as TengExpressionUnaryOperation).Child := aNew; - if not (aNew is TengExpressionUnaryOperation) then begin - while (aStack.Count > 1) do - aStack.PopLast; //remove all but first - end else - aStack.PushLast(aNew); - aNew := nil; - - //existing and new are both normal items - end else - RaiseEx('inconsistent state'); + tmp := n.ExchangeFirst(o); + aOld := nil; + result := aNew; end; - except - FreeAndNil(aNew); - raise; - end; + if Assigned(tmp) then + raise EengExpressionInternal.Create(1, fParent); + end else if (aOld is TengExpressionOperation) then begin + o := (aOld as TengExpressionOperation); + o.ExchangeLast(aNew); + aNew := nil; + result := aOld; + end else if (aNew is TengExpressionOperation) then begin + n := (aNew as TengExpressionOperation); + n.ExchangeFirst(aOld); + aOld := nil; + result := aNew; + end;; + except + FreeAndNil(aOld); + FreeAndNil(aNew); + result := nil; + raise; end; +end; - function BuildTree(const aDepth: Integer = 0): TengExpressionItem; - var - uOp: TengExpressionUnaryOperator; - bOp: TengExpressionBinaryOperator; - expected: TExpectedParams; - stack: TExpressionItemStack; - l, c: Integer; - ei, tmp: TengExpressionItem; - begin - expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; - result := nil; - stack := TExpressionItemStack.Create(false); - try try - repeat - // GroupBegin - if (p.Name = TOKEN_OP_GROUP_BEGIN) then begin - if not (exGroupBegin in expected) then - RaiseEx('unexpected ''' + p.Name + ''''); - l := p.Line; - c := p.Col; - if not NextParam then - RaiseEx('unexpected end'); - tmp := BuildTree(aDepth + 1); - ei := TengExpressionGroup.Create(tmp, aOwner, l, c, aParam.Filename); - try - MergeItems(stack, ei); - if (p.Name <> TOKEN_OP_GROUP_END) then - RaiseEx('missing ''' + TOKEN_OP_GROUP_END + ''''); - expected := [exBinaryOperation, exGroupEnd]; - except - FreeAndNil(ei); - raise; - end; - - // GroupEnd - end else if (p.Name = TOKEN_OP_GROUP_END) then begin - if not (exGroupEnd in expected) or (aDepth = 0) then - RaiseEx('unexpected ''' + TOKEN_OP_GROUP_END + ''''); - exit; - - // UnaryOperation - end else if IsUnaryOperation(p.Name, uOp) then begin - if not (exUnaryOperation in expected) then - RaiseEx('unexpected operator: ' + p.Name); - ei := TengExpressionUnaryOperation.Create(uOp, aOwner, p.Line, p.Col, aParam.Filename); - try - MergeItems(stack, ei); - expected := [exVariable]; - if (uOp <> opDefined) then - expected := expected + [exValue, exGroupBegin, exUnaryOperation] - except - FreeAndNil(ei); - raise; - end; - - // BinaryOperation - end else if IsBinaryOperation(p.Name, bOp) then begin - if not (exBinaryOperation in expected) then - RaiseEx('unexpected operator: ' + p.Name); - ei := TengExpressionBinaryOperation.Create(bOp, aOwner, p.Line, p.Col, aParam.Filename); - try - MergeItems(stack, ei); - expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; - except - FreeAndNil(ei); - raise; - end; - - // Value - end else if p.Quoted and IsValidIdentifier(p.Name) then begin - if not (exValue in expected) then - RaiseEx('unexpected value: ' + p.Name); - ei := TengExpressionValue.Create(p.Name, aOwner,p.Line, p.Col, aParam.Filename); - try - MergeItems(stack, ei); - expected := [exGroupEnd, exBinaryOperation]; - except - FreeAndNil(ei); - raise; - end; - - // Variable - end else if IsValidIdentifier(p.Name) then begin - if not (exVariable in expected) then - RaiseEx('unexpected variable: ' + p.Name); - ei := TengExpressionVariable.Create(p.Name, aOwner, p.Line, p.Col, aParam.Filename); - try - MergeItems(stack, ei); - expected := [exGroupEnd, exBinaryOperation]; - except - FreeAndNil(ei); - raise - end; - - // Unknown - end else - RaiseEx('invalid parameter: ' + p.Name); - until not NextParam; - except - if (stack.Count > 0) then begin - stack[0].Free; - stack[0] := nil; - end; - raise; - end; - finally - if (stack.Count > 0) then - result := stack[0]; - FreeAndNil(stack); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.GetExpr(const aExpected: TExpectedParams): TengExpressionItem; +var + uOp: TengExpressionUnaryOperator; + bOp: TengExpressionBinaryOperator; + item: TengExpressionItem; + param: TengTokenParameter; +begin + item := nil; + result := nil; + try + if NextParam(param) then begin + // GroupBegin + if (param.Name = TOKEN_OP_GROUP_BEGIN) then begin + if not (exGroupBegin in aExpected) then + RaiseEx('unexpected', param); + item := GetGroup; + result := TengExpressionGroup.Create(Move(item), param.Col, param.Line); + + // GroupEnd + end else if (param.Name = TOKEN_OP_GROUP_END) then begin + if not (exGroupEnd in aExpected) then + RaiseEx('unexpected', param); + + // UnaryOperation + end else if IsUnaryOperation(param.Name, uOp) then begin + if not (exUnaryOperation in aExpected) then + RaiseEx('unexpected operation:', param); + item := GetExpr([exVariable, exValue, exGroupBegin, exUnaryOperation]); + result := TengExpressionUnaryOperation.Create(uOp, Move(item), param.Line, param.Col); + + // BinaryOperation + end else if IsBinaryOperation(param.Name, bOp) then begin + if not (exBinaryOperation in aExpected) then + RaiseEx('unexpected operation:', param); + item := GetExpr([exVariable, exValue, exGroupBegin, exUnaryOperation]); + item := TengExpressionBinaryOperation.Create(bOp, nil, Move(item), param.Line, param.Col); + result := Merge(result, item); + + // Value + end else if param.Quoted and IsValidIdentifier(param.Name) then begin + if not (exValue in aExpected) then + RaiseEx('unexpected value:', param); + result := TengExpressionValue.Create(param.Name, param.Line, param.Col); + + // Variable + end else if IsValidIdentifier(param.Name) then begin + if not (exVariable in aExpected) then + RaiseEx('unexpected variable:', param); + result := TengExpressionVariable.Create(param.Name, param.Line, param.Col); + + // Unknown + end else + raise EengExpression.Create('invalid parameter: ' + param.Name, param.Line, param.Col, fParent.Filename, fParent); end; + + if not Assigned(result) and not (exGroupEnd in aExpected) then + RaiseEx('unexpected', param, 'end'); + except + FreeAndNil(item); + FreeAndNil(result); + raise; end; +end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TExpressionParser.GetGroup: TengExpressionItem; +var + ex: TExpectedParams; + item: TengExpressionItem; + b: Boolean; begin - dec(aIndex); - if not NextParam then with aParam[0] do - raise EengShaderPartInternal.Create('invalid parameter count in expression', Line, Col, aParam.Filename, aOwner); - result := BuildTree; + item := nil; + result := nil; + try + ex := [exVariable, exValue, exGroupBegin, exUnaryOperation]; + repeat + item := GetExpr(ex); + b := Assigned(item); + result := Merge(result, Move(item)); + ex := ex + [exBinaryOperation, exGroupEnd]; + until not b; + except + FreeAndNil(result); + FreeAndNil(item); + raise; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TExpressionParser.Create(const aParent: TengShaderPart; const aParams: TengTokenParameterList; const aIndex: Integer); +begin + fParamPos := aIndex - 1; + fParams := aParams; + fParent := aParent; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function ParseExpression(const aParent: TengShaderPart; const aParams: TengTokenParameterList; aIndex: Integer): TengExpressionItem; +var + parser: TExpressionParser; +begin + parser := TExpressionParser.Create(aParent, aParams, aIndex); + try + result := parser.GetGroup; + finally + FreeAndNil(parser); + end; end; end. diff --git a/uengShaderFileTypes.pas b/uengShaderFileTypes.pas index ad9f9ff..a3e2bc7 100644 --- a/uengShaderFileTypes.pas +++ b/uengShaderFileTypes.pas @@ -45,6 +45,10 @@ type end; EengShaderPartInternal = class(EengShaderPart); EengExpression = class(EengShaderPart); + EengExpressionInternal = class(EengExpression) + ErrorCode: Integer; + constructor Create(const aErrorCode: Integer; const aSender: TObject); + end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// EengInvalidToken = class(EengShaderPartInternal) @@ -127,11 +131,30 @@ type constructor Create(const aName: String; const aNew, aOld: TObject; aLine, aCol: Integer; const aFilename: String; const aSender: TObject); overload; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + EengUnknownIdentifier = class(EengShaderPart) + protected + function GenerateMessage: String; override; + public + Name: String; + constructor Create(const aName: String; const aSender: TObject); overload; + constructor Create(const aName: String; aLine, aCol: Integer; const aFilename: String; const aSender: TObject); overload; + end; + implementation uses uengShaderPart; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengExpressionInternal//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengExpressionInternal.Create(const aErrorCode: Integer; const aSender: TObject); +begin + ErrorCode := aErrorCode; + inherited Create('internal error: ' + IntToStr(ErrorCode), aSender); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //EengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -160,7 +183,7 @@ begin p := (Sender as TengShaderPart); aLines.Text := Message; while Assigned(p) do begin - aLines.Add(Format('%s (%d:%d): %s', [p.Filename, p.Line, p.Col, GetName(p)])); + aLines.Add(Format(' %s (%d:%d): %s', [p.Filename, p.Line+1, p.Col, GetName(p)])); p := p.Parent; end; end; @@ -433,5 +456,27 @@ begin inherited Create(aLine, aCol, aFilename, aSender); end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengUnknownIdentifier///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function EengUnknownIdentifier.GenerateMessage: String; +begin + result := 'unknown identifier: ' + Name; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengUnknownIdentifier.Create(const aName: String; const aSender: TObject); +begin + Name := aName; + inherited Create(aSender); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengUnknownIdentifier.Create(const aName: String; aLine, aCol: Integer; const aFilename: String; const aSender: TObject); +begin + Name := aName; + inherited Create(aLine, aCol, aFilename, aSender); +end; + end. diff --git a/uengShaderPart.pas b/uengShaderPart.pas index 6d9b9a4..d931504 100644 --- a/uengShaderPart.pas +++ b/uengShaderPart.pas @@ -19,19 +19,25 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderFileSearchFlag = ( - sfFirstOnly, // search first match only - sfEvaluateIf, // evaluate if statements before search and process with suitable subtree - - sfSearchChildren, // search in children - sfSearchParents, // search in parents - sfSearchInherited, // search in inherited - - sfCurrentFileOnly, // do not leave current file - sfCurrentScopeOnly, // do not leave current scopes - sfCurrentGeneratorOnly // do not leave current generator + 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 ); - TengShaderFileSearchFlags = set of TengShaderFileSearchFlag; + TengSearchFlags = set of TengSearchFlag; TengShaderPart = class; CengShaderPart = class of TengShaderPart; @@ -43,24 +49,34 @@ type 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); + constructor Create(const aOwner: TengShaderPart; const aReverse: Boolean = false); end; - TSearchResults = class(specialize TutlHashSet) + 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 - constructor Create; + 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 } - private { members } + protected { members } fParent: TengShaderPart; fLine: Integer; fCol: Integer; - protected fRoot: TengShaderPart; protected { virtual getter } function GetCount: Integer; virtual; @@ -69,12 +85,11 @@ type function GetFilename: String; virtual; function GetFileReader: IengShaderFileReader; virtual; function GetFileWriter: IengShaderFileWriter; virtual; - protected { parse methodes } - function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; virtual; - public - function ParseText(const aArgs: TengParseArgs): String; { 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; @@ -93,11 +108,10 @@ type function GetParent(const aType: CengShaderPart; out aPart): Boolean; function GetParent(const aType: CengShaderPart): TengShaderPart; - function FindFirst(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart): TengShaderPart; - procedure FindAll(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart; const aList: TSearchResults); - procedure FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchResults); virtual; + procedure Find(const aFlags: TengSearchFlags; const aResults: TSearchResults); function GetEnumerator: TEnumerator; + function GetReverseEnumerator: TEnumerator; constructor Create(const aParent: TengShaderPart); virtual; @@ -108,7 +122,14 @@ type class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); virtual; end; -function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean; + 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 @@ -116,50 +137,74 @@ uses uengShaderPartScope, uengShaderCodeGenerator, uengShaderFile, uengShaderFileConstants; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Helper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean; -var - c: CengShaderPart; +function TengShaderPart.TEnumerator.GetCurrent: TengShaderPart; begin - result := true; - if (Length(aTypes) = 0) then - exit; - for c in aTypes do - if (aShaderPart is c) then - exit; - result := false; + result := fOwner[fPosition]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TengShaderPart.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderPart.TEnumerator.GetCurrent: TengShaderPart; +function TengShaderPart.TEnumerator.GetEnumerator: TEnumerator; begin - result := fOwner[fPosition]; + result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.TEnumerator.MoveNext: Boolean; begin - inc(fPosition); - result := (fPosition < fOwner.Count); + if not fReverse + then inc(fPosition) + else dec(fPosition); + result := (0 <= fPosition) and (fPosition < fOwner.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TengShaderPart.TEnumerator.Create(const aOwner: TengShaderPart); +constructor TengShaderPart.TEnumerator.Create(const aOwner: TengShaderPart; const aReverse: Boolean); begin inherited Create; fOwner := aOwner; - fPosition := -1; + 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TengShaderPart.TSearchResults//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +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; +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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -207,26 +252,49 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderPart.ParseText(const aArgs: TengParseArgs): String; +procedure TengShaderPart.UpdateCache; var - params: TengTokenParameterList; + p: TengShaderPart; 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; + for p in self do + p.UpdateCache; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderPart.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +function TengShaderPart.FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TSearchResults): Boolean; +var + c: TengShaderPart; + b: Boolean; begin - result := ''; // DUMMY + 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -257,60 +325,21 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderPart.FindFirst(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart): TengShaderPart; -var - l: TSearchResults; +procedure TengShaderPart.Find(const aFlags: TengSearchFlags; const aResults: TSearchResults); begin - l := TSearchResults.Create; - try - FindIntern(aFlags + [sfFirstOnly], 0, aTypes, l); - if (l.Count > 0) - then result := l[0] - else result := nil; - finally - FreeAndNil(l); - end; + FindIntern(aFlags, nil, aResults); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TengShaderPart.FindAll(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart; const aList: TSearchResults); -begin - FindIntern(aFlags, 0, aTypes, aList); -end; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TengShaderPart.FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchResults); -var - c: TengShaderPart; +function TengShaderPart.GetEnumerator: TEnumerator; begin - if (sfFirstOnly in aFlags) and (aList.Count > 0) then - exit; - - if (sfSearchChildren in aFlags) then begin - for c in self do - if (not (sfCurrentScopeOnly in aFlags) or not (c is TengShaderPartScope)) and - (not (sfCurrentFileOnly in aFlags) or not (c is TengShaderFile)) and - (not (sfCurrentGeneratorOnly in aFlags) or not (c is TengShaderCodeGenerator)) - then - c.FindIntern(aFlags, aDepth+1, aTypes, aList); - end; - - if CheckType(self, aTypes) then - aList.Add(self); - - if (sfSearchParents in aFlags) and - Assigned(Parent) and - (not (sfCurrentScopeOnly in aFlags) or not (self is TengShaderPartScope)) and - (not (sfCurrentFileOnly in aFlags) or not (self is TengShaderFile)) and - (not (sfCurrentGeneratorOnly in aFlags) or not (self is TengShaderCodeGenerator)) - then - Parent.FindIntern(aFlags, aDepth-1, aTypes, aList); + result := TEnumerator.Create(self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TengShaderPart.GetEnumerator: TEnumerator; +function TengShaderPart.GetReverseEnumerator: TEnumerator; begin - result := TEnumerator.Create(self); + result := TEnumerator.Create(self, true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -341,5 +370,30 @@ 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. diff --git a/uengShaderPartCall.pas b/uengShaderPartCall.pas index 4358ef7..cfa32c1 100644 --- a/uengShaderPartCall.pas +++ b/uengShaderPartCall.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartCall = class(TengShaderPart) + TengShaderPartCall = class(TengShaderCodePart) { Code Loading & Storage } private { member } fName: String; diff --git a/uengShaderPartClass.pas b/uengShaderPartClass.pas index ff869bd..41a84b8 100644 --- a/uengShaderPartClass.pas +++ b/uengShaderPartClass.pas @@ -28,6 +28,8 @@ type 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; @@ -97,6 +99,36 @@ begin 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 diff --git a/uengShaderPartCntr.pas b/uengShaderPartCntr.pas index 67ca6a9..c2ca3f3 100644 --- a/uengShaderPartCntr.pas +++ b/uengShaderPartCntr.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartCntr = class(TengShaderPart) + TengShaderPartCntr = class(TengShaderCodePart) { Code Loading & Storage } private fChildren: TengShaderPartList; @@ -36,7 +36,7 @@ uses uengShaderPartInclude, uengShaderPartParameter, uengShaderPartComment; const - TOKEN_CLASSES: array[0..20] of CengShaderPart = ( + TOKEN_CLASSES: array[0..20] of CengShaderCodePart = ( TengShaderPartCall, TengShaderPartClass, TengShaderPartDefine, @@ -73,8 +73,8 @@ end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartCntr.HandleToken(const aToken: String; const aArgs: TengParseArgs): String; var - p: TengShaderPart; - c: CengShaderPart; + p: TengShaderCodePart; + c: CengShaderCodePart; begin p := nil; for c in TOKEN_CLASSES do begin diff --git a/uengShaderPartComment.pas b/uengShaderPartComment.pas index 6cc9ff9..4a382c8 100644 --- a/uengShaderPartComment.pas +++ b/uengShaderPartComment.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartComment = class(TengShaderPart) + TengShaderPartComment = class(TengShaderCodePart) { Code Loading & Storage } private fText: String; diff --git a/uengShaderPartEcho.pas b/uengShaderPartEcho.pas index ccec4d6..9a0ff20 100644 --- a/uengShaderPartEcho.pas +++ b/uengShaderPartEcho.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartEcho = class(TengShaderPart) + TengShaderPartEcho = class(TengShaderCodePart) { Code Loading & Storage } private fName: String; diff --git a/uengShaderPartIf.pas b/uengShaderPartIf.pas index 7366371..68c2288 100644 --- a/uengShaderPartIf.pas +++ b/uengShaderPartIf.pas @@ -11,12 +11,12 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartIf = class(TengShaderPart) + TengShaderPartIf = class(TengShaderCodePart) { Code Loading & Storage } private fExpression: TengExpressionItem; - fIfPart: TengShaderPart; - fElsePart: TengShaderPart; + fIfPart: TengShaderCodePart; + fElsePart: TengShaderCodePart; function HandleToken(const aToken: String; const aArgs: TengParseArgs): String; protected function HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; virtual; @@ -26,8 +26,9 @@ type function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; { General } + protected + function FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TSearchResults): Boolean; override; public - procedure FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchResults); override; destructor Destroy; override; { Class Methods } @@ -67,12 +68,12 @@ uses //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartIf.HandleToken(const aToken: String; const aArgs: TengParseArgs): String; const - TOKEN_CLASSES: array[0..1] of CengShaderPart = ( + TOKEN_CLASSES: array[0..1] of CengShaderCodePart = ( TengShaderPartElse, TengShaderPartElIf ); var - c: CengShaderPart; + c: CengShaderCodePart; begin for c in TOKEN_CLASSES do begin if c.CheckToken(aToken) then begin @@ -114,7 +115,7 @@ end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartIf.GetText: String; begin - result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fExpression.GetText + TOKEN_CHAR_END + fIfPart.Text; + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fExpression.Text + TOKEN_CHAR_END + fIfPart.Text; if Assigned(fElsePart) then result := result + fElsePart.Text; result := result + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END; @@ -136,20 +137,21 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TengShaderPartIf.FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchResults); +function TengShaderPartIf.FindIntern(aFlags: TengSearchFlags; const aChild: TengShaderPart; const aResults: TSearchResults): Boolean; begin - if (sfEvaluateIf in aFlags) then begin - inherited FindIntern(aFlags - [sfSearchChildren], aDepth, aTypes, aList); - if (sfSearchChildren in aFlags) then begin - if fExpression.GetValue then begin - if Assigned(fIfPart) then - fIfPart.FindIntern(aFlags, aDepth, aTypes, aList); - end else begin - if Assigned(fElsePart) then - fElsePart.FindIntern(aFlags, aDepth, aTypes, aList); - end; + result := true; + if (sfEvaluateIf in aFlags) and (sfSearchChildren in aFlags) then begin + if fExpression.GetValue then begin + if Assigned(fIfPart) then + fIfPart.Find(aFlags, aResults); + end else begin + if Assigned(fElsePart) then + fElsePart.Find(aFlags, aResults); end; end; + if not (sfSearchAllIf in aFlags) then + exclude(aFlags, sfSearchChildren); + result := result and inherited FindIntern(aFlags, aChild, aResults); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/uengShaderPartInclude.pas b/uengShaderPartInclude.pas index e14061b..5cccbca 100644 --- a/uengShaderPartInclude.pas +++ b/uengShaderPartInclude.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartInclude = class(TengShaderPart) + TengShaderPartInclude = class(TengShaderCodePart) { Code Loading & Storage } private fShaderFile: TengShaderFile; diff --git a/uengShaderPartKeyValuePair.pas b/uengShaderPartKeyValuePair.pas index 6a56cb5..4320785 100644 --- a/uengShaderPartKeyValuePair.pas +++ b/uengShaderPartKeyValuePair.pas @@ -16,7 +16,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartKeyValuePair = class(TengShaderPart) + TengShaderPartKeyValuePair = class(TengShaderCodePart) { Code Loading & Storage } private fName: String; @@ -38,7 +38,6 @@ type { Class Methods } public class function GetTokenName: String; override; - class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override; end; TengShaderPartPropertyMap = specialize TutlMap; @@ -102,25 +101,6 @@ begin result := TOKEN_PROPERTY; end; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class procedure TengShaderPartProperty.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); -end; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPartDefine////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/uengShaderPartMessage.pas b/uengShaderPartMessage.pas index b9b8b48..768957b 100644 --- a/uengShaderPartMessage.pas +++ b/uengShaderPartMessage.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartMessage = class(TengShaderPart) + TengShaderPartMessage = class(TengShaderCodePart) end; diff --git a/uengShaderPartMeta.pas b/uengShaderPartMeta.pas index 32fe3cb..86d3b36 100644 --- a/uengShaderPartMeta.pas +++ b/uengShaderPartMeta.pas @@ -33,7 +33,7 @@ type end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartMeta = class(TengShaderPart) + TengShaderPartMeta = class(TengShaderCodePart) { Code Loading & Storage } private fData: TengMetaData; diff --git a/uengShaderPartParameter.pas b/uengShaderPartParameter.pas index f43cf02..66359b2 100644 --- a/uengShaderPartParameter.pas +++ b/uengShaderPartParameter.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartParameter = class(TengShaderPart) + TengShaderPartParameter = class(TengShaderCodePart) { Code Loading & Storage } private fName: String; diff --git a/uengShaderPartProc.pas b/uengShaderPartProc.pas index 0de2c62..02bf68c 100644 --- a/uengShaderPartProc.pas +++ b/uengShaderPartProc.pas @@ -46,7 +46,6 @@ type { Class Members } public class function GetTokenName: String; override; - class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -171,14 +170,6 @@ begin result := TOKEN_PROC; end; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class procedure TengShaderPartProc.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); -begin - if (aParent.HasParent(TengShaderPartProc, true)) then with aArgs do - raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed inside ' + - TOKEN_PROC + ', ' + TOKEN_FUNC + ' or + ' + TOKEN_MAIN, Line, Col, aParent.Filename, aParent); -end; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPartMain//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/uengShaderPartText.pas b/uengShaderPartText.pas index 5bdb69e..d69f196 100644 --- a/uengShaderPartText.pas +++ b/uengShaderPartText.pas @@ -11,7 +11,7 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartText = class(TengShaderPart) + TengShaderPartText = class(TengShaderCodePart) { Code Loading & Storage } private fText: String; @@ -25,7 +25,7 @@ type end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartLineBreak = class(TengShaderPart) + TengShaderPartLineBreak = class(TengShaderCodePart) { Code Loading & Storage } protected function GetText: String; override; @@ -37,7 +37,7 @@ type end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - TengShaderPartCommandEnd = class(TengShaderPart) + TengShaderPartCommandEnd = class(TengShaderCodePart) { Code Loading & Storage } private fToken: String;