File: const.cs

package info (click to toggle)
nrefactory 5.3.0%2B20130718.73b6d0f-4.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 15,720 kB
  • sloc: cs: 296,018; makefile: 24; ansic: 7; sh: 2
file content (237 lines) | stat: -rw-r--r-- 6,216 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
//
// const.cs: Constant declarations.
//
// Author:
//   Miguel de Icaza (miguel@ximian.com)
//   Marek Safar (marek.safar@seznam.cz)
//
// Copyright 2001-2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
//

#if STATIC
using IKVM.Reflection;
#else
using System.Reflection;
#endif

namespace Mono.CSharp {

	public class Const : FieldBase
	{
		const Modifiers AllowedModifiers =
			Modifiers.NEW |
			Modifiers.PUBLIC |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL |
			Modifiers.PRIVATE;

		public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
			: base (parent, type, mod_flags, AllowedModifiers, name, attrs)
		{
			ModFlags |= Modifiers.STATIC;
		}

		/// <summary>
		///   Defines the constant in the @parent
		/// </summary>
		public override bool Define ()
		{
			if (!base.Define ())
				return false;

			if (!member_type.IsConstantCompatible) {
				Error_InvalidConstantType (member_type, Location, Report);
			}

			FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
			// Decimals cannot be emitted into the constant blob.  So, convert to 'readonly'.
			if (member_type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
				field_attr |= FieldAttributes.InitOnly;
			} else {
				field_attr |= FieldAttributes.Literal;
			}

			FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
			spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);

			Parent.MemberCache.AddMember (spec);

			if ((field_attr & FieldAttributes.InitOnly) != 0)
				Parent.PartialContainer.RegisterFieldForInitialization (this,
					new FieldInitializer (this, initializer, Location));

			if (declarators != null) {
				var t = new TypeExpression (MemberType, TypeExpression.Location);
				foreach (var d in declarators) {
					var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
					c.initializer = d.Initializer;
					((ConstInitializer) c.initializer).Name = d.Name.Value;
					c.Define ();
					Parent.PartialContainer.Members.Add (c);
				}
			}

			return true;
		}

		public void DefineValue ()
		{
			var rc = new ResolveContext (this);
			((ConstSpec) spec).GetConstant (rc);
		}

		/// <summary>
		///  Emits the field value by evaluating the expression
		/// </summary>
		public override void Emit ()
		{
			var c = ((ConstSpec) spec).Value as Constant;
			if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
				Module.PredefinedAttributes.DecimalConstant.EmitAttribute (FieldBuilder, (decimal) c.GetValue (), c.Location);
			} else {
				FieldBuilder.SetConstant (c.GetValue ());
			}

			base.Emit ();
		}

		public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
		{
			if (t.IsGenericParameter) {
				Report.Error (1959, loc,
					"Type parameter `{0}' cannot be declared const", t.GetSignatureForError ());
			} else {
				Report.Error (283, loc,
					"The type `{0}' cannot be declared const", t.GetSignatureForError ());
			}
		}

		public override void Accept (StructuralVisitor visitor)
		{
			visitor.Visit (this);
		}
	}

	public class ConstSpec : FieldSpec
	{
		Expression value;

		public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
			: base (declaringType, definition, memberType, fi, mod)
		{
			this.value = value;
		}

		//
		// This expresion is guarantee to be a constant at emit phase only
		//
		public Expression Value {
			get {
				return value;
			}
		}

		//
		// For compiled constants we have to resolve the value as there could be constant dependecies. This
		// is needed for imported constants too to get the right context type
		//
		public Constant GetConstant (ResolveContext rc)
		{
			if (value.eclass != ExprClass.Value)
				value = value.Resolve (rc);

			return (Constant) value;
		}
	}

	public class ConstInitializer : ShimExpression
	{
		bool in_transit;
		readonly FieldBase field;

		public ConstInitializer (FieldBase field, Expression value, Location loc)
			: base (value)
		{
			this.loc = loc;
			this.field = field;
		}

		public string Name { get; set; }

		protected override Expression DoResolve (ResolveContext unused)
		{
			if (type != null)
				return expr;

			var opt = ResolveContext.Options.ConstantScope;
			if (field is EnumMember)
				opt |= ResolveContext.Options.EnumScope;

			//
			// Use a context in which the constant was declared and
			// not the one in which is referenced
			//
			var rc = new ResolveContext (field, opt);
			expr = DoResolveInitializer (rc);
			type = expr.Type;

			return expr;
		}

		protected virtual Expression DoResolveInitializer (ResolveContext rc)
		{
			if (in_transit) {
				field.Compiler.Report.Error (110, expr.Location,
					"The evaluation of the constant value for `{0}' involves a circular definition",
					GetSignatureForError ());

				expr = null;
			} else {
				in_transit = true;
				expr = expr.Resolve (rc);
			}

			in_transit = false;

			if (expr != null) {
				Constant c = expr as Constant;
				if (c != null)
					c = field.ConvertInitializer (rc, c);

				if (c == null) {
					if (TypeSpec.IsReferenceType (field.MemberType))
						Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
					else if (!(expr is Constant))
						Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
					else
						expr.Error_ValueCannotBeConverted (rc, field.MemberType, false);
				}

				expr = c;
			}

			if (expr == null) {
				expr = New.Constantify (field.MemberType, Location);
				if (expr == null)
					expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
				expr = expr.Resolve (rc);
			}

			return expr;
		}

		public override string GetSignatureForError ()
		{
			if (Name == null)
				return field.GetSignatureForError ();

			return field.Parent.GetSignatureForError () + "." + Name;
		}

		public override object Accept (StructuralVisitor visitor)
		{
			return visitor.Visit (this);
		}
	}
}