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