| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| |
| import os |
| import sys |
| import json |
| |
| import argparse |
| |
| class Generator(object): |
| |
| implementationContent = '' |
| |
| def GeneratePrologue(self): |
| |
| self.implementationContent += \ |
| """ |
| /*===- Generated file -------------------------------------------*- C++ -*-===*\ |
| |* *| |
| |* Introspection of available AST node SourceLocations *| |
| |* *| |
| |* Automatically generated file, do not edit! *| |
| |* *| |
| \*===----------------------------------------------------------------------===*/ |
| |
| namespace clang { |
| namespace tooling { |
| |
| using LocationAndString = SourceLocationMap::value_type; |
| using RangeAndString = SourceRangeMap::value_type; |
| """ |
| |
| def GenerateBaseGetLocationsDeclaration(self, CladeName): |
| self.implementationContent += \ |
| """ |
| void GetLocationsImpl(std::shared_ptr<LocationCall> const& Prefix, |
| clang::{0} const *Object, SourceLocationMap &Locs, |
| SourceRangeMap &Rngs); |
| """.format(CladeName) |
| |
| def GenerateSrcLocMethod(self, ClassName, ClassData): |
| |
| self.implementationContent += \ |
| """ |
| static void GetLocations{0}(std::shared_ptr<LocationCall> const& Prefix, |
| clang::{0} const &Object, |
| SourceLocationMap &Locs, SourceRangeMap &Rngs) |
| {{ |
| """.format(ClassName) |
| |
| if 'sourceLocations' in ClassData: |
| for locName in ClassData['sourceLocations']: |
| self.implementationContent += \ |
| """ |
| Locs.insert(LocationAndString(Object.{0}(), |
| std::make_shared<LocationCall>(Prefix, "{0}"))); |
| """.format(locName) |
| |
| self.implementationContent += '\n' |
| |
| if 'sourceRanges' in ClassData: |
| for rngName in ClassData['sourceRanges']: |
| self.implementationContent += \ |
| """ |
| Rngs.insert(RangeAndString(Object.{0}(), |
| std::make_shared<LocationCall>(Prefix, "{0}"))); |
| """.format(rngName) |
| |
| self.implementationContent += '\n' |
| |
| self.implementationContent += '}\n' |
| |
| def GenerateFiles(self, OutputFile): |
| with open(os.path.join(os.getcwd(), |
| OutputFile), 'w') as f: |
| f.write(self.implementationContent) |
| |
| def GenerateBaseGetLocationsFunction(self, ASTClassNames, CladeName): |
| |
| MethodReturnType = 'NodeLocationAccessors' |
| |
| Signature = \ |
| 'GetLocations(clang::{0} const *Object)'.format(CladeName) |
| ImplSignature = \ |
| """ |
| GetLocationsImpl(std::shared_ptr<LocationCall> const& Prefix, |
| clang::{0} const *Object, SourceLocationMap &Locs, |
| SourceRangeMap &Rngs) |
| """.format(CladeName) |
| |
| self.implementationContent += \ |
| 'void {0} {{ GetLocations{1}(Prefix, *Object, Locs, Rngs);'.format( |
| ImplSignature, |
| CladeName) |
| |
| for ASTClassName in ASTClassNames: |
| if ASTClassName != CladeName: |
| self.implementationContent += \ |
| """ |
| if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{ |
| GetLocations{0}(Prefix, *Derived, Locs, Rngs); |
| }} |
| """.format(ASTClassName) |
| |
| self.implementationContent += '}' |
| |
| self.implementationContent += \ |
| """ |
| {0} NodeIntrospection::{1} {{ |
| NodeLocationAccessors Result; |
| std::shared_ptr<LocationCall> Prefix; |
| |
| GetLocationsImpl(Prefix, Object, Result.LocationAccessors, |
| Result.RangeAccessors); |
| """.format(MethodReturnType, |
| Signature) |
| |
| self.implementationContent += 'return Result; }' |
| |
| def GenerateDynNodeVisitor(self, CladeNames): |
| MethodReturnType = 'NodeLocationAccessors' |
| |
| Signature = \ |
| 'GetLocations(clang::DynTypedNode const &Node)' |
| |
| self.implementationContent += MethodReturnType \ |
| + ' NodeIntrospection::' + Signature + '{' |
| |
| for CladeName in CladeNames: |
| self.implementationContent += \ |
| """ |
| if (const auto *N = Node.get<{0}>()) |
| return GetLocations(const_cast<{0} *>(N));""".format(CladeName) |
| |
| self.implementationContent += '\nreturn {}; }' |
| |
| def GenerateEpilogue(self): |
| |
| self.implementationContent += ''' |
| } |
| } |
| ''' |
| |
| def main(): |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--json-input-path', |
| help='Read API description from FILE', metavar='FILE') |
| parser.add_argument('--output-file', help='Generate output in FILEPATH', |
| metavar='FILEPATH') |
| parser.add_argument('--empty-implementation', |
| help='Generate empty implementation', |
| action="store", type=int) |
| |
| options = parser.parse_args() |
| |
| use_empty_implementation = options.empty_implementation |
| |
| if (not use_empty_implementation |
| and not os.path.exists(options.json_input_path)): |
| use_empty_implementation = True |
| |
| if not use_empty_implementation: |
| with open(options.json_input_path) as f: |
| jsonData = json.load(f) |
| |
| if not 'classesInClade' in jsonData or not jsonData["classesInClade"]: |
| use_empty_implementation = True |
| |
| if use_empty_implementation: |
| with open(os.path.join(os.getcwd(), |
| options.output_file), 'w') as f: |
| f.write(""" |
| namespace clang { |
| namespace tooling { |
| |
| NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) { |
| return {}; |
| } |
| NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) { |
| return {}; |
| } |
| NodeLocationAccessors |
| NodeIntrospection::GetLocations(clang::DynTypedNode const &) { |
| return {}; |
| } |
| } // namespace tooling |
| } // namespace clang |
| """) |
| sys.exit(0) |
| |
| g = Generator() |
| |
| g.GeneratePrologue() |
| |
| for (CladeName, ClassNameData) in jsonData['classesInClade'].items(): |
| g.GenerateBaseGetLocationsDeclaration(CladeName) |
| |
| for (ClassName, ClassAccessors) in jsonData['classEntries'].items(): |
| if ClassAccessors: |
| g.GenerateSrcLocMethod(ClassName, ClassAccessors) |
| |
| for (CladeName, ClassNameData) in jsonData['classesInClade'].items(): |
| g.GenerateBaseGetLocationsFunction(ClassNameData, CladeName) |
| |
| g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys()) |
| |
| g.GenerateEpilogue() |
| |
| g.GenerateFiles(options.output_file) |
| |
| if __name__ == '__main__': |
| main() |