private TransformWrite ( |
||
gen | ||
rightValue | System.Linq.Expressions | |
return |
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { // TODO: // {target}[{arguments}] op= rhs // we need to evaluate {arguments} once: http://ironruby.codeplex.com/workitem/4525 // first, read target into a temp: MSA.Expression transformedLeftTarget = _left.TransformTargetRead(gen); MSA.Expression leftTargetTemp; if (transformedLeftTarget != null) { leftTargetTemp = gen.CurrentScope.DefineHiddenVariable(String.Empty, transformedLeftTarget.Type); } else { leftTargetTemp = null; } MSA.Expression transformedRight = _right.TransformRead(gen); // lhs &&= rhs --> lhs && (lhs = rhs) // lhs ||= rhs --> lhs || (lhs = rhs) if (Operation == Symbols.And || Operation == Symbols.Or) { MSA.Expression transformedLeftRead = _left.TransformRead(gen, (transformedLeftTarget != null) ? Ast.Assign(leftTargetTemp, transformedLeftTarget) : null, true // tryRead ); MSA.Expression transformedWrite = _left.TransformWrite(gen, leftTargetTemp, transformedRight); if (Operation == Symbols.And) { return(AndExpression.TransformRead(gen, transformedLeftRead, transformedWrite)); } else { return(OrExpression.TransformRead(gen, transformedLeftRead, transformedWrite)); } } else { // lhs op= rhs --> lhs = lhs op rhs if (Operation != null) { MSA.Expression transformedLeftRead = _left.TransformRead(gen, leftTargetTemp, false); transformedRight = MethodCall.TransformRead(this, gen, false, Operation, transformedLeftRead, null, null, transformedRight, null); } // transform lhs write assigning lhs-target temp: return(_left.TransformWrite(gen, (transformedLeftTarget != null) ? Ast.Assign(leftTargetTemp, transformedLeftTarget) : null, transformedRight )); } }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // internal IfStatementTest /*!*/ Transform(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Length != 0) { var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context)); if (_types.Length == 1) { condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen), _types[0] is SplattedArgument); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Length]; var exprs = new BlockBuilder(); for (int i = 0; i < _types.Length; i++) { var t = _types[i].TransformRead(gen); var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, t.Type); temps[i] = tmp; exprs.Add(Ast.Assign(tmp, t)); } // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) condition = MakeCompareException(gen, comparisonSiteStorage, temps[0], _types[0] is SplattedArgument); for (int i = 1; i < _types.Length; i++) { condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i], _types[i] is SplattedArgument)); } // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs.Add(condition); condition = exprs; } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable); } return(AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) )); }
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); }
// // rescue stmts ... if (StandardError === $!) { stmts; } // rescue <types> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; } // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; } // internal IfStatementTest /*!*/ Transform(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression condition; if (_types.Count != 0 || _splatType != null) { if (_types.Count == 0) { // splat only: condition = MakeCompareSplattedExceptions(gen, TransformSplatType(gen)); } else if (_types.Count == 1 && _splatType == null) { condition = MakeCompareException(gen, _types[0].TransformRead(gen)); } else { // forall{i}: <temps[i]> = evaluate type[i] var temps = new MSA.Expression[_types.Count + (_splatType != null ? 1 : 0)]; var exprs = new MSA.Expression[temps.Length + 1]; int i = 0; while (i < _types.Count) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, _types[i].TransformRead(gen)); i++; } if (_splatType != null) { var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object)); temps[i] = tmp; exprs[i] = Ast.Assign(tmp, TransformSplatType(gen)); i++; } Debug.Assert(i == temps.Length); // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>) i = 0; condition = MakeCompareException(gen, temps[i++]); while (i < _types.Count) { condition = Ast.OrElse(condition, MakeCompareException(gen, temps[i++])); } if (_splatType != null) { condition = Ast.OrElse(condition, MakeCompareSplattedExceptions(gen, temps[i++])); } Debug.Assert(i == temps.Length); // (temps[0] = type[0], ..., temps[n] == type[n], condition) exprs[exprs.Length - 1] = condition; condition = AstFactory.Block(exprs); } } else { condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable); } return(AstUtils.IfCondition(condition, gen.TransformStatements( // <lvalue> = e; (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null, // body: _statements, resultOperation ) )); }