1 // Written in the D programming language. 2 /** 3 * Copyright: Copyright (c) 2015, Joakim Brännström. All rights reserved. 4 * Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 * 6 * Only kept utility functionality and comments of the original implementation. 7 * The rest is synchronized with Token.d in DStep. 8 * 9 * Copyright: Copyright (c) 2016 Wojciech Szęszoł. All rights reserved. 10 * Authors: Wojciech Szęszoł 11 * Version: Initial created: Feb 14, 2016 12 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 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 struct Token { 55 private struct Container { 56 CXTranslationUnit translationUnit; 57 CXToken* tokens; 58 ulong numTokens; 59 60 ~this() { 61 if (tokens != null) { 62 clang_disposeTokens(translationUnit, tokens, to!uint(numTokens)); 63 } 64 } 65 } 66 67 private const RefCounted!Container container; 68 size_t index; 69 70 @property private Container* containerPtr() return const { 71 return cast(Container*)&(container.refCountedPayload()); 72 } 73 74 @property static Cursor empty() { 75 //TODO why is this function needed, remove? 76 auto r = clang_getNullCursor(); 77 return Cursor(r); 78 } 79 80 /// Obtain the TokenKind of the current token. 81 @property CXTokenKind kind() const { 82 return clang_getTokenKind(containerPtr.tokens[index]); 83 } 84 85 /** The spelling of this token. 86 * 87 * This is the textual representation of the token in source. 88 */ 89 @property string spelling() const { 90 auto r = clang_getTokenSpelling(containerPtr.translationUnit, containerPtr.tokens[index]); 91 return toD(r); 92 } 93 94 /// The SourceLocation this Token occurs at. 95 @property SourceLocation location() const { 96 auto r = clang_getTokenLocation(containerPtr.translationUnit, containerPtr.tokens[index]); 97 return SourceLocation(r); 98 } 99 100 /// The SourceRange this Token occupies. 101 @property SourceRange extent() const { 102 auto r = clang_getTokenExtent(containerPtr.translationUnit, containerPtr.tokens[index]); 103 return SourceRange(r); 104 } 105 106 /// The Cursor this Token corresponds to. 107 @property Cursor cursor() { 108 Cursor c = empty; 109 clang_annotateTokens(containerPtr.translationUnit, &containerPtr.tokens[index], 1, &c.cx); 110 111 return c; 112 } 113 } 114 115 struct TokenRange { 116 private const RefCounted!(Token.Container) container; 117 private size_t begin; 118 private size_t end; 119 120 private static RefCounted!(Token.Container) makeContainer( 121 CXTranslationUnit translationUnit, CXToken* tokens, ulong numTokens) { 122 RefCounted!(Token.Container) result; 123 result.translationUnit = translationUnit; 124 result.tokens = tokens; 125 result.numTokens = numTokens; 126 return result; 127 } 128 129 private this(const RefCounted!(Token.Container) container, size_t begin, size_t end) { 130 this.container = container; 131 this.begin = begin; 132 this.end = end; 133 } 134 135 this(CXTranslationUnit translationUnit, CXToken* tokens, ulong numTokens) { 136 container = makeContainer(translationUnit, tokens, numTokens); 137 begin = 0; 138 end = numTokens; 139 } 140 141 @property bool empty() const { 142 return begin >= end; 143 } 144 145 @property Token front() const { 146 return Token(container, begin); 147 } 148 149 @property Token back() const { 150 return Token(container, end - 1); 151 } 152 153 @property void popFront() { 154 ++begin; 155 } 156 157 @property void popBack() { 158 --end; 159 } 160 161 @property TokenRange save() const { 162 return this; 163 } 164 165 @property size_t length() const { 166 return end - begin; 167 } 168 169 Token opIndex(size_t index) const { 170 return Token(container, begin + index); 171 } 172 173 TokenRange opSlice(size_t begin, size_t end) const { 174 return TokenRange(container, this.begin + begin, this.begin + end); 175 } 176 177 size_t opDollar() const { 178 return length; 179 } 180 }