+: cell-bytes ( -- n )
+ cell-bits 8 /i ; inline
+
+: get-tokens ( tokens ntokens -- tokens )
+ <iota> cell-bytes '[
+ _ * swap <displaced-alien>
+ clang_getTokenKind
+ ] with { } map-as ;
+
+: clang-get-file-max-range ( CXTranslationUnit path -- CXSourceRange )
+ [ dupd clang_getFile 0 clang_getLocationForOffset ]
+ [ dupd [ clang_getFile ] [ nip file-info size>> ] 2bi clang_getLocationForOffset ] 2bi
+ clang_getRange ;
+
+: clang-tokenize ( CXTranslationUnit CXSourceRange -- tokens ntokens )
+ f void* <ref>
+ 0 uint <ref>
+ [ clang_tokenize ] 2keep
+ [ void* deref ]
+ [ uint deref ] bi* ;
+
+: tokenize-path ( tu path -- tokens ntokens )
+ [ drop ] [ clang-get-file-max-range ] 2bi
+ clang-tokenize ;
+
+: tokenize-translation-unit ( CXTranslationUnit -- tokens ntokens )
+ [ ] [ clang_getTranslationUnitCursor clang_getCursorExtent ] bi
+ clang-tokenize ;
+
+: tokenize-cursor ( cursor -- tokens ntokens )
+ [ clang_Cursor_getTranslationUnit ] [ clang_getCursorExtent ] bi
+ clang-tokenize ;
+
+: dispose-tokens ( cursor tokens ntokens -- )
+ [ clang_Cursor_getTranslationUnit ] 2dip clang_disposeTokens ;
+
+:: with-cursor-tokens ( cursor quot: ( tu token -- obj ) -- )
+ cursor clang_Cursor_getTranslationUnit :> tu
+ cursor tokenize-cursor :> ( tokens ntokens )
+ tokens ntokens <iota>
+ cell-bytes :> bytesize
+ quot
+ '[
+ [ tu ] 2dip bytesize * swap <displaced-alien> @
+ ] with { } map-as
+ tu tokens ntokens dispose-tokens ; inline
+
+: clang-get-token-spelling ( CXTranslationUnit CXToken -- string )
+ clang_getTokenSpelling clang-get-cstring ;
+