1 module d.parser.identifier;
2 
3 import d.ast.identifier;
4 import d.ast.expression;
5 import d.ast.type;
6 
7 import d.parser.base;
8 import d.parser.dtemplate;
9 
10 /**
11  * Parse Identifier
12  */
13 Identifier parseIdentifier(ref TokenRange trange) {
14 	auto location = trange.front.location;
15 	
16 	auto name = trange.front.name;
17 	trange.match(TokenType.Identifier);
18 	
19 	return trange.parseBuiltIdentifier(new BasicIdentifier(location, name));
20 }
21 
22 /**
23  * Parse dotted identifier (.identifier)
24  */
25 Identifier parseDotIdentifier(ref TokenRange trange) {
26 	auto location = trange.front.location;
27 	trange.match(TokenType.Dot);
28 	
29 	location.spanTo(trange.front.location);
30 	
31 	auto name = trange.front.name;
32 	trange.match(TokenType.Identifier);
33 	
34 	return trange.parseBuiltIdentifier(new DotIdentifier(location, name));
35 }
36 
37 /**
38  * Parse any qualifier identifier (qualifier.identifier)
39  */
40 auto parseQualifiedIdentifier(Namespace)(
41 	ref TokenRange trange,
42 	Location location,
43 	Namespace ns,
44 ) {
45 	auto name = trange.front.name;
46 	location.spanTo(trange.front.location);
47 	trange.match(TokenType.Identifier);
48 	
49 	static if (is(Namespace : Identifier)) {
50 		alias QualifiedIdentifier = IdentifierDotIdentifier;
51 	} else static if (is(Namespace : AstType)) {
52 		alias QualifiedIdentifier = TypeDotIdentifier;
53 	} else static if (is(Namespace : AstExpression)) {
54 		alias QualifiedIdentifier = ExpressionDotIdentifier;
55 	} else {
56 		static assert(
57 			0,
58 			"Namespace can only be an Identifier, a AstType or an Expression."
59 				~ " Not a " ~ Namespace.stringof
60 		);
61 	}
62 	
63 	return trange.parseBuiltIdentifier(
64 		new QualifiedIdentifier(location, name, ns),
65 	);
66 }
67 
68 /**
69  * Parse built identifier
70  */
71 private Identifier parseBuiltIdentifier(
72 	ref TokenRange trange,
73 	Identifier identifier,
74 ) {
75 	auto location = identifier.location;
76 	while (true) {
77 		switch (trange.front.type) with(TokenType) {
78 			case Dot:
79 				trange.popFront();
80 				auto name = trange.front.name;
81 				
82 				location.spanTo(trange.front.location);
83 				trange.match(Identifier);
84 				
85 				identifier = new IdentifierDotIdentifier(
86 					location,
87 					name,
88 					identifier,
89 				);
90 				break;
91 			
92 			case Bang:
93 				auto lookahead = trange.getLookahead();
94 				lookahead.popFront();
95 				if (lookahead.front.type == Is || lookahead.front.type == In) {
96 					return identifier;
97 				}
98 				
99 				trange.popFront();
100 				auto arguments = parseTemplateArguments(trange);
101 				
102 				location.spanTo(trange.previous);
103 				
104 				identifier = new TemplateInstantiation(
105 					location,
106 					identifier,
107 					arguments,
108 				);
109 				break;
110 			
111 			default:
112 				return identifier;
113 		}
114 	}
115 }