如何获取 Kotlin AST?

2024-03-26

我有一个包含 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(使用前将#替换为@)

如何获取 Kotlin AST? 的相关文章

随机推荐

  • 如何更改输入类型=“日期”日期选择器的外观?

    我想将输入 type date 日期选择器的默认外观从箭头更改为日历图标 并使其始终可见 谷歌搜索这个问题并没有透露什么信息 我在 2012 年看到了下面的帖子 上面说这是不可能的 事情有变化吗 https developers googl
  • 为什么有些对象在 Objective-C 中使用前不需要初始化?

    为什么有些对象在 Objective C 中使用前不需要初始化 例如这是为什么NSDate today NSDate date legal 它们在内部初始化date方法 这是在 Objective C 中创建自动释放对象的常见方法 这种形式
  • 按钮标签中的 R 闪亮断线

    请看下面的玩具示例 任何帮助将不胜感激 谢谢 shinyApp ui fluidPage actionButton btnId I want a line break here br since the label is too long
  • 如何在 Android 上正确初始化和终止 EGL

    虽然有很多关于在 Android 上使用 OpenGL ES 的示例 但所有这些示例在 EGL 的初始化 终止方面似乎都是不正确的 即使是 Android SDK NDK 附带的示例 问题的根源在于 Android 应用程序模型 这使得 E
  • 在 Linq to SQL 中重写 NHibernate 应用程序

    我有一个使用 NHibernate 编写的过时的应用程序 现在我想重写它 包括新功能和模型的重大变化 使用 Linq to SQL 而不是 NHibernate 的主要缺点是什么 使用 LINQ to SQL 可能会出现哪些问题 将 Dat
  • GIT - 无法忽略 .suo 文件

    我正在尝试与同事一起在用 C 编写的应用程序中使用 Git 我们已将条目 project1 suo 添加到 gitignore 文件中 但每次我们必须提交该项目时 Git 似乎都会告诉我们也提交文件 project1 suo 我们尝试了很多
  • 安卓smali问题

    我目前正在对 smali 代码混淆器 进行一些研究 并且目前正在尝试熟悉反编译的源代码 为此 我创建了一个简单的应用程序并通过 smali 对其进行了反编译 我现在试图了解反编译的源代码 以改进和比较稍后使用代码混淆器后的安全性 针对反编译
  • 下载失败:未安装自制安装的“curl”

    命令 brew install php 每次我想在 Mac 上更新 php 时 我总是会收到如下错误 Downloading https www freetds org files stable freetds 1 3 13 tar bz2
  • Python 的 time.clock() 与 time.time() 的准确性?

    Python 中计时用哪个更好 time clock 还是 time time 哪一个提供更高的准确性 例如 start time clock do something elapsed time clock start vs start t
  • Google App Engine 始终开启功能

    有人可以解释一下 Google App Engine 中的 始终开启 功能是什么吗 它有什么用 举例说明将不胜感激 始终开启功能是否适用于任务队列 基本上 Google 会在没有流量时关闭应用程序引擎应用程序实例 通过此功能 您可以支付额外
  • 在reactJs中添加动态状态

    我创建了一个 ReactJs 页面 允许管理员将用户添加到平台 现在 管理员可以在提交表单之前添加尽可能多的用户 而不是为每个新用户提交表单 默认情况下 会显示一个包含输入字段的表行 然后单击 添加 按钮 会添加一个新行 管理员可以填写必要
  • 在 rspec 测试中发布到不同的控制器

    如何发布到与测试脚本当前指向的控制器不同的控制器 例子 在 user controller spec rb 中 it should just post to users do post create params this goes to
  • 运行maven时禁止Jasper库下载:mvn package

    我正在下载 Intellij Idea 中的 Spring 项目所需的所有库 我正在使用maven mvn包 除了被禁止的库之外 所有库都成功了 ERROR Failed to execute goal on project remax s
  • 当缓冲区只读时定义键

    当我的缓冲区是只读的 是的 我很懒 时 我尝试以与 C n 和 C p 相同的方式使用键 n 和 p 我在 emacs 文件中使用此代码 when buffer read only local set key n next line whe
  • CefSharp ChromiumWebBrowser - 未显示/渲染

    我有一个简单的应用程序 Grid with a ChromiumWebBrowser里面 当我创建ChromiumWebBrowser在 XAML 中 它可以工作 但是当我从代码隐藏创建它并将其添加到网格时 它不会显示 我只得到网格的黑色背
  • 仅从datetime sql获取日期而不转换为varchar,以便我可以在excel中对其进行排序

    当前 sql 返回日期为 2013 07 01 00 00 00 000 我只想要 mm dd yyyy 格式的日期部分 这样当我将其导出到 Excel 时 我仍然可以根据升序或降序进行排序 我尝试了 varchar 但它没有在 Excel
  • 限制代理可以建立的链接数量

    我有乌龟链接 如果它们的 var1 具有相同的值 这很好 我想将链接数量限制为三个 我在代码的链接部分之前添加了一个 IF 语句 If count my links lt 3 但不起作用 代理继续链接超过我设置的最大值 我读了另一个问题如何
  • 是否可以使用 PIL 减少图像的深度?

    是否可以使用 PIL 减少图像的深度 比如说从常规 8bpp 变为 4bpp 您可以轻松转换图像模式 只需调用im convert newmode 在图像对象上im 它会给你一个新的所需模式的新图像 但没有 4bpp 的模式 列出了支持的模
  • Angular2-mdl 和 webpack

    我已按照以下位置提供的步骤进行操作https www npmjs com package angular2 mdl https www npmjs com package angular2 mdl并使 Angular2 mdl 完美工作 但
  • 如何获取 Kotlin AST?

    我有一个包含 Kotlin 源代码的字符串 如何在运行时编译它并获取抽象语法树和类型信息进行分析 我对 Kotlin 编译器进行了一些调查 一些获得 AST 的概念证明可以在我的网站上看到GitHub 仓库 https github com