Example #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);
        }
        TypeSymbol EmitLoadSourceValue(CodeGenerator cg)
        {
            if (_traitmember is FieldSymbol f)
            {
                TypeSymbol instanceType;
                var        phpf = (IPhpPropertySymbol)f;
                if (phpf.FieldKind == PhpPropertyKind.InstanceField)
                {
                    // Template: LOAD <>trait_T
                    Debug.Assert(_traitInstanceField != null);
                    instanceType = _traitInstanceField.EmitLoad(cg, cg.ThisPlaceOpt);
                }
                else
                {
                    instanceType = null;
                }

                //
                VariableReferenceExtensions.EmitReceiver(cg, f, instanceType);

                // LOAD {FIELD}
                cg.Builder.EmitOpCode(ILOpCode.Ldfld);
                cg.EmitSymbolToken(f, null);
                return(f.Type);
            }

            throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(_traitmember);
        }
Example #3
0
 internal void EmitIteratorNext(CodeGenerator cg)
 {
     if (_iterator_next != null)
     {
         // Template: Iterator.next()
         cg.EmitPop(VariableReferenceExtensions.EmitLoadValue(cg, _iterator_next, _enumeratorLoc));
     }
 }
Example #4
0
        override protected void EmitHolder(ILBuilder il)
        {
            Debug.Assert(_field.IsStatic == (_holder == null));

            if (!_field.IsStatic)
            {
                VariableReferenceExtensions.EmitReceiver(il, _holder);
            }
        }
Example #5
0
        TypeSymbol EmitReceiver(ILBuilder il)
        {
            var lhs = VariableReferenceExtensions.EmitReceiver(il, _holder);

            if (_property.IsStatic)
            {
                if (lhs.Stack != null && !lhs.Stack.IsVoid())
                {
                    il.EmitOpCode(ILOpCode.Pop);
                }
                return(null);
            }

            return(lhs.Stack);
        }
Example #6
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();
                    }
                }
            }
        }