public DMemberRef(DMember /*!*/ member, DType /*!*/ type) { Debug.Assert(member != null && type != null); this.member = member; this.type = type; }
/// <summary> /// Used by all subclasses except for <see cref="GlobalTypeDesc"/>. /// </summary> protected DMemberDesc(DTypeDesc /*!*/ declaringType, PhpMemberAttributes memberAttributes) { Debug.Assert(declaringType != null); this.declaringType = declaringType; this.memberAttributes = memberAttributes; this.member = null; // to be filled by DMember or at run-time (if applicable) }
protected DMemberDesc() { this.declaringType = (DTypeDesc)this; this.memberAttributes = PhpMemberAttributes.None; this.member = null; // to be filled by DMember (if applicable) }
public DMemberRef(DMember/*!*/ member, DType/*!*/ type) { Debug.Assert(member != null && type != null); this.member = member; this.type = type; }
//#endregion #region Name Resolving /// <summary> /// Resolves a function or type name using aliases and imported namespaces of the source unit. /// </summary> /// <param name="qualifiedName">Function qualified name to resolve. Doesn't resolve special names ("self", "parent").</param> /// <param name="kind">Declaration kind.</param> /// <param name="currentScope">Current scope.</param> /// <param name="alias"> /// <B>null</B>, if the function name is resolved immediately. /// Otherwise, if the <paramref name="qualifiedName"/> is simple and an alias exists, contains its qualified target. /// </param> /// <param name="errors">Error sink or <B>null</B> if errors shouldn't be reported.</param> /// <param name="position">Position where to report an error.</param> /// <param name="mustResolve">Whether name must be resolved if possible.</param> /// <returns> /// Resolved member, the unknown member, or <B>null</B> if error reporting is disabled (errors == null). /// </returns> /// <remarks> /// If the name is simple, is not resolved and has an alias then the run-time resolve should be run on the alias. /// If the name is simple, is not resolved and hasn't an alias, the run-time resolve should be run on the name /// within the naming context of the source unit (i.e. imported namespaces should be considered). /// If the name is fully qualified and is not resolved then then the run-time resolve should be run on the name itself. /// </remarks> private DMember ResolveName(QualifiedName qualifiedName, DeclarationKind kind, Scope currentScope, out QualifiedName?alias, ErrorSink errors, Position position, bool mustResolve) { string full_name = null; DMember result; alias = null; // try exact match: result = ResolveExactName(qualifiedName, ref full_name, kind, currentScope, mustResolve); if (result != null) { return(result); } /* // aliases are resolved in parse-time * // try explicit aliases: * if (qualifiedName.IsSimpleName) * { * QualifiedName alias_qualified_name; * * Dictionary<Name, QualifiedName> aliases = null; * switch (kind) * { * case DeclarationKind.Type: aliases = typeAliases; break; * case DeclarationKind.Function: aliases = functionAliases; break; * case DeclarationKind.Constant: aliases = constantAliases; break; * } * * // try alias: * if (aliases != null && aliases.TryGetValue(qualifiedName.Name, out alias_qualified_name)) * { * // alias exists // * * full_name = null; * result = ResolveExactName(alias_qualified_name, ref full_name, kind, currentScope, mustResolve); * if (result != null) * return result; * * alias = alias_qualified_name; * * switch (kind) * { * case DeclarationKind.Type: result = new UnknownType(full_name); break; * case DeclarationKind.Function: result = new UnknownFunction(full_name); break; * case DeclarationKind.Constant: result = new UnknownGlobalConstant(full_name); break; * } * * return result; * } * } */ // try imported namespaces: if (!qualifiedName.IsFullyQualifiedName && HasImportedNamespaces) { result = null; foreach (QualifiedName imported_ns in importedNamespaces) { QualifiedName combined_qualified_name = new QualifiedName(qualifiedName, imported_ns); full_name = null; DMember candidate = ResolveExactName(combined_qualified_name, ref full_name, kind, currentScope, mustResolve); if (candidate != null) { if (result != null) { if (errors != null) { ErrorInfo error; switch (kind) { case DeclarationKind.Type: error = Errors.AmbiguousTypeMatch; break; case DeclarationKind.Function: error = Errors.AmbiguousFunctionMatch; break; case DeclarationKind.Constant: error = Errors.AmbiguousConstantMatch; break; default: throw null; } errors.Add(error, this, position, result.FullName, candidate.FullName, qualifiedName.Name); } } else { result = candidate; } } } if (result != null) { return(result); } } // unknown qualified name: if (errors != null) { switch (kind) { case DeclarationKind.Type: result = new UnknownType(qualifiedName.ToString()); break; case DeclarationKind.Function: result = new UnknownFunction(qualifiedName.ToString()); break; case DeclarationKind.Constant: result = new UnknownGlobalConstant(qualifiedName.ToString()); break; } return(result); } return(null); }
/// <summary> /// Used by all subclasses except for <see cref="GlobalTypeDesc"/>. /// </summary> protected DMemberDesc(DTypeDesc/*!*/ declaringType, PhpMemberAttributes memberAttributes) { Debug.Assert(declaringType != null); this.declaringType = declaringType; this.memberAttributes = memberAttributes; this.member = null; // to be filled by DMember or at run-time (if applicable) }
/// <summary> /// Defines a property that "exports;" a given field or constant. /// </summary> /// <param name="name">The name of the property.</param> /// <param name="member">A <see cref="PhpField"/> or <see cref="ClassConstant"/>.</param> /// <returns>The export property builder.</returns> public static PropertyBuilder/*!*/ DefineFieldExport(string name, DMember/*!*/ member) { Debug.Assert(member is PhpField || member is ClassConstant); DTypeDesc declaring_type_desc = member.DeclaringType.TypeDesc; TypeBuilder type_builder = member.DeclaringPhpType.RealTypeBuilder; // determine name and type Type type = Types.Object[0]; // TODO: field/constant type hints? PropertyBuilder prop_builder = type_builder.DefineProperty( name, Reflection.Enums.ToPropertyAttributes(member.MemberDesc.MemberAttributes), type, Type.EmptyTypes); MethodAttributes accessor_attrs = Reflection.Enums.ToMethodAttributes(member.MemberDesc.MemberAttributes); bool changed; // define getter MethodBuilder getter = type_builder.DefineMethod( GetNonConflictingMethodName(declaring_type_desc, "get_" + name, out changed), accessor_attrs, type, Type.EmptyTypes); getter.SetCustomAttribute(AttributeBuilders.DebuggerHidden); prop_builder.SetGetMethod(getter); // generate setter if (member is PhpField) { MethodBuilder setter = type_builder.DefineMethod( GetNonConflictingMethodName(declaring_type_desc, "set_" + name, out changed), accessor_attrs, Types.Void, new Type[] { type }); setter.SetCustomAttribute(AttributeBuilders.DebuggerHidden); prop_builder.SetSetMethod(setter); } return prop_builder; }
/// <summary> /// Resolves a function or type name using aliases and imported namespaces of the source unit. /// </summary> /// <param name="qualifiedName">Function qualified name to resolve. Doesn't resolve special names ("self", "parent").</param> /// <param name="kind">Declaration kind.</param> /// <param name="currentScope">Current scope.</param> /// <param name="alias"> /// <B>null</B>, if the function name is resolved immediately. /// Otherwise, if the <paramref name="qualifiedName"/> is simple and an alias exists, contains its qualified target. /// </param> /// <param name="errors">Error sink or <B>null</B> if errors shouldn't be reported.</param> /// <param name="position">Position where to report an error.</param> /// <param name="mustResolve">Whether name must be resolved if possible.</param> /// <returns> /// Resolved member, the unknown member, or <B>null</B> if error reporting is disabled (errors == null). /// </returns> /// <remarks> /// If the name is simple, is not resolved and has an alias then the run-time resolve should be run on the alias. /// If the name is simple, is not resolved and hasn't an alias, the run-time resolve should be run on the name /// within the naming context of the source unit (i.e. imported namespaces should be considered). /// If the name is fully qualified and is not resolved then then the run-time resolve should be run on the name itself. /// </remarks> private DMember ResolveName(QualifiedName qualifiedName, DeclarationKind kind, Scope currentScope, out QualifiedName?alias, ErrorSink errors, Text.Span position, bool mustResolve) { string full_name = null; DMember result; alias = null; // try exact match: result = ResolveExactName(qualifiedName, ref full_name, kind, currentScope, mustResolve); if (result != null) { return(result); } // try imported namespaces: if (!qualifiedName.IsFullyQualifiedName && HasImportedNamespaces) { result = null; foreach (QualifiedName imported_ns in this.ImportedNamespaces) { QualifiedName combined_qualified_name = new QualifiedName(qualifiedName, imported_ns); full_name = null; DMember candidate = ResolveExactName(combined_qualified_name, ref full_name, kind, currentScope, mustResolve); if (candidate != null) { if (result != null) { if (errors != null) { ErrorInfo error; switch (kind) { case DeclarationKind.Type: error = Errors.AmbiguousTypeMatch; break; case DeclarationKind.Function: error = Errors.AmbiguousFunctionMatch; break; case DeclarationKind.Constant: error = Errors.AmbiguousConstantMatch; break; default: throw null; } errors.Add(error, this, position, result.FullName, candidate.FullName, qualifiedName.Name); } } else { result = candidate; } } } if (result != null) { return(result); } } // unknown qualified name: if (errors != null) { switch (kind) { case DeclarationKind.Type: result = new UnknownType(qualifiedName.ToString()); break; case DeclarationKind.Function: result = new UnknownFunction(qualifiedName.ToString()); break; case DeclarationKind.Constant: result = new UnknownGlobalConstant(qualifiedName.ToString()); break; } return(result); } return(null); }
private GenericParameterDesc[]/*!!*/ ToGenericParameters(DMember/*!*/ declaringMember, out int mandatoryCount) { Debug.Assert(declaringMember != null); if (typeParams.Count == 0) { mandatoryCount = 0; return GenericParameterDesc.EmptyArray; } GenericParameterDesc[] result = new GenericParameterDesc[typeParams.Count]; mandatoryCount = 0; for (int i = 0; i < typeParams.Count; i++) { result[i] = new GenericParameter(typeParams[i].Name, i, declaringMember).GenericParameterDesc; if (typeParams[i].DefaultType == null) mandatoryCount++; } return result; }
/// <summary> /// Creates a <see cref="PhpRoutineSignature"/> partially initialized with the type parameters of this type signature. /// Used by generic routines. /// </summary> internal PhpRoutineSignature/*!*/ ToPhpRoutineSignature(DMember/*!*/ declaringRoutine) { Debug.Assert(declaringRoutine != null); int mandatory_generic_param_count; GenericParameterDesc[] descs = this.ToGenericParameters(declaringRoutine, out mandatory_generic_param_count); GenericParameter[] types = new GenericParameter[descs.Length]; for (int i = 0; i < descs.Length; i++) types[i] = descs[i].GenericParameter; return new PhpRoutineSignature(types, mandatory_generic_param_count); }
/// <summary> /// Creates an array of generic parameters. /// Used by generic types. /// </summary> internal GenericParameterDesc[]/*!!*/ ToGenericParameters(DMember/*!*/ declaringType) { int mandatory_generic_param_count; return this.ToGenericParameters(declaringType, out mandatory_generic_param_count); }