我有一个包含 Kotlin 源代码的字符串。如何在运行时编译它并获取抽象语法树和类型信息进行分析?
我对 Kotlin 编译器进行了一些调查。一些获得 AST 的概念证明可以在我的网站上看到GitHub 仓库 https://github.com/vektory79/kotlin-script-parser-test.
这只是一个草图,但可能会有所帮助:
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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)