diff --git a/examples/meta/CMakeLists.txt b/examples/meta/CMakeLists.txt index 77302b530c8..f320455314e 100644 --- a/examples/meta/CMakeLists.txt +++ b/examples/meta/CMakeLists.txt @@ -14,7 +14,9 @@ add_custom_target(meta_examples -i ${CMAKE_CURRENT_SOURCE_DIR}/src -o ${CMAKE_CURRENT_BINARY_DIR} -t ${CMAKE_CURRENT_SOURCE_DIR}/generator/targets - COMMENT "Generating examples from meta-language") + -g ${CTAGS_FILE} + COMMENT "Generating examples from meta-language" + DEPENDS ctags) # Collect all meta example listings and store in variable FILE(GLOB_RECURSE META_EXAMPLES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.sg) diff --git a/examples/meta/generator/generate.py b/examples/meta/generator/generate.py index 9bb752bb489..dcc41b816fe 100755 --- a/examples/meta/generator/generate.py +++ b/examples/meta/generator/generate.py @@ -15,7 +15,20 @@ def subfilesRelative(directory, filter_by): if filter_by(file): yield os.path.relpath(dir_, inputDir), file -def translateExamples(inputDir, outputDir, targetsDir, includedTargets=None): +def parseCtags(filename): + tags = {} + if not os.path.exists(filename): + raise Exception('Failed to found ctags file at %s' % (filename)) + with open(filename) as file: + for line in file: + symbol, location = line.strip().split('\t')[:2] + # we assume sources are in src/ + tags[symbol] = location.split('src/')[-1] + return tags + +def translateExamples(inputDir, outputDir, targetsDir, ctagsFile, includedTargets=None): + + tags = parseCtags(ctagsFile) # Load all target dictionaries targets = [] for target in os.listdir(targetsDir): @@ -35,7 +48,7 @@ def translateExamples(inputDir, outputDir, targetsDir, includedTargets=None): # Translate ast to each target language for target in targets: - translation = translate(ast, targetDict=target) + translation = translate(ast, targetDict=target, tags=tags) directory = os.path.join(outputDir, target["OutputDirectoryName"]) extension = target["FileExtension"] @@ -60,7 +73,8 @@ def translateExamples(inputDir, outputDir, targetsDir, includedTargets=None): parser.add_argument("-o", "--output", help="path to output directory") parser.add_argument("-i", "--input", help="path to examples directory (input)") parser.add_argument("-t", "--targetsfolder", help="path to directory with target JSON files") - parser.add_argument('targets', nargs='*', help="Targets to include (one or more of: python java r octave csharp ruby cpp lua). If not specified all targets are produced.") + parser.add_argument("-g", "--ctags", help="path to ctags file") + parser.add_argument('targets', nargs='*', help="Targets to include (one or more of: cpp python java r octave csharp ruby). If not specified all targets are produced.") args = parser.parse_args() @@ -76,4 +90,6 @@ def translateExamples(inputDir, outputDir, targetsDir, includedTargets=None): if args.targetsfolder: targetsDir = args.targetsfolder - translateExamples(inputDir, outputDir, targetsDir, args.targets) + ctagsFile = args.ctags + + translateExamples(inputDir, outputDir, targetsDir, ctagsFile, args.targets) diff --git a/examples/meta/generator/targets/cpp.json b/examples/meta/generator/targets/cpp.json index a62a9620e81..77e7680fc07 100644 --- a/examples/meta/generator/targets/cpp.json +++ b/examples/meta/generator/targets/cpp.json @@ -1,11 +1,10 @@ { - "Program": "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n\n${dependencies}\n\nusing namespace shogun;\n\nint main(int, char*[])\n{\ninit_shogun_with_defaults();\n\n$program\nexit_shogun();\nreturn 0;\n}\n", + "Program": "#include \n#include \n${dependencies}\n\nusing namespace shogun;\n\nint main(int, char*[])\n{\ninit_shogun_with_defaults();\n\n$program\nexit_shogun();\nreturn 0;\n}\n", "Dependencies": { - "AllDependencies": "$enumDependencies\n\n", - "EnumDependencies": "$enums", - "DependencyListElementClass": "$element", - "DependencyListElementEnum": "import static org.shogun.$type.$value;", - "DependencyListSeparator": "\n" + "AllClassDependencies": "$classlist", + "AllDependencies": "$allClassDependencies", + "DependencyListSeparator": "\n", + "DependencyListElementClass": "#include <$include>" }, "Statement": "$statement;\n", "Comment": "//$comment\n", diff --git a/examples/meta/generator/translate.py b/examples/meta/generator/translate.py index 9210cba12d1..295dd50eafb 100644 --- a/examples/meta/generator/translate.py +++ b/examples/meta/generator/translate.py @@ -4,6 +4,7 @@ from sets import Set import os.path import argparse +import re class Translator: def __init__(self, targetDict): @@ -15,7 +16,7 @@ def __init__(self, targetDict): self.targetDict = targetDict - def translateProgram(self, program, programName=None): + def translateProgram(self, program, programName=None, tags={}): """ Translate program AST Args: program: object like [statementAST, statementAST, statementAST, ...] @@ -24,6 +25,7 @@ def translateProgram(self, program, programName=None): self.dependencies["AllClasses"] = Set() self.dependencies["ConstructedClasses"] = Set() self.dependencies["Enums"] = Set() + self.tags = tags targetProgram = "" for line in program: @@ -93,12 +95,32 @@ def seperatedClassDependencies(self, type): # separated dependencies csdependencies = "" for i, x in enumerate(dependencyList): - csdependencies += elementTemplate.substitute(element=x) + if '$include' in elementTemplate.template: + csdependencies += elementTemplate.substitute(element=x, include=self.getIncludePathForClass(x)) + else: + csdependencies += elementTemplate.substitute(element=x) + if i < len(dependencyList)-1: csdependencies += seperator return csdependencies + def getIncludePathForClass(self, type_): + translatedType = self.translateType({"ObjectType": type_}) + template_parameter_matcher = '\<[0-9a-zA-Z_]*\>' + variants = [ + translatedType, + 'C' + translatedType, + re.sub(template_parameter_matcher, '', translatedType), + 'C' + re.sub(template_parameter_matcher, '', translatedType) + ] + for variant in variants: + if variant in self.tags: + return self.tags[variant] + + raise Exception('Failed to obtain include path for %s' % (' or '.join(variants))) + + def seperatedEnumDependencies(self): if len(self.dependencies["Enums"]) == 0: return "" @@ -267,10 +289,10 @@ def translateArgumentList(self, argumentList): elif "ArgumentList" in argumentList: return self.translateArgumentList(argumentList["ArgumentList"]) -def translate(ast, targetDict): +def translate(ast, targetDict, tags): translator = Translator(targetDict) programName = os.path.basename(ast["FilePath"]).split(".")[0] - return translator.translateProgram(ast["Program"], programName) + return translator.translateProgram(ast["Program"], programName, tags) def loadTargetDict(targetJsonPath): try: diff --git a/src/shogun/CMakeLists.txt b/src/shogun/CMakeLists.txt index 2eb09ad4218..6bcdd9c24a5 100644 --- a/src/shogun/CMakeLists.txt +++ b/src/shogun/CMakeLists.txt @@ -116,14 +116,14 @@ if (BUILD_STATIC) ENDIF() IF (CTAGS_FOUND) - ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tags - COMMAND ${CTAGS_EXECUTABLE} -f ${CMAKE_CURRENT_BINARY_DIR}/tags + SET(CTAGS_FILE ${CMAKE_CURRENT_BINARY_DIR}/tags CACHE INTERNAL "" FORCE) + ADD_CUSTOM_COMMAND(OUTPUT ${CTAGS_FILE} + COMMAND ${CTAGS_EXECUTABLE} -f ${CTAGS_FILE} # functions, classes, macroses, enumerations, enumerators, typedefs --c++-kinds=fcdget -R ${CMAKE_CURRENT_SOURCE_DIR}) - ADD_CUSTOM_TARGET(ctags DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tags) - SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/tags PROPERTIES - GENERATED 1) + ADD_CUSTOM_TARGET(ctags DEPENDS ${CTAGS_FILE}) + SET_SOURCE_FILES_PROPERTIES(${CTAGS_FILE} PROPERTIES GENERATED 1) ENDIF() CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/lib/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/lib/config.h)