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.

631 lines
24 KiB

  1. unit uengShaderFileExpression;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils, variants,
  7. uengShaderFileParser;
  8. type
  9. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  10. TengExpressionItem = class(TObject)
  11. private
  12. fLine: Integer;
  13. fCol: Integer;
  14. fFilename: String;
  15. public
  16. property Line: Integer read fLine;
  17. property Col: Integer read fCol;
  18. property Filename: String read fFilename;
  19. function GetText: String; virtual;
  20. function GetValue: Variant; virtual;
  21. constructor Create(const aLine, aCol: Integer; const aFilename: String);
  22. end;
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. TengExpressionValue = class(TengExpressionItem)
  25. private
  26. fValue: Variant;
  27. public
  28. function GetText: String; override;
  29. function GetValue: Variant; override;
  30. constructor Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
  31. end;
  32. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  33. TengExpressionVariable = class(TengExpressionItem)
  34. private
  35. fName: String;
  36. public
  37. function GetText: String; override;
  38. function GetValue: Variant; override;
  39. constructor Create(const aName: String; const aLine, aCol: Integer; const aFilename: String);
  40. end;
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. TengExpressionGroup = class(TengExpressionItem)
  43. private
  44. fChild: TengExpressionItem;
  45. public
  46. property Child: TengExpressionItem read fChild write fChild;
  47. function GetText: String; override;
  48. function GetValue: Variant; override;
  49. constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
  50. destructor Destroy; override;
  51. end;
  52. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  53. TengExpressionUnaryOperator = (
  54. opBinaryNot,
  55. opLogicalNot,
  56. opDefined,
  57. opSet
  58. );
  59. TengExpressionUnaryOperation = class(TengExpressionItem)
  60. private
  61. fChild: TengExpressionItem;
  62. fUnaryOp: TengExpressionUnaryOperator;
  63. public
  64. property Child: TengExpressionItem read fChild write fChild;
  65. property UnaryOp: TengExpressionUnaryOperator read fUnaryOp;
  66. function GetText: String; override;
  67. function GetValue: Variant; override;
  68. constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
  69. destructor Destroy; override;
  70. end;
  71. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators
  73. opBinaryOr, opBinaryAnd, opBinaryXor, // binary
  74. opMultiply, opDivide, opAdd, opSubtract, // arithmetic
  75. opLogicalOr, opLogicalAnd, opLogicalXor, // logical
  76. opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison
  77. );
  78. TengExpressionBinaryOperation = class(TengExpressionItem)
  79. private
  80. fFirst: TengExpressionItem;
  81. fSecond: TengExpressionItem;
  82. fBinaryOp: TengExpressionBinaryOperator;
  83. public
  84. property First: TengExpressionItem read fFirst write fFirst;
  85. property Second: TengExpressionItem read fSecond write fSecond;
  86. property BinaryOp: TengExpressionBinaryOperator read fBinaryOp;
  87. function GetText: String; override;
  88. function GetValue: Variant; override;
  89. constructor Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
  90. destructor Destroy; override;
  91. end;
  92. function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem;
  93. implementation
  94. uses
  95. uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper
  96. {$IFDEF USE_BITSPACE_UTILS}
  97. , uutlGenerics
  98. {$ELSE}
  99. , fgl
  100. {$ENDIF}
  101. ;
  102. const
  103. EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = (
  104. TOKEN_OP_BINARY_NOT, //opBinaryNot
  105. TOKEN_OP_LOGICAL_NOT, //opLogicalNot
  106. TOKEN_OP_DEFINED, //opDefined
  107. TOKEN_OP_SET //opSet
  108. );
  109. EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = (
  110. TOKEN_OP_BINARY_OR, //opBinaryOr
  111. TOKEN_OP_BINARY_AND, //opBinaryAnd
  112. TOKEN_OP_BINARY_XOR, //opBinaryXor
  113. TOKEN_OP_MULTIPLY, //opMultiply
  114. TOKEN_OP_DIVIDE, //opDivide
  115. TOKEN_OP_ADD, //opAdd
  116. TOKEN_OP_SUBTRACT, //opSubtract
  117. TOKEN_OP_LOGICAL_OR, //opLogicalOr
  118. TOKEN_OP_LOGICAL_AND, //opLogicalAnd
  119. TOKEN_OP_LOGICAL_XOR, //opLogicalXor
  120. TOKEN_OP_EQUALS, //opEquals
  121. TOKEN_OP_LESSER, //opLesser
  122. TOKEN_OP_GREATER, //opGreater
  123. TOKEN_OP_LEQUALS, //opLEquals
  124. TOKEN_OP_GEQUALS, //opGEquals
  125. TOKEN_OP_UNEQUALS //opUnequals,
  126. );
  127. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  128. //TengExpressionItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. function TengExpressionItem.GetText: String;
  131. begin
  132. result := ''; // DUMMY
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. function TengExpressionItem.GetValue: Variant;
  136. begin
  137. result := Unassigned; // DUMMY
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. constructor TengExpressionItem.Create(const aLine, aCol: Integer; const aFilename: String);
  141. begin
  142. inherited Create;
  143. fLine := aLine;
  144. fCol := aCol;
  145. fFilename := aFilename;
  146. end;
  147. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. //TengExpressionValue///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. function TengExpressionValue.GetText: String;
  151. begin
  152. result := TOKEN_CHAR_QUOTE + fValue + TOKEN_CHAR_QUOTE;
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. function TengExpressionValue.GetValue: Variant;
  156. begin
  157. result := fValue;
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
  161. begin
  162. inherited Create(aLine, aCol, aFilename);
  163. fValue := aValue;
  164. end;
  165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  166. //TengExpressionVariable////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  168. function TengExpressionVariable.GetText: String;
  169. begin
  170. result := fName;
  171. end;
  172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. function TengExpressionVariable.GetValue: Variant;
  174. begin
  175. result := Unassigned; // TODO
  176. end;
  177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  178. constructor TengExpressionVariable.Create(const aName: String; const aLine, aCol: Integer; const aFilename: String);
  179. begin
  180. inherited Create(aLine, aCol, aFilename);
  181. fName := aName;
  182. end;
  183. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  184. ///TengExpressionGroup//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  185. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  186. function TengExpressionGroup.GetText: String;
  187. begin
  188. if Assigned(fChild)
  189. then result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END
  190. else result := '';
  191. end;
  192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. function TengExpressionGroup.GetValue: Variant;
  194. begin
  195. if Assigned(fChild)
  196. then result := fChild.GetValue
  197. else result := Unassigned;
  198. end;
  199. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  200. constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
  201. begin
  202. inherited Create(aLine, aCol, aFilename);
  203. fChild := aChild;
  204. end;
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. destructor TengExpressionGroup.Destroy;
  207. begin
  208. FreeAndNil(fChild);
  209. inherited Destroy;
  210. end;
  211. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. //TengExpressionUnaryOperation//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  214. function TengExpressionUnaryOperation.GetText: String;
  215. begin
  216. if not Assigned(fChild) then
  217. EengExpression.Create('no child assigned', Line, Col, Filename);
  218. result :=
  219. {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN+{$ENDIF}
  220. EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText
  221. {$IFDEF EXPRESSION_ADD_BRACKET}+TOKEN_OP_GROUP_END{$ENDIF};
  222. end;
  223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  224. function TengExpressionUnaryOperation.GetValue: Variant;
  225. var
  226. v: Variant;
  227. begin
  228. if not Assigned(fChild) then
  229. raise EengExpression.Create('no child assigned', Line, Col, Filename);
  230. try
  231. case fUnaryOp of
  232. opBinaryNot: begin
  233. v := fChild.GetValue;
  234. result := not Integer(v);
  235. end;
  236. opLogicalNot: begin
  237. v := fChild.GetValue;
  238. result := not Boolean(v);
  239. end;
  240. opDefined: begin
  241. // TODO
  242. end;
  243. opSet: begin
  244. // TODO
  245. end;
  246. else
  247. result := inherited GetValue;
  248. end;
  249. except
  250. on ex: Exception do
  251. raise EengInvalidParamter.Create(
  252. ex.Message + '("' + GetText + '" ==> ' +
  253. EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")',
  254. Line, Col, Filename);
  255. end;
  256. end;
  257. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
  259. begin
  260. inherited Create(aLine, aCol, aFilename);
  261. fChild := nil;
  262. fUnaryOp := aUnaryOp;
  263. end;
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. destructor TengExpressionUnaryOperation.Destroy;
  266. begin
  267. FreeAndNil(fChild);
  268. inherited Destroy;
  269. end;
  270. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  271. //TengExpressionBinaryOperation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  273. function TengExpressionBinaryOperation.GetText: String;
  274. begin
  275. if not Assigned(fFirst) or not Assigned(fSecond) then
  276. raise EengExpression.Create('first or second item not assigned');
  277. result :=
  278. {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF}
  279. fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText
  280. {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF};
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. function TengExpressionBinaryOperation.GetValue: Variant;
  284. var
  285. v1: Variant;
  286. v2: Variant;
  287. begin
  288. if not Assigned(fFirst) or not Assigned(fSecond) then
  289. raise EengExpression.Create('first or second item not assigned');
  290. v1 := fFirst.GetValue;
  291. v2 := fSecond.GetValue;
  292. try
  293. case fBinaryOp of
  294. opBinaryOr: result := (Integer(v1) or Integer(v2));
  295. opBinaryAnd: result := (Integer(v1) and Integer(v2));
  296. opBinaryXor: result := (Integer(v1) xor Integer(v2));
  297. opMultiply: result := (v1 * v2);
  298. opDivide: result := (v1 / v2);
  299. opAdd: result := (v1 + v2);
  300. opSubtract: result := (v1 - v2);
  301. opLogicalOr: result := (Boolean(v1) or Boolean(v2));
  302. opLogicalAnd: result := (Boolean(v1) and Boolean(v2));
  303. opLogicalXor: result := (Boolean(v1) xor Boolean(v2));
  304. opEquals: result := (v1 = v2);
  305. opLesser: result := (v1 < v2);
  306. opGreater: result := (v1 > v2);
  307. opLEquals: result := (v1 <= v2);
  308. opGEquals: result := (v1 >= v2);
  309. opUnequals: result := (v1 <> v2);
  310. else
  311. result := inherited GetValue;
  312. end;
  313. except
  314. on ex: Exception do
  315. raise EengInvalidParamter.Create(
  316. ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' +
  317. EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")',
  318. fLine, fCol, fFilename);
  319. end;
  320. end;
  321. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
  323. begin
  324. inherited Create(aLine, aCol, aFilename);
  325. fBinaryOp := aOperator;
  326. fFirst := nil;
  327. fSecond := nil;
  328. end;
  329. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  330. destructor TengExpressionBinaryOperation.Destroy;
  331. begin
  332. FreeAndNil(fFirst);
  333. FreeAndNil(fSecond);
  334. inherited Destroy;
  335. end;
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  338. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  339. type
  340. TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation);
  341. TExpectedParams = set of TExpectedParam;
  342. {$IFDEF USE_BITSPACE_UTILS}
  343. TExpressionItemStack = specialize TutlSimpleList<TengExpressionItem>;
  344. {$ELSE}
  345. TExpressionItemStack = class(specialize TFPList<TengExpressionItem>)
  346. public
  347. end;
  348. {$ENDIF}
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem;
  351. var
  352. p: TengTokenParameter;
  353. procedure RaiseEx(const aMsg: String);
  354. begin
  355. raise EengExpression.Create(aMsg, p.Line, p.Col, aParam.Filename);
  356. end;
  357. function NextParam: Boolean;
  358. begin
  359. inc(aIndex);
  360. result := (aIndex < aParam.Count);
  361. if result then
  362. p := aParam[aIndex];
  363. end;
  364. function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean;
  365. begin
  366. result := true;
  367. for aOperator in TengExpressionUnaryOperator do
  368. if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then
  369. exit;
  370. result := false;
  371. end;
  372. function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean;
  373. begin
  374. result := true;
  375. for aOperator in TengExpressionBinaryOperator do
  376. if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then
  377. exit;
  378. result := false;
  379. end;
  380. procedure MergeItems(const aStack: TExpressionItemStack; var aNew: TengExpressionItem);
  381. var
  382. item: TengExpressionItem;
  383. begin
  384. try
  385. if (aStack.Count = 0) then begin
  386. aStack.PushLast(aNew);
  387. aNew := nil;
  388. exit;
  389. end;
  390. item := aStack.Last;
  391. if (item is TengExpressionBinaryOperation) then begin
  392. if (aNew is TengExpressionBinaryOperation) then begin
  393. //both are binary operators, new is weaker then existing
  394. if ((aNew as TengExpressionBinaryOperation).BinaryOp <
  395. (item as TengExpressionBinaryOperation).BinaryOp) then
  396. begin
  397. (aNew as TengExpressionBinaryOperation).First := item;
  398. aStack.PopLast;
  399. aStack.PushLast(aNew);
  400. aNew := nil;
  401. //both are binary operators, new is stronger than existing
  402. end else begin
  403. if not Assigned((item as TengExpressionBinaryOperation).Second) then
  404. RaiseEx('inconsistent state');
  405. (aNew as TengExpressionBinaryOperation).First := (item as TengExpressionBinaryOperation).Second;
  406. (item as TengExpressionBinaryOperation).Second := aNew;
  407. aStack.PushLast(aNew);
  408. aNew := nil;
  409. end;
  410. //existing is binary operator, new is normal
  411. end else begin
  412. if Assigned((item as TengExpressionBinaryOperation).Second) then
  413. RaiseEx('inconsistent state');
  414. (item as TengExpressionBinaryOperation).Second := aNew;
  415. aNew := nil;
  416. while (aStack.Count > 1) do
  417. aStack.PopLast; //remove all but first
  418. end;
  419. end else begin
  420. //existing is normal item, new is binary operation
  421. if (aNew is TengExpressionBinaryOperation) then begin
  422. aStack.PopLast;
  423. (aNew as TengExpressionBinaryOperation).First := item;
  424. aStack.PushLast(aNew);
  425. aNew := nil;
  426. //existing is unary operation, new is normal item or unary operation
  427. end else if (item is TengExpressionUnaryOperation) then begin
  428. if Assigned((item as TengExpressionUnaryOperation).Child) then
  429. RaiseEx('inconsistent state');
  430. (item as TengExpressionUnaryOperation).Child := aNew;
  431. if not (aNew is TengExpressionUnaryOperation) then begin
  432. while (aStack.Count > 1) do
  433. aStack.PopLast; //remove all but first
  434. end else
  435. aStack.PushLast(aNew);
  436. aNew := nil;
  437. //existing and new are both normal items
  438. end else
  439. RaiseEx('inconsistent state');
  440. end;
  441. except
  442. FreeAndNil(aNew);
  443. raise;
  444. end;
  445. end;
  446. function BuildTree(const aDepth: Integer = 0): TengExpressionItem;
  447. var
  448. uOp: TengExpressionUnaryOperator;
  449. bOp: TengExpressionBinaryOperator;
  450. expected: TExpectedParams;
  451. stack: TExpressionItemStack;
  452. l, c: Integer;
  453. ei, tmp: TengExpressionItem;
  454. begin
  455. expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
  456. result := nil;
  457. stack := TExpressionItemStack.Create(false);
  458. try try
  459. repeat
  460. // GroupBegin
  461. if (p.Name = TOKEN_OP_GROUP_BEGIN) then begin
  462. if not (exGroupBegin in expected) then
  463. RaiseEx('unexpected ''' + p.Name + '''');
  464. l := p.Line;
  465. c := p.Col;
  466. if not NextParam then
  467. RaiseEx('unexpected end');
  468. tmp := BuildTree(aDepth + 1);
  469. ei := TengExpressionGroup.Create(tmp, l, c, aParam.Filename);
  470. try
  471. MergeItems(stack, ei);
  472. if (p.Name <> TOKEN_OP_GROUP_END) then
  473. RaiseEx('missing ''' + TOKEN_OP_GROUP_END + '''');
  474. expected := [exBinaryOperation, exGroupEnd];
  475. except
  476. FreeAndNil(ei);
  477. raise;
  478. end;
  479. // GroupEnd
  480. end else if (p.Name = TOKEN_OP_GROUP_END) then begin
  481. if not (exGroupEnd in expected) or (aDepth = 0) then
  482. RaiseEx('unexpected ''' + TOKEN_OP_GROUP_END + '''');
  483. exit;
  484. // UnaryOperation
  485. end else if IsUnaryOperation(p.Name, uOp) then begin
  486. if not (exUnaryOperation in expected) then
  487. RaiseEx('unexpected operator: ' + p.Name);
  488. ei := TengExpressionUnaryOperation.Create(uOp, p.Line, p.Col, aParam.Filename);
  489. try
  490. MergeItems(stack, ei);
  491. expected := [exVariable];
  492. if (uOp <> opDefined) then
  493. expected := expected + [exValue, exGroupBegin, exUnaryOperation]
  494. except
  495. FreeAndNil(ei);
  496. raise;
  497. end;
  498. // BinaryOperation
  499. end else if IsBinaryOperation(p.Name, bOp) then begin
  500. if not (exBinaryOperation in expected) then
  501. RaiseEx('unexpected operator: ' + p.Name);
  502. ei := TengExpressionBinaryOperation.Create(bOp, p.Line, p.Col, aParam.Filename);
  503. try
  504. MergeItems(stack, ei);
  505. expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
  506. except
  507. FreeAndNil(ei);
  508. raise;
  509. end;
  510. // Value
  511. end else if p.Quoted and IsValidIdentifier(p.Name) then begin
  512. if not (exValue in expected) then
  513. RaiseEx('unexpected value: ' + p.Name);
  514. ei := TengExpressionValue.Create(p.Name, p.Line, p.Col, aParam.Filename);
  515. try
  516. MergeItems(stack, ei);
  517. expected := [exGroupEnd, exBinaryOperation];
  518. except
  519. FreeAndNil(ei);
  520. raise;
  521. end;
  522. // Variable
  523. end else if IsValidIdentifier(p.Name) then begin
  524. if not (exVariable in expected) then
  525. RaiseEx('unexpected variable: ' + p.Name);
  526. ei := TengExpressionVariable.Create(p.Name, p.Line, p.Col, aParam.Filename);
  527. try
  528. MergeItems(stack, ei);
  529. expected := [exGroupEnd, exBinaryOperation];
  530. except
  531. FreeAndNil(ei);
  532. raise
  533. end;
  534. // Unknown
  535. end else
  536. RaiseEx('invalid parameter: ' + p.Name);
  537. until not NextParam;
  538. except
  539. if (stack.Count > 0) then begin
  540. stack[0].Free;
  541. stack[0] := nil;
  542. end;
  543. raise;
  544. end;
  545. finally
  546. if (stack.Count > 0) then
  547. result := stack[0];
  548. FreeAndNil(stack);
  549. end;
  550. end;
  551. begin
  552. dec(aIndex);
  553. if not NextParam then with aParam[0] do
  554. raise EengShaderPartInternal.Create('invalid parameter count in expression', Line, Col, aParam.Filename);
  555. result := BuildTree;
  556. end;
  557. end.