Parser.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. namespace NTERA.Interpreter.Compiler
  5. {
  6. public class Parser
  7. {
  8. protected Lexer Lexer { get; }
  9. protected FunctionDefinition SelfDefinition { get; }
  10. protected ICollection<FunctionDefinition> FunctionDefinitions { get; }
  11. protected ICollection<FunctionDefinition> ProcedureDefinitions { get; }
  12. protected VariableDictionary GlobalVariables { get; }
  13. protected VariableDictionary LocalVariables { get; }
  14. protected ICollection<string> StringStatements { get; }
  15. protected CSVDefinition CsvDefinition { get; }
  16. protected IEnumerator<Token> Enumerator { get; }
  17. protected bool hasPeeked = false;
  18. protected Token peekedToken = Token.Unknown;
  19. protected Token GetNextToken(bool peek = false)
  20. {
  21. if (peek && hasPeeked)
  22. return peekedToken;
  23. if (!hasPeeked)
  24. Enumerator.MoveNext();
  25. peekedToken = Enumerator.Current;
  26. hasPeeked = peek;
  27. return Enumerator.Current;
  28. }
  29. protected Marker CurrentPosition => new Marker(Lexer.TokenMarker.Pointer + SelfDefinition.Position.Pointer,
  30. Lexer.TokenMarker.Line + SelfDefinition.Position.Line - 1,
  31. Lexer.TokenMarker.Column);
  32. public Parser(string input, FunctionDefinition selfDefinition, ICollection<FunctionDefinition> functionDefinitions, ICollection<FunctionDefinition> procedureDefinitions, VariableDictionary globalVariables, VariableDictionary localVariables, ICollection<string> stringStatements, CSVDefinition csvDefinition)
  33. {
  34. Lexer = new Lexer(input);
  35. Enumerator = Lexer.GetEnumerator();
  36. SelfDefinition = selfDefinition;
  37. FunctionDefinitions = functionDefinitions;
  38. ProcedureDefinitions = procedureDefinitions;
  39. GlobalVariables = globalVariables;
  40. LocalVariables = localVariables;
  41. StringStatements = stringStatements;
  42. CsvDefinition = csvDefinition;
  43. }
  44. public IEnumerable<ExecutionNode> Parse(out List<ParserError> errors)
  45. {
  46. errors = new List<ParserError>();
  47. List<ExecutionNode> nodes = new List<ExecutionNode>();
  48. using (Enumerator)
  49. {
  50. do
  51. {
  52. var node = ParseLine(out var error);
  53. if (error != null)
  54. {
  55. errors.Add(error);
  56. nodes.Add(new ExecutionNode
  57. {
  58. Type = "error",
  59. Metadata =
  60. {
  61. ["message"] = error.ErrorMessage,
  62. ["symbol"] = error.SymbolMarker.ToString()
  63. },
  64. Symbol = error.SymbolMarker
  65. });
  66. //resynchronize to a new line
  67. while (Enumerator.MoveNext()
  68. && Enumerator.Current != Token.NewLine
  69. && Enumerator.Current != Token.EOF)
  70. {
  71. }
  72. }
  73. else if (node != null)
  74. {
  75. nodes.Add(node);
  76. }
  77. hasPeeked = false;
  78. } while (Enumerator.MoveNext());
  79. }
  80. return nodes;
  81. }
  82. protected ExecutionNode ParseLine(out ParserError error)
  83. {
  84. error = null;
  85. switch (Enumerator.Current)
  86. {
  87. case Token.Identifer:
  88. if (GlobalVariables.ContainsKey(Lexer.Identifer)
  89. || LocalVariables.ContainsKey(Lexer.Identifer))
  90. {
  91. string variableName = Lexer.Identifer;
  92. bool isGlobal = GlobalVariables.ContainsKey(variableName);
  93. var node = new ExecutionNode
  94. {
  95. Type = "assignment",
  96. Symbol = CurrentPosition
  97. };
  98. var variable = GetVariable(out error);
  99. if (error != null)
  100. return null;
  101. if (GetNextToken() != Token.Equal
  102. && Enumerator.Current != Token.Increment
  103. && Enumerator.Current != Token.Decrement
  104. && !Enumerator.Current.IsArithmetic())
  105. {
  106. error = new ParserError($"Unexpected token, expecting assignment: {Enumerator.Current}", CurrentPosition);
  107. return null;
  108. }
  109. ExecutionNode value = null;
  110. if (Enumerator.Current == Token.Increment)
  111. {
  112. value = OperateNodes(variable, CreateConstant(1), Token.Plus);
  113. }
  114. else if (Enumerator.Current == Token.Decrement)
  115. {
  116. value = OperateNodes(variable, CreateConstant(1), Token.Minus);
  117. }
  118. else if (Enumerator.Current != Token.Equal)
  119. {
  120. Token arithmeticToken = Enumerator.Current;
  121. if (GetNextToken() != Token.Equal)
  122. {
  123. error = new ParserError($"Unexpected token, expecting assignment: {Enumerator.Current}", CurrentPosition);
  124. return null;
  125. }
  126. ExecutionNode newValue = Expression(out error);
  127. value = OperateNodes(variable, newValue, arithmeticToken);
  128. }
  129. else
  130. {
  131. var type = isGlobal
  132. ? GlobalVariables[variableName].Type
  133. : LocalVariables[variableName].Type;
  134. value = type == ValueType.String
  135. ? StringExpression(out error)
  136. : Expression(out error);
  137. }
  138. if (error != null)
  139. return null;
  140. node.SubNodes = new[]
  141. {
  142. variable,
  143. new ExecutionNode
  144. {
  145. Type = "value",
  146. SubNodes = new[] { value }
  147. }
  148. };
  149. return node;
  150. }
  151. else if (Lexer.Identifer == "CASE")
  152. {
  153. var node = new ExecutionNode
  154. {
  155. Type = "case",
  156. Symbol = CurrentPosition
  157. };
  158. List<ExecutionNode> subNodes = new List<ExecutionNode>();
  159. do
  160. {
  161. var value = Expression(out error);
  162. if (error != null)
  163. return null;
  164. if (Enumerator.Current == Token.Identifer)
  165. {
  166. if (Lexer.Identifer == "TO")
  167. {
  168. var value2 = Expression(out error);
  169. if (error != null)
  170. return null;
  171. subNodes.Add(new ExecutionNode
  172. {
  173. Type = "case-to",
  174. SubNodes = new[] { value, value2 }
  175. });
  176. continue;
  177. }
  178. }
  179. subNodes.Add(new ExecutionNode
  180. {
  181. Type = "case-exact",
  182. SubNodes = new[] { value }
  183. });
  184. } while (Enumerator.Current == Token.Comma);
  185. if (Enumerator.Current != Token.NewLine
  186. && Enumerator.Current != Token.EOF)
  187. {
  188. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  189. return null;
  190. }
  191. node.SubNodes = subNodes.ToArray();
  192. return node;
  193. }
  194. else if (Lexer.Identifer == "CALL"
  195. || Lexer.Identifer == "BEGIN")
  196. {
  197. Enumerator.MoveNext();
  198. if (Enumerator.Current != Token.Identifer)
  199. {
  200. error = new ParserError($"Expecting a call to a function, got token instead: {Enumerator.Current}", CurrentPosition);
  201. return null;
  202. }
  203. Marker symbolMarker = CurrentPosition;
  204. string target = Lexer.Identifer;
  205. List<ExecutionNode> parameters = new List<ExecutionNode>();
  206. if (ProcedureDefinitions.All(x => !x.Name.Equals(target, StringComparison.OrdinalIgnoreCase)))
  207. {
  208. error = new ParserError($"Could not find procedure: {Lexer.Identifer}", CurrentPosition);
  209. return null;
  210. }
  211. Enumerator.MoveNext();
  212. while (Enumerator.Current != Token.NewLine
  213. && Enumerator.Current != Token.EOF)
  214. {
  215. parameters.Add(Expression(out error));
  216. if (error != null)
  217. {
  218. error = new ParserError($"{error.ErrorMessage} (target [{target}])", error.SymbolMarker);
  219. return null;
  220. }
  221. if (Enumerator.Current != Token.Comma
  222. && Enumerator.Current != Token.NewLine
  223. && Enumerator.Current != Token.EOF)
  224. {
  225. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  226. return null;
  227. }
  228. }
  229. return CallMethod(target, symbolMarker, parameters.ToArray());
  230. }
  231. else if (Lexer.Identifer == "CALLFORM"
  232. || Lexer.Identifer == "TRYCALLFORM")
  233. {
  234. string statementName = Lexer.Identifer;
  235. var node = new ExecutionNode
  236. {
  237. Type = "callform",
  238. Metadata =
  239. {
  240. ["try"] = statementName.StartsWith("TRY").ToString()
  241. },
  242. Symbol = CurrentPosition
  243. };
  244. ExecutionNode nameValue = null;
  245. List<ExecutionNode> parameters = new List<ExecutionNode>();
  246. Enumerator.MoveNext();
  247. do
  248. {
  249. ExecutionNode newValue = null;
  250. if (Enumerator.Current == Token.Identifer)
  251. {
  252. newValue = CreateConstant(Lexer.Identifer);
  253. }
  254. else if (Enumerator.Current == Token.OpenBracket)
  255. {
  256. newValue = Expression(out error);
  257. if (error != null)
  258. return null;
  259. }
  260. else
  261. {
  262. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  263. return null;
  264. }
  265. nameValue = nameValue == null
  266. ? newValue
  267. : OperateNodes(nameValue, newValue, Token.Plus);
  268. Enumerator.MoveNext();
  269. } while (Enumerator.Current != Token.Comma
  270. && Enumerator.Current != Token.NewLine
  271. && Enumerator.Current != Token.EOF);
  272. while (Enumerator.Current != Token.NewLine
  273. && Enumerator.Current != Token.EOF)
  274. {
  275. parameters.Add(Expression(out error));
  276. if (error != null)
  277. {
  278. error = new ParserError($"{error.ErrorMessage} (statement [{statementName}])", error.SymbolMarker);
  279. return null;
  280. }
  281. if (Enumerator.Current != Token.Comma
  282. && Enumerator.Current != Token.NewLine
  283. && Enumerator.Current != Token.EOF)
  284. {
  285. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  286. return null;
  287. }
  288. }
  289. node.SubNodes = new[]
  290. {
  291. new ExecutionNode
  292. {
  293. Type = "name",
  294. SubNodes = new[] { nameValue }
  295. },
  296. new ExecutionNode
  297. {
  298. Type = "parameters",
  299. SubNodes = parameters.ToArray()
  300. },
  301. };
  302. return node;
  303. }
  304. else //treat as statement
  305. {
  306. string statementName = Lexer.Identifer;
  307. var node = new ExecutionNode
  308. {
  309. Type = "statement",
  310. Metadata =
  311. {
  312. ["name"] = statementName
  313. },
  314. Symbol = CurrentPosition
  315. };
  316. List<ExecutionNode> parameters = new List<ExecutionNode>();
  317. if (StringStatements.Contains(statementName))
  318. {
  319. var value = StringExpression(out error);
  320. if (error != null)
  321. return null;
  322. if (value != null)
  323. parameters.Add(value);
  324. node.SubNodes = parameters.ToArray();
  325. return node;
  326. }
  327. if (GetNextToken(true) == Token.NewLine
  328. || GetNextToken(true) == Token.EOF)
  329. {
  330. return node;
  331. }
  332. else if (GetNextToken(true) == Token.Colon
  333. || GetNextToken(true) == Token.Equal)
  334. {
  335. error = new ParserError($"Undeclared variable: {statementName}", node.Symbol);
  336. return null;
  337. }
  338. while (Enumerator.Current != Token.NewLine
  339. && Enumerator.Current != Token.EOF)
  340. {
  341. parameters.Add(Expression(out error));
  342. if (error != null)
  343. {
  344. error = new ParserError($"{error.ErrorMessage} (statement [{statementName}])", error.SymbolMarker);
  345. return null;
  346. }
  347. if (Enumerator.Current != Token.Comma
  348. && Enumerator.Current != Token.NewLine
  349. && Enumerator.Current != Token.EOF)
  350. {
  351. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  352. return null;
  353. }
  354. }
  355. node.SubNodes = parameters.ToArray();
  356. return node;
  357. }
  358. case Token.Function:
  359. case Token.Sharp:
  360. while (Enumerator.MoveNext()
  361. && Enumerator.Current != Token.NewLine
  362. && Enumerator.Current != Token.EOF)
  363. {
  364. }
  365. return null;
  366. case Token.NewLine:
  367. case Token.EOF:
  368. return null;
  369. default:
  370. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  371. return null;
  372. }
  373. }
  374. protected ExecutionNode GetVariable(out ParserError error)
  375. {
  376. string variableName = Lexer.Identifer;
  377. var node = new ExecutionNode
  378. {
  379. Type = "variable",
  380. Metadata =
  381. {
  382. ["name"] = variableName
  383. },
  384. Symbol = CurrentPosition
  385. };
  386. List<ExecutionNode> indices = new List<ExecutionNode>();
  387. error = null;
  388. while (GetNextToken(true) == Token.Colon)
  389. {
  390. GetNextToken();
  391. var token = GetNextToken();
  392. if (token == Token.LParen)
  393. {
  394. indices.Add(Expression(out error));
  395. if (error != null)
  396. return null;
  397. if (Enumerator.Current != Token.RParen)
  398. {
  399. error = new ParserError("Invalid expression - Expected right bracket", CurrentPosition);
  400. return null;
  401. }
  402. }
  403. else if (token == Token.Value)
  404. {
  405. indices.Add(CreateConstant(Lexer.Value));
  406. }
  407. else if (token == Token.Identifer)
  408. {
  409. if (CsvDefinition.VariableIndexDictionary.TryGetValue(variableName, out var varTable)
  410. && varTable.TryGetValue(Lexer.Identifer, out int index))
  411. {
  412. indices.Add(CreateConstant(index));
  413. continue;
  414. }
  415. if (GlobalVariables.ContainsKey(Lexer.Identifer)
  416. || LocalVariables.ContainsKey(Lexer.Identifer))
  417. {
  418. var subNode = new ExecutionNode
  419. {
  420. Type = "variable",
  421. Metadata =
  422. {
  423. ["name"] = Lexer.Identifer
  424. },
  425. Symbol = CurrentPosition
  426. };
  427. indices.Add(subNode);
  428. continue;
  429. }
  430. if (FunctionDefinitions.Any(x => x.Name == Lexer.Identifer))
  431. {
  432. indices.Add(GetFunction(out error));
  433. if (error != null)
  434. return null;
  435. continue;
  436. }
  437. error = new ParserError($"Unknown identifier: {Lexer.Identifer}", CurrentPosition);
  438. return null;
  439. }
  440. }
  441. if (indices.Count > 0)
  442. {
  443. ExecutionNode indexNode = new ExecutionNode
  444. {
  445. Type = "index",
  446. SubNodes = indices.ToArray()
  447. };
  448. node.SubNodes = new[] { indexNode };
  449. }
  450. return node;
  451. }
  452. protected ExecutionNode GetFunction(out ParserError error)
  453. {
  454. error = null;
  455. Token token;
  456. Marker symbolMarker = CurrentPosition;
  457. List<ExecutionNode> parameters = new List<ExecutionNode>();
  458. string functionName = Lexer.Identifer;
  459. if (GetNextToken() != Token.LParen)
  460. {
  461. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  462. return null;
  463. }
  464. while ((token = GetNextToken(true)) == Token.Identifer
  465. || token == Token.Value
  466. || token.IsUnary())
  467. {
  468. parameters.Add(Expression(out error));
  469. if (error != null)
  470. return null;
  471. if (Enumerator.Current != Token.Comma
  472. && Enumerator.Current != Token.RParen)
  473. {
  474. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  475. return null;
  476. }
  477. if (Enumerator.Current == Token.RParen)
  478. break;
  479. }
  480. if (Enumerator.Current != Token.RParen)
  481. {
  482. error = new ParserError($"Unexpected token: {Enumerator.Current}", CurrentPosition);
  483. return null;
  484. }
  485. if (hasPeeked)
  486. {
  487. GetNextToken();
  488. }
  489. var functionDefinition = FunctionDefinitions.FirstOrDefault(x => x.Name == functionName
  490. && (x.Parameters.Length >= parameters.Count
  491. || x.Parameters.Any(y => y.IsArrayParameter)));
  492. if (functionDefinition == null)
  493. {
  494. error = new ParserError($"No matching method with same amount of parameters: {functionName} ({parameters.Count})", CurrentPosition);
  495. return null;
  496. }
  497. return CallMethod(functionName, symbolMarker, parameters.ToArray());
  498. }
  499. private static readonly Dictionary<Token, int> OrderOfOps = new Dictionary<Token, int>
  500. {
  501. { Token.Or, 0 }, { Token.And, 0 }, { Token.Not, 0 },
  502. { Token.Equal, 1 }, { Token.NotEqual, 1 },
  503. { Token.Less, 1 }, { Token.More, 1 }, { Token.LessEqual, 1 }, { Token.MoreEqual, 1 },
  504. { Token.Plus, 2 }, { Token.Minus, 2 },
  505. { Token.Asterisk, 3 }, { Token.Slash, 3 }, { Token.Modulo, 3 },
  506. { Token.Caret, 4 }
  507. };
  508. protected ExecutionNode Expression(out ParserError error, bool useModulo = true)
  509. {
  510. error = null;
  511. var operators = new Stack<Token>();
  512. var operands = new Stack<ExecutionNode>();
  513. Token token;
  514. void ProcessOperation(out ParserError localError)
  515. {
  516. localError = null;
  517. Token op = operators.Pop();
  518. if (op.IsUnary() && operands.Count >= 1)
  519. {
  520. var operand = operands.Pop();
  521. operands.Push(new ExecutionNode
  522. {
  523. Type = "operation",
  524. Metadata =
  525. {
  526. ["type"] = GetOperationName(op),
  527. ["unary"] = "true"
  528. },
  529. SubNodes = new[]
  530. {
  531. operand
  532. }
  533. });
  534. }
  535. else if (operands.Count >= 2)
  536. {
  537. ExecutionNode right = operands.Pop();
  538. ExecutionNode left = operands.Pop();
  539. operands.Push(new ExecutionNode
  540. {
  541. Type = "operation",
  542. Metadata =
  543. {
  544. ["type"] = GetOperationName(op),
  545. ["unary"] = "false"
  546. },
  547. SubNodes = new[]
  548. {
  549. left,
  550. right
  551. }
  552. });
  553. }
  554. else
  555. localError = new ParserError("Invalid expression - not enough operands", CurrentPosition);
  556. }
  557. void AttemptUnaryConversion(out ParserError localError)
  558. {
  559. localError = null;
  560. while (operators.Count > 0
  561. && operators.Peek().IsUnary())
  562. {
  563. ProcessOperation(out localError);
  564. if (localError != null)
  565. return;
  566. }
  567. }
  568. while ((token = GetNextToken()) != Token.NewLine
  569. && token != Token.EOF
  570. && token != Token.Comma
  571. && token != Token.Colon
  572. && token != Token.Format
  573. && token != Token.CloseBracket
  574. && (useModulo || token != Token.Modulo))
  575. {
  576. if (token == Token.Value)
  577. {
  578. operands.Push(CreateConstant(Lexer.Value));
  579. AttemptUnaryConversion(out error);
  580. if (error != null)
  581. return null;
  582. }
  583. else if (token == Token.Identifer)
  584. {
  585. if (GlobalVariables.ContainsKey(Lexer.Identifer)
  586. || LocalVariables.ContainsKey(Lexer.Identifer))
  587. {
  588. operands.Push(GetVariable(out error));
  589. if (error != null)
  590. return null;
  591. }
  592. else if (FunctionDefinitions.Any(x => x.Name == Lexer.Identifer))
  593. {
  594. operands.Push(GetFunction(out error));
  595. if (error != null)
  596. return null;
  597. }
  598. else
  599. {
  600. break;
  601. //this should be converted into a warning
  602. error = new ParserError($"Unknown identifier: {Lexer.Identifer}", CurrentPosition);
  603. return null;
  604. }
  605. }
  606. else if (token.IsArithmetic())
  607. {
  608. if (token.IsUnary())
  609. {
  610. operators.Push(token);
  611. continue;
  612. }
  613. if (!operands.Any() && !token.IsUnary())
  614. {
  615. error = new ParserError($"Invalid unary operator: {token}", CurrentPosition);
  616. return null;
  617. }
  618. while (operators.Any() && OrderOfOps[token] <= OrderOfOps[operators.Peek()])
  619. {
  620. ProcessOperation(out error);
  621. if (error != null)
  622. return null;
  623. }
  624. operators.Push(token);
  625. }
  626. else if (token == Token.LParen)
  627. {
  628. operands.Push(Expression(out var localError));
  629. if (localError != null)
  630. {
  631. error = localError;
  632. return null;
  633. }
  634. }
  635. else if (token == Token.RParen)
  636. {
  637. break;
  638. }
  639. else
  640. {
  641. error = new ParserError($"Unexpected token: {token}", CurrentPosition);
  642. return null;
  643. }
  644. }
  645. while (operators.Any())
  646. {
  647. ProcessOperation(out error);
  648. if (error != null)
  649. return null;
  650. }
  651. if (!operands.Any())
  652. {
  653. error = new ParserError("Invalid expression - Empty operand stack", CurrentPosition);
  654. return null;
  655. }
  656. return operands.Pop();
  657. }
  658. protected ExecutionNode StringExpression(out ParserError error)
  659. {
  660. error = null;
  661. ExecutionNode value = null;
  662. Lexer.Type = LexerType.String;
  663. while (Enumerator.MoveNext()
  664. && (Enumerator.Current == Token.Value
  665. || Enumerator.Current == Token.Format
  666. || Enumerator.Current == Token.OpenBracket))
  667. {
  668. if (Enumerator.Current == Token.Value)
  669. {
  670. value = value == null
  671. ? CreateConstant(Lexer.Value)
  672. : OperateNodes(value, CreateConstant(Lexer.Value), Token.Plus);
  673. }
  674. else
  675. {
  676. List<ExecutionNode> formatParams = new List<ExecutionNode>();
  677. Marker symbolMarker = CurrentPosition;
  678. bool isSpecialFormat = Enumerator.Current == Token.OpenBracket;
  679. do
  680. {
  681. Lexer.Type = LexerType.Both;
  682. var tempValue = Expression(out error, isSpecialFormat);
  683. if (error != null)
  684. return null;
  685. formatParams.Add(tempValue);
  686. } while (Enumerator.Current == Token.Comma);
  687. var formattedValue = CallMethod("_FORMAT", symbolMarker, formatParams.ToArray());
  688. value = value == null
  689. ? formattedValue
  690. : OperateNodes(value, formattedValue, Token.Plus);
  691. Lexer.Type = LexerType.String;
  692. }
  693. }
  694. Lexer.Type = LexerType.Both;
  695. return value;
  696. }
  697. private static readonly Dictionary<Token, string> OperationNames = new Dictionary<Token, string>
  698. {
  699. [Token.Plus] = "add",
  700. [Token.Asterisk] = "multiply",
  701. [Token.Minus] = "subtract",
  702. [Token.Slash] = "divide",
  703. };
  704. private static string GetOperationName(Token token)
  705. {
  706. return OperationNames.TryGetValue(token, out string result)
  707. ? result
  708. : token.ToString();
  709. }
  710. private ExecutionNode CreateConstant(Value value)
  711. {
  712. return new ExecutionNode
  713. {
  714. Type = "constant",
  715. Metadata =
  716. {
  717. ["type"] = value.Type.ToString(),
  718. ["value"] = value.ToString()
  719. },
  720. Symbol = CurrentPosition
  721. };
  722. }
  723. private static ExecutionNode OperateNodes(ExecutionNode left, ExecutionNode right, Token token)
  724. {
  725. return new ExecutionNode
  726. {
  727. Type = "operation",
  728. Metadata =
  729. {
  730. ["type"] = GetOperationName(token)
  731. },
  732. SubNodes = new[]
  733. {
  734. left,
  735. right
  736. }
  737. };
  738. }
  739. private static ExecutionNode CallMethod(string methodName, Marker symbolMarker, params ExecutionNode[] parameters)
  740. {
  741. return new ExecutionNode
  742. {
  743. Type = "call",
  744. Metadata =
  745. {
  746. ["target"] = methodName
  747. },
  748. Symbol = symbolMarker,
  749. SubNodes = new[]
  750. {
  751. new ExecutionNode
  752. {
  753. Type = "parameters",
  754. SubNodes = parameters.ToArray()
  755. }
  756. }
  757. };
  758. }
  759. }
  760. }