public static MSA.Expression /*!*/ MakeArrayOpCall(IList <MSA.Expression> /*!*/ args) { Assert.NotNull(args); switch (args.Count) { case 0: return(Methods.MakeArray0.OpCall()); case 1: return(Methods.MakeArray1.OpCall(AstUtils.Box(args[0]))); case 2: return(Methods.MakeArray2.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1]))); case 3: return(Methods.MakeArray3.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2]))); case 4: return(Methods.MakeArray4.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2]), AstUtils.Box(args[3]))); case 5: return(Methods.MakeArray5.OpCall(new AstExpressions { AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2]), AstUtils.Box(args[3]), AstUtils.Box(args[4]) })); default: Debug.Assert(args.Count > Runtime.RubyOps.OptimizedOpCallParamCount); return(Methods.MakeArrayN.OpCall(AstUtils.NewArrayHelper(typeof(object), args))); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Methods.DefineMethod.OpCall( (_target != null) ? AstUtils.Box(_target.TransformRead(gen)) : AstUtils.Constant(null), gen.CurrentScopeVariable, Ast.Constant(new RubyMethodBody(this, gen.Document, gen.Encoding)) )); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Ast.Condition( _condition.TransformReadBoolean(gen, !_negateCondition), AstUtils.Box(_body.TransformRead(gen)), (_elseStatement != null) ? AstUtils.Box(_elseStatement.TransformRead(gen)) : (MSA.Expression)AstUtils.Constant(null) )); }
internal LoopFunc CreateDelegate() { var loop = Visit(_loop); var body = new List <Expression>(); var finallyClause = new List <Expression>(); foreach (var variable in _loopVariables) { LocalVariable local; if (!_outerVariables.TryGetValue(variable.Key, out local)) { local = _closureVariables[variable.Key]; } Expression elemRef = local.LoadFromArray(_frameDataVar, _frameClosureVar); if (local.InClosureOrBoxed) { var box = variable.Value.BoxStorage; Debug.Assert(box != null); body.Add(Expression.Assign(box, elemRef)); AddTemp(box); } else { // Always initialize the variable even if it is only written to. // If a write-only variable is actually not assigned during execution of the loop we will still write some value back. // This value must be the original value, which we assign at entry. body.Add(Expression.Assign(variable.Key, AstUtils.Convert(elemRef, variable.Key.Type))); if ((variable.Value.Access & ExpressionAccess.Write) != 0) { finallyClause.Add(Expression.Assign(elemRef, AstUtils.Box(variable.Key))); } AddTemp(variable.Key); } } if (finallyClause.Count > 0) { body.Add(Expression.TryFinally(loop, Expression.Block(finallyClause))); } else { body.Add(loop); } body.Add(Expression.Label(_returnLabel, Expression.Constant(_loopEndInstructionIndex - _loopStartInstructionIndex))); var lambda = Expression.Lambda <LoopFunc>( _temps != null ? Expression.Block(_temps, body) : Expression.Block(body), new[] { _frameDataVar, _frameClosureVar, _frameVar } ); return(lambda.Compile()); }
internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen) { // MRI doesn't evaluate the arguments MSA.Expression result = AstUtils.LightDynamic( RubyCallAction.Make(gen.Context, _methodName, RubyCallSignature.IsDefined(_target == null)), typeof(bool), gen.CurrentScopeVariable, (_target != null) ? AstUtils.Box(_target.TransformRead(gen)) : gen.CurrentSelfVariable ); return((_target != null) ? gen.TryCatchAny(result, AstFactory.False) : result); }
internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, MSA.Expression /*!*/ left, MSA.Expression /*!*/ right) { MSA.ParameterExpression temp; MSA.Expression result = AstUtils.CoalesceFalse( AstUtils.Box(left), AstUtils.Box(right), Methods.IsTrue, out temp ); gen.CurrentScope.AddHidden(temp); return(result); }
public static RuleGenerator /*!*/ GetException() { return(new RuleGenerator((metaBuilder, args, name) => { Debug.Assert(args.Target is Exception); // 1 optional parameter (exceptionArg): var argsBuilder = new ArgsBuilder(0, 0, 1, false); argsBuilder.AddCallArguments(metaBuilder, args); if (!metaBuilder.Error) { if (argsBuilder.ExplicitArgumentCount == 0) { metaBuilder.Result = args.TargetExpression; } else { RubyClass cls = args.RubyContext.GetClassOf(args.Target); var classExpression = AstUtils.Constant(cls); args.SetTarget(classExpression, cls); ParameterExpression messageVariable = null; // RubyOps.MarkException(new <exception-type>(GetClrMessage(<class>, #message = <message>))) if (cls.BuildAllocatorCall(metaBuilder, args, () => Ast.Call(null, new Func <RubyClass, object, string>(GetClrMessage).Method, classExpression, Ast.Assign(messageVariable = metaBuilder.GetTemporary(typeof(object), "#message"), AstUtils.Box(argsBuilder[0])) ) )) { // ReinitializeException(<result>, #message) metaBuilder.Result = Ast.Call(null, new Func <RubyContext, Exception, object, Exception>(ReinitializeException).Method, AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), metaBuilder.Result, messageVariable ?? AstUtils.Box(argsBuilder[0]) ); } else { metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass)))); } } } })); }
internal virtual MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { MSA.Expression transformedQualifier; MSA.Expression name = QualifiedName.TransformName(gen); switch (QualifiedName.TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.DefineGlobalModule.OpCall(gen.CurrentScopeVariable, name)); case StaticScopeKind.EnclosingModule: return(Methods.DefineNestedModule.OpCall(gen.CurrentScopeVariable, name)); case StaticScopeKind.Explicit: return(Methods.DefineModule.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedQualifier), name)); } throw Assert.Unreachable; }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { MSA.Expression transformedQualifier; MSA.Expression name = QualifiedName.TransformName(gen); MSA.Expression transformedSuper = (_superClass != null) ? AstUtils.Box(_superClass.TransformRead(gen)) : AstUtils.Constant(null); switch (QualifiedName.TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.DefineGlobalClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.EnclosingModule: return(Methods.DefineNestedClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.Explicit: return(Methods.DefineClass.OpCall(gen.CurrentScopeVariable, transformedQualifier, name, transformedSuper)); } throw Assert.Unreachable; }
// return the target object on error: protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { metaBuilder.Result = Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList)); }
// return the target object on error: protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { return(Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList))); }
// return the target object on error: protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { metaBuilder.Result = AstUtils.Box(args.TargetExpression); }
// return the target object on error: protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType) { return(AstUtils.Box(args.TargetExpression)); }
protected override Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result) { return(AstUtils.LightDynamic(ConvertToStrAction.Make(args.RubyContext), AstUtils.Box(result))); }
protected virtual Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result) { var validator = ConversionResultValidator; return((validator != null) ? validator.OpCall(targetClassNameConstant, AstUtils.Box(result)) : result); }
private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue) { // We need to distinguish various special cases here. // Each of the bool variables defined below is true iff the corresponding special form of LHS/RHS occurs. // These flags drive the DLR AST being produced by this method. // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment". // L(0,-) not applicable Debug.Assert(!(_leftValues.Count == 0 && _unsplattedValue == null)); // L(1,-)? bool leftOneNone = _leftValues.Count == 1 && _unsplattedValue == null; // L(0,*)? bool leftNoneSplat = _leftValues.Count == 0 && _unsplattedValue != null; // R(0,*)? bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null; // R(1,-)? bool rightOneNone = rightValues.Count == 1 && splattedValue == null; // R(1,*)? bool rightOneSplat = rightValues.Count == 1 && splattedValue != null; // R(0,-) not applicable Debug.Assert(!(rightValues.Count == 0 && splattedValue == null)); MSA.Expression resultExpression; if (leftOneNone) { // L(1,-): // recurse right away (X) = RHS is equivalent to X = RHS: CompoundLeftValue compound = _leftValues[0] as CompoundLeftValue; if (compound != null) { return(compound.TransformWrite(gen, rightValues, splattedValue)); } if (rightOneSplat) { // R(1,*) resultExpression = Methods.SplatPair.OpCall( AstUtils.Box(rightValues[0]), AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue) ); } else { // case 1: R(1,-) // case 2: R(0,*) // case 3: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, true /* Splat */); } return(_leftValues[0].TransformWrite(gen, resultExpression)); } bool optimizeReads = true; if (rightOneNone && !leftNoneSplat) { // R(1,-) && !L(0,*) resultExpression = Methods.Unsplat.OpCall( AstUtils.LightDynamic(ConvertToArraySplatAction.Make(gen.Context), rightValues[0]) ); optimizeReads = false; } else { // case 1: R(0,*) = L // case 2: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */); optimizeReads = !rightNoneSplat; } var writes = new AstBlock(); MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(IList)); writes.Add(Ast.Assign(result, resultExpression)); MethodInfo itemGetter = Methods.IList_get_Item; for (int i = 0; i < _leftValues.Count; i++) { MSA.Expression rvalue; if (optimizeReads) { if (i < rightValues.Count) { // unchecked get item: rvalue = Ast.Call(result, itemGetter, AstUtils.Constant(i)); } else if (splattedValue != null) { // checked get item: rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i)); } else { // missing item: rvalue = AstUtils.Constant(null); } } else { rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i)); } writes.Add(_leftValues[i].TransformWrite(gen, rvalue)); } // unsplatting the rest of rhs values into an array: if (_unsplattedValue != null) { // copies the rest of resulting array to the *LHS; // the resulting array contains splatted *RHS - no need for additional appending: MSA.Expression array = Methods.GetArraySuffix.OpCall(result, AstUtils.Constant(_leftValues.Count)); // assign the array (possibly empty) to *LHS: writes.Add(_unsplattedValue.TransformWrite(gen, array)); } writes.Add(result); return(writes); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { return(Methods.SetGlobalVariable.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, TransformName(gen))); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Return internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(gen.Return(Methods.EvalReturn.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)))); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockReturn.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue)))); } // method: return(gen.Return(transformedReturnValue)); }
protected override Expression VisitGoto(GotoExpression node) { BranchLabel label; var target = node.Target; var value = Visit(node.Value); // TODO: Is it possible for an inner reducible node of the loop to rely on nodes produced by reducing outer reducible nodes? // Unknown label => must be within the loop: if (!_labelMapping.TryGetValue(target, out label)) { return(node.Update(target, value)); } // Known label within the loop: if (label.TargetIndex >= _loopStartInstructionIndex && label.TargetIndex < _loopEndInstructionIndex) { return(node.Update(target, value)); } return(Expression.Return(_returnLabel, (value != null) ? Expression.Call(_frameVar, InterpretedFrame.GotoMethod, Expression.Constant(label.LabelIndex), AstUtils.Box(value)) : Expression.Call(_frameVar, InterpretedFrame.VoidGotoMethod, Expression.Constant(label.LabelIndex)), node.Type )); }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { return(Methods.DefineSingletonClass.OpCall(gen.CurrentScopeVariable, AstUtils.Box(_singleton.TransformRead(gen)))); }