1 module d.ir.symbol;
2 
3 import d.ir.dscope;
4 import d.ir.expression;
5 import d.ir.type;
6 
7 import d.common.node;
8 
9 import source.context;
10 import source.name;
11 
12 public import d.common.qualifier;
13 
14 enum Step {
15 	Parsed,
16 	Populated,
17 	Signed,
18 	Processed,
19 }
20 
21 enum InTemplate {
22 	No,
23 	Yes,
24 }
25 
26 class Symbol : Node {
27 	Name name;
28 	Name mangle;
29 
30 	import std.bitmanip;
31 	mixin(bitfields!(
32 		// sdfmt off
33 		Step, "step", 2,
34 		Linkage, "linkage", 3,
35 		Visibility, "visibility", 3,
36 		InTemplate, "inTemplate", 1,
37 		bool, "hasThis", 1,
38 		bool, "hasContext", 1,
39 		bool, "isPoisoned", 1,
40 		bool, "isAbstract", 1,
41 		bool, "isProperty", 1,
42 		uint, "__derived", 18,
43 		// sdfmt on
44 	));
45 
46 	this(Location location, Name name) {
47 		super(location);
48 
49 		this.name = name;
50 	}
51 
52 	string toString(const Context c) const {
53 		return name.toString(c);
54 	}
55 
56 protected:
57 	@property
58 	uint derived() const {
59 		return __derived;
60 	}
61 
62 	@property
63 	uint derived(uint val) {
64 		__derived = val;
65 		return derived;
66 	}
67 }
68 
69 /**
70  * Symbol that introduce a scope.
71  * NB: Symbols that introduce non standard scope may not extend this.
72  */
73 abstract class ScopeSymbol : Symbol, Scope {
74 	mixin ScopeImpl;
75 
76 	this(Location location, Scope parentScope, Name name) {
77 		super(location, name);
78 		fillParentScope(parentScope);
79 	}
80 }
81 
82 /**
83  * Symbol that represent a value once resolved.
84  */
85 abstract class ValueSymbol : Symbol {
86 	this(Location location, Name name) {
87 		super(location, name);
88 	}
89 }
90 
91 /**
92  * Package
93  */
94 class Package : Symbol, Scope {
95 	mixin ScopeImpl!(ScopeType.Module);
96 
97 	Package parent;
98 
99 	this(Location location, Name name, Package parent) {
100 		super(location, name);
101 
102 		this.parent = parent;
103 	}
104 }
105 
106 /**
107  * Function
108  */
109 class Function : ValueSymbol, Scope {
110 	mixin ScopeImpl;
111 	FunctionType type;
112 
113 	Variable[] params;
114 	uint[Variable] closure;
115 
116 	import d.ir.instruction;
117 	Body fbody;
118 
119 	this(Location location, Scope parentScope, FunctionType type, Name name,
120 	     Variable[] params) {
121 		super(location, name);
122 		fillParentScope(parentScope);
123 
124 		this.type = type;
125 		this.params = params;
126 	}
127 
128 	@property
129 	Intrinsic intrinsicID() const {
130 		if (hasThis) {
131 			return Intrinsic.None;
132 		}
133 
134 		return cast(Intrinsic) __derived;
135 	}
136 
137 	@property
138 	Intrinsic intrinsicID(Intrinsic id) in {
139 		assert(!hasThis, "Method can't be intrinsic");
140 		assert(intrinsicID == Intrinsic.None, "This is already an intrinsic");
141 	} do {
142 		__derived = id;
143 		return intrinsicID;
144 	}
145 
146 	void dump(const Context c) const {
147 		import std.algorithm, std.range;
148 		auto params = params.map!(p => p.name.toString(c)).join(", ");
149 
150 		auto retStr =
151 			(step >= Step.Signed) ? type.returnType.toString(c) : "__untyped";
152 
153 		import std.stdio;
154 		write(retStr, ' ', name.toString(c), '(', params, ") {");
155 		fbody.dump(c);
156 		writeln("}\n");
157 	}
158 }
159 
160 /**
161  * Entry for template parameters
162  */
163 class TemplateParameter : Symbol {
164 	this(Location location, Name name, uint index) {
165 		super(location, name);
166 
167 		this.derived = index;
168 	}
169 
170 final:
171 	@property
172 	uint index() const {
173 		return derived;
174 	}
175 }
176 
177 /**
178  * Superclass for struct, class and interface.
179  */
180 abstract class Aggregate : ScopeSymbol {
181 	Name[] aliasThis;
182 	Symbol[] members;
183 
184 	this(Location location, Scope parentScope, Name name, Symbol[] members) {
185 		super(location, parentScope, name);
186 
187 		this.members = members;
188 	}
189 }
190 
191 final:
192 /**
193  * Module
194  */
195 class Module : Package {
196 	Symbol[] members;
197 	Function[] tests;
198 
199 	this(Location location, Name name, Package parent) {
200 		super(location, name, parent);
201 		dmodule = this;
202 	}
203 }
204 
205 /**
206  * Placeholder in symbol tables for templates and functions.
207  */
208 class OverloadSet : Symbol {
209 	Symbol[] set;
210 
211 	this(Location location, Name name, Symbol[] set) {
212 		super(location, name);
213 		this.mangle = name;
214 		this.set = set;
215 	}
216 
217 	OverloadSet clone() {
218 		auto os = new OverloadSet(location, name, set);
219 		os.mangle = mangle;
220 		return os;
221 	}
222 
223 	@property
224 		isResolved() const {
225 		return !!__derived;
226 	}
227 
228 	@property
229 		isResolved(bool resolved) {
230 		__derived = resolved;
231 		return resolved;
232 	}
233 }
234 
235 /**
236  * Variable
237  */
238 class Variable : ValueSymbol {
239 	Expression value;
240 	ParamType paramType;
241 
242 	this(Location location, ParamType paramType, Name name,
243 	     Expression value = null) {
244 		super(location, name);
245 
246 		this.paramType = paramType;
247 		this.value = value;
248 	}
249 
250 	this(Location location, Type type, Name name, Expression value = null) {
251 		super(location, name);
252 
253 		this.type = type;
254 		this.value = value;
255 	}
256 
257 	@property
258 	inout(Type) type() inout {
259 		return paramType.getType();
260 	}
261 
262 	@property
263 	Type type(Type t) {
264 		paramType = t.getParamType(ParamKind.Regular);
265 		return t;
266 	}
267 
268 	@property
269 	bool isRef() const {
270 		return paramType.isRef;
271 	}
272 
273 	@property
274 	bool isFinal() const {
275 		return paramType.isFinal;
276 	}
277 
278 	@property
279 		storage() const {
280 		return cast(Storage) (__derived & 0x03);
281 	}
282 
283 	@property
284 		storage(Storage storage) {
285 		__derived = storage;
286 		return storage;
287 	}
288 
289 	override string toString(const Context c) const {
290 		return type.toString(c) ~ " " ~ name.toString(c) ~ " = "
291 			~ value.toString(c) ~ ";";
292 	}
293 }
294 
295 /**
296  * Field
297  * Simply a Variable with a field index.
298  */
299 class Field : ValueSymbol {
300 	CompileTimeExpression value;
301 	Type type;
302 
303 	this(Location location, uint index, Type type, Name name,
304 	     CompileTimeExpression value = null) {
305 		super(location, name);
306 
307 		this.value = value;
308 		this.type = type;
309 		this.derived = index;
310 
311 		// Always true for fields.
312 		this.hasThis = true;
313 	}
314 
315 	@property
316 		index() const {
317 		return derived;
318 	}
319 }
320 
321 /**
322  * Template
323  */
324 class Template : ScopeSymbol {
325 	TemplateInstance[string] instances;
326 	Type[] ifti;
327 
328 	TemplateParameter[] parameters;
329 
330 	import d.ast.declaration : Declaration;
331 	Declaration[] members;
332 
333 	this(Location location, Scope parentScope, Name name,
334 	     TemplateParameter[] parameters, Declaration[] members) {
335 		super(location, parentScope, name);
336 
337 		this.parameters = parameters;
338 		this.members = members;
339 	}
340 
341 	@property
342 		storage() const {
343 		return cast(Storage) (__derived & 0x03);
344 	}
345 
346 	@property
347 		storage(Storage storage) {
348 		__derived = storage;
349 		return storage;
350 	}
351 }
352 
353 /**
354  * Template type parameter
355  */
356 class TypeTemplateParameter : TemplateParameter {
357 	Type specialization;
358 	Type defaultValue;
359 
360 	this(Location location, Name name, uint index, Type specialization,
361 	     Type defaultValue) {
362 		super(location, name, index);
363 
364 		this.specialization = specialization;
365 		this.defaultValue = defaultValue;
366 	}
367 
368 	override string toString(const Context c) const {
369 		return name.toString(c) ~ " : " ~ specialization.toString(c) ~ " = "
370 			~ defaultValue.toString(c);
371 	}
372 }
373 
374 /**
375  * Template value parameter
376  */
377 class ValueTemplateParameter : TemplateParameter {
378 	Type type;
379 	Expression defaultValue;
380 
381 	this(Location location, Name name, uint index, Type type,
382 	     Expression defaultValue) {
383 		super(location, name, index);
384 
385 		this.type = type;
386 		this.defaultValue = defaultValue;
387 	}
388 }
389 
390 /**
391  * Template alias parameter
392  */
393 class AliasTemplateParameter : TemplateParameter {
394 	this(Location location, Name name, uint index) {
395 		super(location, name, index);
396 	}
397 }
398 
399 /**
400  * Template typed alias parameter
401  */
402 class TypedAliasTemplateParameter : TemplateParameter {
403 	Type type;
404 
405 	this(Location location, Name name, uint index, Type type) {
406 		super(location, name, index);
407 
408 		this.type = type;
409 	}
410 }
411 
412 /**
413  * Template instance
414  */
415 class TemplateInstance : Symbol, Scope {
416 	mixin ScopeImpl!(ScopeType.WithParent, Template);
417 
418 	TemplateArgument[] args;
419 	Symbol[] members;
420 
421 	this(Location location, Template tpl, TemplateArgument[] args) {
422 		super(location, tpl.name);
423 		fillParentScope(tpl);
424 
425 		this.args = args;
426 	}
427 
428 	Template getTemplate() {
429 		return getParentScope();
430 	}
431 
432 	@property
433 		storage() const {
434 		return cast(Storage) (__derived & 0x03);
435 	}
436 
437 	@property
438 		storage(Storage storage) {
439 		__derived = storage;
440 		return storage;
441 	}
442 }
443 
444 alias TemplateArgument =
445 	Type.UnionType!(typeof(null), Symbol, CompileTimeExpression);
446 
447 auto apply(alias undefinedHandler, alias handler)(TemplateArgument a) {
448 	alias Tag = typeof(a.tag);
449 	final switch (a.tag) with (Tag) {
450 		case Undefined:
451 			return undefinedHandler();
452 
453 		case Symbol:
454 			return handler(a.get!Symbol);
455 
456 		case CompileTimeExpression:
457 			return handler(a.get!CompileTimeExpression);
458 
459 		case Type:
460 			return handler(a.get!Type);
461 	}
462 }
463 
464 unittest {
465 	TemplateArgument.init.apply!(() {}, (i) {
466 		assert(0);
467 	})();
468 }
469 
470 /**
471  * Alias of symbols
472  */
473 class SymbolAlias : Symbol {
474 	Symbol symbol;
475 
476 	this(Location location, Name name, Symbol symbol) {
477 		super(location, name);
478 
479 		this.symbol = symbol;
480 	}
481 
482 	/+
483 	invariant() {
484 		if (step >= Step.Signed) {
485 			assert(symbol && hasContext == symbol.hasContext);
486 		}
487 	}
488 	+/
489 }
490 
491 /**
492  * Alias of types
493  */
494 class TypeAlias : Symbol {
495 	Type type;
496 
497 	this(Location location, Name name, Type type) {
498 		super(location, name);
499 
500 		this.type = type;
501 	}
502 }
503 
504 /**
505  * Alias of values
506  */
507 class ValueAlias : ValueSymbol {
508 	CompileTimeExpression value;
509 
510 	this(Location location, Name name, CompileTimeExpression value) {
511 		super(location, name);
512 
513 		this.value = value;
514 	}
515 }
516 
517 /**
518  * Struct
519  */
520 class Struct : Aggregate {
521 	this(Location location, Scope parentScope, Name name, Symbol[] members) {
522 		super(location, parentScope, name, members);
523 	}
524 
525 	// XXX: std.bitmanip should really offer the possibility to create bitfield
526 	// out of unused bits of existing bitfields.
527 	@property
528 	bool hasIndirection() const in {
529 		assert(step >= Step.Signed,
530 		       "Struct need to be signed to use hasIndirection");
531 	} do {
532 		return !!(derived & 0x01);
533 	}
534 
535 	@property
536 	bool hasIndirection(bool hasIndirection) {
537 		if (hasIndirection) {
538 			derived = derived | 0x01;
539 		} else {
540 			derived = derived & ~0x01;
541 		}
542 
543 		return hasIndirection;
544 	}
545 
546 	@property
547 	bool isPod() const in {
548 		assert(step >= Step.Signed, "Struct need to be signed to use isPod");
549 	} do {
550 		return !!(derived & 0x02);
551 	}
552 
553 	@property
554 	bool isPod(bool isPod) {
555 		if (isPod) {
556 			derived = derived | 0x02;
557 		} else {
558 			derived = derived & ~0x02;
559 		}
560 
561 		return isPod;
562 	}
563 
564 	@property
565 	bool isSmall() const in {
566 		assert(step >= Step.Signed, "Struct need to be signed to use isSmall");
567 	} do {
568 		return !!(derived & 0x04);
569 	}
570 
571 	@property
572 	bool isSmall(bool isSmall) {
573 		if (isSmall) {
574 			derived = derived | 0x04;
575 		} else {
576 			derived = derived & ~0x04;
577 		}
578 
579 		return isSmall;
580 	}
581 }
582 
583 /**
584  * Union
585  */
586 class Union : Aggregate {
587 	this(Location location, Scope parentScope, Name name, Symbol[] members) {
588 		super(location, parentScope, name, members);
589 	}
590 
591 	@property
592 		hasIndirection() const in {
593 		assert(step >= Step.Signed,
594 		       "Union need to be signed to use hasIndirection");
595 	} do {
596 		return !!derived;
597 	}
598 
599 	@property
600 		hasIndirection(bool hasIndirection) {
601 		derived = hasIndirection;
602 		return hasIndirection;
603 	}
604 }
605 
606 /**
607  * Class
608  */
609 class Class : Aggregate {
610 	Class base;
611 	Interface[] interfaces;
612 
613 	this(Location location, Scope parentScope, Name name, Symbol[] members) {
614 		super(location, parentScope, name, members);
615 
616 		this.name = name;
617 	}
618 }
619 
620 /**
621  * Interface
622  */
623 class Interface : Aggregate {
624 	Interface[] bases;
625 
626 	this(Location location, Scope parentScope, Name name, Interface[] bases,
627 	     Symbol[] members) {
628 		super(location, parentScope, name, members);
629 		this.bases = bases;
630 	}
631 }
632 
633 /**
634  * Enum
635  */
636 class Enum : ScopeSymbol {
637 	Type type;
638 	Variable[] entries;
639 
640 	this(Location location, Scope parentScope, Name name, Type type,
641 	     Variable[] entries) {
642 		super(location, parentScope, name);
643 
644 		this.type = type;
645 		this.entries = entries;
646 	}
647 }
648 
649 /**
650  * Virtual method
651  * Simply a function declaration with its index in the vtable.
652  */
653 class Method : Function {
654 	uint index;
655 
656 	this(Location location, Scope parentScope, uint index, FunctionType type,
657 	     Name name, Variable[] params) {
658 		super(location, parentScope, type, name, params);
659 
660 		this.index = index;
661 	}
662 }