如何获得Kotlin AST?

我有一个与Kotlin源的字符串。 如何在运行时编译它并获取抽象语法树和类型信息来分析?

我有一些Kotlin编译器的调查。 在我的GitHub仓库中可以看到一些AST的概念证明。

这只是一个草图,但可以帮助:

 class KotlinScriptParser { companion object { private val LOG = Logger.getLogger(KotlinScriptParser.javaClass.name) private val messageCollector = object : MessageCollector { override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { val path = location.path val position = if (path == null) "" else "$path: (${location.line}, ${location.column}) " val text = position + message if (CompilerMessageSeverity.VERBOSE.contains(severity)) { LOG.finest(text) } else if (CompilerMessageSeverity.ERRORS.contains(severity)) { LOG.severe(text) } else if (severity == CompilerMessageSeverity.INFO) { LOG.info(text) } else { LOG.warning(text) } } } private val classPath: ArrayList<File> by lazy { val classpath = arrayListOf<File>() classpath += PathUtil.getResourcePathForClass(AnnotationTarget.CLASS.javaClass) classpath } } fun parse(vararg files: String): TopDownAnalysisContext { // The Kotlin compiler configuration val configuration = CompilerConfiguration() val groupingCollector = GroupingMessageCollector(messageCollector) val severityCollector = MessageSeverityCollector(groupingCollector) configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, severityCollector) configuration.addJvmClasspathRoots(PathUtil.getJdkClassesRoots()) // The path to .kt files sources files.forEach { configuration.addKotlinSourceRoot(it) } // Configuring Kotlin class path configuration.addJvmClasspathRoots(classPath) configuration.put(JVMConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME) configuration.put<List<AnalyzerScriptParameter>>(JVMConfigurationKeys.SCRIPT_PARAMETERS, CommandLineScriptUtils.scriptParameters()) val rootDisposable = Disposer.newDisposable() try { val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) val ktFiles = environment.getSourceFiles() val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName()) val project = moduleContext.project val allFiles = JvmAnalyzerFacade.getAllFilesToAnalyze(project, null, ktFiles) val providerFactory = FileBasedDeclarationProviderFactory(moduleContext.storageManager, allFiles) val lookupTracker = LookupTracker.DO_NOTHING val packagePartProvider = JvmPackagePartProvider(environment) val container = createContainerForTopDownAnalyzerForJvm( moduleContext, sharedTrace, providerFactory, GlobalSearchScope.allScope(project), lookupTracker, packagePartProvider) val additionalProviders = ArrayList<PackageFragmentProvider>() additionalProviders.add(container.javaDescriptorResolver.packageFragmentProvider) return container.lazyTopDownAnalyzerForTopLevel.analyzeFiles(TopDownAnalysisMode.LocalDeclarations, allFiles, additionalProviders) } finally { rootDisposable.dispose() if (severityCollector.anyReported(CompilerMessageSeverity.ERROR)) { throw RuntimeException("Compilation error") } } } } fun main(args: Array<String>) { val scriptFile = "/media/data/java/blackfern/kotlin-compile-test/test.kt" val parser = KotlinScriptParser() // Getting a root element of the AST val analyzeContext = parser.parse(scriptFile) // Sample AST investigation val function = analyzeContext.functions.keys.first() val body = function.bodyExpression as KtBlockExpression } 

目前没有标准的API来做到这一点。 您可以使用Kotlin编译器和REPL 源代码来尝试实现这一点。

Interesting Posts