public virtual Proc /*!*/ ToProc(RubyScope /*!*/ scope) { ContractUtils.RequiresNotNull(scope, "scope"); if (_procDispatcher == null) { var site = CallSite <Func <CallSite, object, object, object> > .Create( // TODO: use InvokeBinder RubyCallAction.Make( scope.RubyContext, "call", new RubyCallSignature(1, RubyCallFlags.HasImplicitSelf | RubyCallFlags.HasSplattedArgument) ) ); var block = new BlockCallTargetUnsplatN((blockParam, self, args, unsplat) => { // block takes no parameters but unsplat => all actual arguments are added to unsplat: Debug.Assert(args.Length == 0); return(site.Target(site, this, unsplat)); }); _procDispatcher = new BlockDispatcherUnsplatN(0, BlockDispatcher.MakeAttributes(BlockSignatureAttributes.HasUnsplatParameter, _info.GetArity()), null, 0 ); _procDispatcher.SetMethod(block); } // TODO: // MRI: source file/line are that of the to_proc method call: return(new Proc(ProcKind.Block, scope.SelfObject, scope, _procDispatcher)); }
public static Proc /*!*/ Create(RubyContext /*!*/ context, int parameterCount, BlockSignatureAttributes signatureAttributes, Delegate /*!*/ clrMethod) { // scope is used to get to the execution context: return(new Proc(ProcKind.Block, null, context.EmptyScope, BlockDispatcher.Create(parameterCount, signatureAttributes, null, 0).SetMethod(clrMethod) )); }
/// <summary> /// Creates a proc that invokes a method of given name. /// <code> /// Proc.new do |*args| /// raise ArgumentException if args.size == 0 /// obj.methodName(args.delete_at(0), args) /// end /// </code> /// </summary> public static Proc /*!*/ CreateMethodInvoker(RubyScope /*!*/ scope, string /*!*/ methodName) { ContractUtils.RequiresNotNull(scope, "scope"); // TODO: // This should pass a proc parameter (use BlockDispatcherUnsplatProcN). // MRI 1.9.2 doesn't do so though (see http://redmine.ruby-lang.org/issues/show/3792). var site = CallSite <Func <CallSite, object, object, object, object> > .Create( RubyCallAction.Make( scope.RubyContext, methodName, new RubyCallSignature(0, RubyCallFlags.HasScope | RubyCallFlags.HasSplattedArgument) ) ); var block = new BlockCallTargetUnsplatN((blockParam, self, args, unsplat) => { Debug.Assert(args.Length == 0); if (unsplat.Count == 0) { throw RubyExceptions.CreateArgumentError("no receiver given"); } object target = unsplat[0]; unsplat.RemoveAt(0); return(site.Target(site, scope, target, unsplat)); }); var procDispatcher = new BlockDispatcherUnsplatN(0, BlockDispatcher.MakeAttributes(BlockSignatureAttributes.HasUnsplatParameter, -1), null, 0 ); procDispatcher.SetMethod(block); return(new Proc(ProcKind.Proc, scope.SelfObject, scope, procDispatcher)); }
internal BlockSignatureAttributes GetBlockSignatureAttributes() { var result = BlockSignatureAttributes.None; if (_unsplat != null) { result |= BlockSignatureAttributes.HasUnsplatParameter; } if (_block != null) { result |= BlockSignatureAttributes.HasProcParameter; } int arity = _mandatory.Length; if (_unsplat != null) { arity = -(arity + 1); } else if (arity > 0 && _mandatory[_mandatory.Length - 1] is Placeholder) { arity--; } return(BlockDispatcher.MakeAttributes(result, arity)); }
internal Proc(ProcKind kind, object self, RubyScope /*!*/ scope, BlockDispatcher /*!*/ dispatcher) { Assert.NotNull(scope, dispatcher); _kind = kind; _self = self; _scope = scope; _dispatcher = dispatcher; }
internal BlockSignatureAttributes GetBlockSignatureAttributes() { var result = BlockSignatureAttributes.None; CompoundLeftValue compound; if (_unsplattedValue != null) { result |= BlockSignatureAttributes.HasUnsplatParameter; compound = this; } else if (_leftValues.Count == 1 && (compound = _leftValues[0] as CompoundLeftValue) != null) { result |= BlockSignatureAttributes.HasSingleCompoundParameter; } else { compound = this; } int arity; if (this == UnspecifiedBlockSignature) { arity = -1; } else { arity = compound._leftValues.Count; if (compound._unsplattedValue != null) { arity = -arity - 1; } else if (compound._leftValues.Count > 0 && compound._leftValues[compound._leftValues.Count - 1] is Placeholder) { arity--; } } return(BlockDispatcher.MakeAttributes(result, arity)); }
public static Proc /*!*/ Create(RubyContext /*!*/ context, BlockCallTarget1 /*!*/ clrMethod) { return(Create(context, 1, BlockDispatcher.MakeAttributes(BlockSignatureAttributes.None, -1), clrMethod)); }
internal MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen, bool isLambda) { ScopeBuilder scope = DefineLocals(gen.CurrentScope); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.ParameterExpression blockParameter, selfParameter; var parameters = DefineParameters(out selfParameter, out blockParameter); MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder, filterVariable; MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line; traceCall = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine)); traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine)); } else { traceCall = traceReturn = Ast.Empty(); } MSA.Expression body = AstUtils.Try( paramInit, traceCall, Ast.Label(redoLabel), AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"), Methods.FilterBlockException.OpCall(scopeVariable, filterVariable) ).Finally( traceReturn, Ast.Empty() ); body = gen.AddReturnTarget( scope.CreateScope( scopeVariable, Methods.CreateBlockScope.OpCall(new AstExpressions { scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), blockParameter, selfParameter, EnterInterpretedFrameExpression.Instance }), body ) ); gen.LeaveBlockDefinition(); int parameterCount = ParameterCount; var attributes = _parameters.GetBlockSignatureAttributes(); var dispatcher = Ast.Constant( BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher) ); return(Ast.Coalesce( (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher), (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher, BlockDispatcher.CreateLambda( body, RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode), parameters, parameterCount, attributes ) ) )); }
public static Proc /*!*/ Create(RubyContext /*!*/ context, BlockCallTarget1 /*!*/ clrMethod) { return(Create(context, 1, BlockDispatcher.MakeAttributes(BlockSignatureAttributes.HasSingleCompoundParameter, -1), clrMethod)); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression parentScope = gen.CurrentScopeVariable; ScopeBuilder scope = new ScopeBuilder(); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.Expression blockParameter, selfParameter; MSA.ParameterExpression[] parameters = DefineParameters(out selfParameter, out blockParameter); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); if (_definedScope != null) { _definedScope.TransformLocals(scope); } MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder = scope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder)); MSA.Expression loop = AstFactory.Infinite(null, redoLabel, AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder, // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Continue(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ); if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body[0].Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body[_body.Count - 1].Location.End.Line : Location.End.Line; loop = Ast.TryFinally( Ast.Block( Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(firstStatementLine)), loop ), Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastStatementLine)) ); } MSA.Expression body = Ast.Block( Ast.Assign(scopeVariable, Methods.CreateBlockScope.OpCall(scope.VisibleVariables(), parentScope, blockParameter, selfParameter) ), paramInit, loop, Ast.Empty() ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveBlockDefinition(); int parameterCount = _parameters.LeftValues.Count; var attributes = _parameters.GetBlockSignatureAttributes(); return(Methods.DefineBlock.OpCall( gen.CurrentScopeVariable, gen.CurrentRfcVariable, gen.CurrentSelfVariable, Ast.Lambda( BlockDispatcher.GetDelegateType(parameterCount, attributes), body, gen.EncodeMethodName(gen.CurrentMethod.MethodName, Location), new ReadOnlyCollection <MSA.ParameterExpression>(parameters) ), Ast.Constant(parameterCount), Ast.Constant(attributes) )); }
public static Proc /*!*/ Create(RubyContext /*!*/ context, Delegate /*!*/ clrMethod, object self, int parameterCount) { // scope is used to get to the execution context: return(new Proc(ProcKind.Block, self, context.EmptyScope, BlockDispatcher.Create(clrMethod, parameterCount, BlockSignatureAttributes.None))); }