A Lua binding to the libclang
library, which allows you to parse C and C++ code using the Clang compiler.
luaclang-parser
provides an object-oriented interface over the libclang
API. As of right now, a meaningful subset of libclang
API is available, allowing you to write C/C++ header parsers, file diagnostics (warnings, errors) and code completion.
No more error-prone hand-written header/documentation parsers, yay! :)
- Lua 5.1
- LLVM/Clang - read the getting started guide to find out how to obtain Clang from source.
libclang
is built and installed along with Clang compiler.
luaclang-parser
uses CMake to find your Lua installation and libclang
. The preferred way to build the module is this:
luaclang-parser$ mkdir build; cd build
luaclang-parser/build$ cmake ..
luaclang-parser/build$ make
The example uses this directory layout to find the luaclang-parser
without the need to install it system-wide.
libclang
provides a cursor-based API to the abstract syntax tree (AST) of the C/C++ source files. This means that you can see what the compiler sees. These are the main classes used in libclang
/luaclang-parser
:
Index
- represents a set of translation units that could be linked togetherTranslationUnit
- represents a source fileCursor
- represents an element in the AST in a translation unitType
- the type of an element (variable, field, parameter, return type)
A simple code browser demonstrating the abilities of luaclang-parser
is provided in cindex.lua
. It takes command line arguments as the Clang compiler would and passes them to TranslationUnit:parse(args)
(see below). Then it processes the headers and gathers information about classes, methods, functions and their argument, and saves this information into a SQLite3 database code.db
with the following schema:
CREATE TABLE args (ismethod, parent, name, idx, type, const, defval);
CREATE TABLE classes (module, name, parent);
CREATE TABLE functions (module, name, result, signature);
CREATE TABLE methods (class, name, kind, access, result, signature, static, virtual, signal, slot);
References between arguments, functions/methods and classes are done through the SQLite row identifier. For example to construct the database for libclang
, run the following command:
lua cindex.lua /usr/local/include/clang-c/Index.h
You can then query the functions using SQL, for example to gather all functions which take CXCursor
as the first argument:
SELECT *
FROM functions F
JOIN args A ON A.parent = F.rowid
WHERE A.idx = 1 AND A.type = 'CXCursor'
A sample file allqt.cpp
which takes in most Qt headers is available. Using the qt4-qobjectdefs-injected.h
include file, annotations for signals and slots are injected into QObject, which is recognized by cindex.lua
and it is able to mark methods as either signals or slots. For example to find all classes and their signals, run:
SELECT C.name, M.signature
FROM classes C
JOIN methods M ON M.class = C.rowid
WHERE M.signal = 1
Just for a taste on how big the Qt framework is:
sqlite> SELECT COUNT(*) FROM classes;
1302
sqlite> SELECT COUNT(*) FROM methods;
19612
Use local parser = require "luaclang-parser"
to load the module. It exports one function:
-
createIndex(excludePch : boolean, showDiagnostics : boolean) -> Index
Binding for clang_createIndex. Will create an
Index
into which you can parse or load pre-compiledTranslationUnit
s.
-
Index:parse([sourceFile : string,] args : table) -> TranslationUnit
Binding for clang_parseTranslationUnit. This will parse a given source file
sourceFile
with the command line argumentsargs
, which would be given to the compiler for compilation, i.e. include paths, defines. If only theargs
table is given, the source file is expected to be included inargs
. -
Index:load(astFile : string) -> TranslationUnit
Binding for clang_createTranslationUnit. This will load the translation unit from an AST file which was constructed using
clang -emit-ast
. Useful when repeatedly processing large sets of files (like frameworks).
-
TranslationUnit:cursor() -> Cursor
Binding for clang_getTranslationUnitCursor. Returns the
Cursor
representing a given translation unit, which means you can access to classes and functions defined in a given file. -
TranslationUnit:file(fileName : string) -> string, number
Binding for clang_getFile. Returns the absolute file path and a
time_t
last modification time offileName
. -
TranslationUnit:diagnostics() -> { Diagnostic* }
Binding for clang_getDiagnostic. Returns a table array of
Diagnostic
, which represent warnings and errors. Each diagnostic is a table consisting of these keys:text
- the diagnostic message,category
- a diagnostic category. -
TranslationUnit:codeCompleteAt(file : string, line : number, column : number) -> { Completion* }, { Diagnostics* }
Binding for code completion API. Returns the available code completion options at a given location using prior content. Each
Completion
is a table consisting of several chunks, each of which has a text and a chunk kind without theCXCompletionChunk_
prefix. If there are any annotations, theannotations
key is a table of strings:completion = { priority = number, priority of given completion chunks = { kind = string, chunk kind text = string, chunk text }, [annotations = { string* }] }
You can compare whether two Cursor
s represent the same element using the standard ==
Lua operator.
-
Cursor:children() -> { Cursor * }
Binding over clang_visitChildren. This is the main function for AST traversal. Traverses the direct descendats of a given cursor and collects them in a table. If no child cursors are found, returns an empty table.
-
Cursor:parent() -> Cursor
Binding for clang_getCursorSemanticParent. Returns a cursor to the semantic parent of a given element. For example, for a method cursor, returns its class. For a global declaration, returns the translation unit cursor.
-
Cursor:name() -> string
Binding over clang_getCursorSpelling. Returns the name of the entity referenced by cursor.
__tostring
forCursor
also points to this function. -
Cursor:displayName() -> string
Binding over clang_getCursorDisplayName. Returns the display name of the entity, which for example is a function signature.
-
Cursor:kind() -> string
Returns the cursor kind without the
CXCursor_
prefix, i.e."FunctionDecl"
. -
Cursor:arguments() -> { Cursor* }
Binding of clang_Cursor_getArgument. Returns a table array of
Cursor
s representing arguments of a function or a method. Returns an empty table if a cursor is not a method or function. -
Cursor:resultType() -> Type
Binding for clang_getCursorResultType. For a function or a method cursor, returns the return type of the function.
-
Cursor:type() -> Type
Returns the
Type
of a given element ornil
if not available. -
Cursor:access() -> string
When cursor kind is
"AccessSpecifier"
, returns one of"private"
,"protected"
and"public"
. -
Cursor:location() -> string, number, number, number, number
Binding for clang_getCursorExtent. Returns the file name, starting line, starting column, ending line and ending column of the given cursor. This can be used to look up the text a cursor consists of.
-
Cursor:referenced() -> Cursor
Binding for clang_getCursorReferenced. For a reference type, returns a cursor to the element it references, otherwise returns
nil
. -
Cursor:definition() -> Cursor
Binding for clang_getCursorDefinition. For a reference or declaration, returns a cursor to the definition of the entity, otherwise returns
nil
. -
Cursor:isVirtual() -> boolean
For a C++ method, returns whether the method is virtual.
-
Cursor:isStatic() -> boolean
For a C++ method, returns whether the method is static.
You can compare whether two Type
s represent the same type using the standard ==
Lua operator.
-
Type:name() -> string
Binding of clang_getTypeKindSpelling. Returns one of CXTypeKind as a string without the
CXType_
prefix. Type also has__tostring
set to this method. -
Type:canonical() -> Type
Binding of clang_getCanonicalType. Returns underlying type with all typedefs removed.
-
Type:pointee() -> Type
Binding of clang_getPointeeType. For pointer type returns the type of the pointee.
-
Type:isPod() -> boolean
Binding of clang_isPODTypeReturns true if the type is a "Plain Old Data" type.
-
Type:isConst() -> boolean
Binding of clang_isConstQualifiedType. Returns true if the type has a "const" qualifier.
-
Type:declaration() -> Cursor
Binding of clang_getTypeDeclaration. Returns a
Cursor
to the declaration of a given type, ornil
.
Copyright (c) 2012 Michal Kottman
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.