PageRenderTime 79ms CodeModel.GetById 20ms RepoModel.GetById 2ms app.codeStats 0ms

/Scripting/Parser/Construct/Expression.cs

http://github.com/polyethene/IronAHK
C# | 874 lines | 728 code | 143 blank | 3 comment | 300 complexity | f1802673accc8348a1eb9ee5d39960b0 MD5 | raw file
  1. using System;
  2. using System.CodeDom;
  3. using System.Collections.Generic;
  4. namespace IronAHK.Scripting
  5. {
  6. partial class Parser
  7. {
  8. #region Wrappers
  9. CodeExpressionStatement[] ParseMultiExpression(string code)
  10. {
  11. var tokens = SplitTokens(code);
  12. #region Date/time
  13. int n = tokens.Count - 2;
  14. if (tokens.Count > 1 && ((string)tokens[n]).Length > 0 && ((string)tokens[n])[0] == Multicast)
  15. {
  16. string arg = ((string)tokens[n + 1]).ToUpperInvariant().Trim();
  17. arg = arg.Length == 1 ? arg : arg.TrimEnd('S');
  18. switch (arg)
  19. {
  20. case "S":
  21. case "SECOND":
  22. case "M":
  23. case "MINUTE":
  24. case "H":
  25. case "HOUR":
  26. case "D":
  27. case "DAY":
  28. return new[] { new CodeExpressionStatement(ParseDateExpression(code)) };
  29. }
  30. }
  31. #endregion
  32. var result = ParseMultiExpression(tokens.ToArray());
  33. var statements = new CodeExpressionStatement[result.Length];
  34. for (int i = 0; i < result.Length; i++)
  35. statements[i] = new CodeExpressionStatement(result[i]);
  36. return statements;
  37. }
  38. CodeExpression ParseSingleExpression(string code)
  39. {
  40. var tokens = SplitTokens(code);
  41. return ParseExpression(tokens);
  42. }
  43. CodeExpression[] ParseMultiExpression(object[] parts)
  44. {
  45. var expr = new List<CodeExpression>();
  46. var sub = new List<object>();
  47. for (int i = 0; i < parts.Length; i++)
  48. {
  49. if (!(parts[i] is string) || ((string)parts[i]).Length == 0)
  50. {
  51. sub.Add(parts[i]);
  52. continue;
  53. }
  54. int next = Set(parts, i);
  55. if (next > 0)
  56. {
  57. for (; i < next; i++)
  58. sub.Add(parts[i]);
  59. i--;
  60. continue;
  61. }
  62. var check = (string)parts[i];
  63. if (check.Length == 1 && check[0] == Multicast && sub.Count != 0)
  64. {
  65. expr.Add(ParseExpression(sub));
  66. sub.Clear();
  67. continue;
  68. }
  69. else
  70. sub.Add(parts[i]);
  71. }
  72. if (sub.Count != 0)
  73. expr.Add(ParseExpression(sub));
  74. return expr.ToArray();
  75. }
  76. #endregion
  77. #region Parser
  78. CodeExpression ParseExpression(List<object> parts)
  79. {
  80. RemoveExcessParentheses(parts);
  81. #region Scanner
  82. start:
  83. bool rescan = false;
  84. for (int i = 0; i < parts.Count; i++)
  85. {
  86. if (parts[i] is string)
  87. {
  88. var part = (string)parts[i];
  89. object result;
  90. #region Parentheses
  91. if (part[0] == ParenOpen)
  92. {
  93. int n = i + 1;
  94. var paren = Dissect(parts, n, Set(parts, i));
  95. parts.RemoveAt(n);
  96. n -= 2;
  97. bool call = n > -1 && parts[n] is CodeExpression && !(parts[n] is CodePrimitiveExpression);
  98. if (call && parts[n] is CodeMethodInvokeExpression && ((CodeMethodInvokeExpression)parts[n]).Parameters[0] is CodeFieldReferenceExpression)
  99. call = false;
  100. if (call)
  101. {
  102. var invoke = (CodeMethodInvokeExpression)InternalMethods.Invoke;
  103. invoke.Parameters.Add((CodeExpression)parts[n]);
  104. if (paren.Count != 0)
  105. {
  106. var passed = ParseMultiExpression(paren.ToArray());
  107. invoke.Parameters.AddRange(passed);
  108. }
  109. parts[i] = invoke;
  110. parts.RemoveAt(n);
  111. }
  112. else
  113. {
  114. if (paren.Count == 0)
  115. parts.RemoveAt(i);
  116. else
  117. parts[i] = ParseExpression(paren);
  118. }
  119. }
  120. else if (part[0] == ParenClose)
  121. rescan = true;
  122. #endregion
  123. #region Strings
  124. else if (part.Length > 1 && part[0] == StringBound && part[part.Length - 1] == StringBound)
  125. parts[i] = new CodePrimitiveExpression(EscapedString(part.Substring(1, part.Length - 2), false));
  126. #endregion
  127. #region Numerics
  128. else if (IsPrimativeObject(part, out result))
  129. parts[i] = new CodePrimitiveExpression(result);
  130. #endregion
  131. #region Variables
  132. else if (IsIdentifier(part, true) && !IsKeyword(part))
  133. {
  134. var low = part.ToLowerInvariant();
  135. if (libProperties.ContainsKey(low))
  136. parts[i] = new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(bcl), libProperties[low]);
  137. else
  138. parts[i] = VarIdOrConstant(part);
  139. }
  140. #endregion
  141. #region JSON
  142. else if (part.Length == 1 && part[0] == BlockOpen)
  143. {
  144. int n = i + 1;
  145. var paren = Dissect(parts, n, Set(parts, i));
  146. var invoke = (CodeMethodInvokeExpression)InternalMethods.Dictionary;
  147. CodePrimitiveExpression[] keys;
  148. CodeExpression[] values;
  149. ParseObject(paren, out keys, out values);
  150. invoke.Parameters.Add(new CodeArrayCreateExpression(typeof(string), keys));
  151. invoke.Parameters.Add(new CodeArrayCreateExpression(typeof(object), values));
  152. parts[i] = invoke;
  153. parts.RemoveAt(n);
  154. i--;
  155. }
  156. else if (part.Length == 1 && part[0] == ArrayOpen)
  157. {
  158. int n = i + 1;
  159. var paren = Dissect(parts, n, Set(parts, i));
  160. parts.RemoveAt(n);
  161. if (i > 0 && parts[i - 1] is CodeExpression)
  162. {
  163. var invoke = (CodeMethodInvokeExpression)InternalMethods.Index;
  164. n = i - 1;
  165. invoke.Parameters.Add((CodeExpression)parts[n]);
  166. var index = ParseMultiExpression(paren.ToArray());
  167. if (index.Length > 1)
  168. throw new ParseException("Cannot have multipart expression in index.");
  169. else if (index.Length == 0)
  170. {
  171. var extend = (CodeMethodInvokeExpression)InternalMethods.ExtendArray;
  172. var sub = new List<object>(1);
  173. sub.Add(parts[n]);
  174. extend.Parameters.Add(ParseExpression(sub));
  175. invoke = extend;
  176. }
  177. else
  178. invoke.Parameters.Add(index[0]);
  179. parts[i] = invoke;
  180. parts.RemoveAt(n);
  181. i--;
  182. }
  183. else
  184. {
  185. var array = new CodeArrayCreateExpression(typeof(object[]), ParseMultiExpression(paren.ToArray()));
  186. parts[i] = array;
  187. }
  188. }
  189. #endregion
  190. #region Invokes
  191. else if (part.Length > 1 && part[part.Length - 1] == ParenOpen)
  192. {
  193. string name = part.Substring(0, part.Length - 1);
  194. bool dynamic = false;
  195. if (!IsIdentifier(name))
  196. {
  197. if (IsDynamicReference(name))
  198. dynamic = true;
  199. else
  200. throw new ParseException("Invalid function name");
  201. }
  202. else
  203. CheckPersistent(name);
  204. int n = i + 1;
  205. var paren = Dissect(parts, n, Set(parts, i));
  206. parts.RemoveAt(n);
  207. CodeMethodInvokeExpression invoke;
  208. if (dynamic)
  209. {
  210. invoke = (CodeMethodInvokeExpression)InternalMethods.FunctionCall;
  211. invoke.Parameters.Add(VarIdExpand(name));
  212. }
  213. else
  214. invoke = LocalMethodInvoke(name);
  215. if (paren.Count != 0)
  216. {
  217. var passed = ParseMultiExpression(paren.ToArray());
  218. invoke.Parameters.AddRange(passed);
  219. }
  220. parts[i] = invoke;
  221. invokes.Add(invoke);
  222. }
  223. #endregion
  224. #region Assignments
  225. else if (IsAssignOp(part) || IsImplicitAssignment(parts, i))
  226. {
  227. int n = i - 1;
  228. if (i > 0 && IsJsonObject(parts[n])) { }
  229. else if (n < 0 || !IsVarReference(parts[n]))
  230. {
  231. if (LaxExpressions)
  232. {
  233. if (parts[n] is CodePrimitiveExpression && ((CodePrimitiveExpression)parts[n]).Value is decimal)
  234. parts[n] = VarId(((decimal)((CodePrimitiveExpression)parts[n]).Value).ToString());
  235. }
  236. else
  237. throw new ParseException("Can only assign to a variable");
  238. }
  239. // (x += y) => (x = x + y)
  240. parts[i] = CodeBinaryOperatorType.Assign;
  241. if (part[0] != AssignPre && part.Length != 1)
  242. {
  243. parts.Insert(++i, ParenOpen.ToString());
  244. parts.Insert(++i, parts[i - 3]);
  245. if (part.Length > 1)
  246. {
  247. parts.Insert(++i, OperatorFromString(part.Substring(0, part.Length - 1)));
  248. parts.Insert(++i, ParenOpen.ToString());
  249. parts.Add(ParenClose.ToString());
  250. }
  251. parts.Add(ParenClose.ToString());
  252. }
  253. }
  254. #endregion
  255. #region Multiple statements
  256. else if (part.Length == 1 && part[0] == Multicast)
  257. {
  258. if (!LaxExpressions)
  259. throw new ParseException("Nested multipart expression not allowed.");
  260. // implement as: + Dummy(expr..)
  261. int z = i + 1, l = parts.Count - z;
  262. var sub = new List<object>(l);
  263. for (; z < parts.Count; z++)
  264. sub.Add(parts[z]);
  265. parts.RemoveRange(i, parts.Count - i);
  266. var invoke = (CodeMethodInvokeExpression)InternalMethods.OperateZero;
  267. invoke.Parameters.Add(ParseExpression(sub));
  268. parts.Add(Script.Operator.Add);
  269. parts.Add(invoke);
  270. }
  271. #endregion
  272. #region Binary operators
  273. else
  274. {
  275. var ops = OperatorFromString(part);
  276. #region Increment/decrement
  277. if (ops == Script.Operator.Increment || ops == Script.Operator.Decrement)
  278. {
  279. int z = -1, x = i - 1, y = i + 1;
  280. int d = ops == Script.Operator.Increment ? 1 : -1;
  281. CodeMethodInvokeExpression shadow = null;
  282. // UNDONE: use generic approach to ++/-- for all types of operands?
  283. if (x > -1 && parts[x] is CodeMethodInvokeExpression)
  284. {
  285. var sub = new List<object>(5);
  286. sub.Add(parts[x]);
  287. sub.Add(CodeBinaryOperatorType.Assign);
  288. sub.Add(parts[x]);
  289. sub.Add(Script.Operator.Add);
  290. sub.Add(d);
  291. parts.RemoveAt(i);
  292. parts[x] = ParseExpression(sub);
  293. i = x;
  294. continue;
  295. }
  296. #region Compounding increment/decrement operators
  297. if (LaxExpressions)
  298. {
  299. while (y < parts.Count)
  300. {
  301. Script.Operator nextOps = Script.Operator.ValueEquality;
  302. if (parts[y] is Script.Operator)
  303. nextOps = (Script.Operator)parts[y];
  304. else if (parts[y] is string)
  305. {
  306. try { nextOps = OperatorFromString((string)parts[y]); }
  307. catch { break; }
  308. }
  309. else
  310. break;
  311. if (nextOps == Script.Operator.Increment)
  312. d++;
  313. else if (nextOps == Script.Operator.Decrement)
  314. d--;
  315. else
  316. break;
  317. parts.RemoveAt(y);
  318. }
  319. }
  320. #endregion
  321. if (x > -1 && (IsVarReference(parts[x]) || parts[x] is CodePropertyReferenceExpression))
  322. z = x;
  323. if (y < parts.Count && parts[y] is string && !IsOperator((string)parts[y]))
  324. {
  325. if (z != -1)
  326. {
  327. if (LaxExpressions)
  328. {
  329. parts.Insert(y, Script.Operator.Concat);
  330. z = x;
  331. }
  332. else
  333. throw new ParseException("Cannot use both prefix and postfix operators on the same variable");
  334. }
  335. if (z == -1)
  336. z = y;
  337. if (LaxExpressions)
  338. {
  339. if (parts[z] is string && ((string)parts[z]).Length == 1 && ((string)parts[z])[0] == ParenOpen)
  340. {
  341. var zx = new[] { z + 1, z + 2 };
  342. if (zx[1] < parts.Count &&
  343. parts[zx[1]] is string && ((string)parts[zx[1]]).Length == 1 && ((string)parts[zx[1]])[0] == ParenClose &&
  344. (parts[zx[0]] is string && IsDynamicReference((string)parts[zx[0]]) || IsVarReference(parts[zx[0]])))
  345. {
  346. parts.RemoveAt(zx[1]);
  347. parts.RemoveAt(z);
  348. }
  349. else
  350. {
  351. parts.RemoveAt(i);
  352. i--;
  353. continue;
  354. }
  355. }
  356. }
  357. }
  358. if (z == -1)
  359. {
  360. if (LaxExpressions)
  361. {
  362. if ((x > 0 && (parts[x] is CodeBinaryOperatorExpression || parts[x] is CodeMethodInvokeExpression || parts[x] is CodePrimitiveExpression)) ||
  363. (y < parts.Count && (parts[y] is string && !IsOperator(parts[y] as string) || parts[y] is Script.Operator)))
  364. {
  365. parts.RemoveAt(i);
  366. i--;
  367. continue;
  368. }
  369. }
  370. else
  371. throw new ParseException("Neither left or right hand side of operator is a variable");
  372. }
  373. if (parts[z] is string && ((string)parts[z]).Length > 0 && ((string)parts[z])[0] == StringBound)
  374. {
  375. parts.RemoveAt(Math.Max(i, z));
  376. parts.RemoveAt(Math.Min(i, z));
  377. continue;
  378. }
  379. if (LaxExpressions)
  380. {
  381. int w = z + (z == x ? 2 : 1);
  382. if (w < parts.Count && (parts[w] is string && IsAssignOp((string)parts[w]) || IsVarAssignment(parts[w])))
  383. {
  384. int l = parts.Count - w;
  385. var sub = new List<object>(l + 1);
  386. sub.Add(parts[z]);
  387. for (int wx = w; wx < parts.Count; wx++)
  388. sub.Add(parts[wx]);
  389. shadow = (CodeMethodInvokeExpression)InternalMethods.OperateZero;
  390. shadow.Parameters.Add(ParseExpression(sub));
  391. parts.RemoveRange(w, l);
  392. }
  393. }
  394. var list = new List<object>(9);
  395. list.Add(parts[z]);
  396. list.Add(new string(new[] { Add, Equal }));
  397. list.Add(new CodePrimitiveExpression(d));
  398. if (shadow != null)
  399. {
  400. list.Add(Script.Operator.Add);
  401. list.Add(shadow);
  402. }
  403. if (z < i) // postfix, so adjust
  404. {
  405. list.Insert(0, ParenOpen.ToString());
  406. list.Add(ParenClose.ToString());
  407. list.Add(d > 0 ? Script.Operator.Minus : Script.Operator.Add);
  408. list.Add(new CodePrimitiveExpression(d));
  409. }
  410. x = Math.Min(i, z);
  411. y = Math.Max(i, z);
  412. parts[x] = ParseExpression(list);
  413. parts.RemoveAt(y);
  414. i = x;
  415. }
  416. #endregion
  417. else
  418. {
  419. #region Dereference
  420. if (part.Length == 1 && part[0] == Dereference)
  421. {
  422. bool deref = false;
  423. if (i == 0)
  424. deref = true;
  425. else
  426. {
  427. int x = i - 1;
  428. deref = parts[x] is Script.Operator || IsVarAssignment(parts[x]) ||
  429. (parts[x] is string && ((string)parts[x]).Length == 1 && ((string)parts[x])[0] == '(');
  430. }
  431. if (deref)
  432. {
  433. int y = i + 1;
  434. if (y < parts.Count && (IsVarReference(parts[y]) ||
  435. (parts[y] is string && IsIdentifier((string)parts[y]) && !IsKeyword((string)parts[y]))))
  436. ops = Script.Operator.Dereference;
  437. }
  438. }
  439. #endregion
  440. parts[i] = ops;
  441. }
  442. }
  443. #endregion
  444. }
  445. }
  446. if (rescan)
  447. goto start;
  448. #endregion
  449. #region Operators
  450. #region Unary (precedent)
  451. for (int i = 1; i < parts.Count; i++)
  452. {
  453. if (parts[i] is Script.Operator &&
  454. (parts[i - 1] is Script.Operator || parts[i - 1] as CodeBinaryOperatorType? == CodeBinaryOperatorType.Assign || IsVarAssignment(parts[i - 1])) &&
  455. IsUnaryOperator((Script.Operator)parts[i]))
  456. {
  457. int n = i + 1, m = n + 1;
  458. int u = n;
  459. while (u < parts.Count && parts[u] is Script.Operator && IsUnaryOperator((Script.Operator)parts[u])) u++;
  460. if (u == parts.Count)
  461. {
  462. if (LaxExpressions)
  463. {
  464. u--;
  465. while (parts[u] is Script.Operator && ((Script.Operator)parts[u] == Script.Operator.Add || (Script.Operator)parts[u] == Script.Operator.Subtract))
  466. parts.RemoveAt(u--);
  467. if (u + 1 < n)
  468. {
  469. i = u;
  470. continue;
  471. }
  472. }
  473. throw new ParseException("Compounding unary operator with no operand");
  474. }
  475. if (u > n)
  476. {
  477. var sub = new List<object>(++u - n);
  478. for (int x = n; x < u; x++)
  479. sub.Add(parts[x]);
  480. parts.RemoveRange(n, u - n);
  481. parts.Insert(n, ParseExpression(sub));
  482. }
  483. if (m + 1 < parts.Count && IsVarReference(parts[n]) && IsVarAssignment(parts[m]))
  484. MergeAssignmentAt(parts, i + 2);
  485. if (m > parts.Count)
  486. throw new ParseException("Unary operator without operand");
  487. var op = (Script.Operator)parts[i];
  488. if (parts[n] is CodePrimitiveExpression && op == Script.Operator.Subtract)
  489. {
  490. var parent = ((CodePrimitiveExpression)parts[n]);
  491. if (parent.Value is int)
  492. parent.Value = -(int)parent.Value;
  493. else if (parent.Value is decimal)
  494. parent.Value = -(decimal)parent.Value;
  495. else if (parent.Value is double)
  496. parent.Value = -(double)parent.Value;
  497. else if (parent.Value is string)
  498. parent.Value = string.Concat(Minus.ToString(), (string)parent.Value);
  499. else
  500. throw new ArgumentOutOfRangeException();
  501. parts.RemoveAt(i);
  502. }
  503. else if (op == Script.Operator.Add)
  504. {
  505. parts.RemoveAt(i);
  506. }
  507. else
  508. {
  509. var invoke = (CodeMethodInvokeExpression)InternalMethods.OperateUnary;
  510. invoke.Parameters.Add(OperatorAsFieldReference(op));
  511. if (LaxExpressions)
  512. {
  513. if (!(IsVarReference(parts[n]) || IsVarAssignment(parts[n])))
  514. {
  515. invoke.Parameters.Add(new CodePrimitiveExpression(null));
  516. goto next;
  517. }
  518. }
  519. invoke.Parameters.Add(VarMixedExpr(parts[n]));
  520. next:
  521. parts[i] = invoke;
  522. parts.RemoveAt(n);
  523. }
  524. }
  525. }
  526. #endregion
  527. #region Generic
  528. bool scan = true;
  529. int level = -1;
  530. while (scan)
  531. {
  532. scan = false;
  533. for (int i = 0; i < parts.Count; i++)
  534. {
  535. if (parts[i] is Script.Operator && (Script.Operator)parts[i] != Script.Operator.Assign)
  536. {
  537. scan = true;
  538. var op = (Script.Operator)parts[i];
  539. if (OperatorPrecedence(op) < level)
  540. continue;
  541. int x = i - 1, y = i + 1;
  542. var invoke = new CodeMethodInvokeExpression();
  543. if (i + 3 < parts.Count && IsVarReference(parts[i + 1]) && parts[i + 2] as CodeBinaryOperatorType? == CodeBinaryOperatorType.Assign)
  544. MergeAssignmentAt(parts, i + 2);
  545. #region Ternary
  546. if (op == Script.Operator.TernaryA)
  547. {
  548. if (x < 0)
  549. {
  550. if (LaxExpressions)
  551. return new CodePrimitiveExpression(null);
  552. else
  553. throw new ParseException("Ternary with no condition.");
  554. }
  555. var eval = (CodeMethodInvokeExpression)InternalMethods.IfElse;
  556. eval.Parameters.Add(VarMixedExpr(parts[x]));
  557. var ternary = new CodeTernaryOperatorExpression { Condition = eval };
  558. int depth = 1, max = parts.Count - i, start = i;
  559. var branch = new[] { new List<object>(max), new List<object>(max) };
  560. for (i++; i < parts.Count; i++)
  561. {
  562. switch (parts[i] as Script.Operator?)
  563. {
  564. case Script.Operator.TernaryA:
  565. depth++;
  566. break;
  567. case Script.Operator.TernaryB:
  568. depth--;
  569. break;
  570. }
  571. if (depth == 0)
  572. {
  573. for (int n = i + 1; n < parts.Count; n++)
  574. branch[1].Add(parts[n]);
  575. break;
  576. }
  577. else
  578. branch[0].Add(parts[i]);
  579. }
  580. if (branch[0].Count == 0)
  581. throw new ParseException("Ternary operator must have at least one branch");
  582. if (branch[1].Count == 0)
  583. branch[1].Add(new CodePrimitiveExpression(null));
  584. ternary.TrueBranch = ParseExpression(branch[0]);
  585. ternary.FalseBranch = ParseExpression(branch[1]);
  586. parts[x] = ternary;
  587. parts.Remove(y);
  588. parts.RemoveRange(start, parts.Count - start);
  589. }
  590. else if (op == Script.Operator.NullAssign)
  591. {
  592. if (x < 0)
  593. throw new ParseException("Nullable assignment with no condition.");
  594. int n = i + 1;
  595. if (n >= parts.Count)
  596. throw new ParseException("Nullable assignment with no right-hand operator");
  597. var result = InternalVariable;
  598. var left = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.Assign, VarMixedExpr(parts[x]));
  599. var eval = (CodeMethodInvokeExpression)InternalMethods.IfElse;
  600. eval.Parameters.Add(left);
  601. var ternary = new CodeTernaryOperatorExpression { Condition = eval, TrueBranch = result };
  602. var right = new List<object>();
  603. while (n < parts.Count)
  604. right.Add(parts[n++]);
  605. ternary.FalseBranch = ParseExpression(right);
  606. parts[x] = ternary;
  607. parts.RemoveRange(i, parts.Count - i);
  608. }
  609. #endregion
  610. #region Unary
  611. else if (x == -1)
  612. {
  613. int z = y + 1;
  614. if (op == Script.Operator.LogicalNotEx && IsVarReference(parts[y]) && z < parts.Count)
  615. MergeAssignmentAt(parts, z);
  616. if (LaxExpressions)
  617. {
  618. if (y > parts.Count - 1)
  619. return new CodePrimitiveExpression(null);
  620. }
  621. invoke.Method = (CodeMethodReferenceExpression)InternalMethods.OperateUnary;
  622. invoke.Parameters.Add(OperatorAsFieldReference(op));
  623. invoke.Parameters.Add(VarMixedExpr(parts[y]));
  624. parts[i] = invoke;
  625. parts.RemoveAt(y);
  626. }
  627. #endregion
  628. #region Binary
  629. else
  630. {
  631. if (op == Script.Operator.BooleanAnd || op == Script.Operator.BooleanOr)
  632. {
  633. var boolean = new CodeBinaryOperatorExpression();
  634. boolean.Operator = op == Script.Operator.BooleanAnd ? CodeBinaryOperatorType.BooleanAnd : CodeBinaryOperatorType.BooleanOr;
  635. var iftest = (CodeMethodInvokeExpression)InternalMethods.IfElse;
  636. iftest.Parameters.Add(VarMixedExpr(parts[x]));
  637. boolean.Left = iftest;
  638. iftest = (CodeMethodInvokeExpression)InternalMethods.IfElse;
  639. var next = parts[y] as Script.Operator?;
  640. if (next == Script.Operator.BooleanAnd || next == Script.Operator.BooleanOr)
  641. {
  642. if (LaxExpressions)
  643. iftest.Parameters.Add(new CodePrimitiveExpression(false));
  644. else
  645. throw new ParseException(ExInvalidExpression);
  646. }
  647. else
  648. {
  649. iftest.Parameters.Add(VarMixedExpr(parts[y]));
  650. parts.RemoveAt(y);
  651. }
  652. boolean.Right = iftest;
  653. parts[x] = boolean;
  654. }
  655. else
  656. {
  657. if (LaxExpressions)
  658. {
  659. if (parts[x] is Script.Operator && (Script.Operator)parts[x] == Script.Operator.TernaryA)
  660. {
  661. parts[x] = new CodePrimitiveExpression(null);
  662. goto next;
  663. }
  664. if (y > parts.Count - 1)
  665. return new CodePrimitiveExpression(null);
  666. }
  667. else
  668. throw new ParseException(ExInvalidExpression);
  669. invoke.Method = (CodeMethodReferenceExpression)InternalMethods.Operate;
  670. invoke.Parameters.Add(OperatorAsFieldReference(op));
  671. if (LaxExpressions && parts[i] is Script.Operator && (Script.Operator)parts[i] == Script.Operator.Concat && parts[x] as CodeBinaryOperatorType? == CodeBinaryOperatorType.Assign)
  672. invoke.Parameters.Add(new CodePrimitiveExpression(string.Empty));
  673. else
  674. invoke.Parameters.Add(VarMixedExpr(parts[x]));
  675. invoke.Parameters.Add(VarMixedExpr(parts[y]));
  676. parts[x] = invoke;
  677. next:
  678. parts.RemoveAt(y);
  679. }
  680. parts.RemoveAt(i);
  681. }
  682. #endregion
  683. i--;
  684. }
  685. else if (parts[i] as CodeBinaryOperatorType? != CodeBinaryOperatorType.Assign)
  686. {
  687. var x = i - 1;
  688. if (x > 0 && !(parts[x] is Script.Operator || parts[x] is CodeBinaryOperatorType))
  689. {
  690. parts.Insert(i, Script.Operator.Concat);
  691. i--;
  692. continue;
  693. }
  694. }
  695. }
  696. level--;
  697. }
  698. #endregion
  699. #endregion
  700. #region Assignments
  701. for (int i = parts.Count - 1; i > 0; i--)
  702. MergeAssignmentAt(parts, i);
  703. #endregion
  704. #region Result
  705. if (parts.Count > 1)
  706. {
  707. for (int i = 0; i < parts.Count; i++)
  708. {
  709. bool typed = false;
  710. if (LaxExpressions)
  711. typed = IsVarAssignment(parts[i]) || IsVarReference(parts[i]);
  712. if (!(typed || parts[i] is CodeMethodInvokeExpression || parts[i] is CodePrimitiveExpression || parts[i] is CodeTernaryOperatorExpression || parts[i] is CodeBinaryOperatorExpression || parts[i] is CodePropertyReferenceExpression))
  713. throw new ArgumentOutOfRangeException();
  714. if (i % 2 == 1)
  715. parts.Insert(i, Script.Operator.Concat);
  716. }
  717. var concat = ParseExpression(parts);
  718. parts.Clear();
  719. parts.Add(concat);
  720. }
  721. if (parts.Count != 1)
  722. throw new ArgumentOutOfRangeException();
  723. if (IsVarAssignment(parts[0]))
  724. return (CodeBinaryOperatorExpression)parts[0];
  725. else
  726. return (CodeExpression)parts[0];
  727. #endregion
  728. }
  729. #endregion
  730. }
  731. }