1 /**
2  * This file is part of DCD, a development tool for the D programming language.
3  * Copyright (C) 2014 Brian Schott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 module dsymbol.conversion;
20 
21 import dsymbol.cache_entry;
22 import dsymbol.conversion.first;
23 import dsymbol.conversion.second;
24 import dsymbol.modulecache;
25 import dsymbol.scope_;
26 import dsymbol.string_interning;
27 import dsymbol.symbol;
28 import dsymbol.semantic;
29 import dparse.ast;
30 import dparse.lexer;
31 import dparse.parser;
32 import dparse.rollback_allocator;
33 import stdx.allocator;
34 import std.functional;
35 import std.typecons;
36 
37 /**
38  * Used by autocompletion.
39  */
40 ScopeSymbolPair generateAutocompleteTrees(const(Token)[] tokens,
41 	IAllocator symbolAllocator, RollbackAllocator* parseAllocator,
42 	size_t cursorPosition, ref ModuleCache cache)
43 {
44 	Module m = parseModuleForAutocomplete(tokens, internString("stdin"),
45 		parseAllocator, cursorPosition);
46 
47 	auto first = scoped!FirstPass(m, internString("stdin"), symbolAllocator,
48 		symbolAllocator, true, &cache);
49 	first.run();
50 
51 	secondPass(first.rootSymbol, first.moduleScope, cache);
52 	auto r = first.rootSymbol.acSymbol;
53 	typeid(SemanticSymbol).destroy(first.rootSymbol);
54 	return ScopeSymbolPair(r, first.moduleScope);
55 }
56 
57 struct ScopeSymbolPair
58 {
59 	void destroy()
60 	{
61 		typeid(DSymbol).destroy(symbol);
62 		typeid(Scope).destroy(scope_);
63 	}
64 
65 	DSymbol* symbol;
66 	Scope* scope_;
67 }
68 
69 /**
70  * Used by import symbol caching.
71  *
72  * Params:
73  *     tokens = the tokens that compose the file
74  *     fileName = the name of the file being parsed
75  *     parseAllocator = the allocator to use for the AST
76  * Returns: the parsed module
77  */
78 Module parseModuleSimple(const(Token)[] tokens, string fileName, RollbackAllocator* parseAllocator)
79 {
80 	assert (parseAllocator !is null);
81 	auto parser = scoped!SimpleParser();
82 	parser.fileName = fileName;
83 	parser.tokens = tokens;
84 	parser.messageDg = toDelegate(&doesNothing);
85 	parser.allocator = parseAllocator;
86 	return parser.parseModule();
87 }
88 
89 private:
90 
91 Module parseModuleForAutocomplete(const(Token)[] tokens, string fileName,
92 	RollbackAllocator* parseAllocator, size_t cursorPosition)
93 {
94 	auto parser = scoped!AutocompleteParser();
95 	parser.fileName = fileName;
96 	parser.tokens = tokens;
97 	parser.messageDg = toDelegate(&doesNothing);
98 	parser.allocator = parseAllocator;
99 	parser.cursorPosition = cursorPosition;
100 	return parser.parseModule();
101 }
102 
103 class AutocompleteParser : Parser
104 {
105 	override BlockStatement parseBlockStatement()
106 	{
107 		if (current.index > cursorPosition)
108 		{
109 			BlockStatement bs = allocator.make!(BlockStatement);
110 			bs.startLocation = current.index;
111 			skipBraces();
112 			bs.endLocation = tokens[index - 1].index;
113 			return bs;
114 		}
115 		immutable start = current.index;
116 		auto b = setBookmark();
117 		skipBraces();
118 		if (tokens[index - 1].index < cursorPosition)
119 		{
120 			abandonBookmark(b);
121 			BlockStatement bs = allocator.make!BlockStatement();
122 			bs.startLocation = start;
123 			bs.endLocation = tokens[index - 1].index;
124 			return bs;
125 		}
126 		else
127 		{
128 			goToBookmark(b);
129 			return super.parseBlockStatement();
130 		}
131 	}
132 
133 private:
134 	size_t cursorPosition;
135 }
136 
137 class SimpleParser : Parser
138 {
139 	override Unittest parseUnittest()
140 	{
141 		expect(tok!"unittest");
142 		if (currentIs(tok!"{"))
143 			skipBraces();
144 		return null;
145 	}
146 
147 	override FunctionBody parseFunctionBody()
148 	{
149 		if (currentIs(tok!";"))
150 			advance();
151 		else if (currentIs(tok!"{"))
152 			skipBraces();
153 		else
154 		{
155 			if (currentIs(tok!"in"))
156 			{
157 				advance();
158 				if (currentIs(tok!"{"))
159 					skipBraces();
160 				if (currentIs(tok!"out"))
161 				{
162 					advance();
163 					if (currentIs(tok!"("))
164 						skipParens();
165 					if (currentIs(tok!"{"))
166 						skipBraces();
167 				}
168 			}
169 			else if (currentIs(tok!"out"))
170 			{
171 				advance();
172 				if (currentIs(tok!"("))
173 					skipParens();
174 				if (currentIs(tok!"{"))
175 					skipBraces();
176 				if (currentIs(tok!"in"))
177 				{
178 					advance();
179 					if (currentIs(tok!"{"))
180 						skipBraces();
181 				}
182 			}
183 			expect(tok!"body");
184 			if (currentIs(tok!"{"))
185 				skipBraces();
186 		}
187 		return allocator.make!FunctionBody();
188 	}
189 }
190 
191 void doesNothing(string, size_t, size_t, string, bool) {}