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.
libclangis 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) -> IndexBinding for clang_createIndex. Will create an
Indexinto which you can parse or load pre-compiledTranslationUnits.
-
Index:parse([sourceFile : string,] args : table) -> TranslationUnitBinding for clang_parseTranslationUnit. This will parse a given source file
sourceFilewith the command line argumentsargs, which would be given to the compiler for compilation, i.e. include paths, defines. If only theargstable is given, the source file is expected to be included inargs. -
Index:load(astFile : string) -> TranslationUnitBinding 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() -> CursorBinding for clang_getTranslationUnitCursor. Returns the
Cursorrepresenting a given translation unit, which means you can access to classes and functions defined in a given file. -
TranslationUnit:file(fileName : string) -> string, numberBinding for clang_getFile. Returns the absolute file path and a
time_tlast 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
Completionis a table consisting of several chunks, each of which has a text and a chunk kind without theCXCompletionChunk_prefix. If there are any annotations, theannotationskey 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 Cursors 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() -> CursorBinding 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() -> stringBinding over clang_getCursorSpelling. Returns the name of the entity referenced by cursor.
__tostringforCursoralso points to this function. -
Cursor:displayName() -> stringBinding over clang_getCursorDisplayName. Returns the display name of the entity, which for example is a function signature.
-
Cursor:kind() -> stringReturns the cursor kind without the
CXCursor_prefix, i.e."FunctionDecl". -
Cursor:arguments() -> { Cursor* }Binding of clang_Cursor_getArgument. Returns a table array of
Cursors representing arguments of a function or a method. Returns an empty table if a cursor is not a method or function. -
Cursor:resultType() -> TypeBinding for clang_getCursorResultType. For a function or a method cursor, returns the return type of the function.
-
Cursor:type() -> TypeReturns the
Typeof a given element ornilif not available. -
Cursor:access() -> stringWhen cursor kind is
"AccessSpecifier", returns one of"private","protected"and"public". -
Cursor:location() -> string, number, number, number, numberBinding 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() -> CursorBinding for clang_getCursorReferenced. For a reference type, returns a cursor to the element it references, otherwise returns
nil. -
Cursor:definition() -> CursorBinding for clang_getCursorDefinition. For a reference or declaration, returns a cursor to the definition of the entity, otherwise returns
nil. -
Cursor:isVirtual() -> booleanFor a C++ method, returns whether the method is virtual.
-
Cursor:isStatic() -> booleanFor a C++ method, returns whether the method is static.
You can compare whether two Types represent the same type using the standard == Lua operator.
-
Type:name() -> stringBinding of clang_getTypeKindSpelling. Returns one of CXTypeKind as a string without the
CXType_prefix. Type also has__tostringset to this method. -
Type:canonical() -> TypeBinding of clang_getCanonicalType. Returns underlying type with all typedefs removed.
-
Type:pointee() -> TypeBinding of clang_getPointeeType. For pointer type returns the type of the pointee.
-
Type:isPod() -> booleanBinding of clang_isPODTypeReturns true if the type is a "Plain Old Data" type.
-
Type:isConst() -> booleanBinding of clang_isConstQualifiedType. Returns true if the type has a "const" qualifier.
-
Type:declaration() -> CursorBinding of clang_getTypeDeclaration. Returns a
Cursorto 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.