|
// ---------------------------------------------------------------------------
// Copyright (C) 2006 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------
#define CODE_ANALYSIS
using System.CodeDom;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities.Common;
namespace System.Workflow.Activities.Rules
{
#region RuleExpressionWalker
public static class RuleExpressionWalker
{
#region IRuleExpression wrapper factories for CodeDom
class CustomExpressionWrapper : RuleExpressionInternal
{
private IRuleExpression ruleExpr;
internal CustomExpressionWrapper(IRuleExpression ruleExpr)
{
this.ruleExpr = ruleExpr;
}
internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
{
ruleExpr.AnalyzeUsage(analysis, isRead, isWritten, qualifier);
}
internal override CodeExpression Clone(CodeExpression expression)
{
return ruleExpr.Clone();
}
internal override void Decompile(CodeExpression expression, StringBuilder decompilation, CodeExpression parentExpression)
{
ruleExpr.Decompile(decompilation, parentExpression);
}
internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
{
return ruleExpr.Evaluate(execution);
}
internal override bool Match(CodeExpression leftExpression, CodeExpression rightExpression)
{
return ruleExpr.Match(rightExpression);
}
internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
{
return ruleExpr.Validate(validation, isWritten);
}
}
class TypeWrapperTuple
{
internal Type codeDomType;
internal RuleExpressionInternal internalExpression;
internal TypeWrapperTuple(Type type, RuleExpressionInternal internalExpression)
{
this.codeDomType = type;
this.internalExpression = internalExpression;
}
}
static TypeWrapperTuple[] typeWrappers = new TypeWrapperTuple[] {
new TypeWrapperTuple(typeof(CodeThisReferenceExpression), new ThisExpression()),
new TypeWrapperTuple(typeof(CodePrimitiveExpression), new PrimitiveExpression()),
new TypeWrapperTuple(typeof(CodeFieldReferenceExpression), new FieldReferenceExpression()),
new TypeWrapperTuple(typeof(CodePropertyReferenceExpression), new PropertyReferenceExpression()),
new TypeWrapperTuple(typeof(CodeBinaryOperatorExpression), new BinaryExpression()),
new TypeWrapperTuple(typeof(CodeMethodInvokeExpression), new MethodInvokeExpression()),
new TypeWrapperTuple(typeof(CodeIndexerExpression), new IndexerPropertyExpression()),
new TypeWrapperTuple(typeof(CodeArrayIndexerExpression), new ArrayIndexerExpression()),
new TypeWrapperTuple(typeof(CodeDirectionExpression), new DirectionExpression()),
new TypeWrapperTuple(typeof(CodeTypeReferenceExpression), new TypeReferenceExpression()),
new TypeWrapperTuple(typeof(CodeCastExpression), new CastExpression()),
new TypeWrapperTuple(typeof(CodeObjectCreateExpression), new ObjectCreateExpression()),
new TypeWrapperTuple(typeof(CodeArrayCreateExpression), new ArrayCreateExpression())
};
private static RuleExpressionInternal GetExpression(CodeExpression expression)
{
Type exprType = expression.GetType();
int numTypeWrappers = typeWrappers.Length;
for (int i = 0; i < numTypeWrappers; ++i)
{
TypeWrapperTuple tuple = typeWrappers[i];
if (exprType == tuple.codeDomType)
return tuple.internalExpression;
}
// It's not a builtin one... try a user extension expression.
IRuleExpression ruleExpr = expression as IRuleExpression;
if (ruleExpr != null)
return new CustomExpressionWrapper(ruleExpr);
return null;
}
#endregion
public static RuleExpressionInfo Validate(RuleValidation validation, CodeExpression expression, bool isWritten)
{
if (validation == null)
throw new ArgumentNullException("validation");
// See if we've visited this node before.
// Always check if written = true
RuleExpressionInfo resultExprInfo = null;
if (!isWritten)
resultExprInfo = validation.ExpressionInfo(expression);
if (resultExprInfo == null)
{
// First time we've seen this node.
RuleExpressionInternal ruleExpr = GetExpression(expression);
if (ruleExpr == null)
{
string message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, expression.GetType().FullName);
ValidationError error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
error.UserData[RuleUserDataKeys.ErrorObject] = expression;
if (validation.Errors == null)
{
string typeName = string.Empty;
if ((validation.ThisType != null) && (validation.ThisType.Name != null))
{
typeName = validation.ThisType.Name;
}
string exceptionMessage = string.Format(
CultureInfo.CurrentCulture, Messages.ErrorsCollectionMissing, typeName);
throw new InvalidOperationException(exceptionMessage);
}
else
{
validation.Errors.Add(error);
}
return null;
}
resultExprInfo = validation.ValidateSubexpression(expression, ruleExpr, isWritten);
}
return resultExprInfo;
}
public static void AnalyzeUsage(RuleAnalysis analysis, CodeExpression expression, bool isRead, bool isWritten, RulePathQualifier qualifier)
{
if (analysis == null)
throw new ArgumentNullException("analysis");
RuleExpressionInternal ruleExpr = GetExpression(expression);
ruleExpr.AnalyzeUsage(expression, analysis, isRead, isWritten, qualifier);
}
public static RuleExpressionResult Evaluate(RuleExecution execution, CodeExpression expression)
{
if (execution == null)
throw new ArgumentNullException("execution");
RuleExpressionInternal ruleExpr = GetExpression(expression);
return ruleExpr.Evaluate(expression, execution);
}
[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")]
public static void Decompile(StringBuilder stringBuilder, CodeExpression expression, CodeExpression parentExpression)
{
RuleExpressionInternal ruleExpr = GetExpression(expression);
ruleExpr.Decompile(expression, stringBuilder, parentExpression);
}
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public static bool Match(CodeExpression firstExpression, CodeExpression secondExpression)
{
// If they're both null, they match.
if (firstExpression == null && secondExpression == null)
return true;
// If only one of them is null, there's no match.
if (firstExpression == null || secondExpression == null)
return false;
if (firstExpression.GetType() != secondExpression.GetType())
return false;
RuleExpressionInternal ruleExpr1 = GetExpression(firstExpression);
return ruleExpr1.Match(firstExpression, secondExpression);
}
public static CodeExpression Clone(CodeExpression originalExpression)
{
if (originalExpression == null)
return null;
RuleExpressionInternal ruleExpr = GetExpression(originalExpression);
CodeExpression newExpr = ruleExpr.Clone(originalExpression);
ConditionHelper.CloneUserData(originalExpression, newExpr);
return newExpr;
}
}
#endregion
#region CodeDomStatementWalker (internal)
internal static class CodeDomStatementWalker
{
#region RuleCodeDomStatement wrapper factories for CodeDom
private delegate RuleCodeDomStatement WrapperCreator(CodeStatement statement);
private static RuleCodeDomStatement GetStatement(CodeStatement statement)
{
Type statementType = statement.GetType();
RuleCodeDomStatement wrapper = null;
if (statementType == typeof(CodeExpressionStatement))
{
wrapper = ExpressionStatement.Create(statement);
}
else if (statementType == typeof(CodeAssignStatement))
{
wrapper = AssignmentStatement.Create(statement);
}
else
{
string message = string.Format(CultureInfo.CurrentCulture, Messages.CodeStatementNotHandled, statement.GetType().FullName);
NotSupportedException exception = new NotSupportedException(message);
exception.Data[RuleUserDataKeys.ErrorObject] = statement;
throw exception;
}
return wrapper;
}
#endregion
internal static bool Validate(RuleValidation validation, CodeStatement statement)
{
RuleCodeDomStatement ruleStmt = GetStatement(statement);
return ruleStmt.Validate(validation);
}
internal static void Execute(RuleExecution execution, CodeStatement statement)
{
RuleCodeDomStatement ruleStmt = GetStatement(statement);
ruleStmt.Execute(execution);
}
internal static void AnalyzeUsage(RuleAnalysis analysis, CodeStatement statement)
{
RuleCodeDomStatement ruleStmt = GetStatement(statement);
ruleStmt.AnalyzeUsage(analysis);
}
internal static void Decompile(StringBuilder stringBuilder, CodeStatement statement)
{
RuleCodeDomStatement ruleStmt = GetStatement(statement);
ruleStmt.Decompile(stringBuilder);
}
internal static bool Match(CodeStatement firstStatement, CodeStatement secondStatement)
{
// If they're both null, they match.
if (firstStatement == null && secondStatement == null)
return true;
// If only one of them is null, there's no match.
if (firstStatement == null || secondStatement == null)
return false;
if (firstStatement.GetType() != secondStatement.GetType())
return false;
RuleCodeDomStatement ruleStmt = GetStatement(firstStatement);
return ruleStmt.Match(secondStatement);
}
internal static CodeStatement Clone(CodeStatement statement)
{
if (statement == null)
return null;
RuleCodeDomStatement ruleStmt = GetStatement(statement);
return ruleStmt.Clone();
}
}
#endregion
}
|