Giter VIP home page Giter VIP logo

ast's Introduction

License Release

kotlinx.ast

kotlinx.ast is a generic AST (Abstract Syntax Tree) parsing library, Kotlin is currently the only supported language. The library is designed that other languages can be easily added. kotlinx.ast does not use the Kotlin Compiler for parsing, it is using ANTLR (the Kotlin variant: https://github.com/Strumenta/antlr-kotlin) using the official Kotlin Grammar (https://kotlinlang.org/docs/reference/grammar.html).

One Component is Klass, a collection of language independent data classes used to represent and easily access the AST.

Status

The Project is in an early stage, but it is already possible to parse Kotlin code. Bug reports, feature requests and pull requests are very welcome.

kotlinx.ast is a multiplatform project, but currently, JVM is the only supported target. Support for JS and native is planned.

antlr-java, antlr-optimized and antlr-kotlin are supported on the JVM. Multiplatform support (Kotlin Native and Kotlin JavaScript) for antlr-kotlin is planned. Because antlr-java and antlr-optimized are JVM-only, support for other platforms is not possible.

Prior art

kastree is using the kotlin compiler for parsing, it can only parse kotlin files. JS and native support is not possible. kastree is currently not under active development.

Example

This Kotlin Code:

@Annotation1("abc")
// line comment between annotations
@Annotation2("\${123}")
fun parse() {}

will be parsed as:

PackageHeader()
importList
KlassDeclaration(fun parse)
  KlassAnnotation(Annotation1)
    KlassArgument()
      KlassString
        "abc"
  KlassAnnotation(Annotation2)
    KlassArgument()
      KlassString
        Escape("\$")
        "{123}"

There are more examples in directory testdata.

  • Files named "*.kt.txt" contains the kotlin source to parse
  • Files named "*.raw.txt" contains the parsed raw kotlin AST as defined by the official Kotlin Grammar
  • Files named "*.summary.txt" contains the AST summary

Open Tasks

There are some parts missing, for example the importList is not converted into an easy-to-use data class

Overview

Currently, there are some libraries that are part of kotlinx.ast:

  • kotlinx.ast:common contains the code that can later be reused by other grammar parsers
  • kotlinx.ast:common-test contains the dependencies to test frameworks, used by kotlinx.ast unit tests
  • kotlinx.ast:parser-antlr-java contains the shared code required to parse grammars using the official antlr4 JVM implementation.
  • kotlinx.ast:parser-antlr-kotlin contains the shared code required to parse grammars using antlr-kotlin
  • kotlinx.ast:parser-antlr-optimized contains the shared code required to parse grammars using the optimized fork of antlr.
  • kotlinx.ast:grammar-kotlin-parser-common contains the shared code required to parse kotlin source
  • kotlinx.ast:grammar-kotlin-parser-antlr-java provides a kotlin ast parsed using antlr-java
  • kotlinx.ast:grammar-kotlin-parser-antlr-kotlin provides a kotlin ast parsed using antlr-kotlin
  • kotlinx.ast:grammar-kotlin-parser-test contains the test data used by the kotlin parsers
  • kotlinx.ast:grammar-antlr4-parser-common contains the shared code required to parse antlr4 grammar files
  • kotlinx.ast:grammar-antlr4-parser-antlr-java provides an antlr4 grammar ast parser using antlr-java
  • kotlinx.ast:grammar-antlr4-parser-test contains the test data used by the antlr4 grammar parsers

External Dependencies

antlr-kotlin

  • ${Versions.antlrKotlinGroup}:antlr-kotlin-runtime:${Versions.antlrKotlin} is required at runtime to be able to parse kotlin code into an AST when using kotlinx.ast:grammar-kotlin-parser-antlr-kotlin.

antlr-java

  • org.antlr:antlr4:${Versions.antlrJava} is required at runtime to be able to parse kotlin code into an AST when using kotlinx.ast:grammar-kotlin-parser-antlr-java.

antlr-optimized

  • com.tunnelvisionlabs:antlr4:${Versions.antlrOptimized} is required at runtime to be able to parse kotlin code into an AST when using kotlinx.ast:grammar-kotlin-parser-antlr-optimized. NOTE: antlr-optimized is a drop-in replacement of antlr-java. Both jars provide the same API, namely the package org.antlr.v4, so you can't use both at the same time. kotlinx.ast:parser-antlr-optimized depends on kotlinx.ast:parser-antlr-java, both provide the same kotlinx.ast API. The difference is that parser-antlr-optimized will exclude the dependency to org.antlr:antlr4 and instead include com.tunnelvisionlabs:antlr4. The generated code of these two libraries is not equal, therefore two different grammar modules are required:
  • kotlinx.ast:parser-antlr-java
  • kotlinx.ast:parser-antlr-optimized (the generated code is linked, for the case that you want to compare it)

(Versions can be found here: Versions.kt)

How to use kotlinx.ast

There is a small example to get started:

Using with Gradle

kotlinx.ast is accessible on Maven & Gradle through Jitpack. In Jitpack basically you can use every commit or tag as a version number. You can find recent versions on the Jitpack page for kotlinx.ast.

You have to add this line to settings.gradle.kts if use Gradle lower than 5.3: (otherwise, the jars are not resolved):

// Enables KotlinMultiplatform publication and resolving (in dependencies)
enableFeaturePreview("GRADLE_METADATA")

You have to add Jitpack to build.gradle.kts:

repositories {
  maven("https://jitpack.io")
}

Add the dependency to kotlinx.ast into your project:

kotlin {
    jvm()

    sourceSets {
        val commonMain by getting {
            dependencies {
                // please look at https://jitpack.io/#drieks/antlr-kotlin to find the latest version
                api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")
            }
        }
    }
}

If you don't use kotlin-multiplatform add this line:

// please look at https://jitpack.io/#drieks/antlr-kotlin to find the latest version
implementation("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")

Or, if you prefer to use the antlr-java parser (JVM only):

// please look at https://jitpack.io/#drieks/antlr-kotlin to find the latest version
implementation("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-java:0123456789")

The latest version can be be seen in the Jitpack-Badge at the top of this page.

ast's People

Contributors

belyaev-mikhail avatar dependabot[bot] avatar drieks avatar kvanttt avatar matkoniecz avatar sullis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ast's Issues

Why column is called row?

Why column is called row? It appears in what astInfoOrNull returns.

Is it some slang/peculiarity in among parser writers? Or some typo? Or maybe I am mistaken about how English works?

I expected lines and columns, not lines and rows. And would expect row to be synonym of line, not of column.


BTW, #21 seems implemented and looks like it can be closed


wider explanation if above is unclear

With

private fun Ast.root(): Ast? {
    var returned: Ast? = null
    this.summary(false).onSuccess { returned = it.firstOrNull() }
    return returned
}

one may extract line and column with following code

private fun Ast.humanReadableDescription(): String {
    val current = this.root() ?: return "NULL"
    return "${current.astInfoOrNull!!.start.line}  ${current.astInfoOrNull!!.start.row}"
}

(I know that I can also use description - but that is not allowing me to format things like I want, in this case it is intended as the first step toward clear matching with parsed text)

I have just one question - why column is called row?

How to Visit Each Node of an AST?

Good morning,
I've been playing with your library for a bit to see if I can use it in a project to analyze Kotlin code. I am confused about what / whether there is a relation between the concept of a "summary" (see Summary.kt extension functions a la Ast.summary() function) and that of visiting nodes as one would do in libraries like ParseJava.

Is there a way for me to execute a visitor pattern on the tree generated by the library and say print out the names of all classes in a file or the names of all methods in a class?

Unable to use example class, because I am unable to import classes

Hi, Please help in what I am doing wrong
I am unable to use this AstSource

Dependencies used -

    implementation 'com.github.drieks.antlr-kotlin:antlr-kotlin-runtime-jvm:b09d76328'
    implementation 'com.github.drieks.antlr-kotlin:antlr-kotlin-runtime:b09d76328'
    api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:b09d76328")

Sample code -

    val source = AstSource.File(
        "grammar-kotlin-parser-antlr-kotlin/src/jvmTest/kotlin/kotlinx/ast/example/ExampleMain.kt"
    )
    val kotlinFile = KotlinGrammarAntlrKotlinParser.parseKotlinFile(source)
    kotlinFile.summary(attachRawAst = false)
        .onSuccess { astList ->
            astList.forEach(Ast::print)
        }.onFailure { errors ->
            errors.forEach(::println)
        }
}

Error -
Unable to import class - AstSource

java.lang.ArrayIndexOutOfBoundsException during parsing

Hi! I tried to parse a very simple file:
class Sample (private val propertyA: String)

using the code from example

fun main() {
    val source = AstSource.File(
        "src/jvmMain/kotlin/sample/Sample.kt"
    )
    val kotlinFile = KotlinGrammarAntlrKotlinParser.parseKotlinFile(source)
    kotlinFile.summary()
        .onSuccess { astList ->
            astList.forEach(Ast::print)
        }.onFailure { errors ->
            errors.forEach(::println)
        }
}

And got such error

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 170
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImpl.toAstTerminal(AntlrKotlinAstParserImpl.kt:27)
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImpl.parse(AntlrKotlinAstParserImpl.kt:82)
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImpl.parse(AntlrKotlinAstParserImpl.kt:75)
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImplKt.antlrKotlinParser(AntlrKotlinAstParserImpl.kt:138)
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImplKt.antlrKotlinParser(AntlrKotlinAstParserImpl.kt:98)
	at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinParser.parse(AntlrKotlinParser.kt:20)
	at kotlinx.ast.grammar.kotlin.common.KotlinGrammarParser$DefaultImpls.parseKotlinFile(KotlinGrammarParser.kt:9)
	at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParser.parseKotlinFile(KotlinGrammarAntlrKotlinParser.kt:10)
	at sample.MainKt.main(Main.kt:14)
	at sample.MainKt.main(Main.kt)

End-of-line comments not available in summary

If I run:

KotlinGrammarAntlrKotlinParser.parseKotlinFile(AstSource.String("source", "//line comment"))

The resulting raw AST contains the line comment (as expected). If I call summary() on that AST, the line comment is represented as a KlassComment (again, as expected).

Then, if I run:

KotlinGrammarAntlrKotlinParser.parseKotlinFile(AstSource.String("source", "val answer = 42 //line comment"))

Again, the resulting raw AST contains the line comment (as expected). However, if I call summary() on that AST I cannot find the comment anywhere.

Am I missing something or is this a limitation/bug in the library?

Properties from companion object are not parsed as KlassDeclaration instances

Given the following code:


class MyClass {
    val myClassProp = "myClassProp"
    companion object {
        const val myCompanionConst = "myCompanionConst"
        val myCompanionProp = "myCompanionProp"
    }
}

the parser returns myConst and myClassProp as a KlassDeclaration instances, but the myCompanionProp is parsed as a tree of DefaultAstNode/DefaultAstTerminal which are hard to analyze:
image

Is this the expected behavior?

small issue in README.md

current:

api("com.github.kotlinx.ast:kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")

fix:

api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")

Best way to add new keywords like in the Spock test

Hi I would like to add some additional keyword (labels) knows from Spock library: Given, When, Then, Expect, And.
These labels would be enabled only when junit test class is annotated with my custom annotation for instance @BddScenario.

I think that currently is not possible or maybe I am wrong?

Error: There is no feature named GRADLE_METADATA

Hi, I'm trying to get set up with this library for the first time so I can start using it. However, after following the instructions in #12 and running the gradle jar command, I keep getting this error: There is no feature named GRADLE_METADATA

I am confused how to proceed at this point? If I comment out that line, I get this error instead: KotlinSourceSet with name 'commonMain' not found. at build.gradle.kts' line: 27.

I am using Gradle 7.0 with Java 11. Below are my code files:

settings.gradle.kts
rootProject.name = "test"

enableFeaturePreview("GRADLE_METADATA")
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    application
    kotlin("jvm") version "1.4.32"
}

group = "me.test"
version = "1.0-SNAPSHOT"

application {
    mainClass.set("MainKt")
}

repositories {
    mavenCentral()
    maven("https://jitpack.io")
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:816803892c")
}

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:816803892c")
            }
        }
    }
}

tasks {
    withType<KotlinCompile> {
        kotlinOptions.jvmTarget = "11"
    }

    withType<Jar> {
        manifest {
            attributes["Main-Class"] = application.mainClass
        }
        exclude("**/module-info.class")
        from(configurations.runtimeClasspath.get().map {if (it.isDirectory) it else zipTree(it)})
    }

    test {
        useJUnitPlatform()
    }
}

Constructor parameters and properties defined in constructor

The parser now handles "escaped" characters inside annotations' values but I have found another missing node.

The AST does not contain constructor parameters and properties declared in constructor e.g.:

class TestClass(
    @Value("test value")
    private val propertyA: String
)

KotlinGrammarAntlrKotlinParser very slow for files with json-strings

Creating a file like this:

package testpackage.

val LARGE_JSON = """
     <very large json with 77000 lines>
"""

Running

val source = AstSource.String("", stringSource)
val kotlinFile = KotlinGrammarAntlrKotlinParser.parseKotlinFile(source)

takes very long on a file like this. If I replace the JSON in the string with base64, it will be much faster.
Does the grammar somehow inspect the braces inside the templating?

Found unsupported ast node. Function uses type projection 'out'

Hello :)
Here's the file under test:

package com.example.app.ui

internal class FeatureFragment :
    BaseFragment<FeatureViewModel, FeatureFragmentBinding>() {

    override fun provideViewIntents(): List<Observable<out Feature.Intent>> = emptyList()

}

and the parser prints out the following message:

found unsupported ast node 'DefaultAstNode(description=typeProjectionModifiers, children=[DefaultAstNode(description=typeProjectionModifier, children=[DefaultAstNode(description=varianceModifier, children=[DefaultAstTerminal(description=OUT, text=out, channel=AstChannel(id=0, name=DEFAULT_TOKEN_CHANNEL), attachments=AstAttachments(attachments={kotlinx.ast.common.ast.AstAttachmentAstInfo@67205a84=   51 [171..174]   [6:47..6:50]}))], attachments=AstAttachments(attachments={kotlinx.ast.common.ast.AstAttachmentAstInfo@67205a84=      [171..174]   [6:47..6:50]}))], attachments=AstAttachments(attachments={kotlinx.ast.common.ast.AstAttachmentAstInfo@67205a84=      [171..174]   [6:47..6:50]}))], attachments=AstAttachments(attachments={kotlinx.ast.common.ast.AstAttachmentAstInfo@67205a84=      [171..174]   [6:47..6:50]}))' in typeProjection!

seems the out makes trouble.

Library version

com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:bdca0630aa

ParseCancellationException - string interpolated functions

Hi, I'm not sure that is it ast library issue but I've got following file:

package com.example.app.ui

internal class FeatureFragment :
    BaseFragment<FeatureViewModel, FeatureFragmentBinding>() {

    private fun handleViewStateChanges(viewState: FeatureViewModel.ViewState): Unit =
        with(
            requireBinding
        ) {
            dateRangePropertyView.text =
                "${monthDayYearDateFormat.format(viewState.dateRange.startDate)} - ${
                    monthDayYearDateFormat.format(viewState.dateRange.endDate)
                }"
        }
}

I'm testing the file as usual:

kotlinFile.summary(attachRawAst = false)
    .onSuccess { astList ->
        astList.forEach(Ast::print)
    }.onFailure { errors ->
        errors.forEach(::println)
    }

and parser throws an exception:

Exception in thread "main" org.antlr.v4.kotlinruntime.misc.ParseCancellationException
at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinErrorListener.syntaxError(AntlrKotlinErrorListener.kt:17)
at org.antlr.v4.kotlinruntime.ProxyErrorListener.syntaxError(ProxyErrorListener.kt:34)
at org.antlr.v4.kotlinruntime.Parser.notifyErrorListeners(Parser.kt:564)
at org.antlr.v4.kotlinruntime.DefaultErrorStrategy.reportUnwantedToken(DefaultErrorStrategy.kt:376)
at org.antlr.v4.kotlinruntime.DefaultErrorStrategy.sync(DefaultErrorStrategy.kt:271)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.generated.KotlinParser.kotlinFile(KotlinParser.kt:1108)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParserExtractor$extractor$1.invoke(KotlinGrammarAntlrKotlinParserAstParserType.kt:18)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParserExtractor$extractor$1.invoke(KotlinGrammarAntlrKotlinParserAstParserType.kt:9)
at kotlinx.ast.common.AstParserExtractor$DefaultImpls.extract(AstParserExtractor.kt:5)
at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinParserExtractor$DefaultImpls.extract(AntlrKotlinParserExtractor.kt)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParserExtractor.extract(KotlinGrammarAntlrKotlinParserAstParserType.kt:9)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParserExtractor.extract(KotlinGrammarAntlrKotlinParserAstParserType.kt:9)
at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImplKt.antlrKotlinParser(AntlrKotlinAstParserImpl.kt:165)
at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinAstParserImplKt.antlrKotlinParser(AntlrKotlinAstParserImpl.kt:121)
at kotlinx.ast.parser.antlr.kotlin.AntlrKotlinParser.parse(AntlrKotlinParser.kt:20)
at kotlinx.ast.grammar.kotlin.common.KotlinGrammarParser$DefaultImpls.parseKotlinFile(KotlinGrammarParser.kt:9)
at kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParser.parseKotlinFile(KotlinGrammarAntlrKotlinParser.kt:10)
at org.jetbrains.kotlin.idea.scratch.generated.ScratchFileRunnerGenerated$ScratchFileRunnerGenerated.(tmp.kt:22)
at org.jetbrains.kotlin.idea.scratch.generated.ScratchFileRunnerGenerated.main(tmp.kt:33)

The problem has to be the line break after ${ because, without that lines, the execution goes smooth

            dateRangePropertyView.text =
                "${monthDayYearDateFormat.format(viewState.dateRange.startDate)} - ${
                    monthDayYearDateFormat.format(viewState.dateRange.endDate)
                }"

Library version

com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:a96e681f90

Consider editing repository setings to remove "Packages" section

"Packages No packages published" is displayed right now, fortunately this pointless section can be removed.

Edit repo page config to remove it (cog next to the description).

I am not making a PR as it is defined in proprietary github settings, not in a git repository - and I have no rights to modify repo settings.

Peek 2020-10-25 09-10

Best way to explore AST to search for specific patterns?

Hello,

i am trying to migrate an existing project using kastree to this library.

I am struggling to retrieve the content of a parameter of an annotation that is on a method of a class.

I have a Kotlin file that looks like this (excerpt):

class MyClass {

@KafkaListener(
        id = "\${'$'}{messaging.command.topic.consumer.group.name}",
        clientIdPrefix = "\${'$'}{messaging.command.topic.consumer.group.name}",
        topics = ["direct.topic.name.2", "\${'$'}{messaging.command.topic.name.2}"],
        concurrency = "\${'$'}{messaging.command.topic.listener-count}"
    )
    fun topicTest4MultipleMixedTopics(@Payload entityCommand: EntityCommand<JsonNode>, record: ConsumerRecord<String, Array<Byte>>) {
    }
}

What's the best way to get the content of the topics argument of the @KafkaListener annotation ?

So far i came up with this. This gives me the members of the class:

kotlinFile.summary(attachRawAst = false)
            .onSuccess { ast ->
                ast
                    .filterIsInstance<KlassDeclaration>() // filter on Classes
                    .flatMap { it.flatten("classBody") } // get the Class body
                    .flatMap { it.children } // get all the declarations within that class (functions etc)
                    .filterIsInstance(KlassDeclaration::class.java) // filter on KlassDeclaration
                    .flatMap { parseTopics2(it) } // parse topics from functions
            }

This tries to parse the function declaration block. I am faced with each node having a single node in its children, over and over, and no good way to get the content of the actual string.

private fun parseTopics2(func: KlassDeclaration): List<Pair<String, List<Schema>>> {
        func.children
            .asSequence()
            .filterIsInstance<KlassAnnotation>()
            .filter { it.description.contains(annotation) }
            .mapNotNull { it.arguments.firstOrNull { it.identifier.identifier == "topics" } }
            .mapNotNull { it.expressions.firstOrNull() }
            .filter { it.description == "collectionLiteral" }
            .filterIsInstance<DefaultAstNode>()
            .mapNotNull { it.children.getOrNull(1) }
            .toList()
            .flatMap { it.flatten("stringLiteral") }
        return emptyList()
    }

I am also not sure that doing a .filterIsInstance<KlassAnnotation>() is a good way of filtering the AST, surely there is a better way of doing that, no ?

Nullable types are not parsed correctly

I'm parsing the following Kotlin code kotlinx.ast and the KotlinGrammarAntlrKotlinParser. But weirdly, I have some nullable types which are not marked as nullable.

package foo.bar
class Spam {
    fun doSomething(i: Int, s: String?, l : List<String>) {}
} 

Here's what I get when printing the AST nodes

PackageHeader(foo.bar)
importList
KlassDeclaration(object Spam)
PackageHeader(foo.bar)
importList
KlassDeclaration(class Spam)
  classBody
    KlassDeclaration(fun doSomething)
      KlassDeclaration(parameter i Int)
      KlassDeclaration(parameter s String)
      KlassDeclaration(parameter l List<String>)

I'm using version c35b50fa44 from JitPack :

implementation("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:c35b50fa44")

How to recursively print the structure of Ast

Hi, thanks for the work!

I am fresh to Kotlin, and I want to convert a Kotlin file to AST.

Here is my Kotlin file:

package com.kickstarter.libs.utils

import android.content.Context
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import com.kickstarter.R

object UrlUtils {

    private const val KEY_REF = "ref"

    fun appendPath(baseUrl: String, path: String): String {
        val uriBuilder = Uri.parse(baseUrl).buildUpon()
        uriBuilder.appendEncodedPath(path)

        return uriBuilder.build().toString()
    }

    fun appendQueryParameter(baseUrl: String, key: String, value: String): String {
        val uriBuilder = Uri.parse(baseUrl).buildUpon()
        uriBuilder.appendQueryParameter(key, value)

        return uriBuilder.build().toString()
    }

    fun appendRefTag(baseUrl: String, tag: String): String {
        return appendQueryParameter(baseUrl, KEY_REF, tag)
    }

    fun baseCustomTabsIntent(context: Context): CustomTabsIntent {
        val builder = CustomTabsIntent.Builder()

        builder.setShowTitle(true)
        builder.setToolbarColor(ContextCompat.getColor(context, R.color.primary))

        return builder.build()
    }

    fun refTag(url: String): String? {
        return Uri.parse(url).getQueryParameter(KEY_REF)
    }
}

Here is the test code:

package kotlinx.ast.example

import kotlinx.ast.common.AstSource
import kotlinx.ast.common.ast.Ast
import kotlinx.ast.common.print
import kotlinx.ast.grammar.kotlin.common.summary
import kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParser

fun main() {
    val source = AstSource.File(
            "gen.kotlin/src/main/resources/2.kt.txt"
    )
    val kotlinFile = KotlinGrammarAntlrKotlinParser.parseKotlinFile(source)
    kotlinFile.summary(attachRawAst = false)
            .onSuccess { astList ->
                astList.forEach(Ast::print)
            }.onFailure { errors ->
                errors.forEach(::println)
            }
}

And here is the result, which only prints the top-level ones:

PackageHeader(com.kickstarter.libs.utils)
importList
  Import(android.content.Context)
  Import(android.net.Uri)
  Import(androidx.browser.customtabs.CustomTabsIntent)
  Import(androidx.core.content.ContextCompat)
  Import(com.kickstarter.R)
KlassDeclaration(object UrlUtils)

However, I found that the children for the top-level object AST is empty, then how to print the whole structure of the file?

How do I rely on this project on Maven?


4.0.0

<groupId>org.example</groupId>
<artifactId>untitled</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <!-- https://mvnrepository.com/artifact/com.github.kotlinx.ast/grammar-kotlin-parser-common-jvm -->
    <dependency>
        <groupId>com.github.kotlinx.ast</groupId>
        <artifactId>grammar-kotlin-parser-common-jvm</artifactId>
        <version>57524bbb21</version>
    </dependency>
</dependencies>

Running at command line or as gradle task

Hi, thanks for this tool. This is really a question and not an issue as am not conversant with ASTs. Is this something that can be run from the command line or as gradle task? If possible (gradle better), could you give me some pointers? At the moment am running this as a unit test and printing the output to a file to be checked later. Ideally, I want to create a gradle task pointing to a dir to load all files in there and print this AST output to a file for analysis later on.

Function with generic parameter with optional breaks the parsing

Example below will crash when calling summary() i.e. KotlinAstParser.parseKotlinFile(source).summary() throws java.lang.UnsupportedOperationException: Empty collection can't be reduced..

Parsing the code below, with the String? in a generic, leads to a new structure and summary() does not work anymore.

package com.example.test

class TestClass {
    fun function(record: Map<String?, String>) {
    }
}

Source code generation from the AST

I've been working on a meta-programming tool that can process generated code for the Android Room database and transform it to insert profiling statements. Since this generates Java code, I've used JavaParser to read the Java code into an AST, transform it and output the transformed AST as source code (since this is a feature that JavaParser supports) to be used in the final build.

I also want to add support for SQLDelight. However, that generates Kotlin code, so I need a tool that can not only parse the generated Kotlin code, but lets me modify it and output transformed source code.

As far as I can tell, kotlinx.ast only supports reading the source code and not generating code from the AST. Would I be correct in that?

How to get the entire AST instead of just the summary?

Hi!

The title says it basically. How do you get the entire AST, with DefaultAstNodes converted to the Klass Data classes, from a kotlinfile. In the example the following function is invoked:

kotlinFile.summary()

This function does not include the body of a function for example.
I tried to create my own function:

kotlinFile.complete()

private val completeTreeMap: TreeMap = DefaultTreeMap(
    annotationsMapper,
    declarationsMapper,
    expressionsMapper.flattenNames("functionDeclaration"),
    globalsMapper,
    kotlinDefaultMapper,
    modifierMapper,
    stringMapper,
    typesMapper
)

fun List<Ast>.complete(): AstResult<List<Ast>> {
    return completeTreeMap.treeMap(this)
}

fun Ast.complete(): AstResult<List<Ast>> {
    return listOf(this).complete()
}

I tried to change the Mappers in the DefaultTreeMap, but couldn't get a configuration to be able to visit the statements in the body of functions.

Hopefully this is enough information to be able to resolve my problem.

Thanks in advance!

Argument with unary prefix is incomplete in summary AST

If I run:

KotlinGrammarAntlrKotlinParser.parseKotlinFile(AstSource.String("source", "val b = f(!thisIsNotAvailable)"))

Then !thisIsNotAvailable is represented in the raw AST as a prefixUnaryExpression with a unaryPrefix (!) and postfixUnaryExpression (thisIsNotAvailable).

When i look at the corresponding summary AST, there is a KlassDeclaration with keyword argument supposedly representing !thisIsNotAvailable. However, looking at the argument's expression shows only a unaryPrefix node for the ! but no node for the identifier thisIsNotAvailable. If I look at the attached raw AST, the identifier is still there as expected.

Unless I'm missing something, I guess this is a bug.

Object is always parsed empty

object node is always parsed empty.
Parsing this piece of code

object MyObject {
   fun myFun() {}
}
class MyClass {
    fun myFun() {}
}

produces the following AST:

PackageHeader(identifier=[])
DefaultAstNode(description=importList, children=[])
KlassDeclaration(keyword=object, identifier=KlassIdentifier(identifier=MyObject, parameter=[], nullable=false, raw=null), type=null, annotations=[], modifiers=[], parameter=[], typeParameters=[], inheritance=[], expressions=[], raw=null)
KlassDeclaration(keyword=class, identifier=KlassIdentifier(identifier=MyClass, parameter=[], nullable=false, raw=null), type=null, annotations=[], modifiers=[], parameter=[], typeParameters=[], inheritance=[], expressions=[DefaultAstNode(description=classBody, children=[KlassDeclaration(keyword=fun, identifier=KlassIdentifier(identifier=myFun, parameter=[], nullable=false, raw=null), type=null, annotations=[], modifiers=[], parameter=[], typeParameters=[], inheritance=[], expressions=[], raw=null)])], raw=null)

MyClass shows myFun node while MyObject does not.

Lib version is 'com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:c7dd6bbd54'

Property delegate not available in summary

If I run:

KotlinGrammarAntlrKotlinParser.parseKotlinFile(AstSource.String("source", "val answer by lazy { 42 }"))

The raw AST contains kotlinFile/topLevelObject/declaration/propertyDeclaration/propertyDelegate which describes the by lazy { 42 } part.

However, in the summary AST that I get back from rawAst.summary(false).get() I cannot find any reference to the property delegation. The KlassDeclararation for val answer is there, but it has no children (no expressions or anything else).

Add support for @JvmSuppressWildcards/ Annotations for types.

Input:

interface Something

class MyClass(
    list: List<@JvmSuppressWildcards Something>
)

Outputs:
found unsupported ast node 'KlassAnnotation(identifier=[KlassIdentifier(identifier=JvmSuppressWildcards ...

Need: When using Kotlin & Java together, we need to often mark Generic types using @JvmSuppressWildcards to strip out ? extend Somthing when kotlin code is compiled and used from Java.
This is especially needed when using Dagger with Kotlin.

Could you please add support for this?
Thanks in advance :)

Failed to parse typeParameter

I noticed that the library has problem to parse generic type with . dot

File under test:

class SimpleType<V : BaseType.SubType> {

}

failed to parse typeParameter

I'm invoking it like at example:

        kotlinFile.summary(attachRawAst = false)
            .onSuccess { astList ->
                astList.forEach {
                    it.print()
                }
            }.onFailure { errors ->
                errors.forEach(::println)
            }

Library version:

com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:75251cf4d8

Record syntax error messages

Right now, the Kotlin parser uses AntlrKotlinErrorListener to deal with errors while parsing. That class throws ParseCancellationException on syntax error, which seems to be a dummy class that doesn't hold any information. Basically, the information on which token the error occurred is completely lost.
Also, the parser explicitly removes all other listeners from the ANTLR parser, so you can't even inject one yourself to get that error information.

I think at least one, if not both, of these are issues that should be fixed. Otherwise, the user only gets a "something is wrong" error.

Installation of the Library

Hello,

I am interested in code generation and worked on it couple of years. I want to implement some code generation app. I used to work with Clang, but decided to switch C++ to Kotlin.

I try to run the application on its own but failed to manage. Is there any way to run it on its own?

Thanks,

java.lang.NoClassDefFoundError: Could not initialize class kotlinx.ast.grammar.kotlin.target.antlr.kotlin.KotlinGrammarAntlrKotlinParser

My project is a Gradle Plugin that parses Kotlin code to generate flat files.

I am trying to replace kastree with this library, but i encounter the captioned error when I run my plugin in another project. My code works fine within my Gradle plugin project and my tests though. I suppose this is a missing transitive dependency problem, but I can't figure out what is missing exactly.

In my Gradle plugin project I have the following dep:

api 'com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin-jvm:a96e681f90'

Note that the Gradle project uses subprojects. The parsing is implemented in one of the subproject, and the Gradle plugin project has an implementation dependency on that subproject. I also tried with an api dependency to no avail.

Should i add a runtime dependency on the kotlin parser ?

Unsupported ast node functionType when function type used as generic type

Hi, I have faced with
java.lang.IllegalStateException: found errors: [found unsupported ast node ... in typeProjection! when was parsing Kotlin file that contains function type at generic type: List<(PricingPlan) -> Boolean>. According to source code only KlassIdentifier or KlassModifier allowed but in case of functionType the right will be DefaultAstNode.

I am really confused, which dependency should be used?

https://github.com/kotlinx/ast#using-with-gradle tells me

            dependencies {
                // please look at https://jitpack.io/#drieks/antlr-kotlin to find the latest version
                api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")

or

// please look at https://jitpack.io/#drieks/antlr-kotlin to find the latest version
implementation("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:0123456789")

https://jitpack.io/#drieks/antlr-kotlin tells me to use implementation 'com.github.drieks:antlr-kotlin:Tag'

https://jitpack.io/#drieks/antlr-kotlin/d4384e4d90 tells me to use implementation 'com.github.drieks.antlr-kotlin:antlr-kotlin-gradle-plugin:d4384e4d90'

Neither api("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:d4384e4d90") nor drieked version with api("com.github.drieks.ast:grammar-kotlin-parser-antlr-kotlin:d4384e4d90") works

And Android Studio requires me to use implementation("com.github.drieks.antlr-kotlin:antlr-kotlin-gradle-plugin:d4384e4d90") (a bit different syntax)

Parsing large files is too slow

These files are currently not included in SelfTest.kt because the processing does not finish within a reasonable time:

  • KotlinLexer.kt
  • KotlinParser.kt
  • UnicodeClasses.kt

HELP Wanted: How to download the gradle artifacts with kotlin("jvm")

I desperately fail to get the artifacts from jitpack into my gradle build.

The module uses the jvm only kotlin plugin

implementation("com.github.kotlinx.ast:grammar-kotlin-parser-antlr-kotlin:c6e164e3c0")

gradle seems to download a descriptor file from jitpack, but nothing else. It doesn't matter if I set the enableFeaturePreview or not.

Do you have any ideas what I'm getting wrong here?

Question: Support for kdoc

So in the examples and the test cases, it seemed that single line comments are stripped from the AST output.
Now I could not find a reference or test case for class or function documentation (kdoc). Will this library parse them into some nodes or will comments be ignored in the output?

Add a grammar for Kotlin Script

It would be great to also have a way to parse *.kts sources this library.
The Kotlin parsers that are present at the moment seem to reject top-level statements, which are allowed in Kotlin Script.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.