/Irony.Samples/MiniPython/MiniPython.cs

http://irony.codeplex.com · C# · 141 lines · 89 code · 22 blank · 30 comment · 0 complexity · fc95fdd611705221ac3defac92c97c05 MD5 · raw file

  1. #region License
  2. /* **********************************************************************************
  3. * Copyright (c) Roman Ivantsov
  4. * This source code is subject to terms and conditions of the MIT License
  5. * for Irony. A copy of the license can be found in the License.txt file
  6. * at the root of this distribution.
  7. * By using this source code in any fashion, you are agreeing to be bound by the terms of the
  8. * MIT License.
  9. * You must not remove this notice from this software.
  10. * **********************************************************************************/
  11. #endregion
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Text;
  15. using Irony.Parsing;
  16. using Irony.Interpreter;
  17. using Irony.Interpreter.Ast;
  18. namespace Irony.Samples.MiniPython {
  19. // The grammar for a very small subset of Python. This is work in progress,
  20. // I will be adding more features as we go along, bringing it closer to real python.
  21. // Current version: expressions, assignments, indented code blocks, function defs, function calls
  22. // Full support for Python line joining rules: line continuation symbol "\", automatic line joining when
  23. // line ends in the middle of expression, with unbalanced parenthesis
  24. // Python is important test case for Irony as an indentation-sensitive language.
  25. [Language("MiniPython", "0.2", "Micro-subset of Python, work in progress")]
  26. public class MiniPythonGrammar : InterpretedLanguageGrammar {
  27. public MiniPythonGrammar() : base(caseSensitive: true) {
  28. // 1. Terminals
  29. var number = TerminalFactory.CreatePythonNumber("number");
  30. var identifier = TerminalFactory.CreatePythonIdentifier("identifier");
  31. var comment = new CommentTerminal("comment", "#", "\n", "\r");
  32. //comment must to be added to NonGrammarTerminals list; it is not used directly in grammar rules,
  33. // so we add it to this list to let Scanner know that it is also a valid terminal.
  34. base.NonGrammarTerminals.Add(comment);
  35. var comma = ToTerm(",");
  36. var colon = ToTerm(":");
  37. // 2. Non-terminals
  38. var Expr = new NonTerminal("Expr");
  39. var Term = new NonTerminal("Term");
  40. var BinExpr = new NonTerminal("BinExpr", typeof(BinaryOperationNode));
  41. var ParExpr = new NonTerminal("ParExpr");
  42. var UnExpr = new NonTerminal("UnExpr", typeof(UnaryOperationNode));
  43. var UnOp = new NonTerminal("UnOp", "operator");
  44. var BinOp = new NonTerminal("BinOp", "operator");
  45. var AssignmentStmt = new NonTerminal("AssignmentStmt", typeof(AssignmentNode));
  46. var Stmt = new NonTerminal("Stmt");
  47. var ExtStmt = new NonTerminal("ExtStmt");
  48. //Just as a test for NotSupportedNode
  49. var ReturnStmt = new NonTerminal("return", typeof(NotSupportedNode));
  50. var Block = new NonTerminal("Block");
  51. var StmtList = new NonTerminal("StmtList", typeof(StatementListNode));
  52. var ParamList = new NonTerminal("ParamList", typeof(ParamListNode));
  53. var ArgList = new NonTerminal("ArgList", typeof(ExpressionListNode));
  54. var FunctionDef = new NonTerminal("FunctionDef", typeof(FunctionDefNode));
  55. var FunctionCall = new NonTerminal("FunctionCall", typeof(FunctionCallNode));
  56. // 3. BNF rules
  57. Expr.Rule = Term | UnExpr | BinExpr;
  58. Term.Rule = number | ParExpr | identifier | FunctionCall;
  59. ParExpr.Rule = "(" + Expr + ")";
  60. UnExpr.Rule = UnOp + Term;
  61. UnOp.Rule = ToTerm("+") | "-";
  62. BinExpr.Rule = Expr + BinOp + Expr;
  63. BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**";
  64. AssignmentStmt.Rule = identifier + "=" + Expr;
  65. Stmt.Rule = AssignmentStmt | Expr | ReturnStmt | Empty;
  66. ReturnStmt.Rule = "return" + Expr; //Not supported for execution! - we associate NotSupportedNode with ReturnStmt
  67. //Eos is End-Of-Statement token produced by CodeOutlineFilter
  68. ExtStmt.Rule = Stmt + Eos | FunctionDef;
  69. Block.Rule = Indent + StmtList + Dedent;
  70. StmtList.Rule = MakePlusRule(StmtList, ExtStmt);
  71. ParamList.Rule = MakeStarRule(ParamList, comma, identifier);
  72. ArgList.Rule = MakeStarRule(ArgList, comma, Expr);
  73. FunctionDef.Rule = "def" + identifier + "(" + ParamList + ")" + colon + Eos + Block;
  74. FunctionDef.NodeCaptionTemplate = "def #{1}(...)";
  75. FunctionCall.Rule = identifier + "(" + ArgList + ")";
  76. FunctionCall.NodeCaptionTemplate = "call #{0}(...)";
  77. this.Root = StmtList; // Set grammar root
  78. // 4. Token filters - created in a separate method CreateTokenFilters
  79. // we need to add continuation symbol to NonGrammarTerminals because it is not used anywhere in grammar
  80. NonGrammarTerminals.Add(ToTerm(@"\"));
  81. // 5. Operators precedence
  82. RegisterOperators(1, "+", "-");
  83. RegisterOperators(2, "*", "/");
  84. RegisterOperators(3, Associativity.Right, "**");
  85. // 6. Miscellaneous: punctuation, braces, transient nodes
  86. MarkPunctuation("(", ")", ":");
  87. RegisterBracePair("(", ")");
  88. MarkTransient(Term, Expr, Stmt, ExtStmt, UnOp, BinOp, ExtStmt, ParExpr, Block);
  89. // 7. Error recovery rule
  90. ExtStmt.ErrorRule = SyntaxError + Eos;
  91. FunctionDef.ErrorRule = SyntaxError + Dedent;
  92. // 8. Syntax error reporting
  93. AddToNoReportGroup("(");
  94. AddToNoReportGroup(Eos);
  95. AddOperatorReportGroup("operator");
  96. // 9. Initialize console attributes
  97. ConsoleTitle = "Mini-Python Console";
  98. ConsoleGreeting =
  99. @"Irony Sample Console for mini-Python.
  100. Supports a small sub-set of Python: assignments, arithmetic operators,
  101. function declarations with 'def'. Supports big integer arithmetics.
  102. Supports Python indentation and line-joining rules, including '\' as
  103. a line joining symbol.
  104. Press Ctrl-C to exit the program at any time.
  105. ";
  106. ConsolePrompt = ">>>";
  107. ConsolePromptMoreInput = "...";
  108. // 10. Language flags
  109. this.LanguageFlags = LanguageFlags.NewLineBeforeEOF | LanguageFlags.CreateAst | LanguageFlags.SupportsBigInt;
  110. }//constructor
  111. public override void CreateTokenFilters(LanguageData language, TokenFilterList filters) {
  112. var outlineFilter = new CodeOutlineFilter(language.GrammarData,
  113. OutlineOptions.ProduceIndents | OutlineOptions.CheckBraces, ToTerm(@"\")); // "\" is continuation symbol
  114. filters.Add(outlineFilter);
  115. }
  116. }//class
  117. }//namespace