Skip to content

Commit

Permalink
Employ ctags to obtain includes list in meta-cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
lisitsyn authored and vigsterkr committed Mar 10, 2016
1 parent ad41bfa commit fd82c47
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 20 deletions.
4 changes: 3 additions & 1 deletion examples/meta/CMakeLists.txt
Expand Up @@ -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)
Expand Down
24 changes: 20 additions & 4 deletions examples/meta/generator/generate.py
Expand Up @@ -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):
Expand All @@ -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"]

Expand All @@ -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()

Expand All @@ -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)
11 changes: 5 additions & 6 deletions examples/meta/generator/targets/cpp.json
@@ -1,11 +1,10 @@
{
"Program": "#include <shogun/base/init.h>\n#include <shogun/io/SGIO.h>\n#include <shogun/base/some.h>\n#include <shogun/features/DenseFeatures.h>\n#include <shogun/labels/MulticlassLabels.h>\n#include <shogun/multiclass/KNN.h>\n#include <shogun/io/CSVFile.h>\n#include <shogun/distance/EuclideanDistance.h>\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 <shogun/base/init.h>\n#include <shogun/base/some.h>\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",
Expand Down
30 changes: 26 additions & 4 deletions examples/meta/generator/translate.py
Expand Up @@ -4,6 +4,7 @@
from sets import Set
import os.path
import argparse
import re

class Translator:
def __init__(self, targetDict):
Expand All @@ -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, ...]
Expand All @@ -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:
Expand Down Expand Up @@ -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 ""
Expand Down Expand Up @@ -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:
Expand Down
10 changes: 5 additions & 5 deletions src/shogun/CMakeLists.txt
Expand Up @@ -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)
Expand Down

0 comments on commit fd82c47

Please sign in to comment.