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 /// The Cursor this Token corresponds to. 99 @property Cursor cursor() { 100 auto c = Cursor.empty; 101 clang_annotateTokens(translationUnit, ctok, 1, &c.cx); 102 return c; 103 } 104 } 105 106 struct TokenRange { 107 private static struct Container { 108 CXTranslationUnit translationUnit; 109 CXToken* tokens; 110 uint numTokens; 111 112 ~this() { 113 if (tokens != null) { 114 clang_disposeTokens(translationUnit, tokens, numTokens); 115 } 116 } 117 } 118 119 private RefCounted!(Container) container; 120 private size_t begin; 121 private size_t end; 122 123 private static RefCounted!(Container) makeContainer( 124 CXTranslationUnit translationUnit, CXToken* tokens, uint numTokens) { 125 RefCounted!(Container) result; 126 result.translationUnit = translationUnit; 127 result.tokens = tokens; 128 result.numTokens = numTokens; 129 return result; 130 } 131 132 private this(RefCounted!(Container) container, size_t begin, size_t end) { 133 this.container = container; 134 this.begin = begin; 135 this.end = end; 136 } 137 138 this(CXTranslationUnit translationUnit, CXToken* tokens, uint numTokens) { 139 container = makeContainer(translationUnit, tokens, numTokens); 140 begin = 0; 141 end = numTokens; 142 } 143 144 @property bool empty() const { 145 return begin >= end; 146 } 147 148 @property Token front() const { 149 return Token(container.translationUnit, container.tokens[begin]); 150 } 151 152 @property Token back() const { 153 return Token(container.translationUnit, container.tokens[end - 1]); 154 } 155 156 @property void popFront() { 157 ++begin; 158 } 159 160 @property void popBack() { 161 --end; 162 } 163 164 @property TokenRange save() { 165 return this; 166 } 167 168 @property size_t length() const { 169 assert(begin <= end); 170 return end - begin; 171 } 172 173 Token opIndex(size_t index) const { 174 assert(begin + index < end); 175 return Token(container.translationUnit, container.tokens[begin + index]); 176 } 177 178 TokenRange opSlice(size_t begin, size_t end) { 179 assert(this.begin + begin <= this.end); 180 assert(this.begin + end <= this.end); 181 return TokenRange(container, this.begin + begin, this.begin + end); 182 } 183 184 size_t opDollar() const { 185 return length; 186 } 187 }