Parser.cs 24 KB

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