Welcome to
aleprojects.com

Using parser - user-defined functions and methods

Name of function or method in expression must start with letter or '_' character and may have any Unicode alphanumeric character (including surrogates) optionally modified by diacritical marks or '_' character. Function and methods can have arbitrary number of parameters. Parameters can be optional and have default values. Named parameters are not supported. All parameters are sent by value.

Function, method and operators are described by the AleOperation class. To create function or method description use this constructor of AleOperation:

public AleOperation(string name)

where name is the name of function or method. Name must be in uppercase if AleExpressionParser.OPTION_IGNORECASE flag is set in options.

To complete description of function, it is necessary to set two properties - AleOperation.Parameters and AleOperation.Evaluator. And one more property for method description - AleOperation.InstanceTypeCode.

public List<Tuple<TypeCode, object>> Parameters { get; set; }
public TypeCode InstanceTypeCode { get; set; }
public EvaluateOperation Evaluator { get; set; }

The AleOperation.Parameters property describes parameters which are passed to function or method. Each list element describes one parameter. First item of tuple defines type of parameter. Set it to TypeCode.Object for types other than primitive. When the first item of tuple is set with primitive type code, you can be sure that passed parameter is convertible to this type. Otherwise, an evaluation error will be generated. When first item has value TypeCode.Object, evaluator is responsible for type checking (using as operator). The second item - default value for optional parameter. Setting the second item to null means that parameter is required. The AleOperation.Parameters property is for syntax checking during expression parsing and for type checking during evaluation.

The AleOperation.InstanceTypeCode property is for description of methods. It defines the type of instance of the class whose method is executed. Evaluator is responsible for checking types other than primitive.

The AleOperation.Evaluator property is a delegate that evaluates function or property.

public delegate bool EvaluateOperation(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result);

If delegate fails to evaluate function it should return false and set error code and error position in result parameter. Error code is one of constants defined in the AleTermResult structure. Error position in most cases is a starting position of corresponding token.

Example:

using AleProjects.AleLexer.AleParser;
using AleProjects.AleLexer;

...

AleExpressionParser AP = new AleExpressionParser();
AP.Options = AleExpressionParser.OPTION_IGNORECASE;

AleOperation MyLog = new AleOperation("LOG")
{
	Parameters = new List<Tuple<TypeCode, object>>() { new Tuple<TypeCode, object>(TypeCode.Double, null) },
	Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result)
	{
		double x = Convert.ToDouble(parameters.FirstParam);
		if (x <= 0)
		{
			result.ErrorCode = AleTermResult.ERROR_INVALIDPARAMETERS;
			result.ErrorPos = term.Token.StartInOrigin;
			return false;
		}
		
		result.Value = Math.Log(x);
		return true;
	}
};

AleOperation MyReverse = new AleOperation("REVERSE")
{
	// Parameters = null - method has no parameters
	InstanceTypeCode = TypeCode.String,
	Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result)
	{
		StringBuilder s = new StringBuilder(parameters.ClassInstance.ToString());
		int n = s.Length;
		int m = (n--) / 2;
		char c;
	
		for (int i = 0; i < m; i++)
		{
			c = s[i];
			s[i] = s[n - i];
			s[n - i] = c;
		}
	
		result.Value = s;
		return true;
	}
};

AP.AddOperation(MyLog);
AP.AddOperation(MyReverse);

It is possible to return value of StringBuilder type. Parser considers StringBuilder and string as compatible types.

The AleExpressionParser.AddOperation method adds new operation to parser set of operations.

public bool AddOperation(AleOperation operation)

Functions or methods with the same name can have different number of parameters. Parser chooses most appropriate operation or fails if it couldn't. Functions or methods with the same name and number of parameters are considered as equal and AleExpressionParser.AddOperation will replace such previously added function or method. To remove operation from set use method AleExpressionParser.Remove.

public void RemoveOperation(string name, int paramCount, bool isClassMethod = false)

More about parameters

If function has three or less parameters, they are passed in FirstParam, SecondParam, ThirdParam properties of the OperationEvalParameter class instance.

public object FirstParam; { get; set; }
public object SecondParam; { get; set; }
public object ThirdParam; { get; set; }

If function has more than three parameters, they are passed in Parameters property.

public List<object> Parameters; { get; set; }

The OperationEvalParameter class has property ActualParamsCount.

public int ActualParamsCount;

This property returns number of parameters actually passed to function. It is useful when function has three or less parameters and last parameter(s) are optional. When there is more than three parameters, the value of this property is equal to Parameters.Length.

How to disable using of methods in expressions

Remove class (member access) operator from the parser set of operations:

using AleProjects.AleLexer.AleParser;
using AleProjects.AleLexer;

...

AleExpressionParser AP = new AleExpressionParser();
AP.InitOperations(AleExpressionParser.OPERATIONS_CLIKESET);
AP.RemoveOperation(".", -1);

The paramCount parameter of the RemoveOperation method for operators must be -1.