1 ! Copyright (C) 2022 Doug Coleman.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.c-types alien.data alien.enums
4 alien.strings ascii byte-arrays classes.struct combinators
5 combinators.smart discord io io.backend io.encodings.utf8
6 io.files.info kernel layouts libc libclang.ffi make math
7 sequences sequences.private splitting strings ;
14 { marked-offset uint } ;
16 : <malloced> ( len -- malloced )
17 malloced malloc-struct
18 over 1 + <byte-array> malloc-byte-array >>byte-array
23 : mark-malloced ( malloced -- malloced )
24 dup offset>> >>marked-offset ;
26 : since-reset ( malloced -- string )
27 [ marked-offset>> ] [ byte-array>> ] bi
28 <displaced-alien> utf8 alien>string ;
30 : reset-malloced ( malloced -- malloced string )
32 [ dup marked-offset>> >>offset ] bi swap ;
34 : malloced-string ( malloced -- string )
35 byte-array>> utf8 alien>string ;
37 : append-oom? ( malloced string -- ? )
38 [ [ len>> ] [ offset>> ] bi - ]
41 : realloc-malloced ( malloced -- malloced' )
43 '[ [ _ 1 + realloc ] change-byte-array ] keep >>len ;
45 : append-malloced ( malloced string -- malloced )
47 [ [ realloc-malloced ] dip append-malloced ] [
50 [ offset>> ] [ byte-array>> ] bi <displaced-alien>
51 ] dip [ utf8 string>alien ] [ length ] bi memcpy
53 '[ _ length + ] change-offset
57 : malloced>string ( malloced -- string )
58 [ byte-array>> utf8 alien>string ] [ free ] bi ;
60 : clang-get-cstring ( CXString -- string )
61 clang_getCString [ utf8 alien>string ] [ clang_disposeString ] bi ;
63 : trim-blanks ( string -- string' )
64 [ blank? ] trim ; inline
66 : cut-tail ( string quot -- before after ) (trim-tail) cut ; inline
68 : cursor-type ( cursor -- string )
70 clang_getTypeSpelling clang-get-cstring
74 [ CHAR: * = ] cut-tail
75 [ [ trim-blanks ] dip append ] when*
79 { [ dup "_Bool" = ] [ drop "bool" ] }
80 { [ dup "unsigned char" = ] [ drop "uchar" ] }
81 { [ "unsigned char" ?head ] [ trim-blanks "uchar" prepend ] }
82 { [ "unsigned int" ?head ] [ trim-blanks "uint" prepend ] }
83 { [ "unsigned short" ?head ] [ trim-blanks "ushort" prepend ] }
84 { [ dup "(*)" swap subseq? ] [ drop "void*" ] }
88 : cursor-name ( cursor -- string )
89 clang_getCursorSpelling clang-get-cstring ;
91 : arg-info ( cursor -- string )
92 [ cursor-type ] [ cursor-name [ "dummy" ] when-empty ] bi " " glue ;
94 : cursor>args ( CXCursor -- args/f )
95 dup clang_Cursor_getNumArguments dup -1 = [
99 clang_Cursor_getArgument
103 : cxprimitive-type>factor ( CXType -- string )
105 { CXType_Bool [ "bool" ] }
106 { CXType_Char_S [ "char" ] }
107 { CXType_Char_U [ "uchar" ] }
108 { CXType_SChar [ "char" ] }
109 { CXType_UChar [ "uchar" ] }
110 { CXType_Short [ "short" ] }
111 { CXType_UShort [ "ushort" ] }
112 { CXType_Int [ "int" ] }
113 { CXType_UInt [ "uint" ] }
114 { CXType_Long [ "long" ] }
115 { CXType_ULong [ "ulong" ] }
116 { CXType_LongLong [ "longlong" ] }
117 { CXType_ULongLong [ "ulonglong" ] }
118 { CXType_Float [ "float" ] }
119 { CXType_Double [ "double" ] }
120 { CXType_Void [ "void" ] }
124 : cxreturn-type>factor ( CXType -- string )
126 { [ dup kind>> CXType_Pointer = ] [
127 clang_getPointeeType dup g... gflush cxreturn-type>factor "*" append
129 { [ dup kind>> CXType_Elaborated = ] [
130 clang_getCanonicalType cxreturn-type>factor
132 { [ dup kind>> CXType_Record = ] [
133 clang_getTypeDeclaration cursor-name
135 { [ dup kind>> CXType_FunctionProto = ] [
136 ! inside a CXType_Pointer, so we get `void*` from that case
139 [ kind>> cxprimitive-type>factor ]
142 : cursor>args-info ( CXCursor -- args-info )
143 cursor>args [ arg-info ] map ", " join ;
145 : function>string ( CXCursor -- string )
148 [ drop "FUNCTION: " ]
149 [ clang_getCursorResultType cxreturn-type>factor ]
153 [ cursor>args-info dup empty? ")\n" " )\n" ? ]
155 ] "" append-outputs-as ;
157 : typedef>string ( CXCursor -- string )
158 [ clang_getTypedefDeclUnderlyingType cxreturn-type>factor ]
163 " " glue "TYPEDEF: " "\n" surround
167 : field-visitor ( -- callback )
170 malloced memory>struct
171 swap dup clang_getCursorKind
173 { CXCursor_FieldDecl [
174 [ cursor-name ] [ cursor-type ] bi " " glue
175 "\n { " " }" surround
177 CXChildVisit_Continue
179 ! { CXCursor_TypedefDecl [ 2drop CXChildVisit_Continue ] }
180 ! { CXCursor_StructDecl [ 2drop CXChildVisit_Continue ] }
181 [ dup g... 3drop CXChildVisit_Recurse ]
186 : enum-visitor ( -- callback )
189 malloced memory>struct
190 swap dup clang_getCursorKind
192 { CXCursor_EnumConstantDecl [
194 cursor-name g... gflush
196 CXChildVisit_Continue
198 { CXCursor_IntegerLiteral [
200 cursor-name g... gflush
202 CXChildVisit_Continue
204 [ 3drop CXChildVisit_Recurse ]
209 : struct>string ( malloced CXCursor -- )
210 [ mark-malloced ] dip
211 tuck cursor-name append-malloced
212 [ field-visitor ] dip
213 [ clang_visitChildren drop ] keep
214 ! hack to removev typedefs like `typedef struct foo foo;`
215 dup malloced-string "}" tail? [
216 reset-malloced "STRUCT: " " ;\n" surround
219 reset-malloced "C-TYPE: " "\n" surround
223 : enum>string ( malloced CXCursor -- )
224 [ mark-malloced ] dip
225 tuck cursor-name "ENUM: " prepend append-malloced
227 [ clang_visitChildren drop ] keep
230 : cursor-visitor ( -- callback )
233 malloced memory>struct
234 swap dup clang_getCursorKind
237 { CXCursor_Namespace [ 2drop CXChildVisit_Recurse ] }
238 { CXCursor_FunctionDecl [ function>string append-malloced drop CXChildVisit_Continue ] }
239 { CXCursor_TypedefDecl [ typedef>string append-malloced drop CXChildVisit_Continue ] }
240 { CXCursor_StructDecl [ struct>string CXChildVisit_Continue ] }
241 { CXCursor_EnumDecl [ enum>string CXChildVisit_Continue ] }
242 [ dup g... 3drop CXChildVisit_Recurse ]
247 : with-clang-index ( quot: ( index -- string ) -- )
248 [ 0 0 clang_createIndex ] dip keep clang_disposeIndex ; inline
250 : with-clang-translation-unit ( idx source-file command-line-args nargs unsaved-files nunsaved-files options quot: ( tu -- string ) -- )
251 [ enum>number clang_parseTranslationUnit ] dip
252 keep clang_disposeTranslationUnit ; inline
254 : with-clang-default-translation-unit ( path quot: ( tu path -- string ) -- )
256 _ f 0 f 0 CXTranslationUnit_None [
258 ] with-clang-translation-unit
259 ] with-clang-index ; inline
261 : with-clang-cursor ( path quot: ( tu path cursor -- string ) -- )
263 _ f 0 f 0 CXTranslationUnit_None [
264 _ over clang_getTranslationUnitCursor @
265 ] with-clang-translation-unit
266 ] with-clang-index ; inline
268 : clang-get-file-max-range ( CXTranslationUnit path -- CXSourceRange )
269 [ dupd clang_getFile 0 clang_getLocationForOffset ]
270 [ dupd [ clang_getFile ] [ nip file-info size>> ] 2bi clang_getLocationForOffset ] 2bi
273 : clang-tokenize ( CXTranslationUnit CXSourceRange -- tokens ntokens )
276 [ clang_tokenize ] 2keep
280 : tokenize-path ( tu path -- tokens ntokens )
281 [ drop ] [ clang-get-file-max-range ] 2bi
284 : tokenize-translation-unit ( CXTranslationUnit -- tokens ntokens )
285 [ ] [ clang_getTranslationUnitCursor clang_getCursorExtent ] bi
288 : tokenize-cursor ( cursor -- tokens ntokens )
289 [ clang_Cursor_getTranslationUnit ] [ clang_getCursorExtent ] bi
292 : clang-get-token-spelling ( CXTranslationUnit CXToken -- string )
293 clang_getTokenSpelling clang-get-cstring ;
295 : parse-c-defines ( path -- string )
300 cell-bits 8 /i * swap <displaced-alien>
303 ] with-clang-default-translation-unit ;
305 : parse-c-exports ( path -- string )
307 nipd cursor-visitor rot file-info size>> 2 * <malloced>
308 [ clang_visitChildren drop ] keep malloced>string
309 ] with-clang-cursor ;
311 : parse-include ( path -- string )
314 ! [ parse-c-defines ]
318 ! "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/php/ext/sqlite3/libsqlite/sqlite3.h" parse-include
320 ! "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include"