Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload for And,Or operators. Custom Error messages. #67

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
24d7400
Unsigned library; Fixed failing LongScriptTests (couldn't find test s…
Stanislav-Stoyanov Sep 19, 2018
65d3acc
Fixed paths in nuspec
Stanislav-Stoyanov Sep 19, 2018
218b166
nuspec tweak
Stanislav-Stoyanov Oct 4, 2018
9fb9915
Unseal expression context
Stanislav-Stoyanov Oct 5, 2018
c924693
Nuspec change
Stanislav-Stoyanov Oct 5, 2018
e67ad3f
Made CompileDynamic method virtual
Stanislav-Stoyanov Oct 5, 2018
31fadaa
Made one of the constructors of ExpressionCompileException public.
Stanislav-Stoyanov Oct 5, 2018
ed9dc71
Made ExpressionContext.Variables virtual and made VariableCollection'…
Stanislav-Stoyanov Oct 5, 2018
1b4ee82
Added CompilationErrorKey to compile exception. Reverted some of the …
Stanislav-Stoyanov Oct 11, 2018
9a91f2e
Fixed previous commit
Stanislav-Stoyanov Oct 11, 2018
8dabbed
Fixed a typo.
Stanislav-Stoyanov Oct 12, 2018
06c5919
nuspec
Stanislav-Stoyanov Oct 12, 2018
ac53888
Conditional now accepts types convertible to bool.
Stanislav-Stoyanov Nov 16, 2018
30cf4e6
nuspec
Stanislav-Stoyanov Nov 16, 2018
71b6f83
Removed ambiguous binary operator case.
Stanislav-Stoyanov Nov 16, 2018
d8ea9f5
AndOr operators can now be overloaded
Stanislav-Stoyanov Nov 20, 2018
b4fef15
added custom error messages when failing to evaluate the expresion
Mar 7, 2019
fccb7ea
fixes after PR
Mar 7, 2019
4c32684
Merge pull request #1 from riskfirst/feature/customerrormesage
Stanislav-Stoyanov Mar 7, 2019
69d45da
if the catched exception contains an inner exception message, throw …
Apr 15, 2019
61061b7
Merge pull request #2 from riskfirst/feature/innerexceptionmessage
irinasmt Apr 15, 2019
116a87f
Merge branch 'master' of https://github.com/mparlak/Flee
Jun 24, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ You should install [Flee with NuGet](https://www.nuget.org/packages/Flee):
Or via the .NET Core command line interface:

dotnet add package Flee

## NuGet Packages

| Name | NuGet |
| :--- | :--- |
| [Flee](https://www.nuget.org/packages/Flee) | [![Flee](https://img.shields.io/badge/nuget-v1.2.2-blue.svg)](https://www.nuget.org/packages/Flee)

## More information
* [Examples](https://github.com/mparlak/Flee/wiki/Examples) to learn how to create and evaluate expressions.
Expand Down
9 changes: 8 additions & 1 deletion nuget/flee.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<metadata>
<id>Flee</id>
<title>Flee</title>
<version>1.0.7</version>
<version>1.2.1</version>
<authors>Muhammet Parlak</authors>
<owners>Muhammet Parlak</owners>
<licenseUrl>https://github.com/mparlak/Flee</licenseUrl>
Expand All @@ -14,6 +14,13 @@
<copyright>Copyright 2017</copyright>
<tags>flee,expression evaluator,Expression Evaluator for c#</tags>
<releaseNotes>
1.2.1
• Fix for IndexOutOfRange when running complex(?) formulas
• Update Arithmetic.cs
1.2.0
• new – digitally sign a strong named assembly
1.1.0
• new – added strong name key
1.0.7
• Fixed – Flee fails to parse "if" formula
1.0.6
Expand Down
5 changes: 3 additions & 2 deletions src/Flee.Net45/ExpressionElements/Base/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ protected MethodInfo GetOverloadedBinaryOperator(string name, object operation)
}
else
{
return leftMethod;
// Ambiguous call
base.ThrowAmbiguousCallException(leftType, rightType, operation);
return null;
//base.ThrowAmbiguousCallException(leftType, rightType, operation);
//return null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ protected void ThrowCompileException(string messageKey, CompileExceptionReason r
string messageTemplate = FleeResourceManager.Instance.GetCompileErrorString(messageKey);
string message = string.Format(messageTemplate, arguments);
message = string.Concat(this.Name, ": ", message);
throw new ExpressionCompileException(message, reason);
throw new ExpressionCompileException(message, reason, arguments);
}

protected void ThrowAmbiguousCallException(Type leftType, Type rightType, object operation)
Expand Down
2 changes: 1 addition & 1 deletion src/Flee.Net45/ExpressionElements/Compare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public CompareElement()
public void Initialize(ExpressionElement leftChild, ExpressionElement rightChild, LogicalCompareOperation op)
{
MyLeftChild = leftChild;
MyRightChild = (Int32LiteralElement)rightChild;
MyRightChild = rightChild;
_myOperation = op;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Flee.Net45/ExpressionElements/Conditional.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public ConditionalElement(ExpressionElement condition, ExpressionElement whenTru
_myCondition = condition;
_myWhenTrue = whenTrue;
_myWhenFalse = whenFalse;

if ((!object.ReferenceEquals(_myCondition.ResultType, typeof(bool))))
if (!ImplicitConverter.EmitImplicitConvert(_myCondition.ResultType, typeof(bool), null))
{
base.ThrowCompileException(CompileErrorResourceKeys.FirstArgNotBoolean, CompileExceptionReason.TypeMismatch);
}
Expand Down
57 changes: 49 additions & 8 deletions src/Flee.Net45/ExpressionElements/LogicalBitwise/AndOr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using Flee.ExpressionElements.Base;
using Flee.InternalTypes;
Expand All @@ -26,6 +27,15 @@ protected override void GetOperation(object operation)

protected override System.Type GetResultType(System.Type leftType, System.Type rightType)
{
MethodInfo overloadedMethod = this.GetOverloadedAndOrOperator();

// Is an overloaded operator defined for our left and right children?
if ((overloadedMethod != null))
{
// Yes, so use its return type
return overloadedMethod.ReturnType;
}

Type bitwiseOpType = Utility.GetBitwiseOpType(leftType, rightType);
if ((bitwiseOpType != null))
{
Expand All @@ -41,21 +51,52 @@ protected override System.Type GetResultType(System.Type leftType, System.Type r
}
}

private MethodInfo GetOverloadedAndOrOperator()
{
// Get the name of the operator
string name = GetOverloadedOperatorFunctionName(_myOperation);
return base.GetOverloadedBinaryOperator(name, _myOperation);
}

private static string GetOverloadedOperatorFunctionName(AndOrOperation op)
{
switch (op)
{
case AndOrOperation.And:
return "BitwiseAnd";
case AndOrOperation.Or:
return "BitwiseOr";
default:
Debug.Assert(false, "unknown operator type");
return null;
}
}

public override void Emit(FleeILGenerator ilg, IServiceProvider services)
{
Type resultType = this.ResultType;
MethodInfo overloadedMethod = this.GetOverloadedAndOrOperator();

if (object.ReferenceEquals(resultType, typeof(bool)))
if ((overloadedMethod != null))
{
this.DoEmitLogical(ilg, services);
// Emit a call to an overloaded operator
this.EmitOverloadedOperatorCall(overloadedMethod, ilg, services);
}
else
{
MyLeftChild.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(MyLeftChild.ResultType, resultType, ilg);
MyRightChild.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(MyRightChild.ResultType, resultType, ilg);
EmitBitwiseOperation(ilg, _myOperation);
Type resultType = this.ResultType;

if (object.ReferenceEquals(resultType, typeof(bool)))
{
this.DoEmitLogical(ilg, services);
}
else
{
MyLeftChild.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(MyLeftChild.ResultType, resultType, ilg);
MyRightChild.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(MyRightChild.ResultType, resultType, ilg);
EmitBitwiseOperation(ilg, _myOperation);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Flee.Net45/Flee.Net45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>flee.pfx</AssemblyOriginatorKeyFile>
Expand Down
9 changes: 3 additions & 6 deletions src/Flee.Net45/InternalTypes/BranchManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,10 @@ public bool IsLongBranch(FleeILGenerator ilg, Label target)
if (index > -1 && index < MyBranchInfos.Count)
{
bi = MyBranchInfos[index];
return bi.IsLongBranch;
}
else
{
return true; // temp fix: not sure why, but MyBranchInfos seems to be missing elements when executing long scripts
}
}

return bi.IsLongBranch;
}

/// <summary>
/// Add a branch from a location to a target label
Expand Down
44 changes: 42 additions & 2 deletions src/Flee.Net45/InternalTypes/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,55 @@ private void ValidateOwner(object owner)
}
}

private T HandleEvaluationException<T>(Func<T> function)
{
try
{
return function.Invoke();
}
catch (Exception e)
{
if (e.InnerException?.Message != null)
{
throw new ExpressionEvaluationException(e.InnerException.Message);
}
var variables = _myInfo.GetReferencedVariables();
if (variables.Length != 0)
{
var exception = GetCustomExceptionMessage<T>(variables);
throw new ExpressionEvaluationException(exception);
}
throw new ExpressionEvaluationException(e.Message);
}
}

private string GetCustomExceptionMessage<T>(string[] variables)
{
var errorMessage = "";
foreach (var variable in variables)
{
var inputValue = Context.Variables.GetVariableValueInternal<string>(variable);
errorMessage += string.IsNullOrWhiteSpace(inputValue)
? $"{variable} = empty "
: $"{variable} = {inputValue} " + " ";
}

var exception = variables.Length == 1
? $"failed to run expression {_myExpression} with input {errorMessage}"
: $"failed to run expression {_myExpression} with inputs: {errorMessage}";
return exception;
}

public object Evaluate()
{
return _myEvaluator(_myOwner, _myContext, _myContext.Variables);
return HandleEvaluationException(() => _myEvaluator(_myOwner, _myContext, _myContext.Variables));
}

public T EvaluateGeneric()
{
return _myEvaluator(_myOwner, _myContext, _myContext.Variables);
return HandleEvaluationException(() => _myEvaluator(_myOwner, _myContext, _myContext.Variables));
}

T IGenericExpression<T>.Evaluate()
{
return EvaluateGeneric();
Expand Down
17 changes: 16 additions & 1 deletion src/Flee.Net45/PublicTypes/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ public enum CompileExceptionReason
public sealed class ExpressionCompileException : Exception
{
private readonly CompileExceptionReason _myReason;
internal ExpressionCompileException(string message, CompileExceptionReason reason) : base(message)
public object[] Arguments { get; }

internal ExpressionCompileException(string message, CompileExceptionReason reason, object[] arguments) : base(message)
{
Arguments = arguments;
_myReason = reason;
}

Expand Down Expand Up @@ -68,4 +71,16 @@ public override string Message

public CompileExceptionReason Reason => _myReason;
}

/// <summary>
/// Exception, which occured during expression evaluation.
/// </summary>
[Serializable]
public sealed class ExpressionEvaluationException : Exception
{

public ExpressionEvaluationException(string message) : base(message)
{
}
}
}
8 changes: 4 additions & 4 deletions src/Flee.Net45/Resources/CompileErrors.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/Flee.Net45/Resources/CompileErrors.resx
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,10 @@
<value>Type '{0}' is not an array and does not have an indexer which accepts '{1}'</value>
</data>
<data name="UndefinedFunction" xml:space="preserve">
<value>Could find not function '{0}({1})'</value>
<value>Could not find function '{0}({1})'</value>
</data>
<data name="UndefinedFunctionOnType" xml:space="preserve">
<value>Could find not function '{0}({1})' on type '{2}'</value>
<value>Could not find function '{0}({1})' on type '{2}'</value>
</data>
<data name="UNEXPECTED_CHAR" xml:space="preserve">
<value>Unexpected character: {0}</value>
Expand Down
Binary file modified src/Flee.Net45/flee.pfx
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Flee.NetStandard20/ExpressionElements/Arithmetic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ private bool IsOptimizablePower
{
get
{
if (_myOperation != BinaryArithmeticOperation.Power)
if (_myOperation != BinaryArithmeticOperation.Power || !(MyRightChild is Int32LiteralElement))
{
return false;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Flee.NetStandard20/ExpressionElements/Base/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ protected MethodInfo GetOverloadedBinaryOperator(string name, object operation)
}
else
{
return leftMethod;
// Ambiguous call
base.ThrowAmbiguousCallException(leftType, rightType, operation);
return null;
//base.ThrowAmbiguousCallException(leftType, rightType, operation);
//return null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ protected void ThrowCompileException(string messageKey, CompileExceptionReason r
string messageTemplate = FleeResourceManager.Instance.GetCompileErrorString(messageKey);
string message = string.Format(messageTemplate, arguments);
message = string.Concat(this.Name, ": ", message);
throw new ExpressionCompileException(message, reason);
throw new ExpressionCompileException(message, reason, arguments);
}

protected void ThrowAmbiguousCallException(Type leftType, Type rightType, object operation)
Expand Down
2 changes: 1 addition & 1 deletion src/Flee.NetStandard20/ExpressionElements/Compare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public CompareElement()
public void Initialize(ExpressionElement leftChild, ExpressionElement rightChild, LogicalCompareOperation op)
{
MyLeftChild = leftChild;
MyRightChild = (Int32LiteralElement)rightChild;
MyRightChild = rightChild;
_myOperation = op;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Flee.NetStandard20/ExpressionElements/Conditional.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public ConditionalElement(ExpressionElement condition, ExpressionElement whenTru
_myWhenTrue = whenTrue;
_myWhenFalse = whenFalse;

if ((!object.ReferenceEquals(_myCondition.ResultType, typeof(bool))))
if (!ImplicitConverter.EmitImplicitConvert(_myCondition.ResultType, typeof(bool), null))
{
base.ThrowCompileException(CompileErrorResourceKeys.FirstArgNotBoolean, CompileExceptionReason.TypeMismatch);
}
Expand Down
Loading