Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ branches:
before_install:
- sudo apt-get update
- sudo apt-get install --yes gccxml libwt-dev libwthttp-dev libwttest-dev libyaml-dev
- sudo pip install cpp-coveralls
- sudo pip install -U cpp-coveralls
- sudo pip install hererocks
- sudo pip install pygccxml
- sudo pip install pyyaml
Expand Down
189 changes: 108 additions & 81 deletions tools/automate_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
XML_CACHE = 'src/luawt/xml'
INCLUDE_WT = '/usr/include/Wt'

# =============================================================================
# Loading/parsing functions: parse, loadAdditionalChunk.
# Get namespace object by the filename / module name.

def parse(filename, include_paths=None):
# Make sure Wt is installed to correct directory.
wconfigh = '%s/WConfig.h' % INCLUDE_WT
Expand Down Expand Up @@ -76,6 +80,9 @@ def loadAdditionalChunk(module_str):
else:
raise Exception('Unable to load module called %s' % module_str)

# =============================================================================
# Utility functions to transform or extract types/declarations or to get some info about them.

def isTemplate(method_name, decl_obj, namespace):
# Luawt doesn't support C++ templates.
if pygccxml.declarations.templates.is_instantiation(str(decl_obj)):
Expand Down Expand Up @@ -139,65 +146,6 @@ def isBaseOrItsDescendant(child, base_name, Wt):
return True
return False

def checkArgumentType(method_name, arg_type, Wt):
if isTemplate(method_name, arg_type, Wt):
return False
# Is built-in or problematic
if getBuiltinType(str(arg_type)):
# Is problematic
if findCorrespondingKeyInDict(
PROBLEMATIC_TO_BUILTIN_CONVERSIONS,
str(arg_type),
):
if pygccxml.declarations.is_reference(arg_type):
if isConstReference(arg_type):
return True
elif not pygccxml.declarations.is_pointer(arg_type):
return True
# Is built-in
else:
if not pygccxml.declarations.is_pointer(arg_type):
if not pygccxml.declarations.is_reference(arg_type):
return True
elif isBaseOrItsDescendant(clearType(arg_type), 'WWidget', Wt):
if not pygccxml.declarations.is_pointer(arg_type):
logging.info(
'Argument of method %s has strange type %s',
method_name,
arg_type,
)
return True
logging.warning(
'Its impossible to bind method %s: its arg has type %s',
method_name,
arg_type,
)
return False

def checkReturnType(method_name, raw_return_type, Wt):
# Special cases.
if isTemplate(method_name, raw_return_type, Wt):
return False
if str(raw_return_type) == 'void':
return True
# Built-in or problematic return type.
if getBuiltinType(str(raw_return_type)):
if isConstReference(raw_return_type):
return True
elif not pygccxml.declarations.is_pointer(raw_return_type):
return True
elif isBaseOrItsDescendant(clearType(raw_return_type), 'WWidget', Wt):
if pygccxml.declarations.is_pointer(raw_return_type):
return True
elif isConstReference(raw_return_type):
return True
logging.warning(
'Its impossible to bind method %s: of its return type %s',
method_name,
raw_return_type,
)
return False

def getInternalNamespace(decl_str):
chunks = decl_str.split('::')
if len(chunks) == 2:
Expand All @@ -217,7 +165,7 @@ def enumObjFromNamespace(enum_str, namespace):
def getEnumObj(enum_str, default_namespace):
chunks = enum_str.split('::')
if len(chunks) == 2:
# Namespace::Enum --> Enum
# Namespace::Enum --> Enum.
enum_str = chunks[1]
enum_obj = enumObjFromNamespace(enum_str, default_namespace)
if not enum_obj:
Expand Down Expand Up @@ -268,10 +216,73 @@ def addEnum(type_obj, namespace):
GLOBAL_ENUMS_REGISTRY[type_str][1].sort()

def getArgType(arg):
# For compatibility with pygccxml v1.7.1
# For compatibility with pygccxml v1.7.1.
arg_field = hasattr(arg, 'decl_type') and arg.decl_type or arg.type
return arg_field

# =============================================================================
# Checker functions: checkArgumentType, checkReturnType and checkWtFunction.
# They do check that current version of luawt supports them.

def checkArgumentType(method_name, arg_type, Wt):
if isTemplate(method_name, arg_type, Wt):
return False
# Is built-in or problematic.
if getBuiltinType(str(arg_type)):
# Is problematic.
if findCorrespondingKeyInDict(
PROBLEMATIC_TO_BUILTIN_CONVERSIONS,
str(arg_type),
):
if pygccxml.declarations.is_reference(arg_type):
if isConstReference(arg_type):
return True
elif not pygccxml.declarations.is_pointer(arg_type):
return True
# Is built-in.
else:
if not pygccxml.declarations.is_pointer(arg_type):
if not pygccxml.declarations.is_reference(arg_type):
return True
elif isBaseOrItsDescendant(clearType(arg_type), 'WWidget', Wt):
if not pygccxml.declarations.is_pointer(arg_type):
logging.info(
'Argument of method %s has strange type %s',
method_name,
arg_type,
)
return True
logging.warning(
'Its impossible to bind method %s: its arg has type %s',
method_name,
arg_type,
)
return False

def checkReturnType(method_name, raw_return_type, Wt):
# Special cases.
if isTemplate(method_name, raw_return_type, Wt):
return False
if str(raw_return_type) == 'void':
return True
# Built-in or problematic return type.
if getBuiltinType(str(raw_return_type)):
if isConstReference(raw_return_type):
return True
elif not pygccxml.declarations.is_pointer(raw_return_type):
return True
elif isBaseOrItsDescendant(clearType(raw_return_type), 'WWidget', Wt):
if pygccxml.declarations.is_pointer(raw_return_type):
return True
elif isConstReference(raw_return_type):
return True
logging.warning(
'Its impossible to bind method %s: of its return type %s',
method_name,
raw_return_type,
)
return False

def checkWtFunction(is_constructor, func, Wt):
if func.access_type != 'public':
return False
Expand All @@ -287,6 +298,9 @@ def checkWtFunction(is_constructor, func, Wt):
# OK, all checks've passed.
return True

# =============================================================================
# Getter functions: getSignals, getMembers, getConstructors, getIncludes etc.

def isSignal(func):
if len(func.arguments) != 0:
return False
Expand Down Expand Up @@ -344,7 +358,7 @@ def getMembers(global_namespace, module_name, blacklisted):
if module_name == 'WWidget' or module_name == 'WApplication':
base_r = '0'
if not base_r:
raise Exception('Unable to bind %s, because it isnt descendant of WWidget' % module_name)
raise Exception('Unable to bind %s, because it isn\'t descendant of WWidget' % module_name)
custom_matcher = pygccxml.declarations.custom_matcher_t(
lambda decl: checkWtFunction(False, decl, Wt),
)
Expand Down Expand Up @@ -376,8 +390,8 @@ def noParent(args):
# For widget tests generation.
# Function returns flag - constructors type:
# - 0 means error - no constructors supported by luawt.test are available;
# - 1 - only no-args constructors are available
# - 2 means that there're constructors with single WContainerWidget arg
# - 1 - only no-args constructors are available;
# - 2 means that there're constructors with single WContainerWidget arg.
def getConstructorsType(constructors):
has_void_args = False
has_sing_arg = False
Expand Down Expand Up @@ -444,12 +458,16 @@ def getIncludes(module_name, methods, constructors):
includes += getModulesFromFuncSig(method)
for constructor in constructors:
includes += getModulesFromFuncSig(constructor)
# Erase repeats
# Erase repeats.
return set(includes)

def getModuleName(filename):
return os.path.basename(filename)


# =============================================================================
# Generator functions (actual logic of generating the code of bindings).

INCLUDES_TEMPLATE = r'''
#include "boost-xtime.hpp"

Expand Down Expand Up @@ -569,7 +587,7 @@ def getBuiltinTypeArgument(options):
return code
else:
if 'static_cast' in options['func']:
# Enum
# Enum.
return get_enum_arg_template.lstrip() % options
else:
return get_builtin_arg_template.lstrip() % options
Expand Down Expand Up @@ -656,12 +674,12 @@ def returnValue(return_type):
else:
ref_str = ''
builtin_type = getBuiltinType(return_type)
# func - function for returning values to Lua
# func - function for returning values to Lua.
if builtin_type:
_, func_name = BUILTIN_TYPES_CONVERTERS[builtin_type]
else:
func_name = 'luawt_toLua'
# Is reference
# Is reference.
if '&' in return_type:
ref_str = '&'
# Method to convert problematic type to built-in.
Expand Down Expand Up @@ -857,7 +875,7 @@ def generateModuleFunc(module_name, base, is_not_abstract):
assert(base);
'''
if base == '0':
# WApplication or WWidget
# WApplication or WWidget.
get_base = ''
else:
get_base = base_frame.strip() % base.name
Expand Down Expand Up @@ -1017,6 +1035,10 @@ def generateModule(module_name, methods, base, constructors, signals):
))
return ''.join(source)

# =============================================================================
# Main functionality functions (called directly from main()).
# bind, generateBlacklist, addModuleToLists, collectMembers.

def getMatchRange(pattern, content):
first, last = 0, 0
for i, line in enumerate(content):
Expand Down Expand Up @@ -1066,17 +1088,6 @@ def addItem(
content.insert(curr_index, added_str)
return ''.join(content)

def writeToFile(filename, what):
with open(filename, 'wt') as f:
f.write(what)

def readFile(filename):
with open(filename, 'rt') as f:
return f.readlines()

def writeSourceToFile(module_name, source):
writeToFile('src/luawt/%s' % module_name, source)

def addItemToFiles(parameters, module_name, Wt = None):
for parameter in parameters:
content = readFile(parameter['filename'])
Expand Down Expand Up @@ -1179,7 +1190,7 @@ def bind(modules, module_only, blacklist, gen_enums=False):
if not module_only:
addModuleToLists(module_name, global_namespace.namespace('Wt'))
if constructors:
# Is not abstract
# Is not abstract.
addTest(module_name, constructors_type)
writeSourceToFile(module_name + '.cpp', source)
except Exception as e:
Expand Down Expand Up @@ -1276,6 +1287,22 @@ def generateBlacklist(mem1, mem2):
blacklisted['signatures'].sort()
return blacklist

# =============================================================================
# Utility functions.

def writeToFile(filename, what):
with open(filename, 'wt') as f:
f.write(what)

def readFile(filename):
with open(filename, 'rt') as f:
return f.readlines()

def writeSourceToFile(module_name, source):
writeToFile('src/luawt/%s' % module_name, source)

# =============================================================================

def main():
parser = argparse.ArgumentParser(
description=__doc__,
Expand Down