1 // Written in the D programming language. 2 /** 3 * Copyright: Copyright (c) 2015-2018, Joakim Brännström. All rights reserved. 4 * Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 * 6 * Copyright: Copyright (c) 2016 Wojciech Szęszoł. All rights reserved. 7 * Authors: Wojciech Szęszoł 8 * Version: Initial created: Feb 14, 2016 9 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 10 * 11 * Only kept utility functionality and comments of the original implementation. 12 * The rest is synchronized with Token.d in DStep. 13 */ 14 module clang.Token; 15 16 import std.conv : to; 17 import std.typecons; 18 19 import clang.c.Index; 20 21 import clang.Cursor; 22 import clang.SourceLocation; 23 import clang.SourceRange; 24 import clang.TranslationUnit; 25 import clang.Util; 26 import clang.Visitor; 27 28 @property auto toString(Token tok) { 29 import std.format : format; 30 31 return format("%s [%s %s]", tok.spelling, tok.kind, to!string(tok.cursor.cx),); 32 } 33 34 @property auto toString(ref TokenRange toks) { 35 import std..string; 36 37 string s; 38 39 foreach (t; toks) { 40 s ~= t.spelling ~ " "; 41 } 42 43 return s.strip; 44 } 45 46 /** Represents a single token from the preprocessor. 47 * 48 * Tokens are effectively segments of source code. Source code is first parsed 49 * into tokens before being converted into the AST and Cursors. 50 * 51 * Tokens are obtained from parsed TranslationUnit instances. You currently 52 * can't create tokens manually. 53 * 54 * To keep the tokens efficient they are pointers into the range of tokens 55 * derived from clang. This mean that the lifetime of a token is coupled to the 56 * range. 57 */ 58 struct Token { 59 private { 60 CXTranslationUnit translationUnit; 61 CXToken* ctok; 62 } 63 64 this(ref const CXTranslationUnit tu, ref const CXToken t) { 65 this.translationUnit = cast(CXTranslationUnit)(tu); 66 this.ctok = cast(CXToken*)(&t); 67 } 68 69 /// Obtain the TokenKind of the current token. 70 @property CXTokenKind kind() const { 71 return clang_getTokenKind(cast(CXToken)(*ctok)); 72 } 73 74 /** The spelling of this token. 75 * 76 * This is the textual representation of the token in source. 77 */ 78 @property string spelling() const { 79 auto r = clang_getTokenSpelling(cast(CXTranslationUnit)(translationUnit), 80 cast(CXToken)(*ctok)); 81 return toD(r); 82 } 83 84 /// The SourceLocation this Token occurs at. 85 @property SourceLocation location() const { 86 auto r = clang_getTokenLocation(cast(CXTranslationUnit)(translationUnit), 87 cast(CXToken)(*ctok)); 88 return SourceLocation(r); 89 } 90 91 /// The SourceRange this Token occupies. 92 @property SourceRange extent() const { 93 auto r = clang_getTokenExtent(cast(CXTranslationUnit)(translationUnit), 94 cast(CXToken)(*ctok)); 95 return SourceRange(r); 96 } 97 98 // TODO: maybe this should be remove. If so then it would be possible to 99 // remove translationUnit and thus make this struct lighter. 100 /// The Cursor this Token corresponds to. 101 @property Cursor cursor() { 102 auto c = Cursor.empty; 103 clang_annotateTokens(translationUnit, ctok, 1, &c.cx); 104 return c; 105 } 106 } 107 108 struct TokenRange { 109 private static struct Container { 110 CXTranslationUnit translationUnit; 111 CXToken* tokens; 112 uint numTokens; 113 114 ~this() { 115 if (tokens != null) { 116 clang_disposeTokens(translationUnit, tokens, numTokens); 117 } 118 } 119 } 120 121 private RefCounted!(Container) container; 122 private size_t begin; 123 private size_t end; 124 125 private static RefCounted!(Container) makeContainer( 126 CXTranslationUnit translationUnit, CXToken* tokens, uint numTokens) { 127 RefCounted!(Container) result; 128 result.translationUnit = translationUnit; 129 result.tokens = tokens; 130 result.numTokens = numTokens; 131 return result; 132 } 133 134 private this(RefCounted!(Container) container, size_t begin, size_t end) { 135 this.container = container; 136 this.begin = begin; 137 this.end = end; 138 } 139 140 this(CXTranslationUnit translationUnit, CXToken* tokens, uint numTokens) { 141 container = makeContainer(translationUnit, tokens, numTokens); 142 begin = 0; 143 end = numTokens; 144 } 145 146 @property bool empty() const { 147 return begin >= end; 148 } 149 150 @property Token front() const { 151 return Token(container.translationUnit, container.tokens[begin]); 152 } 153 154 @property Token back() const { 155 return Token(container.translationUnit, container.tokens[end - 1]); 156 } 157 158 @property void popFront() { 159 ++begin; 160 } 161 162 @property void popBack() { 163 --end; 164 } 165 166 @property TokenRange save() { 167 return this; 168 } 169 170 @property size_t length() const { 171 assert(begin <= end); 172 return end - begin; 173 } 174 175 Token opIndex(size_t index) const { 176 assert(begin + index < end); 177 return Token(container.translationUnit, container.tokens[begin + index]); 178 } 179 180 TokenRange opSlice(size_t begin, size_t end) { 181 assert(this.begin + begin <= this.end); 182 assert(this.begin + end <= this.end); 183 return TokenRange(container, this.begin + begin, this.begin + end); 184 } 185 186 size_t opDollar() const { 187 return length; 188 } 189 }