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 }