797 lines
22 KiB
C#
797 lines
22 KiB
C#
//
|
|
// module.cs: keeps a tree representation of the generated code
|
|
//
|
|
// Authors: Miguel de Icaza (miguel@gnu.org)
|
|
// Marek Safar (marek.safar@gmail.com)
|
|
//
|
|
// Dual licensed under the terms of the MIT X11 or GNU GPL
|
|
//
|
|
// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
|
|
// Copyright 2003-2008 Novell, Inc.
|
|
// Copyright 2011 Xamarin Inc
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Mono.CompilerServices.SymbolWriter;
|
|
using System.Linq;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using Mono.Security.Cryptography;
|
|
|
|
#if STATIC
|
|
using IKVM.Reflection;
|
|
using IKVM.Reflection.Emit;
|
|
#else
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
#endif
|
|
|
|
namespace Mono.CSharp
|
|
{
|
|
//
|
|
// Module (top-level type) container
|
|
//
|
|
public sealed class ModuleContainer : TypeContainer
|
|
{
|
|
#if STATIC
|
|
//
|
|
// Compiler generated container for static data
|
|
//
|
|
sealed class StaticDataContainer : CompilerGeneratedContainer
|
|
{
|
|
readonly Dictionary<int, Struct> size_types;
|
|
readonly Dictionary<string, FieldSpec> data_hashes;
|
|
|
|
public StaticDataContainer (ModuleContainer module)
|
|
: base (module, new MemberName ("<PrivateImplementationDetails>", Location.Null),
|
|
Modifiers.STATIC | Modifiers.INTERNAL)
|
|
{
|
|
size_types = new Dictionary<int, Struct> ();
|
|
data_hashes = new Dictionary<string, FieldSpec> (StringComparer.Ordinal);
|
|
}
|
|
|
|
public override void CloseContainer ()
|
|
{
|
|
base.CloseContainer ();
|
|
|
|
foreach (var entry in size_types) {
|
|
entry.Value.CloseContainer ();
|
|
}
|
|
}
|
|
|
|
public FieldSpec DefineInitializedData (byte[] data, Location loc)
|
|
{
|
|
Struct size_type;
|
|
if (!size_types.TryGetValue (data.Length, out size_type)) {
|
|
//
|
|
// Build common type for this data length. We cannot use
|
|
// DefineInitializedData because it creates public type,
|
|
// and its name is not unique among modules
|
|
//
|
|
size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
|
|
size_type.CreateContainer ();
|
|
size_type.DefineContainer ();
|
|
|
|
size_types.Add (data.Length, size_type);
|
|
|
|
// It has to work even if StructLayoutAttribute does not exist
|
|
size_type.TypeBuilder.__SetLayout (1, data.Length);
|
|
}
|
|
|
|
FieldSpec fs;
|
|
var data_hash = GenerateDataFieldName (data);
|
|
if (!data_hashes.TryGetValue (data_hash, out fs)) {
|
|
var name = "$field-" + data_hash;
|
|
const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL | Modifiers.READONLY;
|
|
var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
|
|
fbuilder.__SetDataAndRVA (data);
|
|
|
|
fs = new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
|
|
data_hashes.Add (data_hash, fs);
|
|
}
|
|
|
|
return fs;
|
|
}
|
|
|
|
static string GenerateDataFieldName (byte[] bytes)
|
|
{
|
|
using (var hashProvider = new SHA1CryptoServiceProvider ())
|
|
{
|
|
return CryptoConvert.ToHex (hashProvider.ComputeHash (bytes));
|
|
}
|
|
}
|
|
}
|
|
|
|
StaticDataContainer static_data;
|
|
|
|
//
|
|
// Makes const data field inside internal type container
|
|
//
|
|
public FieldSpec MakeStaticData (byte[] data, Location loc)
|
|
{
|
|
if (static_data == null) {
|
|
static_data = new StaticDataContainer (this);
|
|
static_data.CreateContainer ();
|
|
static_data.DefineContainer ();
|
|
|
|
AddCompilerGeneratedClass (static_data);
|
|
}
|
|
|
|
return static_data.DefineInitializedData (data, loc);
|
|
}
|
|
#endif
|
|
|
|
public sealed class PatternMatchingHelper : CompilerGeneratedContainer
|
|
{
|
|
public PatternMatchingHelper (ModuleContainer module)
|
|
: base (module, new MemberName ("<PatternMatchingHelper>", Location.Null),
|
|
Modifiers.STATIC | Modifiers.INTERNAL | Modifiers.DEBUGGER_HIDDEN)
|
|
{
|
|
}
|
|
|
|
public Method NumberMatcher { get; private set; }
|
|
|
|
protected override bool DoDefineMembers ()
|
|
{
|
|
if (!base.DoDefineMembers ())
|
|
return false;
|
|
|
|
NumberMatcher = GenerateNumberMatcher ();
|
|
return true;
|
|
}
|
|
|
|
Method GenerateNumberMatcher ()
|
|
{
|
|
var loc = Location;
|
|
var parameters = ParametersCompiled.CreateFullyResolved (
|
|
new [] {
|
|
new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc),
|
|
new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "value", 0, null, loc),
|
|
new Parameter (new TypeExpression (Compiler.BuiltinTypes.Bool, loc), "enumType", 0, null, loc),
|
|
},
|
|
new [] {
|
|
Compiler.BuiltinTypes.Object,
|
|
Compiler.BuiltinTypes.Object,
|
|
Compiler.BuiltinTypes.Bool
|
|
});
|
|
|
|
var m = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
|
|
Modifiers.PUBLIC | Modifiers.STATIC | Modifiers.DEBUGGER_HIDDEN, new MemberName ("NumberMatcher", loc),
|
|
parameters, null);
|
|
|
|
parameters [0].Resolve (m, 0);
|
|
parameters [1].Resolve (m, 1);
|
|
parameters [2].Resolve (m, 2);
|
|
|
|
ToplevelBlock top_block = new ToplevelBlock (Compiler, parameters, loc);
|
|
m.Block = top_block;
|
|
|
|
//
|
|
// if (enumType)
|
|
// return Equals (obj, value);
|
|
//
|
|
var equals_args = new Arguments (2);
|
|
equals_args.Add (new Argument (top_block.GetParameterReference (0, loc)));
|
|
equals_args.Add (new Argument (top_block.GetParameterReference (1, loc)));
|
|
|
|
var if_type = new If (
|
|
top_block.GetParameterReference (2, loc),
|
|
new Return (new Invocation (new SimpleName ("Equals", loc), equals_args), loc),
|
|
loc);
|
|
|
|
top_block.AddStatement (if_type);
|
|
|
|
//
|
|
// if (obj is Enum || obj == null)
|
|
// return false;
|
|
//
|
|
|
|
var if_enum = new If (
|
|
new Binary (Binary.Operator.LogicalOr,
|
|
new Is (top_block.GetParameterReference (0, loc), new TypeExpression (Compiler.BuiltinTypes.Enum, loc), loc),
|
|
new Binary (Binary.Operator.Equality, top_block.GetParameterReference (0, loc), new NullLiteral (loc))),
|
|
new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc),
|
|
loc);
|
|
|
|
top_block.AddStatement (if_enum);
|
|
|
|
|
|
var system_convert = new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Convert", loc);
|
|
var expl_block = new ExplicitBlock (top_block, loc, loc);
|
|
|
|
//
|
|
// var converted = System.Convert.ChangeType (obj, System.Convert.GetTypeCode (value));
|
|
//
|
|
var lv_converted = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Object, top_block, loc);
|
|
|
|
var arguments_gettypecode = new Arguments (1);
|
|
arguments_gettypecode.Add (new Argument (top_block.GetParameterReference (1, loc)));
|
|
|
|
var gettypecode = new Invocation (new MemberAccess (system_convert, "GetTypeCode", loc), arguments_gettypecode);
|
|
|
|
var arguments_changetype = new Arguments (1);
|
|
arguments_changetype.Add (new Argument (top_block.GetParameterReference (0, loc)));
|
|
arguments_changetype.Add (new Argument (gettypecode));
|
|
|
|
var changetype = new Invocation (new MemberAccess (system_convert, "ChangeType", loc), arguments_changetype);
|
|
|
|
expl_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc)));
|
|
|
|
|
|
//
|
|
// return converted.Equals (value)
|
|
//
|
|
var equals_arguments = new Arguments (1);
|
|
equals_arguments.Add (new Argument (top_block.GetParameterReference (1, loc)));
|
|
var equals_invocation = new Invocation (new MemberAccess (new LocalVariableReference (lv_converted, loc), "Equals"), equals_arguments);
|
|
expl_block.AddStatement (new Return (equals_invocation, loc));
|
|
|
|
var catch_block = new ExplicitBlock (top_block, loc, loc);
|
|
catch_block.AddStatement (new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc));
|
|
top_block.AddStatement (new TryCatch (expl_block, new List<Catch> () {
|
|
new Catch (catch_block, loc)
|
|
}, loc, false));
|
|
|
|
m.Define ();
|
|
m.PrepareEmit ();
|
|
AddMember (m);
|
|
|
|
return m;
|
|
}
|
|
}
|
|
|
|
PatternMatchingHelper pmh;
|
|
|
|
public PatternMatchingHelper CreatePatterMatchingHelper ()
|
|
{
|
|
if (pmh == null) {
|
|
pmh = new PatternMatchingHelper (this);
|
|
|
|
pmh.CreateContainer ();
|
|
pmh.DefineContainer ();
|
|
pmh.Define ();
|
|
AddCompilerGeneratedClass (pmh);
|
|
}
|
|
|
|
return pmh;
|
|
}
|
|
|
|
public CharSet? DefaultCharSet;
|
|
public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
|
|
|
|
readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
|
|
readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
|
|
readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
|
|
readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
|
|
readonly Dictionary<TypeSpec, ReadOnlyReferenceContainer> readonly_reference_types;
|
|
readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
|
|
readonly Dictionary<TypeSpec, AwaiterDefinition> awaiters;
|
|
readonly Dictionary<TypeSpec, TypeInfo> type_info_cache;
|
|
|
|
AssemblyDefinition assembly;
|
|
readonly CompilerContext context;
|
|
readonly RootNamespace global_ns;
|
|
readonly Dictionary<string, RootNamespace> alias_ns;
|
|
|
|
ModuleBuilder builder;
|
|
|
|
bool has_extenstion_method;
|
|
|
|
PredefinedAttributes predefined_attributes;
|
|
PredefinedTypes predefined_types;
|
|
PredefinedMembers predefined_members;
|
|
|
|
public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted;
|
|
public Binary.PredefinedOperator[] OperatorsBinaryLifted;
|
|
|
|
static readonly string[] attribute_targets = new string[] { "assembly", "module" };
|
|
|
|
public ModuleContainer (CompilerContext context)
|
|
: base (null, MemberName.Null, null, 0)
|
|
{
|
|
this.context = context;
|
|
|
|
caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
|
|
|
|
containers = new List<TypeContainer> ();
|
|
anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
|
|
global_ns = new GlobalRootNamespace ();
|
|
alias_ns = new Dictionary<string, RootNamespace> ();
|
|
array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
|
|
pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
|
|
reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
|
|
readonly_reference_types = new Dictionary<TypeSpec, ReadOnlyReferenceContainer> ();
|
|
attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
|
|
awaiters = new Dictionary<TypeSpec, AwaiterDefinition> ();
|
|
type_info_cache = new Dictionary<TypeSpec, TypeInfo> ();
|
|
}
|
|
|
|
#region Properties
|
|
|
|
internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
|
|
get {
|
|
return array_types;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cache for parameter-less attributes
|
|
//
|
|
internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
|
|
get {
|
|
return attrs_cache;
|
|
}
|
|
}
|
|
|
|
public override AttributeTargets AttributeTargets {
|
|
get {
|
|
return AttributeTargets.Assembly;
|
|
}
|
|
}
|
|
|
|
public ModuleBuilder Builder {
|
|
get {
|
|
return builder;
|
|
}
|
|
}
|
|
|
|
public override CompilerContext Compiler {
|
|
get {
|
|
return context;
|
|
}
|
|
}
|
|
|
|
public int CounterAnonymousTypes { get; set; }
|
|
|
|
public AssemblyDefinition DeclaringAssembly {
|
|
get {
|
|
return assembly;
|
|
}
|
|
}
|
|
|
|
internal DocumentationBuilder DocumentationBuilder {
|
|
get; set;
|
|
}
|
|
|
|
public override string DocCommentHeader {
|
|
get {
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public Evaluator Evaluator {
|
|
get; set;
|
|
}
|
|
|
|
public bool HasDefaultCharSet {
|
|
get {
|
|
return DefaultCharSet.HasValue;
|
|
}
|
|
}
|
|
|
|
public bool HasExtensionMethod {
|
|
get {
|
|
return has_extenstion_method;
|
|
}
|
|
set {
|
|
has_extenstion_method = value;
|
|
}
|
|
}
|
|
|
|
public bool HasTypesFullyDefined {
|
|
get; set;
|
|
}
|
|
|
|
//
|
|
// Returns module global:: namespace
|
|
//
|
|
public RootNamespace GlobalRootNamespace {
|
|
get {
|
|
return global_ns;
|
|
}
|
|
}
|
|
|
|
public override ModuleContainer Module {
|
|
get {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
|
|
get {
|
|
return pointer_types;
|
|
}
|
|
}
|
|
|
|
internal PredefinedAttributes PredefinedAttributes {
|
|
get {
|
|
return predefined_attributes;
|
|
}
|
|
}
|
|
|
|
internal PredefinedMembers PredefinedMembers {
|
|
get {
|
|
return predefined_members;
|
|
}
|
|
}
|
|
|
|
internal PredefinedTypes PredefinedTypes {
|
|
get {
|
|
return predefined_types;
|
|
}
|
|
}
|
|
|
|
internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
|
|
get {
|
|
return reference_types;
|
|
}
|
|
}
|
|
|
|
internal Dictionary<TypeSpec, ReadOnlyReferenceContainer> ReadonlyReferenceTypesCache {
|
|
get {
|
|
return readonly_reference_types;
|
|
}
|
|
}
|
|
|
|
internal Dictionary<TypeSpec, TypeInfo> TypeInfoCache {
|
|
get {
|
|
return type_info_cache;
|
|
}
|
|
}
|
|
|
|
public override string[] ValidAttributeTargets {
|
|
get {
|
|
return attribute_targets;
|
|
}
|
|
}
|
|
|
|
public Dictionary<string, string> GetResourceStrings { get; private set; }
|
|
|
|
#endregion
|
|
|
|
public override void Accept (StructuralVisitor visitor)
|
|
{
|
|
visitor.Visit (this);
|
|
}
|
|
|
|
public void AddAnonymousType (AnonymousTypeClass type)
|
|
{
|
|
List<AnonymousTypeClass> existing;
|
|
if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
|
|
if (existing == null) {
|
|
existing = new List<AnonymousTypeClass> ();
|
|
anonymous_types.Add (type.Parameters.Count, existing);
|
|
}
|
|
|
|
existing.Add (type);
|
|
}
|
|
|
|
public void AddAttribute (Attribute attr, IMemberContext context)
|
|
{
|
|
attr.AttachTo (this, context);
|
|
|
|
if (attributes == null) {
|
|
attributes = new Attributes (attr);
|
|
return;
|
|
}
|
|
|
|
attributes.AddAttribute (attr);
|
|
}
|
|
|
|
public void AddAssemblyReferences (List<Assembly> names)
|
|
{
|
|
if (names == null)
|
|
return;
|
|
|
|
#if STATIC
|
|
foreach (var name in names) {
|
|
Builder.__GetAssemblyToken (name);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
public override void AddTypeContainer (TypeContainer tc)
|
|
{
|
|
AddTypeContainerMember (tc);
|
|
}
|
|
|
|
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
|
|
{
|
|
if (a.Target == AttributeTargets.Assembly) {
|
|
assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
|
|
return;
|
|
}
|
|
|
|
if (a.Type == pa.DefaultCharset) {
|
|
switch (a.GetCharSetValue ()) {
|
|
case CharSet.Ansi:
|
|
case CharSet.None:
|
|
break;
|
|
case CharSet.Auto:
|
|
DefaultCharSet = CharSet.Auto;
|
|
DefaultCharSetType = TypeAttributes.AutoClass;
|
|
break;
|
|
case CharSet.Unicode:
|
|
DefaultCharSet = CharSet.Unicode;
|
|
DefaultCharSetType = TypeAttributes.UnicodeClass;
|
|
break;
|
|
default:
|
|
Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
|
|
a.GetSignatureForError ());
|
|
break;
|
|
}
|
|
} else if (a.Type == pa.CLSCompliant) {
|
|
Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
|
|
if (cls == null) {
|
|
Report.Warning (3012, 1, a.Location,
|
|
"You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
|
|
} else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
|
|
Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
|
|
Report.Warning (3017, 1, a.Location,
|
|
"You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
|
|
return;
|
|
}
|
|
}
|
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
|
|
}
|
|
|
|
public override void CloseContainer ()
|
|
{
|
|
if (anonymous_types != null) {
|
|
foreach (var atypes in anonymous_types)
|
|
foreach (var at in atypes.Value)
|
|
at.CloseContainer ();
|
|
}
|
|
|
|
base.CloseContainer ();
|
|
}
|
|
|
|
public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
|
|
{
|
|
return builder.DefineType (name, attr, null, typeSize);
|
|
}
|
|
|
|
//
|
|
// Creates alias global namespace
|
|
//
|
|
public RootNamespace CreateRootNamespace (string alias)
|
|
{
|
|
if (alias == global_ns.Alias) {
|
|
RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
|
|
return global_ns;
|
|
}
|
|
|
|
RootNamespace rn;
|
|
if (!alias_ns.TryGetValue (alias, out rn)) {
|
|
rn = new RootNamespace (alias);
|
|
alias_ns.Add (alias, rn);
|
|
}
|
|
|
|
return rn;
|
|
}
|
|
|
|
public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
|
|
{
|
|
this.assembly = assembly;
|
|
builder = moduleBuilder;
|
|
}
|
|
|
|
public override bool Define ()
|
|
{
|
|
DefineContainer ();
|
|
|
|
ExpandBaseInterfaces ();
|
|
|
|
base.Define ();
|
|
|
|
HasTypesFullyDefined = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool DefineContainer ()
|
|
{
|
|
DefineNamespace ();
|
|
|
|
return base.DefineContainer ();
|
|
}
|
|
|
|
public void EnableRedefinition ()
|
|
{
|
|
is_defined = false;
|
|
}
|
|
|
|
public override void EmitContainer ()
|
|
{
|
|
if (OptAttributes != null)
|
|
OptAttributes.Emit ();
|
|
|
|
if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
|
|
var pa = PredefinedAttributes.UnverifiableCode;
|
|
if (pa.IsDefined)
|
|
pa.EmitAttribute (builder);
|
|
}
|
|
|
|
foreach (var tc in containers) {
|
|
tc.PrepareEmit ();
|
|
}
|
|
|
|
base.EmitContainer ();
|
|
|
|
if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
|
|
VerifyMembers ();
|
|
|
|
if (anonymous_types != null) {
|
|
foreach (var atypes in anonymous_types)
|
|
foreach (var at in atypes.Value)
|
|
at.EmitContainer ();
|
|
}
|
|
}
|
|
|
|
internal override void GenerateDocComment (DocumentationBuilder builder)
|
|
{
|
|
foreach (var tc in containers)
|
|
tc.GenerateDocComment (builder);
|
|
}
|
|
|
|
public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
|
|
{
|
|
List<AnonymousTypeClass> candidates;
|
|
if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
|
|
return null;
|
|
|
|
int i;
|
|
foreach (AnonymousTypeClass at in candidates) {
|
|
for (i = 0; i < parameters.Count; ++i) {
|
|
if (!parameters [i].Equals (at.Parameters [i]))
|
|
break;
|
|
}
|
|
|
|
if (i == parameters.Count)
|
|
return at;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// Return container with awaiter definition. It never returns null
|
|
// but all container member can be null for easier error reporting
|
|
//
|
|
public AwaiterDefinition GetAwaiter (TypeSpec type)
|
|
{
|
|
AwaiterDefinition awaiter;
|
|
if (awaiters.TryGetValue (type, out awaiter))
|
|
return awaiter;
|
|
|
|
awaiter = new AwaiterDefinition ();
|
|
|
|
//
|
|
// Predefined: bool IsCompleted { get; }
|
|
//
|
|
awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
|
|
BindingRestriction.InstanceOnly) as PropertySpec;
|
|
|
|
//
|
|
// Predefined: GetResult ()
|
|
//
|
|
// The method return type is also result type of await expression
|
|
//
|
|
awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
|
|
ParametersCompiled.EmptyReadOnlyParameters, null),
|
|
BindingRestriction.InstanceOnly) as MethodSpec;
|
|
|
|
//
|
|
// Predefined: INotifyCompletion.OnCompleted (System.Action)
|
|
//
|
|
var nc = PredefinedTypes.INotifyCompletion;
|
|
awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
|
|
|
|
awaiters.Add (type, awaiter);
|
|
return awaiter;
|
|
}
|
|
|
|
public override void GetCompletionStartingWith (string prefix, List<string> results)
|
|
{
|
|
var names = Evaluator.GetVarNames ();
|
|
results.AddRange (names.Where (l => l.StartsWith (prefix)));
|
|
}
|
|
|
|
public RootNamespace GetRootNamespace (string name)
|
|
{
|
|
RootNamespace rn;
|
|
alias_ns.TryGetValue (name, out rn);
|
|
return rn;
|
|
}
|
|
|
|
public override string GetSignatureForError ()
|
|
{
|
|
return "<module>";
|
|
}
|
|
|
|
public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
|
|
{
|
|
TypeSpec underlying;
|
|
Binary.Operator mask = 0;
|
|
|
|
if (nullable) {
|
|
underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
|
|
mask = Binary.Operator.NullableMask;
|
|
} else {
|
|
underlying = EnumSpec.GetUnderlyingType (enumType);
|
|
}
|
|
|
|
var operators = new[] {
|
|
new Binary.PredefinedOperator (enumType, underlying,
|
|
mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
|
|
new Binary.PredefinedOperator (underlying, enumType,
|
|
mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
|
|
new Binary.PredefinedOperator (enumType, mask | Binary.Operator.SubtractionMask, underlying)
|
|
};
|
|
|
|
return operators;
|
|
}
|
|
|
|
public void InitializePredefinedTypes ()
|
|
{
|
|
predefined_attributes = new PredefinedAttributes (this);
|
|
predefined_types = new PredefinedTypes (this);
|
|
predefined_members = new PredefinedMembers (this);
|
|
|
|
OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
|
|
OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
|
|
}
|
|
|
|
public override bool IsClsComplianceRequired ()
|
|
{
|
|
return DeclaringAssembly.IsCLSCompliant;
|
|
}
|
|
|
|
public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
|
|
{
|
|
Attribute a = OptAttributes.Search ("assembly", a_type);
|
|
if (a != null) {
|
|
a.Resolve ();
|
|
}
|
|
return a;
|
|
}
|
|
|
|
public void SetDeclaringAssembly (AssemblyDefinition assembly)
|
|
{
|
|
// TODO: This setter is quite ugly but I have not found a way around it yet
|
|
this.assembly = assembly;
|
|
}
|
|
|
|
public void LoadGetResourceStrings (List<string> fileNames)
|
|
{
|
|
foreach (var fileName in fileNames) {
|
|
if (!File.Exists (fileName)) {
|
|
Report.Error (1566, "Error reading resource file `{0}'", fileName);
|
|
return;
|
|
}
|
|
|
|
foreach (var l in File.ReadLines (fileName)) {
|
|
if (GetResourceStrings == null)
|
|
GetResourceStrings = new Dictionary<string, string> ();
|
|
|
|
var line = l.Trim ();
|
|
if (line.Length == 0 || line [0] == '#' || line [0] == ';')
|
|
continue;
|
|
|
|
var epos = line.IndexOf ('=');
|
|
if (epos < 0)
|
|
continue;
|
|
|
|
var key = line.Substring (0, epos).Trim ();
|
|
var value = line.Substring (epos + 1).Trim ();
|
|
|
|
GetResourceStrings [key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|