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 }