{"id":23221052,"url":"https://github.com/aptacode/expressions","last_synced_at":"2025-08-19T10:32:13.517Z","repository":{"id":43257124,"uuid":"307122622","full_name":"Aptacode/Expressions","owner":"Aptacode","description":"A light, cross platform \u0026 flexible .net library for creating, storing and dynamically evaluating expression trees using C#","archived":false,"fork":false,"pushed_at":"2022-03-11T16:12:20.000Z","size":459,"stargazers_count":11,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-08-31T02:53:23.311Z","etag":null,"topics":["aptacode","builder-pattern","csharp","dotnet","dynamic","evaluator","expression","interpreter","visitor-pattern"],"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/Aptacode.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":"2020-10-25T14:55:46.000Z","updated_at":"2024-05-15T08:19:10.000Z","dependencies_parsed_at":"2022-09-08T06:41:01.018Z","dependency_job_id":null,"html_url":"https://github.com/Aptacode/Expressions","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/Aptacode%2FExpressions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aptacode%2FExpressions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aptacode%2FExpressions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aptacode%2FExpressions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aptacode","download_url":"https://codeload.github.com/Aptacode/Expressions/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230345973,"owners_count":18211999,"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":["aptacode","builder-pattern","csharp","dotnet","dynamic","evaluator","expression","interpreter","visitor-pattern"],"created_at":"2024-12-18T22:15:12.101Z","updated_at":"2024-12-18T22:15:12.750Z","avatar_url":"https://github.com/Aptacode.png","language":"C#","readme":"\u003cp align=\"center\"\u003e\n   \u003cdiv style=\"width:640;height:320\"\u003e\n       \u003cimg style=\"width: inherit\" src=\"https://raw.githubusercontent.com/Aptacode/Expressions/main/Resources/Banner.png\"\u003e\n\u003c/div\u003e\n\u003c/p\u003e\n\n\n[![tests](https://github.com/Aptacode/Expressions/actions/workflows/test.yml/badge.svg)](https://github.com/Aptacode/Expressions/actions/workflows/test.yml)\n[![code metrics](https://github.com/Aptacode/Geometry/actions/workflows/metrics.yml/badge.svg)](https://github.com/Aptacode/Geometry/blob/main/CODE_METRICS.md)\n[![code quality](https://app.codacy.com/project/badge/Grade/fbc700bba83c476da496c11e718f9ad4)](https://www.codacy.com/gh/Aptacode/Expressions/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=Aptacode/Expressions\u0026amp;utm_campaign=Badge_Grade)\n[![nuget](https://img.shields.io/nuget/v/Aptacode.Expressions.svg?style=flat\u0026color=brightgreen)](https://www.nuget.org/packages/Aptacode.Expressions/)\n![last commit](https://img.shields.io/github/last-commit/Aptacode/Expressions?style=flat\u0026cacheSeconds=86000\u0026color=brightgreen)\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)\n\nWhilst originally designed to be used to represent and determine connection weights in [StateNet](https://github.com/Aptacode/StateNet), Expressions is a C# library used for writing and evaluating [expressions](https://en.wikipedia.org/wiki/Expression_(computer_science)) in a given context.\n\n## Overview\n\nExpressions can be used to write simple expressions:\n\n```csharp\nvar Expression = new ConstantInteger\u003cTContext\u003e(1) //An expression representing the int value 1\n```\n\nAs well as more complex nested expressions:\n\n```csharp\nvar Expression = new And\u003cTContext\u003e( //An expression following the usual boolean logic of the 'and' operator\n                     new GreaterThan\u003cint, TContext\u003e( //An expression for the comparison operator \u003e, this will evaluate to true as 4 \u003e 1\n                        new ConstantInteger\u003cTContext\u003e(4), new ConstantInteger\u003cTContext\u003e(1)),\n                     new EqualTo\u003cint, TContext\u003e(new ConstantInteger\u003cTContext\u003e(1), new ConstantInteger\u003cTContext\u003e(1))); //An expression for the equality operator.\n```\nTo evaluate these expressions into the correct context, the Expressions library utilises the Interpreter design pattern; Every expression type has an `.Interpret(context)` method. When called on a given context, any non-terminal expressions will recursively call `.Interpret(context)` (passing through the same context) on the expressions within them until a terminal expression is reached. Terminal expressions can then be evaluated to their respective values and value types in the given context. These in turn are passed on to the containing non-terminal expressions until the expression is completely evaluated.\n\n\n## ExpressionFactory\n\nBuilding complex expressions manually can be a bit messy syntactically and so there is also an `ExpressionFactory` class.\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _ex = new ExpressionFactory\u003cTContext\u003e();\nvar one = _ex.Int(1); //Creates a new ConstantInteger expression with value 1\nvar true = new _ex.Bool(true); //Creates a new ConstantBool expression with value true\nvar SevenIsGreaterThanFive = new _ex.GreaterThan\u003cint\u003e(_ex.Int(7), _ex.Int(5)); //This is much tidier than the basic implementation\n```\n\nA more complicated example highlights the improvement in conciseness:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\nvar fibListExpression = _expressions.List(new int[] { 1, 1, 2, 3, 5, 8 });\n\nfor(int i = 0; i \u003c 20; i++)\n{\n    fibListExpression = _expressions.List(_expressions.ConditionalList(_expressions.LessThan(_expressions.Last(fibListExpression), _expressions.Int(100)),\n                                _expressions.Append(fibListExpression,\n                                    _expressions.Add(_expressions.First(_expressions.TakeLast(fibListExpression, _expressions.Int(2))), \n                                    _expressions.Last(_expressions.TakeLast(fibListExpression, _expressions.Int(2))))),\n                                fibListExpression).Interpret(_context)); //An expression that when intepreted will add the next number in the fibonacci sequence to the list as long as that number is less than 100 and return the list as an expression or will just return the list as an expression if the next number is greater than 100.\n}\n\n\nvar fibLessThan100 = fibListExpression.Interpret(_context); //Interpreting the expression above will return a list of containing the numbers in the Fibonacci sequence less than 100.\n```\n\n## Fluent API\n\nIn the above example operators on our expressions such as `_expressions.Add()` are to the left of a pair of expressions `(lhs, rhs)` that is acted on by an operator i.e\n\n```csharp\nvar addEx = _expressions.Add(_expressions.Int(2), _expressions.Int(2);\n```\n\nUsing the roman alphabet we are more used to reading from left to right and so the above expression can still be a little tricky to read, especially when the arguments are also complicated expressions. To improve this we also have a more fluent API for our operators. With this the above expression becomes:\n\n```csharp\nvar addEx = _expressions.Int(2).Add(_expressions.Int(2));\n```\n\n## Usage and Examples\n\n### Constant Expressions\n\nConstant expressions of any type can be created using the generic `ConstantExpression`:\n\n```csharp\nvar ConstantExpression = new ConstantExpression\u003cTType, TContext\u003e(TType a); //An expression 'a' of some generic type \n```\nAnd also using the `ExpressionFactory`:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\n\nvar ConstantExpression = _expressions.Expression\u003cTType\u003e(TType a);\n```\n\nWe can also create various type specific constant expressions:\n\n```csharp\nvar ConstantFloatEx =  _expressions.Float(3.14f); // An expression representing the float value 3.14\nvar ConstantColorEx = _expressions.Color(System.Drawing.Color.Red); // An expression representing the color red\nvar ConstantGuidEx = _expressions.Guid(Guid.NewGuid()); // An expression representing a constant guid\n```\n\nWe can also make constant lists that can be used to represent expressions of lists of any generic type:\n\n```csharp\nvar ConstantListExpression = _expressions.List\u003cTType\u003e(TType[] list); //An expression representing a list of some generic type\n```\n\n### Arithmetic Operators\n\nArithmetic operations can act on expressions of any type with the `GenericArithmeticOperators`, though care must be exercised to ensure [the operators are implemented on the given type properly](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading):\n\n```csharp\nvar AddExpression = new Add\u003cTType, TContext\u003e(IExpression\u003cTType, TContext\u003e a, IExpression\u003cTType, TContext\u003e b); //An expression representing addition on the expressions a \u0026 b: a + b\n```\n\nWith the fluent API and `ExpressionFactory` we also have:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\n\nvar SubtractExpression = _ex.Expression\u003cTType\u003e(a).Subtract(_ex.Expression\u003cTType\u003e(b)); //An expression representing subtraction on the expressions a \u0026 b: a - b\nvar MultiplyExpression = _ex.Expression\u003cTType\u003e(a).Multiply(_ex.Expression\u003cTType\u003e(b));; //An expression representing multiplication on the expressions a \u0026 b: a * b\n```\n\nAbove we can see that the type can be inferred by the operator but if we want to be more explicit again there are also type specific variations of these operators:\n\n```csharp\nvar AddFloatExpression =  _expressions.Float(2.72f).AddFloat(_expressions.Float(1.41f)); //An expression representing addition of two floats: 2.72 + 1.41\nvar SubtractDecimalExpression = _expressions.Decimal(2.6m).SubtractDecimal(_expressions.Decimal(1.9m)); //An expression respresenting subtraction of the right float from the left:  2.6 - 1.3\nvar MultiplyDoubleExpression =_expressions.Double(1.2).MultiplyDouble(_expressions.Double(3.4)); //An expression representing the multiplication of two doubles: 1.2 * 3.4\n```\n\nThere is also the special case of string concatenation that can be considered as the addition operator acting on string expressions:\n\n```csharp\nvar ConcatStringExpression = _expressions.String(foo).ConcatString(_expressions.String(bar)); //An expression representing the concatenation (addition) of two string expressions: 'foo' + 'bar'\n```\n\n### Boolean Relational Operators and Equality Operators\n\nSimilarly to the arithmetic operators, expressions with boolean relational operators can be made on any given type, though - again - care must be taken to ensure the [operators are properly implemented on the type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators#operator-overloadability):\n\n```csharp\nvar GreaterThanExpression = new GreaterThan\u003cTContext\u003e(IExpression\u003cTType, TContext\u003e a, IExpression\u003cTType, TContext\u003e b); // An expression representing the comparison 'a \u003e b'\n```\n\nUsing the the fluent API and `ExpressionFactory`:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\n\n\nvar LessThanExpression = _expressions.Expression\u003cTType\u003e(a).LessThan(_expressions.Expression\u003cTType\u003e(b)); //An expression representing the comparison a \u003c b\nvar GreaterThanOrEqualToExpression = _expressions.Expression\u003cTType\u003e(a).GreaterThan(_expressions.Expression\u003cTType\u003e(b)); // An expression representing the comparison a \u003e= b\nvar LessThanOrEqualToExpression = _expressions.Expression\u003cTType\u003e(a).LessThanOrEqualTo(_expressions.Expression\u003cTType\u003e(b)); // An expression representing the comparison a \u003c= b\n```\n\nSimilarly, expressions with boolean equality operators can be made on any given type:\n\n```csharp\nvar EqualToExpression = _expressions.Expression\u003cTType\u003e(a).EqualTo(_expressions.Expression\u003cTType\u003e(b)); //An expression represent the comparison 'a == b'\nvar NotEqualToExpression = _expressions.Expression\u003cTType\u003e(a).NotEqualTo(_expressions.Expression\u003cTType\u003e(b)); //An expression represent the comparison 'a != b'\n```\n\n### Boolean Logical Operators\n\nFor boolean expressions we have the usual boolean logical operators. Using the fluent API and `ExpressionFactory`:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\n\nvar OrExpression = _expressions.Bool(true).Or(_expressions.Bool(false)); //An expression representing the boolean expression 'true OR false'\nvar NotExpression = _expressions.Bool(true).Not(); //An expression representing the boolean expression 'NOT true'\nvar AndExpression = _expressions.Bool(true).And(_expressions.Bool(false)); //An expression representing the boolean expression 'true AND false'\nvar XOrExpression = _expressions.Bool(true).XOr(_expressions.Bool(false)); //An expression representing the boolean expression 'true XOR false'\n```\n\nThere are also the `All` and `Any` operations that are equivalent to the boolean logic operations NAND and NOR, respectively:\n\n```csharp\nvar AllExpression = _expressions.Bool(true).All(_expressions.Bool(true), _expressions.Bool(false)); //An expression respresenting the boolean expression 'true AND true AND false'\nvar AnyExpression = _expressions.Bool(true).Any(_expressions.Bool(true), _expressions.Bool(false)); //An expression respresenting the boolean expression 'true OR true OR false'\n```\n\n\n### List Operators\n\nFor list expressions we also have some of the usual list operations. Using the fluent API and `ExpressionFactory`:\n\n```csharp\npublic readonly ExpressionFactory\u003cTContext\u003e _expressions = new ExpressionFactory\u003cTContext\u003e();\n\nvar list1 = new TType[] { a, b };\nvar list2 = new TType[] { c, d };\nvar ConcatListExpression = _expressions.List(list1).ConcatList(list2); //A list expression representing the concatenation of two list expressions 'list1 + list2'\nvar FirstExpression = _expressions.List(list1).First(); //An expression representing the first item in the list\nvar LastExpression = _expressions.List(list1).Last(); //An expression representing the last item in the list\nvar TakeFirstExpression = _expressions.List(list1).TakeFirst(_expressions.Int(n)); //A list expression of the first n items in 'list1'\nvar TakeLastExpression = _expressions.List(list1).TakeLast(_expressions.Int(m)); //A list expression of the last m items in 'list1'\nvar CountExpression = _expressions.List(list1).Count(); //An integer expression representing the number of items in the list\n```\n\n## License\n[MIT](https://choosealicense.com/licenses/mit/)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faptacode%2Fexpressions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faptacode%2Fexpressions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faptacode%2Fexpressions/lists"}