- SPEEDTRAP ALERT for Android
- Headless CMS
- Simple geo calculations
- Expression parser and evaluator (.NET, C#)
- Start - simple example
- Variables, properties, arrays and collections
- Functions and methods
- Operators
- Reference
- Something about iterating through UTF-16 Unicode strings (.NET, C#)
- Few words about toolkit:ExpanderView (XAML, .NET, C#, Windows Phone)
Using parser - variables, properties, arrays and collections
Name of variable or property in expression must start with letter or '_' character and may have any Unicode alphanumeric character (including surrogates) optionally modified by diacritical marks or '_' character. Elements of arrays or collections are accessed by indexes or keys written in square brackets. Example of expression: "MyVar + myClass.SomeProperty + MyArray[0,1]". Here MyVar, myClass, MyArray are variables, SomeProperty is a property, MyArray[0,1] is an array element.
There are two actions with variables, properties and array/collection elements that may occur during evaluation: retrieving value and assigning value. These actions take place in delegates passed to the AleTerm.Evaluate method. Full syntax of AleTerm.Evaluate method is:
public bool Evaluate(out AleTermResult result, TermEvaluate userEvaluate = null, TermAssign userAssign = null)
Retrieving value takes place in userEvaluate delegate. Syntax of this delegate is:
public delegate void TermEvaluate(AleTerm term, AleTermEvaluateArgs e);
where term is AleTerm instance which has executed delegate. e parameter contains information about the object whose value is retrieved.
using AleProjects.AleLexer.AleParser;
using AleProjects.AleLexer;
...
string myVar = "some value";
int[,] matrix = new int[,] { { 10, 11, 12, 13 }, { 14, 15, 16, 20 }, { 27, 28, 29, 40 } };
private class MyClass
{
public string SomeProperty { get; set; }
}
MyClass myClass = new MyClass() { SomeProperty = "property value"; };
private void OnEvaluate(AleTerm term, AleTermEvaluateArgs e)
{
/* VARIABLES
* e.Instance is null
* e.Name - name of variable (in uppercase when we ignore case)
* e.NameHash - hash of e.Name (obtained by GetHashCode())
* e.Indexes is null when we evaluate variable
* e.Result - stores value of variable on exit
*/
if (e.Instance == null)
{
if (e.NameHash == -1770187129 && e.Name == "MYVAR") e.Result = myVar;
else if (e.NameHash == -413117458 && e.Name == "MYCLASS") e.Result = myClass;
else if (e.NameHash == 614904363 && e.Name == "MYARRAY")) e.Result = matrix;
else
{
// error - no variable with such name
e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin);
}
return;
}
/* MEMBERS OF CLASSES (class operator '.')
* e.Instance - instance of class.
* e.Name - name of class property (in uppercase when we ignore case)
* e.NameHash - hash of e.Name (obtained by GetHashCode())
* e.Indexes is null when we evaluate class property
* e.Result - stores value of property or result of method
*/
if (!String.IsNullOrEmpty(e.Name))
{
if (e.Instance is MyClass)
{
MyClass _myClass = e.Instance as MyClass;
if (e.NameHash = 1760601946 && e.Name == "SOMEPROPERTY") e.Result = _myClass.SomeProperty;
else e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin);
}
else e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin);
return;
}
/* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator)
* e.Instance - instance of array or collection.
* e.Name == ""
* e.NameHash == 0
* e.Indexes is List<object> with indexes of array or keys of collection
* e.Result - stores value of member
*/
Type typ = e.Instance.GetType();
if (typ.IsArray && typ.FullName == "System.Int32[,]")
{
if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) return;
int[,] _matrix = e.Instance as int[,];
try
{
e.Result = _matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])];
}
catch
{
e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin);
}
}
else e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin);
}
...
AleExpressionParser AP = new AleExpressionParser();
AP.Options = AleExpressionParser.OPTION_IGNORECASE;
AP.InitOperations(AleExpressionParser.OPERATIONS_STANDARDSET);
AP.Text = "MyVar + myClass.SomeProperty + MyArray[0,1]";
AleTerm term = AP.Parse();
AleTermResult result;
if (term.Evaluate(out result, OnEvaluate)) .....
...
Assigning is initiated by assignment operators (=, +=, -=, ++, etc) and takes place in userAssign delegate. Syntax of this delegate is:
public delegate void TermAssign(AleTerm term, AleTermAssignArgs e);
where term is AleTerm instance which has executed delegate. e parameter contains information about the object the value is assigned to.
using AleProjects.AleLexer.AleParser;
using AleProjects.AleLexer;
...
string myVar = "some value";
int[,] matrix = new int[,] { { 10, 11, 12, 13 }, { 14, 15, 16, 20 }, { 27, 28, 29, 40 } };
private class MyClass
{
public string SomeProperty { get; set; }
}
MyClass myClass = new MyClass() { SomeProperty = "property value"; };
private void OnEvaluate(AleTerm term, AleTermEvaluateArgs e)
{
// the same code as in example above
}
private void OnAssign(AleTerm term, AleTermAssignArgs e)
{
/* VARIABLES
* e.Instance is null.
* e.Name - name of variable (in uppercase when we ignore case)
* e.NameHash - hash of e.Name (obtained by GetHashCode())
* e.Indexes is null
* e.Value - value that we assign
*/
if (e.Instance == null)
{
if (e.NameHash == -1770187129 && e.Name == "MYVAR") myVar = e.Value.ToString();
else if (e.NameHash == -413117458 && e.Name == "MYCLASS") myClass = e.Value as MyClass;
else if (e.NameHash == 614904363 && e.Name == "MYARRAY")) matrix = e.Value as int[,];
else
{
// error - no variable with such name
e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin);
}
return;
}
/* MEMBERS OF CLASSES (class operator '.')
* e.Instance - instance of class.
* e.Name - name of class property (in uppercase when we ignore case)
* e.NameHash - hash of e.Name (obtained by GetHashCode())
* e.Indexes is null
* e.Value - value that we assign
*/
if (!String.IsNullOrEmpty(e.Name))
{
if (e.Instance is MyClass)
{
MyClass _myClass = e.Instance as MyClass;
if (e.NameHash = 1760601946 && e.Name == "SOMEPROPERTY") _myClass.SomeProperty = e.Value.ToString();
else e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin);
}
else e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin);
return;
}
/* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator)
* e.Instance - instance of array or collection.
* e.Name == ""
* e.NameHash == 0
* e.Indexes - list<object> with indexes or keys
* e.Value - value that we assign
*/
Type typ = e.Instance.GetType();
if (typ.IsArray && typ.FullName == "System.Int32[,]")
{
if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) return;
int[,] _matrix = e.Instance as int[,];
try
{
_matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])] = Convert.ToInt32(e.Value);
}
catch
{
e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin);
}
}
else e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin);
}
...
AleExpressionParser AP = new AleExpressionParser();
AP.Options = AleExpressionParser.OPTION_IGNORECASE;
AP.InitOperations(AleExpressionParser.OPERATIONS_STANDARDSET);
AP.Text = "myClass.SomeProperty = \"text \" + (MyVar = \"value=\" + (MyArray[0,1] = 2))";
AleTerm term = AP.Parse();
AleTermResult result;
if (term.Evaluate(out result, OnEvaluate, OnAssign)) .....
...
Associative arrays and object constants
The syntax of associative array constant is: {key1=>value1, key2=>value2, ... }. Internally associative array is stored in the instance of Dictionary<object, object> type.
The syntax of object constant is: {"propertyName1": value1, "propertyName2": value2, ... }. Internally object is stored in the instance of Dictionary<string, object> type.
To disable associative array constants and object constants, set property InitListBrackets of the parser to empty string "" or null. Setting this property to '{}' enables constants. The first character is an opening bracket, the second is a closing one. Combining diacritical marks or surrogate pairs are not allowed.
using AleProjects.AleLexer.AleParser;
using AleProjects.AleLexer;
...
AleExpressionParser AP = new AleExpressionParser();
AP.InitListBrackets = ""; // disable
..
AP.InitListBrackets = "{}"; // enable
How to disable elements access
To disable elements access, set property ArrayBrackets of the parser to empty string "" or null. Setting this property to '[]' enables constants. The first character is an opening bracket, the second is a closing one. Combining diacritical marks or surrogate pairs are not allowed.
using AleProjects.AleLexer.AleParser; using AleProjects.AleLexer; ... AleExpressionParser AP = new AleExpressionParser(); AP.ArrayBrackets = ""; // disable .. AP.ArrayBrackets = "[]"; // enable