public static CodegenExpression Codegen( ExprCaseNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { Type evaluationType = forge.EvaluationType == null ? typeof(IDictionary<object, object>) : forge.EvaluationType; CodegenMethod methodNode = codegenMethodScope.MakeChild( evaluationType, typeof(ExprCaseNodeForgeEvalSyntax1), codegenClassScope); CodegenBlock block = methodNode.Block.DeclareVar<bool?>("when", ConstantFalse()); foreach (UniformPair<ExprNode> pair in forge.WhenThenNodeList) { block.AssignRef( "when", pair.First.Forge.EvaluateCodegen(typeof(bool?), methodNode, exprSymbol, codegenClassScope)); block.IfCondition(And(NotEqualsNull(Ref("when")), ExprDotName(Ref("when"), "Value"))) .BlockReturn(CodegenToType(forge, pair.Second, methodNode, exprSymbol, codegenClassScope)); } if (forge.OptionalElseExprNode != null) { block.MethodReturn( CodegenToType(forge, forge.OptionalElseExprNode, methodNode, exprSymbol, codegenClassScope)); } else { block.MethodReturn(ConstantNull()); } return LocalMethod(methodNode); }
public static CodegenExpression Codegen( ExprCaseNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { var evaluationType = forge.EvaluationType == null ? typeof(IDictionary<object, object>) : forge.EvaluationType; var compareType = forge.OptionalCompareExprNode.Forge.EvaluationType; var methodNode = codegenMethodScope.MakeChild( evaluationType, typeof(ExprCaseNodeForgeEvalSyntax2), codegenClassScope); var checkResultType = compareType == null ? typeof(object) : compareType; var block = methodNode.Block .DeclareVar( checkResultType, "checkResult", forge.OptionalCompareExprNode.Forge.EvaluateCodegen( checkResultType, methodNode, exprSymbol, codegenClassScope)); var num = 0; foreach (var pair in forge.WhenThenNodeList) { var refname = "r" + num; var lhsType = pair.First.Forge.EvaluationType; var lhsDeclaredType = lhsType == null ? typeof(object) : lhsType; block.DeclareVar( lhsDeclaredType, refname, pair.First.Forge.EvaluateCodegen(lhsDeclaredType, methodNode, exprSymbol, codegenClassScope)); var compareExpression = CodegenCompare( Ref("checkResult"), compareType, Ref(refname), pair.First.Forge.EvaluationType, forge, methodNode, codegenClassScope); block.IfCondition(compareExpression) .BlockReturn(CodegenToType(forge, pair.Second, methodNode, exprSymbol, codegenClassScope)); num++; } if (forge.OptionalElseExprNode != null) { block.MethodReturn( CodegenToType(forge, forge.OptionalElseExprNode, methodNode, exprSymbol, codegenClassScope)); } else { block.MethodReturn(ConstantNull()); } return LocalMethod(methodNode); }
public ExprCaseNodeForgeEvalSyntax1( ExprCaseNodeForge forge, IList<UniformPair<ExprEvaluator>> whenThenNodeList, ExprEvaluator optionalElseExprNode) { this.forge = forge; this.whenThenNodeList = whenThenNodeList; this.optionalElseExprNode = optionalElseExprNode; }
private static CodegenExpression CodegenCompare( CodegenExpressionRef lhs, Type lhsType, CodegenExpressionRef rhs, Type rhsType, ExprCaseNodeForge forge, CodegenMethodScope codegenMethodScope, CodegenClassScope codegenClassScope) { if (lhsType == null) { return EqualsNull(rhs); } if (rhsType == null) { return EqualsNull(lhs); } if (lhsType.CanNotBeNull() && rhsType.CanNotBeNull() && !forge.IsMustCoerce) { return CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce(lhs, lhsType, rhs, rhsType); } var block = codegenMethodScope .MakeChild(typeof(bool), typeof(ExprCaseNodeForgeEvalSyntax2), codegenClassScope) .AddParam(lhsType, "leftResult") .AddParam(rhsType, "rightResult") .Block; if (lhsType.CanBeNull()) { var ifBlock = block.IfCondition(EqualsNull(Ref("leftResult"))); if (rhsType.CanNotBeNull()) { ifBlock.BlockReturn(ConstantFalse()); } else { ifBlock.BlockReturn(EqualsNull(Ref("rightResult"))); } } if (rhsType.CanBeNull()) { block.IfCondition(EqualsNull(Ref("rightResult"))).BlockReturn(ConstantFalse()); } CodegenMethod method; if (!forge.IsMustCoerce) { method = block.MethodReturn( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftResult"), lhsType, Ref("rightResult"), rhsType)); } else { block.DeclareVar<object>("left", forge.Coercer.CoerceCodegen(Ref("leftResult"), lhsType)); block.DeclareVar<object>("right", forge.Coercer.CoerceCodegen(Ref("rightResult"), rhsType)); method = block.MethodReturn(StaticMethod<object>("Equals", Ref("left"), Ref("right"))); } return LocalMethodBuild(method).Pass(lhs).Pass(rhs).Call(); }
internal ExprCaseNodeForgeEvalSyntax2( ExprCaseNodeForge forge, IList<UniformPair<ExprEvaluator>> whenThenNodeList, ExprEvaluator compareExprNode, ExprEvaluator optionalElseExprNode) { this.forge = forge; this.whenThenNodeList = whenThenNodeList; this.compareExprNode = compareExprNode; this.optionalElseExprNode = optionalElseExprNode; }
protected internal static CodegenExpression CodegenToType( ExprCaseNodeForge forge, ExprNode node, CodegenMethod methodNode, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { Type nodeEvaluationType = node.Forge.EvaluationType; if (nodeEvaluationType == forge.EvaluationType || !forge.IsNumericResult) { return node.Forge.EvaluateCodegen(nodeEvaluationType, methodNode, exprSymbol, codegenClassScope); } if (nodeEvaluationType == null) { return ConstantNull(); } return TypeHelper.CoerceNumberToBoxedCodegen( node.Forge.EvaluateCodegen(nodeEvaluationType, methodNode, exprSymbol, codegenClassScope), nodeEvaluationType, forge.EvaluationType); }
public static CodegenExpression CodegenTypeableSingle( ExprCaseNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { CodegenMethod methodNode = codegenMethodScope.MakeChild( typeof(object[]), typeof(ExprCaseNodeForgeEvalTypable), codegenClassScope); CodegenBlock block = methodNode.Block .DeclareVar<IDictionary<object, object>>( "map", StaticMethod( typeof(CompatExtensions), "UnwrapDictionary", forge.EvaluateCodegen( typeof(IDictionary<object, object>), methodNode, exprSymbol, codegenClassScope))) .DeclareVar<object[]>( "row", NewArrayByLength(typeof(object), ExprDotName(Ref("map"), "Count"))); int index = -1; foreach (KeyValuePair<string, object> entry in forge.mapResultType) { index++; block.AssignArrayElement( Ref("row"), Constant(index), ExprDotMethod(Ref("map"), "Get", Constant(entry.Key))); } block.MethodReturn(Ref("row")); return LocalMethod(methodNode); }
public override ExprNode Validate(ExprValidationContext validationContext) { var analysis = AnalyzeCase(); foreach (var pair in analysis.WhenThenNodeList) { if (!IsCase2) { var returnType = pair.First.Forge.EvaluationType; if (returnType != typeof(bool) && returnType != typeof(bool?)) { throw new ExprValidationException("Case node 'when' expressions must return a boolean value"); } } } var mustCoerce = false; Coercer coercer = null; if (IsCase2) { // validate we can compare result types var comparedTypes = new List<Type>(); comparedTypes.Add(analysis.OptionalCompareExprNode.Forge.EvaluationType); foreach (var pair in analysis.WhenThenNodeList) { comparedTypes.Add(pair.First.Forge.EvaluationType); } // Determine common denominator type try { var coercionType = TypeHelper.GetCommonCoercionType(comparedTypes.ToArray()); // Determine if we need to coerce numbers when one type doesn't match any other type if (coercionType.IsNumeric()) { mustCoerce = false; foreach (var comparedType in comparedTypes) { if (comparedType != coercionType) { mustCoerce = true; } } if (mustCoerce) { coercer = SimpleNumberCoercerFactory.GetCoercer(null, coercionType); } } } catch (CoercionException ex) { throw new ExprValidationException("Implicit conversion not allowed: " + ex.Message); } } // Determine type of each result (then-node and else node) child node expression IList<Type> childTypes = new List<Type>(); IList<IDictionary<string, object>> childMapTypes = new List<IDictionary<string, object>>(); foreach (var pair in analysis.WhenThenNodeList) { if (pair.Second.Forge is ExprTypableReturnForge) { var typableReturn = (ExprTypableReturnForge) pair.Second.Forge; var rowProps = typableReturn.RowProperties; if (rowProps != null) { childMapTypes.Add(rowProps); continue; } } childTypes.Add(pair.Second.Forge.EvaluationType); } if (analysis.OptionalElseExprNode != null) { if (analysis.OptionalElseExprNode.Forge is ExprTypableReturnForge) { var typableReturn = (ExprTypableReturnForge) analysis.OptionalElseExprNode.Forge; var rowProps = typableReturn.RowProperties; if (rowProps != null) { childMapTypes.Add(rowProps); } else { childTypes.Add(analysis.OptionalElseExprNode.Forge.EvaluationType); } } else { childTypes.Add(analysis.OptionalElseExprNode.Forge.EvaluationType); } } if (!childMapTypes.IsEmpty() && !childTypes.IsEmpty()) { var message = "Case node 'when' expressions require that all results either return a single value or a Map-type (new-operator) value"; string check; var count = -1; foreach (var pair in analysis.WhenThenNodeList) { count++; if (pair.Second.Forge.EvaluationType != null && pair.Second.Forge.EvaluationType.IsNotGenericDictionary()) { check = ", check when-condition number " + count; throw new ExprValidationException(message + check); } } if (analysis.OptionalElseExprNode != null) { if (analysis.OptionalElseExprNode.Forge.EvaluationType != null && analysis.OptionalElseExprNode.Forge.EvaluationType.IsNotGenericDictionary()) { check = ", check the else-condition"; throw new ExprValidationException(message + check); } } throw new ExprValidationException(message); } IDictionary<string, object> mapResultType = null; Type resultType = null; var isNumericResult = false; if (childMapTypes.IsEmpty()) { // Determine common denominator type try { resultType = TypeHelper .GetCommonCoercionType(childTypes.ToArray()) .GetBoxedType(); if (resultType.IsNumeric()) { isNumericResult = true; } } catch (CoercionException ex) { throw new ExprValidationException("Implicit conversion not allowed: " + ex.Message); } } else { resultType = typeof(IDictionary<string, object>); mapResultType = childMapTypes[0]; for (var i = 1; i < childMapTypes.Count; i++) { var other = childMapTypes[i]; var messageEquals = BaseNestableEventType.IsDeepEqualsProperties( "Case-when number " + i, mapResultType, other); if (messageEquals != null) { throw new ExprValidationException( "Incompatible case-when return types by new-operator in case-when number " + i + ": " + messageEquals.Message, messageEquals); } } } forge = new ExprCaseNodeForge( this, resultType, mapResultType, isNumericResult, mustCoerce, coercer, analysis.WhenThenNodeList, analysis.OptionalCompareExprNode, analysis.OptionalElseExprNode); return null; }
public ExprCaseNodeForgeEvalTypable(ExprCaseNodeForge forge) { this.forge = forge; this.evaluator = forge.ExprEvaluator; }