{"id":19991832,"url":"https://github.com/daxnet/irony","last_synced_at":"2026-02-07T19:11:05.282Z","repository":{"id":54228322,"uuid":"83311332","full_name":"daxnet/irony","owner":"daxnet","description":"A modified version of the Irony project (https://irony.codeplex.com) with .NET Core support","archived":false,"fork":false,"pushed_at":"2021-03-02T09:32:47.000Z","size":389,"stargazers_count":155,"open_issues_count":8,"forks_count":47,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-05T00:18:31.670Z","etag":null,"topics":["parser-generator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daxnet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-27T13:08:14.000Z","updated_at":"2025-03-13T04:17:55.000Z","dependencies_parsed_at":"2022-08-13T09:40:37.037Z","dependency_job_id":null,"html_url":"https://github.com/daxnet/irony","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daxnet%2Firony","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daxnet%2Firony/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daxnet%2Firony/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daxnet%2Firony/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daxnet","download_url":"https://codeload.github.com/daxnet/irony/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252329017,"owners_count":21730536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["parser-generator"],"created_at":"2024-11-13T04:51:55.989Z","updated_at":"2026-02-07T19:11:00.244Z","avatar_url":"https://github.com/daxnet.png","language":"C#","readme":"# Irony\nA modified version of the Irony project ([https://irony.codeplex.com](https://irony.codeplex.com)) with .NET Core support.\n\n[![Build status](https://dev.azure.com/sunnycoding/Irony/_apis/build/status/Irony-Build-Pipeline)](https://dev.azure.com/sunnycoding/Irony/_build/latest?definitionId=4)\n\nIrony is a .NET Language Implementation Kit written originally by Roman Ivantsov, you should be able to find his blog related to Irony via [http://irony-roman.blogspot.com/](http://irony-roman.blogspot.com/). He also developed an ORM framework, VITA, which can be found [here](http://vita.codeplex.com/ \"here\").\n\nBased on the fact that the project on its official site hasn't been updated for a long time (last commit was on Dec 13th 2013) and cannot support .NET Core, I just made a copy of the project and made some modifications in order to support .NET Core. I still kept the MIT license and made the project to be licensed under Roman's name.  \n\n## Major Changes\n- Fixed the compile issues found during .NET Core migration\n\t- Changed `StringComparer.InvariantCulture(IgnoreCase)` to `StringComparer.CurrentCulture(IgnoreCase)`\n\t- Changed `char.GetUnicodeCategory()` to `CharUnicodeInfo.GetUnicodeCategory(current)`\n\t- Temporary removed `ParseTreeExtensions` implementation\n\t- Migrated the unit test project to xUnit\n\t- Removed the original `Test`, `Sample`, `GrammarExplorer` projects from the Visual Studio solution. And the GrammarExplorer is supposed to be provided in another repo\n\n## Adding the NuGet Package\nThe Irony and Irony.Interpreter packages have been published to NuGet, with the package id `Irony.NetCore` and `Irony.Interpreter.NetCore`, in distinguishing from the original `Irony` and `Irony.Interpreter` packages published by Roman.\n \n \n## Example\nThis repo contains a full example of an arithmetic expression evaluator, which accepts an arithmetic expression as a string and evaluates and calculates the result. You can find the source code under `Irony.SampleApp` folder. The expression grammar can be represented by the following C# class:\n\n```cs\nusing Irony.Interpreter.Ast;\nusing Irony.Parsing;\nusing System;\n\nnamespace Irony.SampleApp\n{\n    /// \u003csummary\u003e\n    /// Represents the grammar of a custom expression.\n    /// \u003c/summary\u003e\n    /// \u003cseealso cref=\"Irony.Parsing.Grammar\" /\u003e\n    [Language(\"Expression Grammar\", \"1.0\", \"abc\")]\n    public class ExpressionGrammar : Grammar\n    {\n        /// \u003csummary\u003e\n        /// Initializes a new instance of the \u003csee cref=\"ExpressionGrammar\"/\u003e class.\n        /// \u003c/summary\u003e\n        public ExpressionGrammar() : base(false)\n        {\n            var number = new NumberLiteral(\"Number\");\n            number.DefaultIntTypes = new TypeCode[] { TypeCode.Int16, TypeCode.Int32, TypeCode.Int64 };\n            number.DefaultFloatType = TypeCode.Single;\n\n            var identifier = new IdentifierTerminal(\"Identifier\");\n            var comma = ToTerm(\",\");\n\n            var BinOp = new NonTerminal(\"BinaryOperator\", \"operator\");\n            var ParExpr = new NonTerminal(\"ParenthesisExpression\");\n            var BinExpr = new NonTerminal(\"BinaryExpression\", typeof(BinaryOperationNode));\n            var Expr = new NonTerminal(\"Expression\");\n            var Term = new NonTerminal(\"Term\");\n\n            var Program = new NonTerminal(\"Program\", typeof(StatementListNode));\n\n            Expr.Rule = Term | ParExpr | BinExpr;\n            Term.Rule = number | identifier;\n\n            ParExpr.Rule = \"(\" + Expr + \")\";\n            BinExpr.Rule = Expr + BinOp + Expr;\n            BinOp.Rule = ToTerm(\"+\") | \"-\" | \"*\" | \"/\";\n\n            RegisterOperators(10, \"+\", \"-\");\n            RegisterOperators(20, \"*\", \"/\");\n\n            MarkPunctuation(\"(\", \")\");\n            RegisterBracePair(\"(\", \")\");\n            MarkTransient(Expr, Term, BinOp, ParExpr);\n\n            this.Root = Expr;\n        }\n    }\n}\n\n```\nThe following class diagram illustrates the object model that can represent an arithmetic expression, the classes shown in this diagram can be found under `Irony.SampleApp.Evaluations` namespace.\n\n![](https://raw.githubusercontent.com/daxnet/irony/master/doc/ClassDiagram.png)\n\nThe `Evaluator` class under `Irony.SampleApp.Evaluations` namespace is responsible for creating the parser based on the above expression grammar definition and parse the input string and finally comes out the evaluated value.\n\n```cs\nusing Irony.Parsing;\nusing System;\nusing System.Text;\n\nnamespace Irony.SampleApp.Evaluations\n{\n    internal sealed class Evaluator\n    {\n        public Evaluation Evaluate(string input)\n        {\n            var language = new LanguageData(new ExpressionGrammar());\n            var parser = new Parser(language);\n            var syntaxTree = parser.Parse(input);\n\n            if (syntaxTree.HasErrors())\n            {\n                throw new InvalidOperationException(BuildParsingErrorMessage(syntaxTree.ParserMessages));\n            }\n\n            return PerformEvaluate(syntaxTree.Root);\n        }\n\n        private Evaluation PerformEvaluate(ParseTreeNode node)\n        {\n            switch (node.Term.Name)\n            {\n                case \"BinaryExpression\":\n                    var leftNode = node.ChildNodes[0];\n                    var opNode = node.ChildNodes[1];\n                    var rightNode = node.ChildNodes[2];\n                    Evaluation left = PerformEvaluate(leftNode);\n                    Evaluation right = PerformEvaluate(rightNode);\n                    BinaryOperation op = BinaryOperation.Add;\n                    switch (opNode.Term.Name)\n                    {\n                        case \"+\":\n                            op = BinaryOperation.Add;\n                            break;\n                        case \"-\":\n                            op = BinaryOperation.Sub;\n                            break;\n                        case \"*\":\n                            op = BinaryOperation.Mul;\n                            break;\n                        case \"/\":\n                            op = BinaryOperation.Div;\n                            break;\n                    }\n                    return new BinaryEvaluation(left, right, op);\n                case \"Number\":\n                    var value = Convert.ToSingle(node.Token.Text);\n                    return new ConstantEvaluation(value);\n            }\n\n            throw new InvalidOperationException($\"Unrecognizable term {node.Term.Name}.\");\n        }\n\n        private static string BuildParsingErrorMessage(LogMessageList messages)\n        {\n            var sb = new StringBuilder();\n            sb.AppendLine(\"Parsing failed with the following errors:\");\n            messages.ForEach(msg =\u003e sb.AppendLine($\"\\t{msg.Message}\"));\n            return sb.ToString();\n        }\n    }\n}\n\n```\nAnd the `Program.Main` method simply creates the evaluator and output the evaluated value:\n\n```cs\nusing Irony.SampleApp.Evaluations;\nusing System;\n\nnamespace Irony.SampleApp\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var evaluator = new Evaluator();\n            var evaluation = evaluator.Evaluate(\"2.5+(3-1)*5\");\n            Console.WriteLine(evaluation.Value);\n        }\n    }\n}\n\n```\n\nProgram output:\n\n![](https://raw.githubusercontent.com/daxnet/irony/master/doc/ProgramOutput.png)\n","funding_links":[],"categories":["C\\#"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaxnet%2Firony","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaxnet%2Firony","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaxnet%2Firony/lists"}