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); } } }
public TypeSymbol EmitLoad(CodeGenerator cg) { Debug.Assert(Access.IsRead); var type = Field.Type; // Ensure Object (..->Field->.. =) if (Access.EnsureObject) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); // PhpAlias return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureObject) .Expect(SpecialType.System_Object); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureObject) .Expect(SpecialType.System_Object); } else { if (type.IsReferenceType) { // TODO: ensure it is not null EmitOpCode_Load(cg); return type; } else { // return new stdClass(ctx) throw new NotImplementedException(); } } } // Ensure Array (xxx->Field[] =) else if (Access.EnsureArray) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { EmitOpCode_LoadAddress(cg); // ensure value is not null 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(); } // Ensure Alias (&...->Field) else if (Access.IsReadRef) { if (type == cg.CoreTypes.PhpAlias) { // TODO: <place>.AddRef() EmitOpCode_Load(cg); return type; } else if (type == cg.CoreTypes.PhpValue) { // return <place>.EnsureAlias() EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias) .Expect(cg.CoreTypes.PhpAlias); } else { Debug.Assert(false, "value cannot be aliased"); // new PhpAlias((PhpValue)<place>, 1) EmitOpCode_Load(cg); cg.EmitConvertToPhpValue(type, 0); return cg.Emit_PhpValue_MakeAlias(); } } // Read (...->Field) & Dereference eventually else { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { default: if (Access.TargetType == cg.CoreTypes.PhpArray) { // <PhpAlias>.Value.ToArray() cg.Builder.EmitOpCode(ILOpCode.Ldflda); cg.EmitSymbolToken(cg.CoreMethods.PhpAlias.Value, null); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } return cg.Emit_PhpAlias_GetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { case SpecialType.System_Double: EmitOpCode_LoadAddress(cg); // &PhpValue.ToDouble() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToDouble); case SpecialType.System_Int64: EmitOpCode_LoadAddress(cg); // &PhpValue.ToLong() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToLong); case SpecialType.System_Boolean: EmitOpCode_LoadAddress(cg); // &PhpValue.ToBoolean() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToBoolean); case SpecialType.System_String: EmitOpCode_LoadAddress(cg); // &PhpValue.ToString(ctx) cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToString_Context); case SpecialType.System_Object: EmitOpCode_LoadAddress(cg); // &PhpValue.ToClass() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToClass); default: if (Access.TargetType == cg.CoreTypes.PhpArray) { EmitOpCode_LoadAddress(cg); // &PhpValue.ToArray() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } // TODO: dereference if applicable (=> PhpValue.Alias.Value) EmitOpCode_Load(cg); return type; } else { EmitOpCode_Load(cg); return type; } } }