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.

383 lines
14 KiB

  1. unit uengShaderFileHelper;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. uengShaderPart, uengShaderFileParser, uengShaderPartClass;
  7. type
  8. TInfoFlag = (
  9. ifWarning,
  10. ifRaiseEx
  11. );
  12. TInfoFlags = set of TInfoFlag;
  13. function IsValidIdentifier(const aIdent: String): Boolean;
  14. function CheckEndToken(const aToken: String; const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;
  15. function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean;
  16. function ExtractSearchResult(
  17. const aSender: TengShaderPart;
  18. const aIdent: String;
  19. const aList: TengShaderPartList;
  20. const aFlags: TInfoFlags = [ifWarning, ifRaiseEx];
  21. aLine: Integer = -1;
  22. aCol: Integer = -1;
  23. aFilename: String = ''): TengShaderPart;
  24. type
  25. TengSearchFlag = (
  26. sfSearchChildren, // search in children
  27. sfEvaluateIf, // evaluate if and search in suitable subtree
  28. sfIgnoreIf, // do not search in if items
  29. sfSearchChildrenLazy, // set sfSearchChildren in next recursion level
  30. sfSearchParents, // search in Parents
  31. sfSearchInherited, // search in inherited classes
  32. sfIgnoreOwner // ignore owner of search walker
  33. );
  34. TengSearchFlags = set of TengSearchFlag;
  35. TengSearchResults = class(TengShaderPartList)
  36. public
  37. function Add(const aItem: TengShaderPart): Integer; reintroduce;
  38. constructor Create;
  39. end;
  40. TengSearchWalker = class(TengShaderPartWalker)
  41. private type
  42. TArgs = packed record
  43. Flags: TengSearchFlags;
  44. end;
  45. PArgs = ^TArgs;
  46. private
  47. fOwner: TengShaderPart;
  48. fResults: TengSearchResults;
  49. fSearchFlags: TengSearchFlags;
  50. fResultTypes: CengShaderPartArr;
  51. fChildrenDoNotLeave: CengShaderPartArr;
  52. fParentsDoNotLeave: CengShaderPartArr;
  53. fChildrenForceLeave: CengShaderPartArr;
  54. fParentsForceLeave: CengShaderPartArr;
  55. protected
  56. procedure Visit(const aPart, aSender: TengShaderPart; const aArgs: Pointer); override;
  57. function Check(const aPart: TengShaderPart): Boolean; virtual;
  58. public
  59. property Owner: TengShaderPart read fOwner write fOwner;
  60. property SearchFlags: TengSearchFlags read fSearchFlags write fSearchFlags;
  61. property ResultTypes: CengShaderPartArr read fResultTypes write fResultTypes;
  62. property ChildrenDoNotLeave: CengShaderPartArr read fChildrenDoNotLeave write fChildrenDoNotLeave;
  63. property ParentsDoNotLeave: CengShaderPartArr read fParentsDoNotLeave write fParentsDoNotLeave;
  64. property ChildrenForceLeave: CengShaderPartArr read fChildrenForceLeave write fChildrenForceLeave;
  65. property ParentsForceLeave: CengShaderPartArr read fParentsForceLeave write fParentsForceLeave;
  66. constructor Create(const aResults: TengSearchResults);
  67. end;
  68. TengKeyValuePairSearchWalker = class(TengSearchWalker)
  69. private
  70. fName: String;
  71. protected
  72. function Check(const aPart: TengShaderPart): Boolean; override;
  73. public
  74. property Name: String read fName write fName;
  75. end;
  76. TengInheritedSearchWalker = class(TengSearchWalker)
  77. private
  78. fName: String;
  79. protected
  80. function Check(const aPart: TengShaderPart): Boolean; override;
  81. public
  82. property Name: String read fName write fName;
  83. constructor Create(const aClass: TengShaderPartClass; const aResults: TengSearchResults);
  84. end;
  85. TengProcSearchWalker = class(TengSearchWalker)
  86. private
  87. fName: String;
  88. protected
  89. function Check(const aPart: TengShaderPart): Boolean; override;
  90. public
  91. property Name: String read fName write fName;
  92. constructor Create(const aResults: TengSearchResults);
  93. end;
  94. implementation
  95. uses
  96. sysutils,
  97. uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair, uengShaderPartProc,
  98. uengShaderPartIf;
  99. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  100. function IsValidIdentifier(const aIdent: String): Boolean;
  101. var
  102. i, len: Integer;
  103. begin
  104. len := Length(aIdent);
  105. result := false;
  106. for i := 1 to len do
  107. if not (aIdent[i] in VALID_IDENT_CHARS) then
  108. exit;
  109. result := true;
  110. end;
  111. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  112. function CheckEndToken(const aToken: String; const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;
  113. var
  114. oldLine, oldCol: Integer;
  115. param: TengTokenParameterList;
  116. begin
  117. oldLine := aArgs.Line;
  118. oldCol := aArgs.Col;
  119. if (aToken <> TOKEN_END) then
  120. raise EengUnexpectedToken.Create(aToken, TOKEN_END, oldLine, oldCol, aShaderPart.Filename, aShaderPart);
  121. param := TengTokenParameterList.Create('');
  122. try
  123. if not aArgs.ExtractToken(aShaderPart, param) then
  124. EengUnexpectedToken.Create(TOKEN_NONE, TOKEN_END, oldLine, oldCol, aShaderPart.Filename, aShaderPart);
  125. if (param[0].Name <> TOKEN_END) then
  126. EengUnexpectedToken.Create(param[0].Name, TOKEN_END, oldLine, oldCol, aShaderPart.Filename, aShaderPart);
  127. if (param.Count <> 1) then
  128. EengInvalidParamterCount.Create(TOKEN_END, 1, oldLine, oldCol, aShaderPart.Filename, aShaderPart);
  129. result := '';
  130. finally
  131. FreeAndNil(param);
  132. end;
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean;
  136. var
  137. t: CengShaderPart;
  138. begin
  139. result := true;
  140. for t in aTypes do
  141. if (aShaderPart is t) then
  142. exit;
  143. result := (Length(aTypes) = 0);
  144. end;
  145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. function ExtractSearchResult(const aSender: TengShaderPart; const aIdent: String; const aList: TengShaderPartList;
  147. const aFlags: TInfoFlags; aLine: Integer; aCol: Integer; aFilename: String): TengShaderPart;
  148. var
  149. s: String;
  150. i: Integer;
  151. begin
  152. result := nil;
  153. if Assigned(aSender) then begin
  154. if (aLine < 0) then
  155. aLine := aSender.Line;
  156. if (aCol < 0) then
  157. aCol := aSender.Col;
  158. if (aFilename = '') then
  159. aFilename := aSender.Filename;
  160. end;
  161. if (aList.Count <= 0) then begin
  162. if (ifRaiseEx in aFlags) then
  163. raise EengUnknownIdentifier.Create(aIdent, aLine, aCol, aFilename, aSender);
  164. exit;
  165. end;
  166. result := aList[aList.Count-1];
  167. if (aList.Count > 1) and Assigned(aSender) and (ifWarning in aFlags) then begin
  168. s := Format('use of duplicate identifier: %s (%s %d:%d)', [aIdent, result.Filename, result.Line + 1, result.Col]) + sLineBreak +
  169. 'previously declared here:' + sLineBreak;
  170. i := aList.Count - 2;
  171. while (i >= 0) do begin
  172. s := s + Format(' %s %d:%d', [aList[i].Filename, aList[i].Line + 1, aList[i].Col]) + sLineBreak;
  173. dec(i);
  174. end;
  175. aSender.LogMsg(llWarning, s);
  176. end;
  177. end;
  178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. function TengSearchResults.Add(const aItem: TengShaderPart): Integer;
  180. var
  181. i: Integer;
  182. begin
  183. result := -1;
  184. for i := 0 to Count-1 do
  185. if (Items[i] = aItem) then
  186. exit;
  187. result := inherited Add(aItem);
  188. end;
  189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  190. //TengSearchResults/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  192. constructor TengSearchResults.Create;
  193. begin
  194. inherited Create(false);
  195. end;
  196. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  197. //TengSearchWalker//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  198. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. procedure TengSearchWalker.Visit(const aPart, aSender: TengShaderPart; const aArgs: Pointer);
  200. function VisitChild(const aItem: TengShaderPart): Boolean;
  201. var
  202. c: CengShaderPart;
  203. begin
  204. result := Assigned(aItem) and (aItem <> aSender);
  205. if not result then
  206. exit;
  207. for c in fChildrenDoNotLeave do
  208. if (aItem is c) then
  209. result := false;
  210. for c in fChildrenForceLeave do
  211. if (aItem is c) then
  212. result := true;
  213. end;
  214. function VisitParent: Boolean;
  215. var
  216. c: CengShaderPart;
  217. begin
  218. result := Assigned(aPart.Parent) and (aPart.Parent <> aSender);
  219. if not result then
  220. exit;
  221. for c in fParentsDoNotLeave do
  222. if (aPart is c) then
  223. result := false;
  224. for c in fParentsForceLeave do
  225. if (aPart is c) then
  226. result := true;
  227. end;
  228. var
  229. p: TengShaderPart;
  230. c: TengShaderPartClass;
  231. args: TArgs;
  232. nextArgs: TArgs;
  233. begin
  234. if not Assigned(aPart) then
  235. exit;
  236. if Assigned(aArgs) then
  237. args := PArgs(aArgs)^
  238. else
  239. args.Flags := fSearchFlags;
  240. // calculate args for next iteration
  241. nextArgs := args;
  242. if (sfSearchChildrenLazy in nextArgs.Flags) then
  243. nextArgs.Flags := nextArgs.Flags + [sfSearchChildren] - [sfSearchChildrenLazy];
  244. // sfSearchParents
  245. if (sfSearchParents in args.Flags) then begin
  246. if Check(aPart.Parent) then
  247. fResults.Add(aPart.Parent);
  248. if VisitParent then
  249. Visit(aPart.Parent, aPart, @nextArgs);
  250. end;
  251. // sfSearchInherited
  252. if (sfSearchInherited in args.Flags) and (aPart is TengShaderPartClass) then begin
  253. for c in (aPart as TengShaderPartClass).InheritedClasses do begin
  254. if Check(c) then
  255. fResults.Add(c);
  256. Visit(c, aPart, @nextArgs);
  257. end;
  258. end;
  259. // sfSearchChildren
  260. if (sfSearchChildren in args.Flags) then begin
  261. // sfEvaluateIf, sfIgnoreIf
  262. if (aPart is TengShaderPartIf) then with (aPart as TengShaderPartIf) do begin
  263. if (sfEvaluateIf in args.Flags) then begin
  264. if Expression.GetValue
  265. then p := IfPart
  266. else p := ElsePart;
  267. if Assigned(p) then
  268. Visit(p, aPart, @nextArgs);
  269. exit;
  270. end else if (sfIgnoreIf in args.Flags) then
  271. exit;
  272. end;
  273. // normal children
  274. for p in aPart do begin
  275. if Check(p) then
  276. fResults.Add(p);
  277. if VisitChild(p) then
  278. Visit(p, aPart, @nextArgs);
  279. end;
  280. end;
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. function TengSearchWalker.Check(const aPart: TengShaderPart): Boolean;
  284. var
  285. c: CengShaderPart;
  286. begin
  287. result := (aPart <> fOwner) or not (sfIgnoreOwner in fSearchFlags);
  288. if result then
  289. for c in fResultTypes do
  290. if (aPart is c) then
  291. exit;
  292. result := false;
  293. end;
  294. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. constructor TengSearchWalker.Create(const aResults: TengSearchResults);
  296. begin
  297. inherited Create;
  298. fResults := aResults;
  299. end;
  300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. //TengKeyValuePairSearchWalker//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  302. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  303. function TengKeyValuePairSearchWalker.Check(const aPart: TengShaderPart): Boolean;
  304. begin
  305. result :=
  306. inherited Check(aPart) and
  307. (aPart is TengShaderPartKeyValuePair) and
  308. ((aPart as TengShaderPartKeyValuePair).Name = fName);
  309. end;
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. //TengInheritedSearchWalker/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313. function TengInheritedSearchWalker.Check(const aPart: TengShaderPart): Boolean;
  314. begin
  315. result :=
  316. inherited Check(aPart) and
  317. (aPart is TengShaderPartClass) and
  318. ((aPart as TengShaderPartClass).Name = fName);
  319. end;
  320. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  321. constructor TengInheritedSearchWalker.Create(const aClass: TengShaderPartClass; const aResults: TengSearchResults);
  322. begin
  323. inherited Create(aResults);
  324. ResultTypes := CengShaderPartArr.Create(TengShaderPartClass);
  325. SearchFlags := [sfSearchInherited, sfIgnoreOwner];
  326. Owner := aClass;
  327. end;
  328. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  329. //TengProcSearchWalker//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  330. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  331. function TengProcSearchWalker.Check(const aPart: TengShaderPart): Boolean;
  332. begin
  333. result :=
  334. inherited Check(aPart) and
  335. (aPart is TengShaderPartProc) and
  336. ((aPart as TengShaderPartProc).Name = fName);
  337. end;
  338. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  339. constructor TengProcSearchWalker.Create(const aResults: TengSearchResults);
  340. begin
  341. inherited Create(aResults);
  342. ResultTypes := CengShaderPartArr.Create(TengShaderPartProc);
  343. end;
  344. end.