// when [<expr>, ...] *<array> // // generates this code: // // IEnumerator<object>/*!*/ enumVar = RubyOps.Unsplat(<array>).GetEnumerator(); // bool result = false; // while (enumVar.MoveNext()) { // if (<MakeTest>(enumVar.Current)) { // result = true; // break; // } // } private static MSA.Expression /*!*/ MakeArrayTest(AstGenerator /*!*/ gen, MSA.Expression /*!*/ array, MSA.Expression value) { MSA.Expression enumVariable = gen.CurrentScope.DefineHiddenVariable("#case-enumerator", typeof(IEnumerator <object>)); MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#case-compare-result", typeof(bool)); MSA.LabelTarget label = Ast.Label(); return(AstFactory.Block( Ast.Assign(enumVariable, Ast.Call( Methods.Unsplat.OpCall(AstFactory.Box(array)), Methods.IEnumerable_Of_Object_GetEnumerator )), Ast.Assign(resultVariable, Ast.Constant(false)), AstUtils.While( Ast.Call(enumVariable, Methods.IEnumerator_MoveNext), AstUtils.If( MakeTest(gen, Ast.Call(enumVariable, Methods.IEnumerator_get_Current), value), Ast.Block( Ast.Assign(resultVariable, Ast.Constant(true)), Ast.Break(label), Ast.Empty() ) ), null, label, null ), resultVariable )); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Next internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( transformedReturnValue, // evaluate for side-effects Ast.Continue(gen.CurrentLoop.ContinueLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(transformedReturnValue)); } // method: return(Methods.MethodNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Break internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalBreak.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( Ast.Assign( gen.CurrentLoop.ResultVariable, Ast.Convert(transformedReturnValue, gen.CurrentLoop.ResultVariable.Type) ), Ast.Break(gen.CurrentLoop.BreakLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstFactory.Box(transformedReturnValue)))); } // primary frame: return(Methods.MethodBreak.OpCall(AstFactory.Box(transformedReturnValue))); }
internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, List <MSA.Expression> /*!*/ rightValues, MSA.Expression splattedValue, bool doSplat) { Assert.NotNull(gen, rightValues); MSA.Expression result; // We need to distinguish various special cases here. // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment". // R(0,*)? bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null; // R(1,-)? bool rightOneNone = rightValues.Count == 1 && splattedValue == null; if (rightNoneSplat) { result = (doSplat ? Methods.Splat : Methods.Unsplat).OpCall(AstFactory.Box(splattedValue)); } else if (rightOneNone && doSplat) { result = rightValues[0]; } else { result = Methods.MakeArrayOpCall(rightValues); if (splattedValue != null) { result = Methods.SplatAppend.OpCall(result, AstFactory.Box(splattedValue)); } } return(result); }
private MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, int /*!*/ opKind) { MSA.Expression transformedName = TransformName(gen); MSA.Expression transformedQualifier; switch (TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return((opKind == OpGet ? Methods.GetGlobalConstant : Methods.IsDefinedGlobalConstant). OpCall(gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.EnclosingModule: return((opKind == OpGet ? Methods.GetUnqualifiedConstant : Methods.IsDefinedUnqualifiedConstant). OpCall(gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.Explicit: if (opKind == OpGet) { return(Methods.GetQualifiedConstant.OpCall(AstFactory.Box(transformedQualifier), gen.CurrentScopeVariable, transformedName)); } else { return(gen.TryCatchAny( Methods.IsDefinedQualifiedConstant.OpCall(AstFactory.Box(transformedQualifier), gen.CurrentScopeVariable, transformedName), Ast.Constant(false) )); } } throw Assert.Unreachable; }
/// <code> /// End-exclusive range: /// if state /// state = IsFalse({end}) /// true /// else /// state = IsTrue({begin}) /// end /// /// End-inclusive range: /// if state || IsTrue({begin}) /// state = IsFalse({end}) /// true /// else /// false /// end /// </code> private MSA.Expression /*!*/ TransformReadCondition(AstGenerator /*!*/ gen) { // Define state variable in the inner most method scope. var stateVariable = gen.CurrentMethod.Builder.DefineHiddenVariable("#in_range", typeof(bool)); var begin = AstFactory.Box(_begin.TransformRead(gen)); var end = AstFactory.Box(_end.TransformRead(gen)); if (_isExclusive) { return(Ast.Condition( stateVariable, Ast.Block(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.Constant(true)), Ast.Assign(stateVariable, Methods.IsTrue.OpCall(begin)) )); } else { return(Ast.Condition( Ast.OrElse(stateVariable, Methods.IsTrue.OpCall(begin)), Ast.Block(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.Constant(true)), Ast.Constant(false) )); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(AstFactory.Condition( Methods.IsFalse.OpCall(AstFactory.Box(_condition.TransformRead(gen))), gen.TransformStatementsToExpression(_statements), gen.TransformStatementsToExpression(_elseClause != null ? _elseClause.Statements : null) )); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Ast.Condition( TransformCondition(gen), AstFactory.Box(_body.TransformRead(gen)), (_elseStatement != null) ? AstFactory.Box(_elseStatement.TransformRead(gen)) : (MSA.Expression)Ast.Constant(null) )); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { if (gen.CompilerOptions.IsEval || gen.GetCurrentNonSingletonModule() != null) { return(Methods.SetClassVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); } else { return(Methods.SetObjectClassVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { if (_isCondition) { return(TransformReadCondition(gen)); } else { return((_isExclusive ? Methods.CreateExclusiveRange : Methods.CreateInclusiveRange). OpCall(gen.CurrentScopeVariable, AstFactory.Box(_begin.TransformRead(gen)), AstFactory.Box(_end.TransformRead(gen)))); } }
internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, MSA.Expression /*!*/ left, MSA.Expression /*!*/ right) { MSA.ParameterExpression temp; MSA.Expression result = AstUtils.CoalesceTrue( AstFactory.Box(left), AstFactory.Box(right), Methods.IsTrue, out temp ); gen.CurrentScope.AddHidden(temp); return(result); }
internal MSA.Expression /*!*/ AddReturnTarget(MSA.Expression /*!*/ expression) { if (expression.Type != typeof(object)) { expression = AstFactory.Box(expression); } if (_returnLabel != null) { expression = Ast.Label(_returnLabel, expression); _returnLabel = null; } return(expression); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { if (_transformed != null) { // static lookup: return(Ast.Assign(_transformed, AstUtils.Convert(rightValue, _transformed.Type))); } else { // dynamic lookup: return(Methods.SetLocalVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression transformedCondition = AstFactory.Box(_condition.TransformRead(gen)); MSA.Expression tmpVariable = gen.CurrentScope.DefineHiddenVariable("#tmp_cond", transformedCondition.Type); return(AstFactory.Block( Ast.Assign(tmpVariable, transformedCondition), AstUtils.IfThen( (_negateCondition ? AstFactory.IsFalse(tmpVariable) : AstFactory.IsTrue(tmpVariable)), _jumpStatement.Transform(gen) ), (_value != null) ? _value.TransformRead(gen) : tmpVariable )); }
internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen) { if (_target != null) { return(gen.TryCatchAny( Methods.IsDefinedMethod.OpCall( AstFactory.Box(_target.TransformRead(gen)), gen.CurrentScopeVariable, AstUtils.Constant(_methodName) ), Ast.Constant(false) )); } else { return(Methods.IsDefinedMethod.OpCall(gen.CurrentSelfVariable, gen.CurrentScopeVariable, AstUtils.Constant(_methodName))); } }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { MSA.Expression transformedName = TransformName(gen); MSA.Expression transformedQualifier; switch (TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.SetGlobalConstant.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.EnclosingModule: return(Methods.SetUnqualifiedConstant.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.Explicit: return(Methods.SetQualifiedConstant.OpCall(AstFactory.Box(rightValue), transformedQualifier, gen.CurrentScopeVariable, transformedName)); } throw Assert.Unreachable; }
// 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.CurrentRfcVariable, AstFactory.Box(transformedReturnValue)))); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockReturn.OpCall(gen.CurrentBlock.BfcVariable, AstFactory.Box(transformedReturnValue)))); } // method: return(gen.Return(transformedReturnValue)); }
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, AstFactory.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) ? AstFactory.Box(_superClass.TransformRead(gen)) : Ast.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; }
internal static MSA.Expression /*!*/ YieldExpression( IList <MSA.Expression> /*!*/ arguments, MSA.Expression splattedArgument, MSA.Expression rhsArgument, MSA.Expression /*!*/ bfcVariable, MSA.Expression /*!*/ selfArgument) { Assert.NotNull(arguments, bfcVariable, selfArgument); bool hasArgumentArray; var opMethod = Methods.Yield(arguments.Count, splattedArgument != null, rhsArgument != null, out hasArgumentArray); var args = new List <MSA.Expression>(); foreach (var arg in arguments) { args.Add(AstFactory.Box(arg)); } if (hasArgumentArray) { args = CollectionUtils.MakeList <MSA.Expression>(Ast.NewArrayInit(typeof(object), args)); } if (splattedArgument != null) { args.Add(AstFactory.Box(splattedArgument)); } if (rhsArgument != null) { args.Add(AstFactory.Box(rhsArgument)); } args.Add(AstFactory.Box(selfArgument)); args.Add(bfcVariable); return(Ast.Call(opMethod, args.ToArray())); }
internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.LabelTarget label = Ast.Label(); return(AstFactory.Block( Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), AstFactory.Infinite(label, null, (!isBlockDefinition) ? (MSA.Expression)Ast.Empty() : (MSA.Expression)Methods.InitializeBlock.OpCall(blockArgVariable), AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder, Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), // if result != RetrySingleton then break end AstUtils.Unless(Methods.IsRetrySingleton.OpCall(AstFactory.Box(resultVariable)), Ast.Break(label)), // if blockParam == #block then retry end (gen.CurrentMethod.IsTopLevelCode) ? Ast.Empty() : AstUtils.IfThen(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen)) ), resultVariable )); }
private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, List <MSA.Expression> /*!*/ 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(AstFactory.Box(rightValues[0]), AstFactory.Box(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(AstFactory.Box(rightValues[0])); optimizeReads = false; } else { // case 1: R(0,*) = L // case 2: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */); optimizeReads = !rightNoneSplat; } int writesCount = _leftValues.Count + (_unsplattedValue != null ? 1 : 0); if (writesCount == 0) { return(resultExpression); } var writes = new MSA.Expression[ 1 + // store result to a temp writesCount + 1 // load from the temp ]; int writeIndex = 0; MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(List <object>)); writes[writeIndex++] = Ast.Assign(result, resultExpression); MethodInfo itemGetter = typeof(List <object>).GetMethod("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, Ast.Constant(i)); } else if (splattedValue != null) { // checked get item: rvalue = Methods.GetArrayItem.OpCall(result, Ast.Constant(i)); } else { // missing item: rvalue = Ast.Constant(null); } } else { rvalue = Methods.GetArrayItem.OpCall(result, Ast.Constant(i)); } writes[writeIndex++] = _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, Ast.Constant(_leftValues.Count)); // assign the array (possibly empty) to *LHS: writes[writeIndex++] = _unsplattedValue.TransformWrite(gen, array); } writes[writeIndex++] = result; Debug.Assert(writes.Length == writeIndex); return(AstFactory.Block(writes)); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { return(Methods.SetInstanceVariable.OpCall(gen.CurrentSelfVariable, AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); }
private MSA.Expression /*!*/ MakeCompareException(AstGenerator /*!*/ gen, MSA.Expression /*!*/ expression) { return(Methods.CompareException.OpCall(gen.CurrentScopeVariable, AstFactory.Box(expression))); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { return(Methods.SetGlobalVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, TransformName(gen))); }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { return(Methods.DefineSingletonClass.OpCall(gen.CurrentScopeVariable, AstFactory.Box(_singleton.TransformRead(gen)))); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Methods.IsFalse.OpCall(AstFactory.Box(_expression.TransformRead(gen)))); }