/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(MSAst.ParameterExpression exception, bool preventAdditionalAdds) { Debug.Assert(exception.Type == typeof(Exception)); return(Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), Ast.Call( AstMethods.UpdateStackTrace, exception, LocalContext, _funcCodeExpr, _GetCurrentMethod, AstUtils.Constant(Name), AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"), new LastFaultingLineExpression(LineNumberExpression) ) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() )); }
/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(bool preventAdditionalAdds) { MSAst.Expression res; if (preventAdditionalAdds) { res = _saveLineNumberNoAdds; } else { res = _saveLineNumberAdds; } if (res == null) { res = Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), Ast.Call( AstMethods.UpdateStackTrace, LocalContext, _funcCodeExpr, _GetCurrentMethod, AstUtils.Constant(Name), AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"), new LastFaultingLineExpression(LineNumberExpression) ) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() ); if (preventAdditionalAdds) { _saveLineNumberNoAdds = res; } else { _saveLineNumberAdds = res; } } return(res); }
/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(MSAst.ParameterExpression exception, bool preventAdditionalAdds) { Debug.Assert(exception.Type == typeof(Exception)); return Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), UpdateStackTrace(exception) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() ); }
/// <summary> /// Helper to produce the rule for converting T to Nullable of T /// </summary> private void MakeConvertingToTToNullableOfTTarget(Type toType) { Type valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (Action.ResultKind == ConversionResultKind.ExplicitCast) { var action = OldConvertToAction.Make(Binder, valueType, Action.ResultKind); var conversion = Expression.Dynamic(action, action.ToType, _rule.Context, _rule.Parameters[0]); // if the conversion to T fails we just throw _rule.Target = _rule.MakeReturn( Binder, Ast.New( toType.GetConstructor(new Type[] { valueType }), conversion ) ); } else { // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) var conversion = Expression.Dynamic(OldConvertToAction.Make(Binder, valueType, Action.ResultKind), typeof(object), _rule.Context, _rule.Parameters[0]); ParameterExpression tmp = _rule.GetTemporary(typeof(object), "tmp"); _rule.Target = AstUtils.If( Ast.NotEqual( Ast.Assign(tmp, conversion), Ast.Constant(null) ), _rule.MakeReturn( Binder, Ast.New( toType.GetConstructor(new Type[] { valueType }), Ast.Convert( tmp, valueType ) ) ) ).Else( CompilerHelpers.GetTryConvertReturnValue(Context, _rule) ); } }
/// <summary> if a member-injector is defined-on or registered-for this type call it </summary> protected void MakeOperatorGetMemberBody(Type type, string name) { MethodInfo getMem = GetMethod(type, name); if (getMem != null && getMem.IsSpecialName) { ParameterExpression tmp = Rule.GetTemporary(typeof(object), "getVal"); AddToBody( AstUtils.If( Ast.NotEqual( Ast.Assign( tmp, Binder.MakeCallExpression(Rule.Context, getMem, Instance, Ast.Constant(StringName)) ), Ast.Field(null, typeof(OperationFailed).GetField("Value")) ), Rule.MakeReturn(Binder, tmp) ) ); } }
/// <summary> if a member-injector is defined-on or registered-for this type call it </summary> private bool MakeOperatorGetMemberBody(Type type, string name) { MethodInfo delMem = GetMethod(type, name); if (delMem != null && delMem.IsSpecialName) { Expression call = Binder.MakeCallExpression(Rule.Context, delMem, Rule.Parameters[0], Ast.Constant(StringName)); Expression ret; if (delMem.ReturnType == typeof(bool)) { ret = AstUtils.If(call, Rule.MakeReturn(Binder, Ast.Constant(null))); } else { ret = Rule.MakeReturn(Binder, call); } AddToBody(ret); return(delMem.ReturnType != typeof(bool)); } return(false); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object)); MSA.Expression redoVariable = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool)); MSA.ParameterExpression unwinder; bool isInnerLoop = gen.CurrentLoop != null; MSA.LabelTarget breakLabel = Ast.Label(); MSA.LabelTarget continueLabel = Ast.Label(); gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel); MSA.Expression transformedBody = gen.TransformStatements(_statements, ResultOperation.Ignore); MSA.Expression transformedCondition = _condition.TransformCondition(gen, true); gen.LeaveLoop(); MSA.Expression conditionPositiveStmt, conditionNegativeStmt; if (_isWhileLoop) { conditionPositiveStmt = AstUtils.Empty(); conditionNegativeStmt = Ast.Break(breakLabel); } else { conditionPositiveStmt = Ast.Break(breakLabel); conditionNegativeStmt = AstUtils.Empty(); } // make the loop first: MSA.Expression loop = new AstBlock { gen.ClearDebugInfo(), Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)), AstFactory.Infinite(breakLabel, continueLabel, AstUtils.Try( AstUtils.If(redoVariable, Ast.Assign(redoVariable, AstUtils.Constant(false)) ).ElseIf(transformedCondition, conditionPositiveStmt ).Else( conditionNegativeStmt ), transformedBody, AstUtils.Empty() ).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo = u.IsRedo Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)), AstUtils.Empty() ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak), // result = unwinder.ReturnValue Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)), Ast.Break(breakLabel) ) ), gen.ClearDebugInfo(), AstUtils.Empty(), }; // wrap it to try finally that updates RFC state: if (!isInnerLoop) { loop = AstUtils.Try( Methods.EnterLoop.OpCall(gen.CurrentScopeVariable), loop ).Finally( Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable) ); } return(Ast.Block(loop, resultVariable)); }