| @@ -0,0 +1,5 @@ | |||
| */lib/ | |||
| *.lps | |||
| *.exe | |||
| *.res | |||
| *.ico | |||
| @@ -0,0 +1,210 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <CONFIG> | |||
| <ProjectOptions> | |||
| <Version Value="9"/> | |||
| <PathDelim Value="\"/> | |||
| <General> | |||
| <SessionStorage Value="InProjectDir"/> | |||
| <MainUnit Value="0"/> | |||
| <Title Value="ShaderFileTests"/> | |||
| <ResourceType Value="res"/> | |||
| <UseXPManifest Value="True"/> | |||
| <Icon Value="0"/> | |||
| </General> | |||
| <i18n> | |||
| <EnableI18N LFM="False"/> | |||
| </i18n> | |||
| <VersionInfo> | |||
| <StringTable ProductVersion=""/> | |||
| </VersionInfo> | |||
| <BuildModes Count="1"> | |||
| <Item1 Name="Default" Default="True"/> | |||
| </BuildModes> | |||
| <PublishOptions> | |||
| <Version Value="2"/> | |||
| </PublishOptions> | |||
| <RunParams> | |||
| <local> | |||
| <FormatVersion Value="1"/> | |||
| </local> | |||
| </RunParams> | |||
| <RequiredPackages Count="3"> | |||
| <Item1> | |||
| <PackageName Value="FPCUnitTestRunner"/> | |||
| </Item1> | |||
| <Item2> | |||
| <PackageName Value="LCL"/> | |||
| </Item2> | |||
| <Item3> | |||
| <PackageName Value="FCL"/> | |||
| </Item3> | |||
| </RequiredPackages> | |||
| <Units Count="27"> | |||
| <Unit0> | |||
| <Filename Value="ShaderFileTests.lpr"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="ShaderFileTests"/> | |||
| </Unit0> | |||
| <Unit1> | |||
| <Filename Value="uShaderFileTestCase.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uShaderFileTestCase"/> | |||
| </Unit1> | |||
| <Unit2> | |||
| <Filename Value="..\uengShaderPart.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPart"/> | |||
| </Unit2> | |||
| <Unit3> | |||
| <Filename Value="..\uengShaderFileTypes.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileTypes"/> | |||
| </Unit3> | |||
| <Unit4> | |||
| <Filename Value="..\uengShaderFile.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFile"/> | |||
| </Unit4> | |||
| <Unit5> | |||
| <Filename Value="..\uengShaderGenerator.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderGenerator"/> | |||
| </Unit5> | |||
| <Unit6> | |||
| <Filename Value="..\uengShaderFileConstants.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileConstants"/> | |||
| </Unit6> | |||
| <Unit7> | |||
| <Filename Value="..\uengShaderFileExpression.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileExpression"/> | |||
| </Unit7> | |||
| <Unit8> | |||
| <Filename Value="..\uengShaderFileHelper.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileHelper"/> | |||
| </Unit8> | |||
| <Unit9> | |||
| <Filename Value="..\uengShaderFileParser.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileParser"/> | |||
| </Unit9> | |||
| <Unit10> | |||
| <Filename Value="..\uengShaderFileScope.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileScope"/> | |||
| </Unit10> | |||
| <Unit11> | |||
| <Filename Value="..\uengShaderGeneratorArgs.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderGeneratorArgs"/> | |||
| </Unit11> | |||
| <Unit12> | |||
| <Filename Value="..\uengShaderPartCall.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartCall"/> | |||
| </Unit12> | |||
| <Unit13> | |||
| <Filename Value="..\uengShaderPartClass.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartClass"/> | |||
| </Unit13> | |||
| <Unit14> | |||
| <Filename Value="..\uengShaderPartCntr.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartCntr"/> | |||
| </Unit14> | |||
| <Unit15> | |||
| <Filename Value="..\uengShaderPartComment.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartComment"/> | |||
| </Unit15> | |||
| <Unit16> | |||
| <Filename Value="..\uengShaderPartEcho.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartEcho"/> | |||
| </Unit16> | |||
| <Unit17> | |||
| <Filename Value="..\uengShaderPartIf.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartIf"/> | |||
| </Unit17> | |||
| <Unit18> | |||
| <Filename Value="..\uengShaderPartInclude.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartInclude"/> | |||
| </Unit18> | |||
| <Unit19> | |||
| <Filename Value="..\uengShaderPartKeyValuePair.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartKeyValuePair"/> | |||
| </Unit19> | |||
| <Unit20> | |||
| <Filename Value="..\uengShaderPartMessage.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartMessage"/> | |||
| </Unit20> | |||
| <Unit21> | |||
| <Filename Value="..\uengShaderPartMeta.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartMeta"/> | |||
| </Unit21> | |||
| <Unit22> | |||
| <Filename Value="..\uengShaderPartParameter.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartParameter"/> | |||
| </Unit22> | |||
| <Unit23> | |||
| <Filename Value="..\uengShaderPartProc.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartProc"/> | |||
| </Unit23> | |||
| <Unit24> | |||
| <Filename Value="..\uengShaderPartScope.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartScope"/> | |||
| </Unit24> | |||
| <Unit25> | |||
| <Filename Value="..\uengShaderPartText.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartText"/> | |||
| </Unit25> | |||
| <Unit26> | |||
| <Filename Value="..\uengShaderCodePart.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderCodePart"/> | |||
| </Unit26> | |||
| </Units> | |||
| </ProjectOptions> | |||
| <CompilerOptions> | |||
| <Version Value="11"/> | |||
| <PathDelim Value="\"/> | |||
| <Target> | |||
| <Filename Value="ShaderFileTests"/> | |||
| </Target> | |||
| <SearchPaths> | |||
| <IncludeFiles Value="$(ProjOutDir);.."/> | |||
| <OtherUnitFiles Value="..;..\..\Utils"/> | |||
| <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | |||
| </SearchPaths> | |||
| <Other> | |||
| <CompilerMessages> | |||
| <IgnoredMessages idx5024="True"/> | |||
| </CompilerMessages> | |||
| </Other> | |||
| </CompilerOptions> | |||
| <Debugging> | |||
| <Exceptions Count="3"> | |||
| <Item1> | |||
| <Name Value="EAbort"/> | |||
| </Item1> | |||
| <Item2> | |||
| <Name Value="ECodetoolError"/> | |||
| </Item2> | |||
| <Item3> | |||
| <Name Value="EFOpenError"/> | |||
| </Item3> | |||
| </Exceptions> | |||
| </Debugging> | |||
| </CONFIG> | |||
| @@ -0,0 +1,15 @@ | |||
| program ShaderFileTests; | |||
| {$mode objfpc}{$H+} | |||
| uses | |||
| Interfaces, Forms, GuiTestRunner, uShaderFileTestCase; | |||
| {$R *.res} | |||
| begin | |||
| Application.Initialize; | |||
| Application.CreateForm(TGuiTestRunner, TestRunner); | |||
| Application.Run; | |||
| end. | |||
| @@ -0,0 +1,8 @@ | |||
| {$PROPERTY TestProp '0'} | |||
| {$IF TestProp = '0'} | |||
| int i = 0; | |||
| {$ELIF TestProp = '1'} | |||
| int i = 1; | |||
| {$ELSE} | |||
| int i = 2; | |||
| {$END} | |||
| @@ -0,0 +1,9 @@ | |||
| {$PROPERTY TestProp '0'} | |||
| some code here = {$IF TestProp = '0'}this code{$ELSE}that code{$END}; | |||
| some code here = {$IF TestProp = '0'} | |||
| this code * | |||
| more code | |||
| {$ELSE} | |||
| that code * | |||
| more code | |||
| {$END}; | |||
| @@ -0,0 +1 @@ | |||
| int i = 0; | |||
| @@ -0,0 +1 @@ | |||
| int i = 1; | |||
| @@ -0,0 +1 @@ | |||
| int i = 2; | |||
| @@ -0,0 +1,4 @@ | |||
| some code here = this code; | |||
| some code here = | |||
| this code * | |||
| more code; | |||
| @@ -0,0 +1,4 @@ | |||
| some code here = that code; | |||
| some code here = | |||
| that code * | |||
| more code; | |||
| @@ -0,0 +1,72 @@ | |||
| unit uShaderFileTestCase; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils, fpcunit, testregistry, | |||
| uengShaderFile, uengShaderGenerator, uengShaderFileTypes; | |||
| type | |||
| TShaderFileTestCase = class(TTestCase) | |||
| private | |||
| procedure DoTest(const aCode: String; const aValue: Integer; const aResult: String); | |||
| published | |||
| procedure IfElseElifEnd; | |||
| procedure InlineIf; | |||
| end; | |||
| implementation | |||
| uses | |||
| Forms; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TShaderFileTestCase/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TShaderFileTestCase.DoTest(const aCode: String; const aValue: Integer; const aResult: String); | |||
| var | |||
| shdr: TengShaderFile; | |||
| gen: TengShaderGenerator; | |||
| code: TengShaderCode; | |||
| sl: TStringList; | |||
| begin | |||
| shdr := TengShaderFile.Create; | |||
| code := TengShaderCode.Create; | |||
| sl := TStringList.Create; | |||
| try | |||
| shdr.LoadFromFile(ExpandFileName(aCode)); | |||
| gen := shdr.Generator['']; | |||
| if (gen.PropertyCount > 0) then | |||
| gen.PropertyByIndex[0] := aValue; | |||
| gen.GenerateCode(code); | |||
| sl.LoadFromFile(ExpandFileName(aResult)); | |||
| AssertEquals(sl.Text, code.Text); | |||
| finally | |||
| FreeAndNil(sl); | |||
| FreeAndNil(code); | |||
| FreeAndNil(shdr); | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TShaderFileTestCase.IfElseElifEnd; | |||
| begin | |||
| DoTest('code_IfElseElifEnd.shdr', 0, 'result_IfElseElifEnd_0.shdr'); | |||
| DoTest('code_IfElseElifEnd.shdr', 1, 'result_IfElseElifEnd_1.shdr'); | |||
| DoTest('code_IfElseElifEnd.shdr', 2, 'result_IfElseElifEnd_2.shdr'); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TShaderFileTestCase.InlineIf; | |||
| begin | |||
| DoTest('code_InlineIf.shdr', 0, 'result_InlineIf_0.shdr'); | |||
| DoTest('code_InlineIf.shdr', 1, 'result_InlineIf_1.shdr'); | |||
| end; | |||
| initialization | |||
| RegisterTest(TShaderFileTestCase); | |||
| end. | |||
| @@ -60,7 +60,8 @@ type | |||
| property OnLog: TengShaderFileLogEvent read fOnLog write fOnLog; | |||
| procedure Clear; override; | |||
| constructor Create(const aParent: TengShaderPart); override; | |||
| constructor Create; overload; | |||
| constructor Create(const aParent: TengShaderPart); override; overload; | |||
| destructor Destroy; override; | |||
| end; | |||
| @@ -309,6 +310,12 @@ begin | |||
| fClasses.Clear; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TengShaderFile.Create; | |||
| begin | |||
| Create(nil); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TengShaderFile.Create(const aParent: TengShaderPart); | |||
| begin | |||
| @@ -16,7 +16,7 @@ type | |||
| TInfoFlags = set of TInfoFlag; | |||
| function IsValidIdentifier(const aIdent: String): Boolean; | |||
| function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; | |||
| function CheckEndToken(const aToken: String; const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; | |||
| function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean; | |||
| function ExtractSearchResult( | |||
| const aSender: TengShaderPart; | |||
| @@ -97,7 +97,8 @@ implementation | |||
| uses | |||
| sysutils, | |||
| uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair, uengShaderPartProc, uengShaderPartIf; | |||
| uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair, uengShaderPartProc, | |||
| uengShaderPartIf, uengShaderPartClass; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function IsValidIdentifier(const aIdent: String): Boolean; | |||
| @@ -113,15 +114,17 @@ begin | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; | |||
| function CheckEndToken(const aToken: String; const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; | |||
| var | |||
| oldLine, oldCol: Integer; | |||
| param: TengTokenParameterList; | |||
| begin | |||
| oldLine := aArgs.Line; | |||
| oldCol := aArgs.Col; | |||
| if (aToken <> TOKEN_END) then | |||
| raise EengUnexpectedToken.Create(aToken, TOKEN_END, oldLine, oldCol, aShaderPart.Filename, aShaderPart); | |||
| param := TengTokenParameterList.Create(''); | |||
| try | |||
| oldLine := aArgs.Line; | |||
| oldCol := aArgs.Col; | |||
| if not aArgs.ExtractToken(aShaderPart, param) then | |||
| EengUnexpectedToken.Create(TOKEN_NONE, TOKEN_END, oldLine, oldCol, aShaderPart.Filename, aShaderPart); | |||
| if (param[0].Name <> TOKEN_END) then | |||
| @@ -227,6 +230,7 @@ var | |||
| var | |||
| p: TengShaderPart; | |||
| c: TengShaderPartClass; | |||
| nextArgs: TArgs; | |||
| begin | |||
| if not Assigned(aPart) then | |||
| @@ -245,6 +249,12 @@ begin | |||
| if VisitParent then | |||
| Visit(aPart.Parent, aPart, @nextArgs); | |||
| // visit inherited | |||
| if (sfSearchInherited in args.Flags) and (aPart is TengShaderPartClass) then begin | |||
| for c in (aPart as TengShaderPartClass).InheritedClasses do | |||
| Visit(c, aPart, @nextArgs); | |||
| end; | |||
| // visit children | |||
| if (sfSearchChildren in args.Flags) then begin | |||
| if (aPart is TengShaderPartIf) then with (aPart as TengShaderPartIf) do begin | |||
| @@ -253,7 +263,7 @@ begin | |||
| then p := IfPart | |||
| else p := ElsePart; | |||
| if Assigned(p) then | |||
| Visit(p, aPart, @args); | |||
| Visit(p, aPart, @nextArgs); | |||
| exit; | |||
| end else if (sfIgnoreIf in args.Flags) then | |||
| exit; | |||
| @@ -263,7 +273,7 @@ begin | |||
| if Check(p) then | |||
| fResults.Add(p); | |||
| if VisitChild(p) then | |||
| Visit(p, aPart, @args); | |||
| Visit(p, aPart, @nextArgs); | |||
| end; | |||
| end; | |||
| end; | |||
| @@ -9,7 +9,7 @@ interface | |||
| uses | |||
| Classes, SysUtils, | |||
| uengShaderFilePart; | |||
| uengShaderPart; | |||
| type | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -201,7 +201,8 @@ type | |||
| gfToken, // current line has a token in it | |||
| gfTokenOnly, // current line has only a token (or whitespaces) in it | |||
| gfPrevIsEmpty, // previouse line was empty (or whitespaces only) | |||
| gfCodeIsEmpty // nothing has added to code | |||
| gfCodeIsEmpty, // nothing has added to code | |||
| gfAddToPrev // add current line to previouse line | |||
| ); | |||
| TGenFlags = set of TGenFlag; | |||
| @@ -291,12 +292,15 @@ var | |||
| Include(f, gfPrevIsEmpty); | |||
| end; | |||
| end else begin | |||
| aCode.Add(line); | |||
| if (gfAddToPrev in f) and not (gfCodeIsEmpty in f) | |||
| then aCode[aCode.Count-1] := aCode[aCode.Count-1] + TrimLeft(line) | |||
| else aCode.Add(line); | |||
| Exclude(f, gfPrevIsEmpty); | |||
| Exclude(f, gfCodeIsEmpty); | |||
| end; | |||
| Exclude(f, gfToken); | |||
| Exclude(f, gfTokenOnly); | |||
| Exclude(f, gfAddToPrev); | |||
| line := ''; | |||
| end; | |||
| @@ -313,6 +317,8 @@ var | |||
| gtBlockEnd: begin | |||
| IndentBlock(FirstLineIndex, aIndent); | |||
| if (Trim(line) = '') and not (gfPrevIsEmpty in f) then | |||
| include(f, gfAddToPrev); | |||
| exit; | |||
| end; | |||
| @@ -198,7 +198,7 @@ procedure TengShaderPartInherited.GenerateCodeIntern(const aArgs: TengShaderGene | |||
| if (walker.Name = '') then | |||
| walker.Name := ParentProc.Name; | |||
| walker.Owner := ParentProc; | |||
| walker.SearchFlags := [sfEvaluateIf, sfIgnoreOwner, sfSearchChildrenLazy, sfSearchInherited, sfSearchParents]; | |||
| walker.SearchFlags := [sfEvaluateIf, sfIgnoreOwner, sfSearchChildrenLazy, sfSearchInherited]; | |||
| walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass); | |||
| walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass); | |||
| walker.Run(ParentProc); | |||
| @@ -38,8 +38,9 @@ type | |||
| { General } | |||
| public | |||
| property Name: String read fName; | |||
| property Extends: TStrings read GetExtends; | |||
| property Name: String read fName; | |||
| property Extends: TStrings read GetExtends; | |||
| property InheritedClasses: TengShaderPartClassList read fInherited; | |||
| constructor Create(const aParent: TengShaderPart); override; | |||
| destructor Destroy; override; | |||
| @@ -154,7 +155,7 @@ begin | |||
| end; | |||
| UpdateInherited; | |||
| result := inherited ParseIntern(aArgs, aParams); | |||
| result := CheckEndToken(aArgs, self); | |||
| result := CheckEndToken(result, aArgs, self); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -101,6 +101,7 @@ begin | |||
| break; | |||
| end; | |||
| end; | |||
| result := aToken; | |||
| if Assigned(fElsePart) then | |||
| result := fElsePart.ParseText(aArgs); | |||
| result := HandeEndToken(result, aArgs); | |||
| @@ -109,7 +110,7 @@ end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderPartIf.HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; | |||
| begin | |||
| result := CheckEndToken(aArgs, self); | |||
| result := CheckEndToken(aToken, aArgs, self); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -185,7 +186,7 @@ function TengShaderPartElIf.HandeEndToken(const aToken: String; const aArgs: Ten | |||
| begin | |||
| result := aToken; | |||
| if (result <> TOKEN_END) then | |||
| raise EengInvalidToken.Create(ClassName, result, aArgs.Line, aArgs.Col, Filename, self); | |||
| raise EengUnexpectedToken.Create(aToken, TOKEN_END, aArgs.Col, aArgs.Line, Filename, self); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -179,8 +179,8 @@ begin | |||
| end; | |||
| if (state <> pasType) then | |||
| raise EengInvalidParamterCount.Create('invalid parameter count in ' + GetTokenName + '(expected multiple of 2)', self); | |||
| inherited ParseIntern(aArgs, aParams); | |||
| result := CheckEndToken(aArgs, self); | |||
| result := inherited ParseIntern(aArgs, aParams); | |||
| result := CheckEndToken(result, aArgs, self); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||