mirror of
https://github.com/github/codeql.git
synced 2026-06-26 23:27:06 +02:00
Compare commits
4 Commits
main
...
tausbn/yea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70ca7af04c | ||
|
|
664f0125b9 | ||
|
|
1b7f589000 | ||
|
|
eb7f8cc43d |
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -13,9 +13,7 @@ buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +39,6 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +39,6 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +39,6 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,15 +32,13 @@ buildscript {
|
||||
* dependencies used by all modules in your project, such as third-party plugins
|
||||
* or libraries. However, you should configure module-specific dependencies in
|
||||
* each module-level build.gradle file. For new projects, Android Studio
|
||||
* includes Maven Central and Google's Maven repository by default, but it does not
|
||||
* includes JCenter and Google's Maven repository by default, but it does not
|
||||
* configure any dependencies (unless you select a template that requires some).
|
||||
*/
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/junit/jupiter/junit-jupiter-api/5.12.1/junit-jupiter-api-5.12.1.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/junit/platform/junit-platform-commons/1.12.1/junit-platform-commons-1.12.1.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar
|
||||
https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar
|
||||
https://repo.maven.apache.org/maven2/org/junit/jupiter/junit-jupiter-api/5.12.1/junit-jupiter-api-5.12.1.jar
|
||||
https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.12.1/junit-platform-commons-1.12.1.jar
|
||||
https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
https://maven-central.storage-download.googleapis.com/maven2/joda-time/joda-time/2.12.7/joda-time-2.12.7-no-tzdb.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
https://repo.maven.apache.org/maven2/joda-time/joda-time/2.12.7/joda-time-2.12.7-no-tzdb.jar
|
||||
https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1 +1 @@
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1 +1 @@
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.12/junit-4.12.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
|
||||
https://maven-central.storage-download.googleapis.com/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar
|
||||
https://jcenter.bintray.com/junit/junit/4.12/junit-4.12.jar
|
||||
https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
|
||||
https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar
|
||||
https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar
|
||||
https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar
|
||||
https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar
|
||||
@@ -13,6 +12,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r
|
||||
https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar
|
||||
https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar
|
||||
https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar
|
||||
https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar
|
||||
https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar
|
||||
https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar
|
||||
https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<settings>
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>google-maven-central</id>
|
||||
<name>GCS Maven Central mirror</name>
|
||||
<url>https://maven-central.storage-download.googleapis.com/maven2/</url>
|
||||
<mirrorOf>central</mirrorOf>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
</settings>
|
||||
@@ -26,5 +26,4 @@ maven-project-2/src/main/resources/my-app.properties
|
||||
maven-project-2/src/main/resources/page.xml
|
||||
maven-project-2/src/main/resources/struts.xml
|
||||
maven-project-2/src/test/java/com/example/AppTest4.java
|
||||
settings.xml
|
||||
test-db/working/settings.xml
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import os
|
||||
|
||||
def test(codeql, use_java_11, java, actions_toolchains_file, check_diagnostics_java):
|
||||
# The version of gradle used doesn't work on java 17
|
||||
codeql.database.create(
|
||||
@@ -7,6 +5,5 @@ def test(codeql, use_java_11, java, actions_toolchains_file, check_diagnostics_j
|
||||
"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true",
|
||||
"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true",
|
||||
"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file),
|
||||
"LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -14,9 +14,7 @@ pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
@@ -35,9 +33,7 @@ dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Android Sample"
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,8 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven-central.storage-download.googleapis.com/maven2/")
|
||||
}
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -12,9 +12,9 @@ apply plugin: 'java'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use 'jcenter' for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
// In this section you declare the dependencies for your production and test code
|
||||
|
||||
@@ -11,9 +11,7 @@ version = '0.0.1-SNAPSHOT'
|
||||
// but I omit it to test we recognise the Spring Boot plugin version.
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -15,9 +15,8 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
application {
|
||||
|
||||
@@ -15,9 +15,8 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
application {
|
||||
|
||||
@@ -4,9 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -15,9 +15,8 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven-central.storage-download.googleapis.com/maven2/'
|
||||
}
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
application {
|
||||
|
||||
@@ -121,37 +121,3 @@ pub fn rule(input: TokenStream) -> TokenStream {
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Define a desugaring rule whose transform is a hand-written Rust block.
|
||||
///
|
||||
/// Use `manual_rule!` when the transform needs control over capture
|
||||
/// translation timing — for example, when an outer rule needs to set
|
||||
/// state in `ctx` (the `BuildCtx`'s user context) before recursive
|
||||
/// translation reaches inner rules that read that state.
|
||||
///
|
||||
/// ```text
|
||||
/// manual_rule!(
|
||||
/// (query_pattern field: (_) @name)
|
||||
/// {
|
||||
/// // `ctx` is a `&mut BuildCtx<'_, C>`; capture variables
|
||||
/// // (`name: NodeRef`, etc.) are bound from the query.
|
||||
/// let translated = ctx.translate(name)?;
|
||||
/// Ok(translated)
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// Differences from [`rule!`]:
|
||||
/// - Captures are **not** auto-translated before the body runs; they
|
||||
/// refer to raw input-schema nodes. Use [`BuildCtx::translate`] (or
|
||||
/// [`BuildCtx::translate_opt`]) to translate them when you choose.
|
||||
/// - The body is plain Rust returning `Result<Vec<Id>, String>` — no
|
||||
/// tree template, no `Ok(...)` wrap.
|
||||
#[proc_macro]
|
||||
pub fn manual_rule(input: TokenStream) -> TokenStream {
|
||||
let input2: TokenStream2 = input.into();
|
||||
match parse::parse_manual_rule_top(input2) {
|
||||
Ok(output) => output.into(),
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,9 @@ pub fn parse_query_top(input: TokenStream) -> Result<TokenStream> {
|
||||
/// Parse a single query node (possibly with a trailing `@capture`).
|
||||
fn parse_query_node(tokens: &mut Tokens) -> Result<TokenStream> {
|
||||
let base = parse_query_atom(tokens)?;
|
||||
// Check for trailing @capture
|
||||
// Check for trailing @capture or @@capture
|
||||
if peek_is_at(tokens) {
|
||||
tokens.next(); // consume @
|
||||
let capture_name = expect_ident(tokens, "expected capture name after @")?;
|
||||
let capture_name = consume_capture_marker(tokens)?;
|
||||
let name_str = capture_name.to_string();
|
||||
Ok(quote! {
|
||||
yeast::query::QueryNode::Capture {
|
||||
@@ -159,8 +158,7 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
|
||||
push_field_elem(&mut field_order, &mut field_elems, field_str, elem);
|
||||
} else {
|
||||
let child = if peek_is_at(tokens) {
|
||||
tokens.next();
|
||||
let capture_name = expect_ident(tokens, "expected capture name after @")?;
|
||||
let capture_name = consume_capture_marker(tokens)?;
|
||||
let name_str = capture_name.to_string();
|
||||
quote! {
|
||||
yeast::query::QueryNode::Capture {
|
||||
@@ -650,6 +648,9 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result<Vec<TokenStream
|
||||
struct CaptureInfo {
|
||||
name: String,
|
||||
multiplicity: CaptureMultiplicity,
|
||||
/// `true` for `@@name` captures: the auto-translate prefix skips them,
|
||||
/// so the bound `NodeRef` refers to the raw (input-schema) node.
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
@@ -708,6 +709,14 @@ fn extract_captures_inner(
|
||||
extract_captures_inner(&mut inner, captures, child_mult);
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == '@' => {
|
||||
// `@@name` marks the capture as raw (skip auto-translate).
|
||||
let raw = matches!(
|
||||
tokens.peek(),
|
||||
Some(TokenTree::Punct(p)) if p.as_char() == '@'
|
||||
);
|
||||
if raw {
|
||||
tokens.next(); // consume the second `@`
|
||||
}
|
||||
if let Some(TokenTree::Ident(name)) = tokens.next() {
|
||||
let mult = if parent_mult == CaptureMultiplicity::Repeated
|
||||
|| last_mult == CaptureMultiplicity::Repeated
|
||||
@@ -723,6 +732,7 @@ fn extract_captures_inner(
|
||||
captures.push(CaptureInfo {
|
||||
name: name.to_string(),
|
||||
multiplicity: mult,
|
||||
raw,
|
||||
});
|
||||
}
|
||||
last_mult = CaptureMultiplicity::Single;
|
||||
@@ -776,6 +786,14 @@ pub fn parse_rule_top(input: TokenStream) -> Result<TokenStream> {
|
||||
// Parse query
|
||||
let query_code = parse_query_top(query_stream.clone())?;
|
||||
|
||||
// Capture names marked `@@name` (raw) — passed to the auto-translate
|
||||
// prefix as a skip list so those captures keep their input-schema ids.
|
||||
let raw_capture_names: Vec<&str> = captures
|
||||
.iter()
|
||||
.filter(|c| c.raw)
|
||||
.map(|c| c.name.as_str())
|
||||
.collect();
|
||||
|
||||
// Generate capture bindings
|
||||
let ctx_ident = Ident::new(IMPLICIT_CTX, Span::call_site());
|
||||
let bindings: Vec<TokenStream> = captures
|
||||
@@ -891,11 +909,14 @@ pub fn parse_rule_top(input: TokenStream) -> Result<TokenStream> {
|
||||
let __query = #query_code;
|
||||
yeast::Rule::new(__query, Box::new(|__ast: &mut yeast::Ast, mut __captures: yeast::captures::Captures, __fresh: &yeast::tree_builder::FreshScope, __source_range: Option<tree_sitter::Range>, __user_ctx: &mut _, __translator: yeast::TranslatorHandle<'_, _>| {
|
||||
// Auto-translation prefix: recursively translate every
|
||||
// captured node before invoking the user's transform body.
|
||||
// captured node before invoking the user's transform body,
|
||||
// except for `@@name` captures listed in `__skip` which the
|
||||
// body consumes raw.
|
||||
// For OneShot rules this preserves the legacy behaviour
|
||||
// (input-schema captures translated to output-schema
|
||||
// nodes); for Repeating rules it is a no-op.
|
||||
__translator.auto_translate_captures(&mut __captures, __ast, __user_ctx)?;
|
||||
let __skip: &[&str] = &[#(#raw_capture_names),*];
|
||||
__translator.auto_translate_captures(&mut __captures, __ast, __user_ctx, __skip)?;
|
||||
#(#bindings)*
|
||||
let mut #ctx_ident = yeast::build::BuildCtx::with_translator(__ast, &__captures, __fresh, __source_range, __user_ctx, __translator);
|
||||
let __result: Vec<usize> = { #transform_body };
|
||||
@@ -905,106 +926,6 @@ pub fn parse_rule_top(input: TokenStream) -> Result<TokenStream> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse `manual_rule!( query { body } )`.
|
||||
///
|
||||
/// Like [`parse_rule_top`] but:
|
||||
/// - Expects a Rust block `{ ... }` after the query (no `=>` arrow).
|
||||
/// - Generates code that does NOT auto-translate captures before
|
||||
/// running the body. Capture variables refer to raw (input-schema)
|
||||
/// nodes; the body is responsible for explicit translation via
|
||||
/// `ctx.translate(...)`.
|
||||
/// - The body is included verbatim and must evaluate to
|
||||
/// `Result<Vec<usize>, String>`.
|
||||
pub fn parse_manual_rule_top(input: TokenStream) -> Result<TokenStream> {
|
||||
let mut tokens = input.into_iter().peekable();
|
||||
|
||||
// Collect query tokens up to the body block `{ ... }`.
|
||||
let mut query_tokens = Vec::new();
|
||||
loop {
|
||||
match tokens.peek() {
|
||||
None => {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"expected a Rust block `{ ... }` after the query in manual_rule!",
|
||||
))
|
||||
}
|
||||
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => break,
|
||||
_ => {
|
||||
query_tokens.push(tokens.next().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let query_stream: TokenStream = query_tokens.into_iter().collect();
|
||||
|
||||
// Extract captures from the query (same as in `rule!`).
|
||||
let captures = extract_captures(&query_stream);
|
||||
|
||||
// Parse the query into the QueryNode-building expression.
|
||||
let query_code = parse_query_top(query_stream)?;
|
||||
|
||||
// Generate capture bindings (same as in `rule!`).
|
||||
let ctx_ident = Ident::new(IMPLICIT_CTX, Span::call_site());
|
||||
let bindings: Vec<TokenStream> = captures
|
||||
.iter()
|
||||
.map(|cap| {
|
||||
let name = Ident::new(&cap.name, Span::call_site());
|
||||
let name_str = &cap.name;
|
||||
match cap.multiplicity {
|
||||
CaptureMultiplicity::Repeated => quote! {
|
||||
let #name: Vec<yeast::NodeRef> = __captures.get_all(#name_str)
|
||||
.into_iter()
|
||||
.map(yeast::NodeRef)
|
||||
.collect();
|
||||
},
|
||||
CaptureMultiplicity::Optional => quote! {
|
||||
let #name: Option<yeast::NodeRef> =
|
||||
__captures.get_opt(#name_str).map(yeast::NodeRef);
|
||||
},
|
||||
CaptureMultiplicity::Single => quote! {
|
||||
let #name: yeast::NodeRef =
|
||||
yeast::NodeRef(__captures.get_var(#name_str).unwrap());
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Consume the body block.
|
||||
let body_group = match tokens.next() {
|
||||
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => g,
|
||||
other => {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
format!(
|
||||
"expected a Rust block `{{ ... }}` after the query in manual_rule!, found: {other:?}"
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
let body_stream = body_group.stream();
|
||||
|
||||
// No tokens should follow the body.
|
||||
if let Some(tok) = tokens.next() {
|
||||
return Err(syn::Error::new_spanned(
|
||||
tok,
|
||||
"unexpected token after manual_rule! body",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(quote! {
|
||||
{
|
||||
let __query = #query_code;
|
||||
yeast::Rule::new(__query, Box::new(|__ast: &mut yeast::Ast, __captures: yeast::captures::Captures, __fresh: &yeast::tree_builder::FreshScope, __source_range: Option<tree_sitter::Range>, __user_ctx: &mut _, __translator: yeast::TranslatorHandle<'_, _>| {
|
||||
// No auto-translate prefix for manual rules — the body
|
||||
// is responsible for translating captures explicitly.
|
||||
#(#bindings)*
|
||||
let mut #ctx_ident = yeast::build::BuildCtx::with_translator(__ast, &__captures, __fresh, __source_range, __user_ctx, __translator);
|
||||
#body_stream
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Token utilities
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1013,6 +934,16 @@ fn peek_is_at(tokens: &mut Tokens) -> bool {
|
||||
matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '@')
|
||||
}
|
||||
|
||||
/// Consume an `@` or `@@` capture marker and the following name ident.
|
||||
/// Caller has already verified `peek_is_at(tokens)`.
|
||||
fn consume_capture_marker(tokens: &mut Tokens) -> Result<Ident> {
|
||||
tokens.next(); // consume the first `@`
|
||||
if peek_is_at(tokens) {
|
||||
tokens.next(); // consume the second `@` of `@@`
|
||||
}
|
||||
expect_ident(tokens, "expected capture name after `@` or `@@`")
|
||||
}
|
||||
|
||||
fn peek_is_literal(tokens: &mut Tokens) -> bool {
|
||||
matches!(tokens.peek(), Some(TokenTree::Literal(_)))
|
||||
}
|
||||
@@ -1113,8 +1044,7 @@ fn expect_repetition(tokens: &mut Tokens) -> Result<TokenStream> {
|
||||
|
||||
fn maybe_wrap_capture(tokens: &mut Tokens, base: TokenStream) -> Result<TokenStream> {
|
||||
if peek_is_at(tokens) {
|
||||
tokens.next(); // consume @
|
||||
let name = expect_ident(tokens, "expected capture name after @")?;
|
||||
let name = consume_capture_marker(tokens)?;
|
||||
let name_str = name.to_string();
|
||||
Ok(quote! {
|
||||
yeast::query::QueryNode::Capture {
|
||||
@@ -1141,13 +1071,12 @@ fn maybe_wrap_repetition(tokens: &mut Tokens, single: TokenStream) -> Result<Tok
|
||||
}
|
||||
}
|
||||
|
||||
/// If `@name` follows a Repeated list element, wrap each child SingleNode
|
||||
/// inside the repetition with a Capture. This matches tree-sitter semantics
|
||||
/// where `(_)* @name` captures each matched node.
|
||||
/// If `@name` (or `@@name`) follows a Repeated list element, wrap each
|
||||
/// child SingleNode inside the repetition with a Capture. This matches
|
||||
/// tree-sitter semantics where `(_)* @name` captures each matched node.
|
||||
fn maybe_wrap_list_capture(tokens: &mut Tokens, elem: TokenStream) -> Result<TokenStream> {
|
||||
if peek_is_at(tokens) {
|
||||
tokens.next();
|
||||
let name = expect_ident(tokens, "expected capture name after @")?;
|
||||
let name = consume_capture_marker(tokens)?;
|
||||
let name_str = name.to_string();
|
||||
// Re-parse the element isn't practical, so we generate a wrapper
|
||||
// that creates a new Repeated with each child wrapped in a capture.
|
||||
|
||||
@@ -292,6 +292,37 @@ Inside `rule!`, captures are Rust variables, so `{name}` inserts a
|
||||
single capture (`Id`) and `{..name}` splices a repeated capture
|
||||
(`Vec<Id>`).
|
||||
|
||||
### Raw captures (`@@name`)
|
||||
|
||||
The default `@name` capture marker is *auto-translated*: in OneShot
|
||||
phases the macro recursively translates the captured node before
|
||||
binding it, so `{name}` in the output template splices a node that
|
||||
already conforms to the output schema.
|
||||
|
||||
For rules that need the raw (input-schema) capture — typically to read
|
||||
its source text or to translate it explicitly with mutable context
|
||||
state between calls — use `@@name` instead. The body sees the original
|
||||
input-schema `NodeRef`:
|
||||
|
||||
```rust
|
||||
yeast::rule!(
|
||||
(assignment left: (_) @@raw_lhs right: (_) @rhs)
|
||||
=>
|
||||
{
|
||||
// raw_lhs is untranslated: read its original source text.
|
||||
let text = ctx.ast.source_text(raw_lhs.into());
|
||||
// rhs is already translated by the auto-translate prefix.
|
||||
tree!((call
|
||||
method: (identifier #{text.as_str()})
|
||||
receiver: {rhs}))
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Mix `@` and `@@` freely in the same rule. In a Repeating phase both
|
||||
markers are equivalent (auto-translation is a no-op for repeating
|
||||
rules).
|
||||
|
||||
## Complete example: for-loop desugaring
|
||||
|
||||
This rule rewrites Ruby's `for pat in val do body end` into
|
||||
|
||||
@@ -80,6 +80,28 @@ impl Captures {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Like [`try_map_all_captures`] but leaves captures whose name appears
|
||||
/// in `skip` untouched. Used by the `rule!` macro to support `@@name`
|
||||
/// (raw) captures alongside the default auto-translated `@name`
|
||||
/// captures.
|
||||
pub fn try_map_captures_except<E>(
|
||||
&mut self,
|
||||
skip: &[&str],
|
||||
mut f: impl FnMut(Id) -> Result<Vec<Id>, E>,
|
||||
) -> Result<(), E> {
|
||||
for (name, ids) in self.captures.iter_mut() {
|
||||
if skip.contains(name) {
|
||||
continue;
|
||||
}
|
||||
let mut new_ids = Vec::with_capacity(ids.len());
|
||||
for &id in ids.iter() {
|
||||
new_ids.extend(f(id)?);
|
||||
}
|
||||
*ids = new_ids;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn map_captures_to(&mut self, from: &str, to: &'static str, f: &mut impl FnMut(Id) -> Id) {
|
||||
if let Some(from_ids) = self.captures.get(from) {
|
||||
let new_values = from_ids.iter().copied().map(f).collect();
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod schema;
|
||||
pub mod tree_builder;
|
||||
mod visitor;
|
||||
|
||||
pub use yeast_macros::{manual_rule, query, rule, tree, trees};
|
||||
pub use yeast_macros::{query, rule, tree, trees};
|
||||
|
||||
use captures::Captures;
|
||||
pub use cursor::Cursor;
|
||||
@@ -48,6 +48,12 @@ impl From<NodeRef> for Id {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for NodeRef {
|
||||
fn from(value: Id) -> Self {
|
||||
NodeRef(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [`std::fmt::Display`], but the formatting routine is given access to
|
||||
/// the [`Ast`] so that node references can resolve to their source text.
|
||||
///
|
||||
@@ -757,13 +763,14 @@ impl<'a, C: Clone> TranslatorHandle<'a, C> {
|
||||
}
|
||||
|
||||
/// Translate every captured node in `captures` in place (OneShot phase
|
||||
/// only). In a Repeating phase this is a no-op — Repeating rules
|
||||
/// receive raw captures.
|
||||
/// only), except for captures whose name appears in `skip` — those are
|
||||
/// left as raw (input-schema) ids for the rule body to consume
|
||||
/// directly. In a Repeating phase this is a no-op — Repeating rules
|
||||
/// receive raw captures regardless of `skip`.
|
||||
///
|
||||
/// Used by the `rule!` macro's generated prefix to preserve the
|
||||
/// pre-existing "auto-translate captures before running the transform
|
||||
/// body" behavior. Manually-written transforms typically translate
|
||||
/// captures selectively via [`translate`] instead.
|
||||
/// Used by the `rule!` macro's generated prefix. `skip` is populated
|
||||
/// from the macro's `@@name` capture markers; for plain `@name`
|
||||
/// captures (and rules with no `@@` markers) it is empty.
|
||||
///
|
||||
/// To avoid infinite recursion, a capture whose id matches the rule's
|
||||
/// matched root (e.g. from a `(_) @_` pattern) is left unchanged.
|
||||
@@ -772,11 +779,12 @@ impl<'a, C: Clone> TranslatorHandle<'a, C> {
|
||||
captures: &mut Captures,
|
||||
ast: &mut Ast,
|
||||
user_ctx: &mut C,
|
||||
skip: &[&str],
|
||||
) -> Result<(), String> {
|
||||
match &self.inner {
|
||||
TranslatorImpl::OneShot { matched_root, .. } => {
|
||||
let root = *matched_root;
|
||||
captures.try_map_all_captures(|cid| {
|
||||
captures.try_map_captures_except(skip, |cid| {
|
||||
if cid == root {
|
||||
Ok(vec![cid])
|
||||
} else {
|
||||
|
||||
@@ -1058,6 +1058,111 @@ fn test_one_shot_does_not_recurse_into_wrapper_output() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Verify that `@@name` capture markers skip the auto-translate prefix:
|
||||
/// the body sees the *raw* (input-schema) NodeRef and can read its
|
||||
/// source text or call `ctx.translate(...)` explicitly. Compare with
|
||||
/// the bare `@name` form, where the auto-translate prefix runs the
|
||||
/// same translation up front and the body sees the post-translate id.
|
||||
#[test]
|
||||
fn test_raw_capture_marker() {
|
||||
let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into();
|
||||
let schema =
|
||||
yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap();
|
||||
let rules: Vec<Rule> = vec![
|
||||
yeast::rule!(
|
||||
(program (_)* @stmts)
|
||||
=>
|
||||
(program stmt: {..stmts})
|
||||
),
|
||||
// `@@raw_lhs` is untranslated: the body reads its source text
|
||||
// ("x") and embeds it directly as the identifier content. `@rhs`
|
||||
// is auto-translated (rhs already points to (integer "INT")).
|
||||
yeast::rule!(
|
||||
(assignment left: (_) @@raw_lhs right: (_) @rhs)
|
||||
=>
|
||||
{
|
||||
let text = ctx.ast.source_text(raw_lhs.into());
|
||||
tree!((call
|
||||
method: (identifier #{text.as_str()})
|
||||
receiver: {rhs}))
|
||||
}
|
||||
),
|
||||
yeast::rule!((identifier) => (identifier "ID")),
|
||||
yeast::rule!((integer) => (integer "INT")),
|
||||
];
|
||||
let phases = vec![Phase::new("translate", PhaseKind::OneShot, rules)];
|
||||
let runner: Runner = Runner::with_schema(lang, &schema, &phases);
|
||||
|
||||
let input = "x = 1";
|
||||
let ast = runner.run(input).unwrap();
|
||||
let dump = dump_ast(&ast, ast.get_root(), input);
|
||||
// `method:` uses the raw source text ("x"); if `@@` were broken and
|
||||
// auto-translation ran on `raw_lhs`, it would still produce the
|
||||
// string "x" (source_text inherits the input range), so the dump
|
||||
// wouldn't change here. The companion test
|
||||
// `test_raw_capture_marker_explicit_translate` exercises the
|
||||
// stronger property that `ctx.translate(raw_lhs)?` succeeds and
|
||||
// produces the translated `(identifier "ID")`.
|
||||
assert_dump_eq(
|
||||
&dump,
|
||||
r#"
|
||||
program
|
||||
stmt:
|
||||
call
|
||||
method: identifier "x"
|
||||
receiver: integer "INT"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
/// Companion to `test_raw_capture_marker`: confirms that calling
|
||||
/// `ctx.translate(raw)` on a `@@`-captured NodeRef from the rule body
|
||||
/// produces the correctly-translated output-schema node. With `@`, the
|
||||
/// translation has already happened, so `ctx.translate(...)` inside the
|
||||
/// body would attempt to re-translate an output node (which has no
|
||||
/// matching rule and would error).
|
||||
#[test]
|
||||
fn test_raw_capture_marker_explicit_translate() {
|
||||
let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into();
|
||||
let schema =
|
||||
yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap();
|
||||
let rules: Vec<Rule> = vec![
|
||||
yeast::rule!(
|
||||
(program (_)* @stmts)
|
||||
=>
|
||||
(program stmt: {..stmts})
|
||||
),
|
||||
yeast::rule!(
|
||||
(assignment left: (_) @@raw_lhs right: (_) @rhs)
|
||||
=>
|
||||
{
|
||||
let translated_lhs = ctx.translate(raw_lhs)?;
|
||||
tree!((call
|
||||
method: {..translated_lhs}
|
||||
receiver: {rhs}))
|
||||
}
|
||||
),
|
||||
yeast::rule!((identifier) => (identifier "ID")),
|
||||
yeast::rule!((integer) => (integer "INT")),
|
||||
];
|
||||
let phases = vec![Phase::new("translate", PhaseKind::OneShot, rules)];
|
||||
let runner: Runner = Runner::with_schema(lang, &schema, &phases);
|
||||
|
||||
let input = "x = 1";
|
||||
let ast = runner.run(input).unwrap();
|
||||
let dump = dump_ast(&ast, ast.get_root(), input);
|
||||
assert_dump_eq(
|
||||
&dump,
|
||||
r#"
|
||||
program
|
||||
stmt:
|
||||
call
|
||||
method: identifier "ID"
|
||||
receiver: integer "INT"
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Cursor tests ----
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use codeql_extractor::extractor::simple;
|
||||
use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, manual_rule, rule, tree};
|
||||
use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree};
|
||||
|
||||
/// User context propagated from outer rules down to the inner rules that
|
||||
/// emit the corresponding output declarations, so that each emitted node
|
||||
@@ -15,26 +15,26 @@ struct SwiftContext {
|
||||
/// (`computed_getter`/`computed_setter`/`computed_modify`/
|
||||
/// `willset_clause`/`didset_clause`/`getter_specifier`/
|
||||
/// `setter_specifier`).
|
||||
property_name: Option<yeast::Id>,
|
||||
property_name: Option<yeast::NodeRef>,
|
||||
/// Translated type node for the property type. Set by the outer
|
||||
/// `property_binding` rule (computed accessors variant) and
|
||||
/// `protocol_property_declaration` when present; read by the
|
||||
/// accessor inner rules.
|
||||
property_type: Option<yeast::Id>,
|
||||
property_type: Option<yeast::NodeRef>,
|
||||
/// Default-value expression for the next translated `parameter`. Set
|
||||
/// by the outer `function_parameter` rule; read by the `parameter`
|
||||
/// rules.
|
||||
default_value: Option<yeast::Id>,
|
||||
default_value: Option<yeast::NodeRef>,
|
||||
/// Translated outer modifiers (e.g. visibility, attributes) to
|
||||
/// attach to each child of a flattening outer rule. Set by
|
||||
/// `property_declaration`, `enum_entry`, and
|
||||
/// `protocol_property_declaration`.
|
||||
outer_modifiers: Vec<yeast::Id>,
|
||||
outer_modifiers: Vec<yeast::NodeRef>,
|
||||
/// The `let`/`var` binding modifier for a `property_declaration`.
|
||||
/// Set by `property_declaration`; read by the inner declaration
|
||||
/// rules (`property_binding` variants, accessor rules) so they
|
||||
/// emit it as part of the output node's `modifier:` field.
|
||||
binding_modifier: Option<yeast::Id>,
|
||||
binding_modifier: Option<yeast::NodeRef>,
|
||||
/// True when the current child of a flattening outer rule is not
|
||||
/// the first one — its inner rule should emit a
|
||||
/// `chained_declaration` modifier so the original grouping can be
|
||||
@@ -45,10 +45,10 @@ struct SwiftContext {
|
||||
/// Build a freshly-created `chained_declaration` modifier node if
|
||||
/// `ctx.is_chained`, else `None`. Used by inner declaration rules to
|
||||
/// emit the chained tag for non-first children of a flattening outer
|
||||
/// rule. Returns `Option<Id>` so it splices via `{..…}` to 0 or 1 ids.
|
||||
fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Option<yeast::Id> {
|
||||
/// rule. Returns `Option<NodeRef>` so it splices via `{..…}` to 0 or 1 ids.
|
||||
fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Option<yeast::NodeRef> {
|
||||
if ctx.is_chained {
|
||||
Some(ctx.literal("modifier", "chained_declaration"))
|
||||
Some(ctx.literal("modifier", "chained_declaration").into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -192,21 +192,15 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// this whole property_binding is itself a non-first declarator
|
||||
// of a containing property_declaration); subsequent accessors
|
||||
// always emit `chained_declaration`.
|
||||
manual_rule!(
|
||||
rule!(
|
||||
(property_binding
|
||||
name: @pattern
|
||||
type: _? @ty
|
||||
computed_value: (computed_property accessor: _+ @accessors))
|
||||
{
|
||||
// Translate `ty` first so the context holds an
|
||||
// output-schema node id.
|
||||
let translated_ty = ctx.translate_opt(ty)?;
|
||||
// Build the property-name identifier from the
|
||||
// (untranslated) pattern leaf.
|
||||
let name_id = tree!((identifier #{pattern}));
|
||||
|
||||
ctx.property_name = Some(name_id);
|
||||
ctx.property_type = translated_ty;
|
||||
computed_value: (computed_property accessor: _+ @@accessors))
|
||||
=>
|
||||
{..{
|
||||
ctx.property_name = Some(tree!((identifier #{pattern})).into());
|
||||
ctx.property_type = ty;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for (i, acc) in accessors.into_iter().enumerate() {
|
||||
@@ -215,8 +209,8 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
}
|
||||
result.extend(ctx.translate(acc)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
result
|
||||
}}
|
||||
),
|
||||
// Computed property: shorthand getter (no explicit get/set, just
|
||||
// statements) → a single accessor_declaration with kind "get".
|
||||
@@ -248,30 +242,26 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// The `variable_declaration` itself inherits the outer rule's
|
||||
// chained state; observers always get `chained_declaration`
|
||||
// because they're subsequent outputs of this flattening rule.
|
||||
manual_rule!(
|
||||
rule!(
|
||||
(property_binding
|
||||
name: (pattern bound_identifier: @name)
|
||||
type: _? @ty
|
||||
value: _? @val
|
||||
observers: (willset_didset_block willset: _? @ws didset: _? @ds))
|
||||
{
|
||||
// Translate ty and val so the variable_declaration
|
||||
// below contains output-schema nodes.
|
||||
let translated_ty = ctx.translate_opt(ty)?;
|
||||
let translated_val = ctx.translate_opt(val)?;
|
||||
|
||||
observers: (willset_didset_block willset: _? @@ws didset: _? @@ds))
|
||||
=>
|
||||
{..{
|
||||
let var_decl = tree!(
|
||||
(variable_declaration
|
||||
modifier: {..ctx.binding_modifier}
|
||||
modifier: {..ctx.outer_modifiers.clone()}
|
||||
modifier: {..chained_modifier(&mut ctx)}
|
||||
pattern: (name_pattern identifier: (identifier #{name}))
|
||||
type: {..translated_ty}
|
||||
value: {..translated_val})
|
||||
type: {..ty}
|
||||
value: {..val})
|
||||
);
|
||||
|
||||
// Publish the property name for the observer rules.
|
||||
ctx.property_name = Some(tree!((identifier #{name})));
|
||||
ctx.property_name = Some(tree!((identifier #{name})).into());
|
||||
// Observers are subsequent outputs of this flattening
|
||||
// rule, so they always get `chained_declaration`.
|
||||
ctx.is_chained = true;
|
||||
@@ -280,8 +270,8 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
for obs in ws.into_iter().chain(ds) {
|
||||
result.extend(ctx.translate(obs)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
result
|
||||
}}
|
||||
),
|
||||
// property_binding with any pattern name (identifier or
|
||||
// destructuring). Reads outer modifiers / chained tag from `ctx`.
|
||||
@@ -309,27 +299,24 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// inner declaration rules (`property_binding` variants,
|
||||
// accessor inner rules) read these fields and emit complete
|
||||
// `modifier:` lists from the start.
|
||||
manual_rule!(
|
||||
rule!(
|
||||
(property_declaration
|
||||
binding: (value_binding_pattern mutability: @binding_kind)
|
||||
declarator: _* @decls
|
||||
binding: (value_binding_pattern mutability: @@binding_kind)
|
||||
declarator: _* @@decls
|
||||
(modifiers)* @mods)
|
||||
{
|
||||
let binding_text = ctx.ast.source_text(binding_kind.0);
|
||||
ctx.binding_modifier = Some(ctx.literal("modifier", &binding_text));
|
||||
let mut modifiers = Vec::new();
|
||||
for m in mods {
|
||||
modifiers.extend(ctx.translate(m)?);
|
||||
}
|
||||
ctx.outer_modifiers = modifiers;
|
||||
=>
|
||||
{..{
|
||||
let binding_text = ctx.ast.source_text(binding_kind.into());
|
||||
ctx.binding_modifier = Some(ctx.literal("modifier", &binding_text).into());
|
||||
ctx.outer_modifiers = mods;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for (i, decl) in decls.into_iter().enumerate() {
|
||||
ctx.is_chained = i > 0;
|
||||
result.extend(ctx.translate(decl)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
result
|
||||
}}
|
||||
),
|
||||
// ---- Enums ----
|
||||
// enum_type_parameter → parameter (with optional name as pattern).
|
||||
@@ -386,22 +373,19 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// into `ctx` and translate each case with `ctx.is_chained`
|
||||
// toggled per iteration so the inner `enum_case_entry` rules
|
||||
// emit complete `modifier:` lists from the start.
|
||||
manual_rule!(
|
||||
(enum_entry case: _+ @cases (modifiers)* @mods)
|
||||
{
|
||||
let mut modifiers = Vec::new();
|
||||
for m in mods {
|
||||
modifiers.extend(ctx.translate(m)?);
|
||||
}
|
||||
ctx.outer_modifiers = modifiers;
|
||||
rule!(
|
||||
(enum_entry case: _+ @@cases (modifiers)* @mods)
|
||||
=>
|
||||
{..{
|
||||
ctx.outer_modifiers = mods;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for (i, case) in cases.into_iter().enumerate() {
|
||||
ctx.is_chained = i > 0;
|
||||
result.extend(ctx.translate(case)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
result
|
||||
}}
|
||||
),
|
||||
// Plain assignment: `x = expr`
|
||||
rule!(
|
||||
@@ -476,12 +460,13 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// optional default values. Publishes the default value into `ctx`
|
||||
// before translating the inner `parameter` so the `parameter`
|
||||
// rules can include it as a `default:` field directly.
|
||||
manual_rule!(
|
||||
(function_parameter parameter: @p default_value: _? @def)
|
||||
{
|
||||
ctx.default_value = ctx.translate_opt(def)?;
|
||||
ctx.translate(p)
|
||||
}
|
||||
rule!(
|
||||
(function_parameter parameter: @@p default_value: _? @def)
|
||||
=>
|
||||
{..{
|
||||
ctx.default_value = def;
|
||||
ctx.translate(p)?
|
||||
}}
|
||||
),
|
||||
// Parameter with external name and type
|
||||
rule!(
|
||||
@@ -1017,28 +1002,25 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
|
||||
// inner `getter_specifier`/`setter_specifier` rules emit
|
||||
// complete nodes from the start (including the
|
||||
// `chained_declaration` tag for non-first accessors).
|
||||
manual_rule!(
|
||||
rule!(
|
||||
(protocol_property_declaration
|
||||
name: (pattern bound_identifier: @name)
|
||||
requirements: (protocol_property_requirements accessor: _+ @accessors)
|
||||
requirements: (protocol_property_requirements accessor: _+ @@accessors)
|
||||
type: _? @ty
|
||||
(modifiers)* @mods)
|
||||
{
|
||||
ctx.property_name = Some(tree!((identifier #{name})));
|
||||
ctx.property_type = ctx.translate_opt(ty)?;
|
||||
let mut modifiers = Vec::new();
|
||||
for m in mods {
|
||||
modifiers.extend(ctx.translate(m)?);
|
||||
}
|
||||
ctx.outer_modifiers = modifiers;
|
||||
=>
|
||||
{..{
|
||||
ctx.property_name = Some(tree!((identifier #{name})).into());
|
||||
ctx.property_type = ty;
|
||||
ctx.outer_modifiers = mods;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for (i, acc) in accessors.into_iter().enumerate() {
|
||||
ctx.is_chained = i > 0;
|
||||
result.extend(ctx.translate(acc)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
result
|
||||
}}
|
||||
),
|
||||
// getter_specifier / setter_specifier → bodyless accessor_declaration
|
||||
// getter_specifier / setter_specifier → bodyless
|
||||
|
||||
Reference in New Issue
Block a user