示例#1
0
        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);
        }
示例#2
0
 internal void EmitIteratorNext(CodeGenerator cg)
 {
     if (_iterator_next != null)
     {
         // Template: Iterator.next()
         cg.EmitPop(VariableReferenceExtensions.EmitLoadValue(cg, _iterator_next, _enumeratorLoc));
     }
 }
示例#3
0
        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();
                    }
                }
            }
        }