Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Lua binding for libclang, the Clang compiler API to access the AST of C/C++ source files
C++ Lua
Branch: master

Merge pull request #3 from justincormack/master

merge of version that works with Ubuntu llvm 3.1 PPA
latest commit e583bf4193
@mkottman authored

README.md

luaclang-parser

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! :)

Requirements

  • 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.

Building

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.

Overview

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 together
  • TranslationUnit - represents a source file
  • Cursor - represents an element in the AST in a translation unit
  • Type - the type of an element (variable, field, parameter, return type)

Examples

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

Reference

luaclang-parser

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-compiled TranslationUnits.

Index

  • Index:parse([sourceFile : string,] args : table) -> TranslationUnit

    Binding for clang_parseTranslationUnit. This will parse a given source file sourceFile with the command line arguments args, which would be given to the compiler for compilation, i.e. include paths, defines. If only the args table is given, the source file is expected to be included in args.

  • 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

  • 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 of fileName.

  • 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 the CXCompletionChunk_ prefix. If there are any annotations, the annotations key is a table of strings:

    completion = {
         priority = number, priority of given completion
         chunks = {
             kind = string, chunk kind
             text = string, chunk text
         },
         [annotations = { string* }]
    }
    

Cursor

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() -> 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 for Cursor 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 Cursors 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 or nil 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.

Type

You can compare whether two Types 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, or nil.

License

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.

Something went wrong with that request. Please try again.