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) {}