public TypeSymbol EmitLoad(CodeGenerator cg) { Debug.Assert(_access.IsRead); var type = _place.TypeOpt; // Ensure Object ($x->.. =) if (_access.EnsureObject) { if (type == cg.CoreTypes.PhpAlias) { _place.EmitLoad(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureObject) .Expect(SpecialType.System_Object); } else if (type == cg.CoreTypes.PhpValue) { _place.EmitLoadAddress(cg.Builder); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureObject) .Expect(SpecialType.System_Object); if (_thint.IsSingleType && cg.IsClassOnly(_thint)) { var tref = cg.Routine.TypeRefContext.GetTypes(_thint)[0]; var clrtype = (TypeSymbol)cg.DeclaringCompilation.GetTypeByMetadataName(tref.QualifiedName.ClrName()); if (clrtype != null && !clrtype.IsErrorType() && clrtype != cg.CoreTypes.Object) { cg.EmitCastClass(clrtype); return clrtype; } } return cg.CoreTypes.Object; } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { // PhpArray -> stdClass // PhpString -> stdClass (?) // otherwise keep the instance on stack throw new NotImplementedException(); } else { if (type.IsReferenceType) { if (type == cg.CoreTypes.Object) { // Operators.EnsureObject(ref <place>) _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureObject_ObjectRef) .Expect(SpecialType.System_Object); } else { // <place> return _place.EmitLoad(cg.Builder); } } else { // return new stdClass(ctx) throw new NotImplementedException(); } } } // Ensure Array ($x[] =) else if (_access.EnsureArray) { if (type == cg.CoreTypes.PhpAlias) { // <place>.EnsureArray() _place.EmitLoad(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type == cg.CoreTypes.PhpValue) { if (cg.IsArrayOnly(_thint)) { // uses typehint and accesses .Array directly if possible // <place>.Array _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.get_Array) .Expect(cg.CoreTypes.PhpArray); } else { // <place>.EnsureArray() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { // Operators.EnsureArray(ref <place>) _place.EmitLoadAddress(cg.Builder); if (type == cg.CoreTypes.PhpArray) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_PhpArrayRef) .Expect(cg.CoreTypes.PhpArray); } else { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_IPhpArrayRef) .Expect(cg.CoreTypes.IPhpArray); } } throw new NotImplementedException("EnsureArray(" + type.Name + ")"); } // Ensure Alias (&$x) else if (_access.IsReadRef) { if (type == cg.CoreTypes.PhpAlias) { // TODO: <place>.AddRef() return _place.EmitLoad(cg.Builder); } else if (type == cg.CoreTypes.PhpValue) { // return <place>.EnsureAlias() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias) .Expect(cg.CoreTypes.PhpAlias); } else if (type == cg.CoreTypes.PhpNumber) { throw new NotImplementedException(); } else { Debug.Assert(false, "value cannot be aliased"); // new PhpAlias((PhpValue)<place>, 1) cg.EmitConvertToPhpValue(_place.EmitLoad(cg.Builder), 0); return cg.Emit_PhpValue_MakeAlias(); } } // Read Value & Dereference eventually else { if (type == cg.CoreTypes.PhpAlias) { _place.EmitLoad(cg.Builder); if (_access.TargetType == cg.CoreTypes.PhpArray) { // <place>.Value.ToArray() cg.Builder.EmitOpCode(ILOpCode.Ldflda); cg.EmitSymbolToken(cg.CoreMethods.PhpAlias.Value, null); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray) .Expect(cg.CoreTypes.PhpArray); } return cg.Emit_PhpAlias_GetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (_access.TargetType == cg.CoreTypes.PhpArray) { // <place>.ToArray() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray) .Expect(cg.CoreTypes.PhpArray); } // TODO: dereference if applicable (=> PhpValue.Alias.Value) return _place.EmitLoad(cg.Builder); } else { return _place.EmitLoad(cg.Builder); } } }