You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
14 KiB

  1. unit uengShaderPartCall;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils,
  7. uengShaderPart, uengShaderCodePart, uengShaderFileParser, uengShaderGeneratorArgs, uengShaderPartClass,
  8. uengShaderPartProc, uengShaderPartKeyValuePair;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. TengShaderPartCall = class(TengShaderCodePart)
  12. { Code Loading & Storage }
  13. private { member }
  14. fName: String;
  15. fParameters: TStringList;
  16. function FindKeyValuePair(const aName: String): TengShaderPartKeyValuePair;
  17. protected { virtual getter }
  18. function GetText: String; override;
  19. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  20. { Code Generation }
  21. public
  22. procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;
  23. { General }
  24. private
  25. function GetParameters: TStrings;
  26. public
  27. property Parameters: TStrings read GetParameters;
  28. constructor Create(const aParent: TengShaderPart); override;
  29. destructor Destroy; override;
  30. { Class Methods }
  31. public
  32. class function GetTokenName: String; override;
  33. end;
  34. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  35. TengShaderPartInherited = class(TengShaderPartCall)
  36. { Code Loading & Storage }
  37. private
  38. fInline: Boolean;
  39. fClass: TengShaderPartClass;
  40. protected
  41. function GetText: String; override;
  42. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  43. { Code Generation }
  44. public
  45. procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;
  46. { Class Methods }
  47. public
  48. class function GetTokenName: String; override;
  49. class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override;
  50. end;
  51. implementation
  52. uses
  53. uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderGenerator,
  54. uengShaderFile, uengShaderPartScope;
  55. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. //TengShaderPartCall////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. function TengShaderPartCall.FindKeyValuePair(const aName: String): TengShaderPartKeyValuePair;
  59. var
  60. sr: TengSearchResults;
  61. walker: TengKeyValuePairSearchWalker;
  62. begin
  63. sr := TengSearchResults.Create;
  64. walker := TengKeyValuePairSearchWalker.Create(sr);
  65. try
  66. walker.Name := aName;
  67. walker.SearchFlags := [sfSearchChildren, sfSearchParents];
  68. walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic);
  69. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartScope);
  70. walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
  71. walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile);
  72. walker.Run(fParent);
  73. result := (ExtractSearchResult(self, aName, sr) as TengShaderPartKeyValuePair);
  74. finally
  75. FreeAndNil(walker);
  76. FreeAndNil(sr);
  77. end;
  78. end;
  79. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  80. function TengShaderPartCall.GetText: String;
  81. var
  82. i: Integer;
  83. begin
  84. result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName;
  85. for i := 0 to fParameters.Count-1 do begin
  86. if Assigned(fParameters.Objects[i])
  87. then result := result + ' ' + TengShaderPartKeyValuePair(fParameters.Objects[i]).Name
  88. else result := result + ' ' + TOKEN_CHAR_QUOTE + fParameters[i] + TOKEN_CHAR_QUOTE;
  89. end;
  90. result := result + TOKEN_CHAR_END;
  91. end;
  92. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  93. function TengShaderPartCall.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  94. var
  95. i: Integer;
  96. begin
  97. if (aParams[0].Name <> GetTokenName) then
  98. raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename, self);
  99. if (aParams.Count < 2) then
  100. raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, self);
  101. fParameters.Clear;
  102. result := '';
  103. fName := aParams[1].Name;
  104. if not IsValidIdentifier(fName) then
  105. raise EengInvalidIdentifier.Create(fName, aParams[1].Line, aParams[1].Col, Filename, self);
  106. for i := 2 to aParams.Count-1 do begin
  107. if not aParams[i].Quoted
  108. then fParameters.AddObject(aParams[i].Name, FindKeyValuePair(aParams[i].Name))
  109. else fParameters.AddObject(aParams[i].Name, nil);
  110. end;
  111. end;
  112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  113. procedure TengShaderPartCall.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
  114. var
  115. sr: TengSearchResults;
  116. walker: TengProcSearchWalker;
  117. proc: TengShaderPartProc;
  118. begin
  119. inherited GenerateCodeIntern(aArgs);
  120. sr := TengSearchResults.Create;
  121. walker := TengProcSearchWalker.Create(sr);
  122. try
  123. walker.Name := fName;
  124. walker.SearchFlags := [sfEvaluateIf, sfSearchChildren, sfSearchInherited];
  125. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
  126. walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
  127. walker.Run(aArgs.Root);
  128. proc := (ExtractSearchResult(self, walker.Name, sr) as TengShaderPartProc);
  129. aArgs.PushProcParams(fParameters);
  130. aArgs.PushFlags(aArgs.Flags - [gfGenerateProcedureCode, gfGenerateInlineCode] + [gfGenerateProcedureCall]);
  131. try
  132. proc.GenerateCodeIntern(aArgs);
  133. finally
  134. aArgs.PopFlags;
  135. aArgs.PopProcParams;
  136. end;
  137. finally
  138. FreeAndNil(walker);
  139. FreeAndNil(sr);
  140. end;
  141. end;
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. function TengShaderPartCall.GetParameters: TStrings;
  144. begin
  145. result := fParameters;
  146. end;
  147. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. constructor TengShaderPartCall.Create(const aParent: TengShaderPart);
  149. begin
  150. inherited Create(aParent);
  151. fParameters := TStringList.Create;
  152. end;
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. destructor TengShaderPartCall.Destroy;
  155. begin
  156. FreeAndNil(fParameters);
  157. inherited Destroy;
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. class function TengShaderPartCall.GetTokenName: String;
  161. begin
  162. result := TOKEN_CALL;
  163. end;
  164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  165. //TengShaderPartInherited///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. function TengShaderPartInherited.GetText: String;
  168. begin
  169. result := inherited GetText;
  170. if fInline then
  171. Insert(' ' + TOKEN_INLINE, result, Length(result) - 1);
  172. end;
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. function TengShaderPartInherited.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  175. function FindInheritedClass(const aName: string): TengShaderPartClass;
  176. var
  177. sr: TengSearchResults;
  178. walker: TengInheritedSearchWalker;
  179. begin
  180. sr := TengSearchResults.Create;
  181. walker := TengInheritedSearchWalker.Create((GetParent(TengShaderPartClass) as TengShaderPartClass), sr);
  182. try
  183. walker.Name := aName;
  184. walker.Run(walker.Owner);
  185. result := (ExtractSearchResult(self, aName, sr, [ifWarning]) as TengShaderPartClass);
  186. finally
  187. FreeAndNil(walker);
  188. FreeAndNil(sr);
  189. end;
  190. end;
  191. type
  192. TExpectedPart = (epClass, epProc, epParam);
  193. TExpectedParts = set of TExpectedPart;
  194. var
  195. i: Integer;
  196. expected: TExpectedParts;
  197. begin
  198. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  199. raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self);
  200. fName := '';
  201. result := '';
  202. fClass := nil;
  203. fInline := false;
  204. expected := [epClass, epProc, epParam];
  205. fParameters.Clear;
  206. for i := 1 to aParams.Count-1 do begin
  207. // quoted parameter
  208. if aParams[i].Quoted then begin
  209. if not (epParam in expected) then
  210. raise EengUnexpectedToken.Create(aParams[i].Name, '[none]', aParams[i].Line, aParams[i].Col, Filename, self);
  211. fParameters.AddObject(aParams[i].Name, nil);
  212. expected := expected - [epClass, epProc];
  213. continue;
  214. end;
  215. // inline
  216. if (aParams[i].Name = TOKEN_INLINE) then begin
  217. fInline := true;
  218. continue;
  219. end;
  220. // class
  221. if (epClass in expected) then begin
  222. fClass := FindInheritedClass(aParams[i].Name);
  223. if Assigned(fClass) then begin
  224. expected := expected - [epClass];
  225. continue;
  226. end;
  227. end;
  228. // proc
  229. if (epProc in expected) then begin
  230. fName := aParams[i].Name;
  231. expected := expected - [epClass, epProc];
  232. continue;
  233. end;
  234. // unquoted param
  235. if (epParam in expected) then begin
  236. fParameters.AddObject(aParams[i].Name, FindKeyValuePair(aParams[i].Name));
  237. continue;
  238. end;
  239. raise EengUnexpectedToken.Create(aParams[i].Name, '[none]', aParams[i].Line, aParams[i].Col, Filename, self);
  240. end;
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. procedure TengShaderPartInherited.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
  244. function FindProc: TengShaderPartProc;
  245. var
  246. sr: TengSearchResults;
  247. walker: TengProcSearchWalker;
  248. c: TengShaderPartClass;
  249. begin
  250. sr := TengSearchResults.Create;
  251. walker := TengProcSearchWalker.Create(sr);
  252. try
  253. walker.Name := fName;
  254. if (walker.Name = '') then
  255. walker.Name := (GetParent(TengShaderPartProc) as TengShaderPartProc).Name;
  256. walker.SearchFlags := [sfEvaluateIf, sfSearchChildren, sfSearchInherited];
  257. walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass);
  258. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass);
  259. if not Assigned(fClass) then begin
  260. for c in (GetParent(TengShaderPartClass) as TengShaderPartClass).InheritedClasses do
  261. walker.Run(c);
  262. end else
  263. walker.Run(fClass);
  264. result := (ExtractSearchResult(self, walker.Name, sr) as TengShaderPartProc);
  265. finally
  266. FreeAndNil(walker);
  267. FreeAndNil(sr);
  268. end;
  269. end;
  270. procedure GenCode(const aProc: TengShaderPartProc; const aParams: TStrings);
  271. begin
  272. if fInline
  273. then aArgs.PushFlags(aArgs.Flags + [gfGenerateInlineCode, gfGenerateProcedureCall] - [gfGenerateProcedureCode])
  274. else aArgs.PushFlags(aArgs.Flags + [gfGenerateProcedureCall] - [gfGenerateProcedureCode]);
  275. aArgs.PushProcParams(aParams);
  276. try
  277. aProc.GenerateCodeIntern(aArgs);
  278. finally
  279. aArgs.PopProcParams;
  280. aArgs.PopFlags;
  281. end;
  282. end;
  283. var
  284. proc: TengShaderPartProc;
  285. i: Integer;
  286. params: TStringList;
  287. begin
  288. aArgs.AddToken(GetTokenName);
  289. proc := FindProc;
  290. if (fParameters.Count > 0) then begin
  291. if (fParameters.Count <> proc.ParameterCount) then
  292. raise EengInvalidParamterCount.Create(proc.name + ' expexts ' + IntToStr(proc.ParameterCount) + ' parameters', self);
  293. for i := 0 to fParameters.Count-1 do
  294. if Assigned(fParameters.Objects[i]) then
  295. fParameters[i] := TengShaderPartKeyValuePair(fParameters.Objects[i]).Value;
  296. GenCode(proc, fParameters);
  297. end else begin
  298. params := TStringList.Create;
  299. try
  300. for i := 0 to proc.ParameterCount-1 do
  301. params.Add(proc.Parameters[i].Name);
  302. GenCode(proc, params);
  303. finally
  304. FreeAndNil(params);
  305. end;
  306. end;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. class function TengShaderPartInherited.GetTokenName: String;
  310. begin
  311. result := TOKEN_INHERITED;
  312. end;
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. class procedure TengShaderPartInherited.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart);
  315. begin
  316. inherited Validate(aArgs, aParent);
  317. if not aParent.HasParent(TengShaderPartProc, true) or
  318. not aParent.HasParent(TengShaderPartClass, true) then
  319. raise EengShaderPart.Create(GetTokenName + ' is not allowed outside of ' +
  320. TOKEN_PROC + ', ' + TOKEN_FUNC + ', ' + TOKEN_MAIN + ' or ' + TOKEN_CLASS);
  321. end;
  322. end.