TypeSymbol EmitGetCurrentHelper(CodeGenerator cg) { var getter = _currentValue ?? _current; Debug.Assert(getter != null); var t = VariableReferenceExtensions.EmitLoadValue(cg, getter, _enumeratorLoc); if (t.Is_PhpValue()) { if (_aliasedValues) // current() may get PhpAlias wrapped in PhpValue, make it PhpAlias again so it is handled properly { // .EnsureAlias() cg.EmitPhpValueAddr(); t = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureAlias_PhpValueRef); } else { // .GetValue() cg.EmitPhpValueAddr(); t = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.GetValue); } } if (_aliasedValueLoc != null && (TypeSymbol)_aliasedValueLoc.Type == t) { // <_aliasedValue> = <STACK> cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(_aliasedValueLoc); } return(t); }
internal void EmitIteratorNext(CodeGenerator cg) { if (_iterator_next != null) { // Template: Iterator.next() cg.EmitPop(VariableReferenceExtensions.EmitLoadValue(cg, _iterator_next, _enumeratorLoc)); } }
internal void EmitGetCurrent(CodeGenerator cg, BoundReferenceExpression valueVar, BoundReferenceExpression keyVar) { Debug.Assert(_enumeratorLoc.IsValid); // NOTE: PHP writes first to {valueVar} then to {keyVar} if (_currentValue != null && _currentKey != null) { // PhpArray enumerator or Iterator cg.EmitSequencePoint(valueVar.PhpSyntax); valueVar.BindPlace(cg).EmitStore(cg, () => EmitGetCurrentHelper(cg), valueVar.TargetAccess()); if (keyVar != null) { cg.EmitSequencePoint(keyVar.PhpSyntax); keyVar.BindPlace(cg).EmitStore(cg, () => VariableReferenceExtensions.EmitLoadValue(cg, _currentKey, _enumeratorLoc), keyVar.TargetAccess()); } } else { if (_current == null) { throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(_current); } var valuetype = _current.ReturnType; // ValueTuple<T1, T2> (Item1, Item2) // KeyValuePair<TKey, TValue> (Key, Value) if (IsAPairValue(valuetype, out var skey, out var svalue)) { // tmp = current; var tmp = cg.GetTemporaryLocal(valuetype); VariableReferenceExtensions.EmitLoadValue(cg, _current, _enumeratorLoc); cg.Builder.EmitLocalStore(tmp); var tmploc = new LocalPlace(tmp); var keyplace = skey switch { FieldSymbol fld => (IPlace) new FieldPlace(tmploc, fld, cg.Module), PropertySymbol prop => new PropertyPlace(tmploc, prop, cg.Module), _ => throw Roslyn.Utilities.ExceptionUtilities.Unreachable, }; var valueplace = svalue switch { FieldSymbol fld => (IPlace) new FieldPlace(tmploc, fld, cg.Module), PropertySymbol prop => new PropertyPlace(tmploc, prop, cg.Module), _ => throw Roslyn.Utilities.ExceptionUtilities.Unreachable, }; // value = tmp.Item2; cg.EmitSequencePoint(valueVar.PhpSyntax); valueVar.BindPlace(cg).EmitStore(cg, valueplace, valueVar.TargetAccess()); // key = tmp.Item1; if (keyVar != null) { cg.EmitSequencePoint(keyVar.PhpSyntax); keyVar.BindPlace(cg).EmitStore(cg, keyplace, keyVar.TargetAccess()); } // cg.ReturnTemporaryLocal(tmp); }
internal void EmitGetCurrent(CodeGenerator cg, BoundReferenceExpression valueVar, BoundReferenceExpression keyVar) { Debug.Assert(_enumeratorLoc.IsValid); // NOTE: PHP writes first to {valueVar} then to {keyVar} if (_currentValue != null && _currentKey != null) { // PhpArray enumerator or Iterator cg.EmitSequencePoint(valueVar.PhpSyntax); valueVar.BindPlace(cg).EmitStore(cg, () => EmitGetCurrentHelper(cg), valueVar.Access); if (keyVar != null) { cg.EmitSequencePoint(keyVar.PhpSyntax); keyVar.BindPlace(cg).EmitStore(cg, () => VariableReferenceExtensions.EmitLoadValue(cg, _currentKey, _enumeratorLoc), keyVar.Access); } } else { Debug.Assert(_current != null); var valuetype = _current.ReturnType; // ValueTuple (key, value) // TODO: KeyValuePair<key, value> // the same if (valuetype.Name == "ValueTuple" && valuetype.IsValueType && ((NamedTypeSymbol)valuetype).Arity == 2) { // tmp = current; var tmp = cg.GetTemporaryLocal(valuetype); VariableReferenceExtensions.EmitLoadValue(cg, _current, _enumeratorLoc); cg.Builder.EmitLocalStore(tmp); // TODO: ValueTuple Helper var item1 = valuetype.GetMembers("Item1").Single() as FieldSymbol; var item2 = valuetype.GetMembers("Item2").Single() as FieldSymbol; var item1place = new FieldPlace(new LocalPlace(tmp), item1, cg.Module); var item2place = new FieldPlace(new LocalPlace(tmp), item2, cg.Module); // value = tmp.Item2; cg.EmitSequencePoint(valueVar.PhpSyntax); valueVar.BindPlace(cg).EmitStore(cg, item2place, valueVar.Access); // key = tmp.Item1; if (keyVar != null) { cg.EmitSequencePoint(keyVar.PhpSyntax); keyVar.BindPlace(cg).EmitStore(cg, item1place, keyVar.Access); } // cg.ReturnTemporaryLocal(tmp); } // just a value else { cg.EmitSequencePoint(valueVar.PhpSyntax); valueVar.BindPlace(cg).EmitStore(cg, () => EmitGetCurrentHelper(cg), valueVar.Access); if (keyVar != null) { throw new InvalidOperationException(); } } } }