commit e5cdf40c2a4e2c2d97d6bb14e76559325a10b067 Author: itsaky Date: Thu Jul 22 19:40:52 2021 +0530 -Updated JDK and backup before implementing JVM's ClassLoader diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..4b613a7fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ diff --git a/README.md b/README.md new file mode 100644 index 000000000..50979b884 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# AndroidIDE +An IDE to develop Android Apps on Android Smartphones. Supports Gradle Build System and OpenJDK 11.0.1 diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..56cc6425e --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,85 @@ +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 000000000..6f5179476 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,130 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.itsaky.androidide' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' +apply plugin: 'stringfog' + +android { + compileSdkVersion rootProject.ext.compileSdk + buildToolsVersion rootProject.ext.buildTools + + defaultConfig { + applicationId rootProject.ext.packageName + minSdkVersion rootProject.ext.minSdk + targetSdkVersion rootProject.ext.targetSdk + versionCode rootProject.ext.versionCode + versionName rootProject.ext.versionName + multiDexEnabled true + vectorDrawables.useSupportLibrary = true + } + + compileOptions { + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + disable "VectorPath", + "NestedWeights", + "UnusedResources", + "ContentDescription" + } + + buildFeatures.viewBinding true + + signingConfigs { + + debug { + storeFile file("/sdcard/Android App Projects/publishKey.keystore") + storePassword "itsaky" + keyAlias "itsaky" + keyPassword "itsaky" + } + + release { + storeFile file("/sdcard/Android App Projects/publishKey.keystore") + storePassword "itsaky" + keyAlias "itsaky" + keyPassword "itsaky" + } + } + + buildTypes { + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug + stringfog.enable false + } + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + stringfog.enable true + } + } + + packagingOptions { + exclude 'META-INF/eclipse.inf' + exclude 'about_files/LICENSE-2.0.txt' + exclude 'plugin.xml' + exclude 'plugin.properties' + } +} + +stringfog { + key 'WVV0aGMwaEFZVzVFVW05SlJFbGtaUT09' + enable true + implementation 'com.github.megatronking.stringfog.xor.StringFogImpl' +} + +dependencies { + // Annotation processors + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' + + implementation 'com.blankj:utilcodex:1.30.6' + implementation 'com.elvishew:xlog:1.8.0' + implementation 'com.github.abhishekti7:UnicornFilePicker:1.0.2' + implementation 'com.github.bumptech.glide:glide:4.12.0' + implementation 'com.github.megatronking.stringfog:xor:1.1.0' + implementation 'com.github.piruin:quickaction:2.4.3' + implementation 'com.github.smart-fun:XmlToJson:1.5.1' + + // Dependencies for java completion + implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.guava:guava:30.1.1-android' + implementation 'org.antlr:antlr4-runtime:4.9.2' + + // AndroidX + implementation 'androidx.annotation:annotation:1.2.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation 'androidx.drawerlayout:drawerlayout:1.1.1' + implementation 'androidx.multidex:multidex:2.0.1' + implementation 'androidx.preference:preference:1.1.1' + implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation 'androidx.vectordrawable:vectordrawable:1.1.0' + implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0' + implementation 'com.google.android.material:material:1.4.0' + + // Firebase + implementation platform('com.google.firebase:firebase-bom:28.1.0') + implementation 'com.google.firebase:firebase-analytics' + implementation 'com.google.firebase:firebase-crashlytics' + implementation 'com.google.firebase:firebase-messaging' + + // Local projects + implementation project(':treeview') + implementation project(':editor') + implementation project(':spinkit') + implementation project(':slidr') + implementation project(':javadocparser') + + implementation fileTree(dir: 'libs', include: ['*.jar']) + + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' +} diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 000000000..c2093494e --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,47 @@ +{ + "project_info": { + "project_number": "675638215311", + "project_id": "android--ide", + "storage_bucket": "android--ide.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:675638215311:android:0db45fd3cbd65abe71e6fa", + "android_client_info": { + "package_name": "com.itsaky.androidide" + } + }, + "oauth_client": [ + { + "client_id": "675638215311-33ngqr6dgg2ujbto9u70nt94scnpm89t.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.itsaky.androidide", + "certificate_hash": "0d182e8f8cf2e1fc702b0f56f81732e21c8b6908" + } + }, + { + "client_id": "675638215311-hgg79t4vd0a6ff1epl56lfqm2ccdu66l.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBVog9KolXaH95_0C41P8o5QPFYFOqaR10" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "675638215311-hgg79t4vd0a6ff1epl56lfqm2ccdu66l.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/libs/ecj.jar b/app/libs/ecj.jar new file mode 100644 index 000000000..1c7e9cad3 Binary files /dev/null and b/app/libs/ecj.jar differ diff --git a/app/libs/jsoup-1.13.1.jar b/app/libs/jsoup-1.13.1.jar new file mode 100644 index 000000000..bb1237c49 Binary files /dev/null and b/app/libs/jsoup-1.13.1.jar differ diff --git a/app/libs/tools-1.8.jar b/app/libs/tools-1.8.jar new file mode 100644 index 000000000..859f7e657 Binary files /dev/null and b/app/libs/tools-1.8.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 000000000..385351e30 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,30 @@ +-keepattributes SourceFile, LineNumberTable +-renamesourcefileattribute FuckYou + +-ignorewarnings +-dontwarn +-dontnote + +-dontwarn android.arch.** +-dontwarn android.lifecycle.** +-keep class android.arch.** { *; } +-keep class android.lifecycle.** { *; } + +-dontwarn androidx.arch.** +-dontwarn androidx.lifecycle.** +-keep class androidx.arch.** { *; } +-keep class androidx.lifecycle.** { *; } +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..98a7429b5 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/changelog.json b/app/src/main/assets/changelog.json new file mode 100644 index 000000000..e4e3cff12 --- /dev/null +++ b/app/src/main/assets/changelog.json @@ -0,0 +1,28 @@ +[ + { + "version": "1.0.1-alpha", + "changes": [ + "Added: Option to choose custom build tools", + "Added: Build output is now shown while starting completion services", + "Added: A preference screen with some basic preferences", + "Added: \u0027Stop all Daemons\u0027 option now force stops a build if it already running", + "Added: Option which shows the status of Gradle Daemons", + "Added: Syntax highlighting and basic (reserved) completion for Gradle files.", + "Added: Option to recreate completion services", + "Added: Basic options while creating a new file", + "Added: You can now invoke the selection mode without selecting a word", + "Fixed: Bug which caused files from previously created project to be copied to new project", + "Fixed: Auto import issue when a completion item is selected", + "Fixed: Orientation issue in downloads activity", + "Fixed: Sometimes, auto closing tags won\u0027t work as expected", + "Enhanced: Speed of Java completion has been improved. But still it needs a lot of work.", + "Enhanced: Starting of completion services is a bit faster as compared to the previous version. But takes more time on first startup." + ] + }, + { + "version": "1.0.0-alpha", + "changes": [ + "First alpha release" + ] + } +] \ No newline at end of file diff --git a/app/src/main/assets/data/d8.jar b/app/src/main/assets/data/d8.jar new file mode 100644 index 000000000..522998852 Binary files /dev/null and b/app/src/main/assets/data/d8.jar differ diff --git a/app/src/main/assets/data/lib/libc++_shared.so b/app/src/main/assets/data/lib/libc++_shared.so new file mode 100644 index 000000000..44ceeb217 Binary files /dev/null and b/app/src/main/assets/data/lib/libc++_shared.so differ diff --git a/app/src/main/assets/data/lib/libgcc.so b/app/src/main/assets/data/lib/libgcc.so new file mode 100644 index 000000000..b3ecce967 Binary files /dev/null and b/app/src/main/assets/data/lib/libgcc.so differ diff --git a/app/src/main/assets/data/lib/libgcc_real.so b/app/src/main/assets/data/lib/libgcc_real.so new file mode 100644 index 000000000..d96dc99d3 Binary files /dev/null and b/app/src/main/assets/data/lib/libgcc_real.so differ diff --git a/app/src/main/assets/data/lib/libhook.so b/app/src/main/assets/data/lib/libhook.so new file mode 100644 index 000000000..23ead2db5 Binary files /dev/null and b/app/src/main/assets/data/lib/libhook.so differ diff --git a/app/src/main/assets/data/lib/libpthread.so b/app/src/main/assets/data/lib/libpthread.so new file mode 100644 index 000000000..98a0f7ba7 Binary files /dev/null and b/app/src/main/assets/data/lib/libpthread.so differ diff --git a/app/src/main/assets/data/lib/librt.so b/app/src/main/assets/data/lib/librt.so new file mode 100644 index 000000000..98a0f7ba7 Binary files /dev/null and b/app/src/main/assets/data/lib/librt.so differ diff --git a/app/src/main/assets/data/lib/libz.so.1 b/app/src/main/assets/data/lib/libz.so.1 new file mode 100644 index 000000000..368b545c1 Binary files /dev/null and b/app/src/main/assets/data/lib/libz.so.1 differ diff --git a/app/src/main/assets/fonts/jetbrains-mono.ttf b/app/src/main/assets/fonts/jetbrains-mono.ttf new file mode 100644 index 000000000..5f2f00fe8 Binary files /dev/null and b/app/src/main/assets/fonts/jetbrains-mono.ttf differ diff --git a/app/src/main/assets/fonts/quicksand.ttf b/app/src/main/assets/fonts/quicksand.ttf new file mode 100644 index 000000000..edfa93f21 Binary files /dev/null and b/app/src/main/assets/fonts/quicksand.ttf differ diff --git a/app/src/main/assets/templates/0.zip b/app/src/main/assets/templates/0.zip new file mode 100644 index 000000000..46b1350bb Binary files /dev/null and b/app/src/main/assets/templates/0.zip differ diff --git a/app/src/main/assets/templates/1.zip b/app/src/main/assets/templates/1.zip new file mode 100644 index 000000000..d99de6d25 Binary files /dev/null and b/app/src/main/assets/templates/1.zip differ diff --git a/app/src/main/assets/templates/2.zip b/app/src/main/assets/templates/2.zip new file mode 100644 index 000000000..1b489cc11 Binary files /dev/null and b/app/src/main/assets/templates/2.zip differ diff --git a/app/src/main/googlePlay.png b/app/src/main/googlePlay.png new file mode 100644 index 000000000..9b68de7fe Binary files /dev/null and b/app/src/main/googlePlay.png differ diff --git a/app/src/main/java/com/itsaky/androidide/DownloadActivity.java b/app/src/main/java/com/itsaky/androidide/DownloadActivity.java new file mode 100644 index 000000000..82f5abb96 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/DownloadActivity.java @@ -0,0 +1,195 @@ +package com.itsaky.androidide; + +import abhishekti7.unicorn.filepicker.UnicornFilePicker; +import android.content.Intent; +import android.content.res.ColorStateList; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.View.OnClickListener; +import androidx.core.content.ContextCompat; +import androidx.transition.TransitionManager; +import com.blankj.utilcode.util.SizeUtils; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivityDownloadBinding; +import com.itsaky.androidide.fragments.sheets.ProgressSheet; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.tasks.callables.ListDirectoryCallable; +import com.itsaky.androidide.utils.FileUtil; +import com.itsaky.androidide.utils.PreferenceManager; +import com.itsaky.toaster.Toaster; +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; + +public class DownloadActivity extends StudioActivity { + + private ActivityDownloadBinding binding; + private ProgressSheet progressSheet; + private File choosenDir = null; + + @Override + protected View bindLayout() { + binding = ActivityDownloadBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + OnClickListener clickListener = v -> handleClick(v); + binding.dismiss.setOnClickListener(clickListener); + binding.choose.setOnClickListener(clickListener); + binding.install.setOnClickListener(clickListener); + + binding.install.setEnabled(false); + } + + private void handleClick(View v) { + final int id = v.getId(); + if(id == binding.dismiss.getId()) { + TransitionManager.beginDelayedTransition(binding.getRoot()); + binding.card.setVisibility(View.GONE); + } else if(id == binding.choose.getId()) { + try { + binding.install.setEnabled(false); + UnicornFilePicker.from(this) + .addConfigBuilder() + .addItemDivider(false) + .selectMultipleFiles(false) + .setRootDirectory(FileUtil.getExternalStorageDir()) + .showHiddenFiles(true) + .showOnlyDirectory(true) + .theme(R.style.AppTheme_FilePicker) + .build() + .forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE); + } catch (Throwable th){ + getApp().writeException(th); + } + } else if(id == binding.install.getId()) { + if(choosenDir == null) { + getApp().toast(R.string.msg_pick_files, Toaster.Type.ERROR); + return; + } + + if(!choosenDir.exists()) { + getApp().toast(R.string.msg_file_doesnt_exist, Toaster.Type.ERROR); + return; + } + + installAll(); + } + } + + private final String DONE = "DONE"; + private void installAll() { + showProgress(); + getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_DOWNLOADED, true); + final ShellServer server = getApp().newShell(__ -> checkInstalled(__)); + final StringBuilder sb = new StringBuilder(); + sb.append("cd $HOME && "); + sb.append("echo 'Installing...' && "); + File[] files = choosenDir.listFiles(ARCHIVE_FILTER); + if(files != null) + for(File f : files) { + if(f.getName().endsWith(".tar.xz")) { + sb.append("$BUSYBOX tar xvJf '" + f.getAbsolutePath() + "' && "); + } else if(f.getName().endsWith(".zip")) { + sb.append("$BUSYBOX unzip '" + f.getAbsolutePath() + "'"); + } + } + sb.append("rm -rf '" + getApp().getToolsDownloadDirectory().getAbsolutePath() + "' && "); + sb.append("echo " + DONE); + server.bgAppend(sb.toString()); + } + + private void checkInstalled(CharSequence out) { + if(out != null) { + final String line = out.toString().trim(); + runOnUiThread(() -> { + getProgressSheet().setSubMessage(line); + if(line.contains(DONE)) { + getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_INSTALLED, true); + showRestartNeeded(); + } + }); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if(requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE && resultCode == RESULT_OK) { + ArrayList files = data.getStringArrayListExtra("filePaths"); + if(files != null) { + if(files.size() == 1) { + File choosenDir = new File(files.get(0)); + if(choosenDir.exists() && choosenDir.isDirectory()) { + this.choosenDir = choosenDir; + setDone(binding.choose); + binding.install.setEnabled(true); + new TaskExecutor().executeAsync(new ListDirectoryCallable(choosenDir), __ -> { + binding.filesText.setText(getString(R.string.msg_installable_files, __)); + }); + } else { + getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR); + choosenDir = null; + } + } else { + getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR); + } + } + } + } + + private void setDone(MaterialButton button) { + final int dp8 = SizeUtils.dp2px(8); + final int dp4 = SizeUtils.dp2px(4); + final int dp24 = SizeUtils.dp2px(24); + button.setText(""); + button.setIconResource(R.drawable.ic_ok); + button.setIconTint(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.bg_green))); + button.setBackgroundColor(android.graphics.Color.TRANSPARENT); + button.setPaddingRelative(dp8, dp4, dp8, dp4); + button.setStrokeWidth(0); + button.setGravity(Gravity.CENTER); + button.setIconPadding(0); + button.setInsetTop(0); + button.setInsetBottom(0); + button.setPaddingRelative(dp24, dp4, dp24, dp4); + } + + private void showProgress() { + getProgressSheet().setCancelable(false); + getProgressSheet().setShowShadow(false); + getProgressSheet().setSubMessageEnabled(true) + .setWelcomeTextEnabled(true) + .show(getSupportFragmentManager(), "progress_sheet"); + } + + private void showRestartNeeded() { + setDone(binding.install); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + builder.setTitle(R.string.title_restart); + builder.setMessage(R.string.msg_restart); + builder.setCancelable(false); + builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity()); + builder.create().show(); + } + + private ProgressSheet getProgressSheet() { + return progressSheet == null ? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait)) : progressSheet; + } + + private final FileFilter ARCHIVE_FILTER = new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isFile() && (p1.getName().endsWith(".tar.xz") || p1.getName().endsWith(".zip")); + } + }; +} diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java new file mode 100644 index 000000000..24b1824cb --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -0,0 +1,1187 @@ +package com.itsaky.androidide; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Color; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.core.content.ContextCompat; +import androidx.core.view.GravityCompat; +import androidx.fragment.app.Fragment; +import androidx.transition.Slide; +import androidx.transition.TransitionManager; +import com.blankj.utilcode.util.ClipboardUtils; +import com.blankj.utilcode.util.FileIOUtils; +import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.IntentUtils; +import com.blankj.utilcode.util.KeyboardUtils; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.navigation.NavigationView; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.transition.MaterialArcMotion; +import com.google.android.material.transition.MaterialContainerTransform; +import com.itsaky.androidide.adapters.EditorPagerAdapter; +import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivityEditorBinding; +import com.itsaky.androidide.databinding.LayoutCreateFileJavaBinding; +import com.itsaky.androidide.databinding.LayoutDialogTextInputBinding; +import com.itsaky.androidide.fragments.EditorFragment; +import com.itsaky.androidide.fragments.FileTreeFragment; +import com.itsaky.androidide.fragments.sheets.OptionsListFragment; +import com.itsaky.androidide.fragments.sheets.TextSheetFragment; +import com.itsaky.androidide.interfaces.CompileListener; +import com.itsaky.androidide.interfaces.DexResultListener; +import com.itsaky.androidide.language.logs.LogLanguageImpl; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.models.ConstantsBridge; +import com.itsaky.androidide.models.LogLine; +import com.itsaky.androidide.models.SheetOption; +import com.itsaky.androidide.receivers.LogReceiver; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.services.Jar2DexService; +import com.itsaky.androidide.services.compiler.model.CompilerDiagnostic; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.tasks.GradleTask; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.androidide.utils.PreferenceManager; +import com.itsaky.androidide.utils.ProjectWriter; +import com.itsaky.androidide.utils.Symbols; +import com.itsaky.androidide.utils.TypefaceUtils; +import com.itsaky.androidide.views.MaterialBanner; +import com.itsaky.toaster.Toaster; +import com.unnamed.b.atv.model.TreeNode; +import io.github.rosemoe.editor.langs.EmptyLanguage; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import me.piruin.quickaction.ActionItem; +import me.piruin.quickaction.QuickAction; +import com.elvishew.xlog.XLog; + +public class EditorActivity extends StudioActivity implements FileTreeFragment.FileActionListener, + IDEService.BuildListener, + TabLayout.OnTabSelectedListener, + NavigationView.OnNavigationItemSelectedListener, + DexResultListener, + CompileListener { + + private ActivityEditorBinding mBinding; + private EditorPagerAdapter mPagerAdapter; + private FileTreeFragment mFileTreeFragment; + private EditorFragment mCurrentFragment; + private static AndroidProject mProject; + public static File mCurrentFile; + private TreeNode mLastHolded; + private CodeEditor buildView; + private CodeEditor logView; + + private LogLanguageImpl mLogLanguageImpl; + + private QuickAction mTabCloseAction; + private TextSheetFragment mDaemonStatusFragment; + private OptionsListFragment mFileOptionsFragment; + + private boolean recreateCompletionServices = false; + + private final String RES_PATH_REGEX = "/.*/src/.*/res"; + private final String LAYOUTRES_PATH_REGEX = "/.*/src/.*/res/layout"; + private final String MENURES_PATH_REGEX = "/.*/src/.*/res/menu"; + private final String DRAWABLERES_PATH_REGEX = "/.*/src/.*/res/drawable"; + private final String JAVA_PATH_REGEX = "/.*/src/.*/java"; + + private final IDEService.BuildListener mBuildListener = this; + private static final String TAG_FILE_OPTIONS_FRAGMENT = "file_options_fragment"; + public static final String TAG = "EditorActivity"; + + private static final int ACTIONID_CLOSE = 100; + private static final int ACTIONID_OTHERS = 101; + private static final int ACTIONID_ALL = 102; + + private static final HashMap> mDiagnosticsMap = new HashMap<>(); + + private LogReceiver mLogReceiver = new LogReceiver().setLogListener(line -> appendApkLog(line)); + private BroadcastReceiver mServiceStartReceiver = new BroadcastReceiver(){ + + @Override + public void onReceive(Context p1, Intent p2) { + unregisterReceiver(this); + getApp().storeBuildServiceInstance(mBuildListener); + if (getApp().isStopGradleDaemon() && getBuildService() != null) getBuildService().stopAllDaemons(); + getBuildService().setModule(mProject.getMainModulePath()); + preBuild(); + invalidateOptionsMenu(); + } + }; + + private final int[] BUILD_IDS = { + R.id.menuEditor_quickRun, + R.id.menuEditor_runDebug, + R.id.menuEditor_runRelease, + R.id.menuEditor_runBuild, + R.id.menuEditor_runBundle, + R.id.menuEditor_runClean, + R.id.menuEditor_runCleanBuild, + R.id.menuEditor_runRecreate, + R.id.menuEditor_lint, + R.id.menuEditor_lintDebug, + R.id.menuEditor_lintRelease + }; + + + @Override + protected View bindLayout() { + mBinding = ActivityEditorBinding.inflate(getLayoutInflater()); + return mBinding.getRoot(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setSupportActionBar(mBinding.editorToolbar); + + this.mProject = getIntent().getParcelableExtra("project"); + mPagerAdapter = new EditorPagerAdapter(getSupportFragmentManager(), this.mProject); + mFileTreeFragment = FileTreeFragment.newInstance(this.mProject).setFileActionListener(this); + mDaemonStatusFragment = new TextSheetFragment().setTextSelectable(true); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mBinding.editorDrawerLayout, mBinding.editorToolbar, R.string.app_name, R.string.app_name); + mBinding.editorDrawerLayout.setDrawerListener(toggle); + mBinding.startNav.setNavigationItemSelectedListener(this); + toggle.syncState(); + loadFragment(mFileTreeFragment); + + createQuickActions(); + + mBinding.editorViewPager.setOffscreenPageLimit(9); + mBinding.editorViewPager.setAdapter(mPagerAdapter); + mBinding.tabs.setupWithViewPager(mBinding.editorViewPager); + mBinding.tabs.setOnTabSelectedListener(this); + mBinding.fabView.setOnClickListener(v -> showViewOptions()); + + getApp().checkAndUpdateGradle(); + if (getBuildService() == null) { + registerServiceReceiver(); + getApp().startBuildService(); + } else { + if (getApp().isStopGradleDaemon() && getBuildService() != null) getBuildService().stopAllDaemons(); + getBuildService().setModule(mProject.getMainModulePath()); + getBuildService().setListener(this); + preBuild(); + invalidateOptionsMenu(); + } + + KeyboardUtils.registerSoftInputChangedListener(this, __ -> onSoftInputChanged()); + registerLogReceiver(); + + setupContainers(); + } + + private void setupContainers() { + if(getBuildView().getParent() != null && getBuildView().getParent() instanceof ViewGroup) { + ((ViewGroup) getBuildView().getParent()).removeView(getBuildView()); + } + + if(getLogView().getParent() != null && getLogView().getParent() instanceof ViewGroup) { + ((ViewGroup) getLogView().getParent()).removeView(getLogView()); + } + + mBinding.buildOutcontainer.addView(getBuildView(), new ViewGroup.LayoutParams(-1, -1)); + mBinding.buildContainer.setVisibility(View.GONE); + mBinding.buildOutToolbar.setNavigationOnClickListener(v -> hideBuildResult()); + mBinding.buildOutToolbar.setOnClickListener(v -> hideBuildResult()); + + mBinding.logOutcontainer.addView(getLogView(), new ViewGroup.LayoutParams(-1, -1)); + mBinding.logContainer.setVisibility(View.GONE); + mBinding.logOutToolbar.setNavigationOnClickListener(v -> hideLogResult()); + mBinding.logOutToolbar.setOnClickListener(v -> hideLogResult()); + + mBinding.viewOptionsCard.setVisibility(View.GONE); + mBinding.transformScrim.setVisibility(View.GONE); + + mBinding.transformScrim.setOnClickListener(v -> hideViewOptions()); + mBinding.viewBuildOut.setOnClickListener(v -> showBuildResult()); + mBinding.viewLogs.setOnClickListener(v -> showLogResult()); + mBinding.viewFiles.setOnClickListener(v -> showFiles()); + mBinding.viewDaemonStatus.setOnClickListener(v -> showDaemonStatus()); + } + + private void onSoftInputChanged() { + invalidateOptionsMenu(); + if(KeyboardUtils.isSoftInputVisible(this)) { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), new Slide(Gravity.TOP)); + mBinding.symbolInput.setVisibility(View.VISIBLE); + mBinding.fabView.hide(); + } else { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), new Slide(Gravity.BOTTOM)); + mBinding.symbolInput.setVisibility(View.GONE); + mBinding.fabView.show(); + } + } + + private void refreshSymbolInput(EditorFragment frag) { + mBinding.symbolInput.bindEditor(frag.binding.editorCodeEditor); + mBinding.symbolInput.setSymbols(Symbols.forFile(frag.getFile())); + } + + private void notifySyncNeeded() { + if(getBuildService() != null && !getBuildService().isBuilding()) { + getSyncBanner() + .setNegative(android.R.string.cancel, null) + .setPositive(android.R.string.ok, v -> { + getBuildService().assembleDebug(false); + }) + .show(); + } + } + + @Override + public void onBackPressed() { + if(mBinding.buildContainer.getVisibility() == View.VISIBLE) { + hideBuildResult(); + } else if(mBinding.logContainer.getVisibility() == View.VISIBLE) { + hideLogResult(); + } else if(mBinding.viewOptionsCard.getVisibility() == View.VISIBLE) { + hideViewOptions(); + } else if(mBinding.getRoot().isDrawerOpen(GravityCompat.END)) { + mBinding.getRoot().closeDrawer(GravityCompat.END); + } else if(mBinding.getRoot().isDrawerOpen(GravityCompat.START)) { + mBinding.getRoot().closeDrawer(GravityCompat.START); + } else if(getDaemonStatusFragment().isShowing()) { + getDaemonStatusFragment().dismiss(); + } else if(mFileOptionsFragment != null && mFileOptionsFragment.isShowing()) { + mFileOptionsFragment.dismiss(); + } else { + super.onBackPressed(); + } + } + + @Override + protected void onResume() { + super.onResume(); + try { + mFileTreeFragment.listProjectFiles(); + } catch (Throwable th) { + getApp().toast(R.string.msg_failed_list_files, Toaster.Type.ERROR); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (getBuildService() != null) { + getBuildService().setListener(null); + } + try { + unregisterReceiver(mServiceStartReceiver); + unregisterReceiver(mLogReceiver); + } catch (Throwable th) {} + } + + @Override + @SuppressLint("AlwaysShowAction") + public boolean onPrepareOptionsMenu(Menu menu) { + for (int id : BUILD_IDS) { + MenuItem item = menu.findItem(id); + if (item != null) { + item.setEnabled(getBuildService() != null && !getBuildService().isBuilding()); + } + } + MenuItem run1 = menu.findItem(R.id.menuEditor_quickRun); + MenuItem run2 = menu.findItem(R.id.menuEditor_run); + MenuItem undo = menu.findItem(R.id.menuEditor_undo); + MenuItem redo = menu.findItem(R.id.menuEditor_redo); + if(KeyboardUtils.isSoftInputVisible(this)) { + run1.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + run2.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + undo.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + redo.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } else { + run1.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + run2.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + undo.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + redo.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + } + return true; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_editor, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (getBuildService() == null) return false; + int id = item.getItemId(); + if (id == R.id.menuEditor_runDebug || id == R.id.menuEditor_quickRun) { + getBuildService().assembleDebug(true); + } else if (id == R.id.menuEditor_runRelease) { + getBuildService().assembleRelease(); + } else if (id == R.id.menuEditor_runClean) { + getBuildService().clean(); + } else if (id == R.id.menuEditor_runCleanBuild) { + getBuildService().cleanAndRebuild(); + } else if (id == R.id.menuEditor_runStopDaemons) { + getBuildService().stopAllDaemons(); + } else if (id == R.id.menuEditor_runBuild) { + getBuildService().build(); + } else if (id == R.id.menuEditor_runBundle) { + getBuildService().bundle(); + } else if (id == R.id.menuEditor_lint) { + getBuildService().lint(); + } else if (id == R.id.menuEditor_lintDebug) { + getBuildService().lintDebug(); + } else if (id == R.id.menuEditor_lintRelease) { + getBuildService().lintRelease(); + } else if (id == R.id.menuEditor_save) { + saveAll(); + } else if (id == R.id.menuEditor_undo && this.mCurrentFragment != null && this.mCurrentFragment.isVisible()) { + this.mCurrentFragment.undo(); + } else if (id == R.id.menuEditor_redo && this.mCurrentFragment != null && this.mCurrentFragment.isVisible()) { + this.mCurrentFragment.redo(); + } else if(id == R.id.menuEditor_runRecreate) { + getBuildService().recreateServices(); + } + invalidateOptionsMenu(); + return true; + } + + /************************************ + * Build Related * + ************************************/ + + private void appendApkLog(LogLine line) { + getLogLanguage().addLine(line); + appendLogOut(line.toString()); + } + + @Override + public void appendOutput(GradleTask task, CharSequence text) { + if(text == null) + return; + if(task != null && !task.canOutput()) { + return; + } + appendBuildOut(text.toString()); + } + + @Override + public void showPreparing() { + boolean isFirstBuild = getApp().getPrefManager().getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true); + setStatus(getString(isFirstBuild ? R.string.preparing_first : R.string.preparing)); + if(isFirstBuild) { + showFirstBuildNotice(); + } + } + + @Override + public void onStartingGradleDaemon(GradleTask task) { + setStatus(getString(R.string.msg_starting_daemon)); + getApp().setStopGradleDaemon(false); + } + + @Override + public void onRunTask(String taskName, GradleTask task) { + if(task != null && task.canOutput()) { + setStatus(getBuildService().typeString(task.getTaskID()) + " " + taskName); + } + } + + @Override + public void onBuildSuccessful(String msg, GradleTask task) { + if(task == null) return; + if(task.canOutput()) + setStatus(msg); + + if(recreateCompletionServices) { + getApp().createCompletionService(mProject); + } else if(task.getType() == GradleTask.Type.BUILD) { + if(task.getTaskID() == IDEService.TASK_ASSEMBLE_DEBUG) { + if(task.buildsApk()) { + install(task.getApk(new File(mProject.getMainModulePath(), "build").getAbsolutePath(), mProject.getMainModule())); + } + } + } + + getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false); + recreateCompletionServices = false; + invalidateOptionsMenu(); + } + + @Override + public void onBuildFailed(String msg, GradleTask task) { + if(task == null) return; + if(task.canOutput()) { + setStatus(msg); + } + + showBuildResult(); + + getApp().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false); + recreateCompletionServices = false; + invalidateOptionsMenu(); + } + + @Override + public void onGetDependencies(List dependencies) { + setStatus(getString(R.string.msg_starting_completion)); + mProject.setClassPaths(dependencies); + getApp().createJavaCompiler(mProject, this); + getApp().getJavaCompiler().compileAll(); + new Jar2DexService(getApp().getIndexedDir(), dependencies, this).startDexing(); + } + + @Override + public void onGetDependenciesFailed() { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + builder.setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, (p1, p2) -> { + p1.dismiss(); + if(getBuildService() != null) + getBuildService().showDependencies(); + }) + .setTitle(R.string.failed) + .setMessage(R.string.msg_first_prepare_failed) + .create().show(); + } + + @Override + public void saveFiles() { + saveAll(); + } + + @Override + public void onDex(String name) { + setStatus(getString(R.string.msg_indexing, name)); + } + + @Override + public void onDexSuccess(List dexes) { + ConstantsBridge.PROJECT_DEXES = dexes; + setStatus(getString(R.string.msg_indexing_success)); + createCompletionServices(); + } + + @Override + public void onDexFailed(String message) { + appendBuildOut(message); + setStatus(getString(R.string.msg_indexing_failed)); + showBuildResult(); + } + + private void appendBuildOut(String str) { + str = str.endsWith("\n") ? str : str.concat("\n"); + getBuildView(true).getText().append(str); + } + + private void appendLogOut(String str) { + str = str.endsWith("\n") ? str : str.concat("\n"); + getLogView(true).getText().append(str); + } + + private void showFiles() { + if(mBinding.viewOptionsCard.getVisibility() == View.VISIBLE) { + hideViewOptions(); + } + + mBinding.getRoot().openDrawer(GravityCompat.END, true); + } + + private void showDaemonStatus() { + if(mBinding.viewOptionsCard.getVisibility() == View.VISIBLE) { + hideViewOptions(); + } + ShellServer shell = getApp().newShell(t -> getDaemonStatusFragment().append(t.toString())); + shell.bgAppend(String.format("echo '%s'", getString(R.string.msg_getting_daemom_status))); + shell.bgAppend("gradle --status"); + if(!getDaemonStatusFragment().isShowing()) + getDaemonStatusFragment().show(getSupportFragmentManager(), "daemon_status"); + } + + private void hideToolbarAndTabs() { + mBinding.editorAppBarLayout.setVisibility(View.INVISIBLE); + } + + private void showToolbarAndTabs() { + mBinding.editorAppBarLayout.setVisibility(View.VISIBLE); + } + + private void showViewOptions() { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.fabView, mBinding.viewOptionsCard)); + mBinding.viewOptionsCard.setVisibility(View.VISIBLE); + mBinding.transformScrim.setVisibility(View.VISIBLE); + mBinding.fabView.setVisibility(View.GONE); + } + + private void hideViewOptions() { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.viewOptionsCard, mBinding.fabView)); + mBinding.viewOptionsCard.setVisibility(View.GONE); + mBinding.transformScrim.setVisibility(View.GONE); + mBinding.fabView.setVisibility(View.VISIBLE); + } + + private void showBuildResult() { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.viewBuildOut, mBinding.buildContainer)); + mBinding.buildContainer.setVisibility(View.VISIBLE); + mBinding.viewOptionsCard.setVisibility(View.GONE); + hideToolbarAndTabs(); + } + + private void hideBuildResult() { + showToolbarAndTabs(); + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.buildContainer, mBinding.viewBuildOut)); + mBinding.buildContainer.setVisibility(View.GONE); + mBinding.viewOptionsCard.setVisibility(View.VISIBLE); + } + + private void showLogResult() { + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.viewLogs, mBinding.logContainer)); + mBinding.logContainer.setVisibility(View.VISIBLE); + mBinding.viewOptionsCard.setVisibility(View.GONE); + hideToolbarAndTabs(); + } + + private void hideLogResult() { + showToolbarAndTabs(); + + TransitionManager.beginDelayedTransition(mBinding.getRoot(), createContainerTransformFor(mBinding.logContainer, mBinding.viewLogs)); + mBinding.logContainer.setVisibility(View.GONE); + mBinding.viewOptionsCard.setVisibility(View.VISIBLE); + } + + private MaterialContainerTransform createContainerTransformFor(View start, View end) { + return createContainerTransformFor(start, end, mBinding.realContainer); + } + + private MaterialContainerTransform createContainerTransformFor(View start, View end, View drawingView) { + MaterialContainerTransform transform = new MaterialContainerTransform(); + transform.setStartView(start); + transform.setEndView(end); + transform.addTarget(end); + transform.setDrawingViewId(drawingView.getId()); + transform.setAllContainerColors(ContextCompat.getColor(this, R.color.primaryDarkColor)); + transform.setElevationShadowEnabled(true); + transform.setPathMotion(new MaterialArcMotion()); + transform.setScrimColor(Color.TRANSPARENT); + return transform; + } + + private void preBuild() { + getBuildService().showDependencies(); + } + + private void install(File apk) { + if(apk.exists()) { + Intent i = IntentUtils.getInstallAppIntent(apk); + if(i != null) { + startActivity(i); + } + } + } + + private void createCompletionServices() { + new TaskExecutor().executeAsync(() -> { + getApp().createCompletionService(mProject); + return null; + }, __ -> { + setStatus(getString(getApp().areCompletorsStarted() ? R.string.msg_service_started : R.string.msg_starting_completion_failed)); + }); + } + + private void registerServiceReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(IDEService.ACTION_CREATED); + registerReceiver(mServiceStartReceiver, filter); + } + + private void registerLogReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(LogReceiver.APPEND_LOG); + registerReceiver(mLogReceiver, filter); + } + + private void setStatus(final CharSequence text) { + try { + runOnUiThread(() -> mBinding.editorStatusText.setText(text)); + } catch (Throwable th) { + } + } + + private void showFirstBuildNotice() { + new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog) + .setPositiveButton(android.R.string.ok, null) + .setTitle(R.string.title_first_build) + .setMessage(R.string.msg_first_build) + .setCancelable(false) + .create().show(); + } + + @Override + public void onCompilationResult(boolean success, Map> diagnostics) { + provideDiagnosticsToEditors(diagnostics); + } + + private void provideDiagnosticsToEditors(Map> diagnostics) { + if(mPagerAdapter != null && mPagerAdapter.getFragments() != null) { + List editors = mPagerAdapter.getFragments(); + if(editors.size() <= 0) return; + for(int i=0;i handleOptionClick(o)); + return mFileOptionsFragment; + } + + private MaterialBanner getSyncBanner() { + return mBinding.syncBanner.setContentTextColor(ContextCompat.getColor(this, R.color.primaryTextColor)) + .setBannerBackgroundColor(ContextCompat.getColor(this, R.color.primaryLightColor)) + .setButtonTextColor(ContextCompat.getColor(this, R.color.secondaryColor)) + .setIcon(R.drawable.ic_sync) + .setContentText(R.string.msg_sync_needed); + } + + private TextSheetFragment getDaemonStatusFragment() { + return mDaemonStatusFragment == null ? mDaemonStatusFragment = new TextSheetFragment().setTextSelectable(true).setTitleText(R.string.gradle_daemon_status) : mDaemonStatusFragment; + } + + private CodeEditor getBuildView() { + return getBuildView(false); + } + + private CodeEditor getBuildView(boolean setup) { + CodeEditor edit = buildView == null ? createBuildView() : buildView; + if(setup && edit.getParent() == null) { + setupContainers(); + } + return edit; + } + + private CodeEditor createBuildView() { + buildView = new CodeEditor(this); + buildView.setEditable(false); + buildView.setDividerWidth(0); + buildView.setEditorLanguage(new EmptyLanguage()); + buildView.setOverScrollEnabled(false); + buildView.setTextActionMode(CodeEditor.TextActionMode.ACTION_MODE); + buildView.setWordwrap(false); + buildView.setUndoEnabled(false); + buildView.setTypefaceLineNumber(TypefaceUtils.jetbrainsMono()); + buildView.setTypefaceText(TypefaceUtils.jetbrainsMono()); + buildView.setTextSize(12); + return buildView; + } + + private CodeEditor getLogView() { + return getLogView(false); + } + + private CodeEditor getLogView(boolean setup) { + CodeEditor edit = logView == null ? createLogView() : logView; + if(setup && edit.getParent() == null) { + setupContainers(); + } + return edit; + } + + private CodeEditor createLogView() { + logView = new CodeEditor(this); + logView.setEditable(false); + logView.setDividerWidth(0); + logView.setEditorLanguage(getLogLanguage()); + logView.setOverScrollEnabled(false); + logView.setTextActionMode(CodeEditor.TextActionMode.ACTION_MODE); + logView.setWordwrap(false); + logView.setUndoEnabled(false); + logView.setTypefaceLineNumber(TypefaceUtils.jetbrainsMono()); + logView.setTypefaceText(TypefaceUtils.jetbrainsMono()); + logView.setTextSize(12); + return logView; + } + + private LogLanguageImpl getLogLanguage() { + return mLogLanguageImpl == null ? mLogLanguageImpl = new LogLanguageImpl() : mLogLanguageImpl; + } + + // ----------------------------- + // ---- File Related + // ----------------------------- + + @Override + public void openFile(File file) { + int i = mPagerAdapter.openFile(file); + if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected()) + mBinding.tabs.getTabAt(i).select(); + mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END); + } + + @Override + public void showFileOptions(File thisFile, TreeNode node) { + mLastHolded = node; + getFileOptionsFragment(thisFile).show(getSupportFragmentManager(), TAG_FILE_OPTIONS_FRAGMENT); + } + + private boolean saveAll() { + boolean isGradleSaved = mPagerAdapter.saveAll(); + getApp().toast(R.string.all_saved, Toaster.Type.SUCCESS); + if(isGradleSaved) notifySyncNeeded(); + return isGradleSaved; + } + + private void handleOptionClick(SheetOption o) { + if(o.extra != null && o.extra instanceof File) { + final File f = (File) o.extra; + switch(o.id) { + case 0 : + ClipboardUtils.copyText("[AndroidIDE] Copied File Path", f.getAbsolutePath()); + getApp().toast(R.string.copied, Toaster.Type.SUCCESS); + break; + case 1 : + renameFile(f); + break; + case 2 : + delete(f); + break; + case 3 : + createNewFile(f); + break; + case 4 : + createNewFolder(f); + break; + } + } + } + + private void createNewFile(File f) { + createNewFile(f, false); + } + + private void createNewFile(final File f, boolean forceUnknownType) { + if(forceUnknownType) { + createNewEmptyFile(f); + } else { + final boolean isJava = Pattern.compile(Pattern.quote(mProject.getProjectPath()) + JAVA_PATH_REGEX).matcher(f.getAbsolutePath()).find(); + final boolean isRes = Pattern.compile(Pattern.quote(mProject.getProjectPath()) + RES_PATH_REGEX).matcher(f.getAbsolutePath()).find(); + final boolean isLayoutRes = Pattern.compile(Pattern.quote(mProject.getProjectPath()) + LAYOUTRES_PATH_REGEX).matcher(f.getAbsolutePath()).find(); + final boolean isMenuRes = Pattern.compile(Pattern.quote(mProject.getProjectPath()) + MENURES_PATH_REGEX).matcher(f.getAbsolutePath()).find(); + final boolean isDrawableRes = Pattern.compile(Pattern.quote(mProject.getProjectPath()) + DRAWABLERES_PATH_REGEX).matcher(f.getAbsolutePath()).find(); + if(isJava) { + createJavaClass(f); + } else if(isLayoutRes && f.getName().equals("layout")) { + createLayoutRes(f); + } else if(isMenuRes && f.getName().equals("menu")) { + createMenuRes(f); + } else if(isDrawableRes && f.getName().equals("drawable")) { + createDrawableRes(f); + } else if(isRes && f.getName().equals("res")) { + createNewResource(f); + } else { + createNewEmptyFile(f); + } + } + } + + private void createJavaClass(final File f) { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + final LayoutCreateFileJavaBinding binding = LayoutCreateFileJavaBinding.inflate(getLayoutInflater()); + builder.setView(binding.getRoot()); + builder.setTitle(R.string.new_java_class); + builder.setPositiveButton(R.string.text_create, (p1, p2) -> { + p1.dismiss(); + final String name = binding.name.getEditText().getText().toString().trim(); + final String pkgName = ProjectWriter.getPackageName(f); + if(pkgName == null || pkgName.trim().length() <= 0) { + getApp().toast(R.string.msg_get_package_failed, Toaster.Type.ERROR); + return; + } else { + final int id = binding.typeGroup.getCheckedButtonId(); + if(id == binding.typeClass.getId()) { + createFile(f, name.endsWith(".java") ? name : name.concat(".java"), ProjectWriter.createJavaClass(pkgName, !name.contains(".") ? name : name.substring(0, name.lastIndexOf(".")))); + } else if(id == binding.typeInterface.getId()) { + createFile(f, name.endsWith(".java") ? name : name.concat(".java"), ProjectWriter.createJavaInterface(pkgName, !name.contains(".") ? name : name.substring(0, name.lastIndexOf(".")))); + } else if(id == binding.typeEnum.getId()) { + createFile(f, name.endsWith(".java") ? name : name.concat(".java"), ProjectWriter.createJavaEnum(pkgName, !name.contains(".") ? name : name.substring(0, name.lastIndexOf(".")))); + } else if(id == binding.typeActivity.getId()) { + createFile(f, name.endsWith(".java") ? name : name.concat(".java"), ProjectWriter.createActivity(pkgName, !name.contains(".") ? name : name.substring(0, name.lastIndexOf(".")))); + } else { + createFile(f, name, ""); + } + + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.setCancelable(false); + builder.create().show(); + } + + private void createLayoutRes(File f) { + createNewFileWithContent(Environment.mkdirIfNotExits(f), ProjectWriter.createLayout(), ".xml"); + } + + private void createMenuRes(File f) { + createNewFileWithContent(Environment.mkdirIfNotExits(f), ProjectWriter.createMenu(), ".xml"); + } + + private void createDrawableRes(File f) { + createNewFileWithContent(Environment.mkdirIfNotExits(f), ProjectWriter.createDrawable(), ".xml"); + } + + private void createNewResource(File f) { + final String[] labels = { + getString(R.string.restype_drawable), + getString(R.string.restype_layout), + getString(R.string.restype_menu), + getString(R.string.restype_other) + }; + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + builder.setTitle(R.string.new_xml_resource); + builder.setItems(labels, (p1, p2) -> { + final int pos = p2; + if(pos == 0) { + createDrawableRes(new File(f, "drawable")); + } else if(pos == 1) { + createLayoutRes(new File(f, "layout")); + } else if(pos == 2) { + createMenuRes(new File(f, "menu")); + } else if(pos == 3) { + createNewFile(f, true); + } + }); + builder.create().show(); + } + + private void createNewEmptyFile(File f) { + createNewFileWithContent(f, ""); + } + + private void createNewFileWithContent(File f, String content) { + createNewFileWithContent(f, content, null); + } + + private void createNewFileWithContent(File folder, String content, String extension) { + final LayoutDialogTextInputBinding binding = LayoutDialogTextInputBinding.inflate(getLayoutInflater()); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + + binding.name.getEditText().setHint(R.string.file_name); + + builder.setTitle(R.string.new_file); + builder.setMessage(getString(R.string.msg_can_contain_slashes).concat("\n\n").concat(getString(R.string.msg_newfile_dest, folder.getAbsolutePath()))); + builder.setView(binding.getRoot()); + builder.setCancelable(false); + builder.setPositiveButton(R.string.text_create, (p1, p2) -> { + p1.dismiss(); + String name = binding.name.getEditText().getText().toString().trim(); + if(extension != null && extension.trim().length() > 0) { + name = name.endsWith(extension) ? name : name.concat(extension); + } + createFile(folder, name, content); + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.create().show(); + } + + private void createFile(File f, String name, String content) { + if(name.length() > 0 && name.length() <= 40 && !name.startsWith("/")) { + final File file = new File(f, name); + if(file.exists()) { + getApp().toast(R.string.msg_file_exists, Toaster.Type.ERROR); + } else { + if(FileIOUtils.writeFileFromString(file, content)) { + getApp().toast(R.string.msg_file_created, Toaster.Type.SUCCESS); + if(mLastHolded != null) { + TreeNode node = new TreeNode(file); + node.setViewHolder(new FileTreeViewHolder(this)); + mLastHolded.addChild(node); + mFileTreeFragment.expandNode(mLastHolded); + } else { + mFileTreeFragment.listProjectFiles(); + } + } else { + getApp().toast(R.string.msg_file_creation_failed, Toaster.Type.ERROR); + } + } + } else { + getApp().toast(R.string.msg_invalid_name, Toaster.Type.ERROR); + } + } + + private void createNewFolder(File f) { + final LayoutDialogTextInputBinding binding = LayoutDialogTextInputBinding.inflate(getLayoutInflater()); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + + binding.name.getEditText().setHint(R.string.folder_name); + + builder.setTitle(R.string.new_folder); + builder.setMessage(R.string.msg_can_contain_slashes); + builder.setView(binding.getRoot()); + builder.setCancelable(false); + builder.setPositiveButton(R.string.text_create, (p1, p2) -> { + p1.dismiss(); + final String name = binding.name.getEditText().getText().toString().trim(); + if(name.length() > 0 && name.length() <= 40 && !name.startsWith("/")) { + final File file = new File(f, name); + if(file.exists()) { + getApp().toast(R.string.msg_folder_exists, Toaster.Type.ERROR); + } else { + if(file.mkdirs()) { + getApp().toast(R.string.msg_folder_created, Toaster.Type.SUCCESS); + if(mLastHolded != null) { + TreeNode node = new TreeNode(file); + node.setViewHolder(new FileTreeViewHolder(EditorActivity.this)); + mLastHolded.addChild(node); + mFileTreeFragment.expandNode(mLastHolded); + } else { + mFileTreeFragment.listProjectFiles(); + } + } else { + getApp().toast(R.string.msg_folder_creation_failed, Toaster.Type.ERROR); + } + } + } else { + getApp().toast(R.string.msg_invalid_name, Toaster.Type.ERROR); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.create().show(); + } + + private void delete(final File f) { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + builder + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, (p1, p2) -> { + p1.dismiss(); + final boolean deleted = FileUtils.delete(f); + getApp().toast(deleted ? R.string.deleted : R.string.delete_failed, deleted ? Toaster.Type.SUCCESS : Toaster.Type.ERROR); + if(deleted) { + if(mLastHolded != null) { + TreeNode parent = mLastHolded.getParent(); + parent.deleteChild(mLastHolded); + mFileTreeFragment.expandNode(parent); + } else { + mFileTreeFragment.listProjectFiles(); + } + } + }) + .setTitle(R.string.title_confirm_delete) + .setMessage(getString(R.string.msg_confirm_delete, String.format("%s [%s]", f.getName(), f.getAbsolutePath()))) + .setCancelable(false) + .create().show(); + } + + private void renameFile(File f) { + final LayoutDialogTextInputBinding binding = LayoutDialogTextInputBinding.inflate(LayoutInflater.from(this)); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + + binding.name.getEditText().setHint(getString(R.string.new_name)); + binding.name.getEditText().setText(f.getName()); + + builder.setTitle(R.string.rename_file); + builder.setMessage(R.string.msg_rename_file); + builder.setView(binding.getRoot()); + builder.setNegativeButton(android.R.string.cancel, null); + builder.setPositiveButton(R.string.rename_file, (p1, p2) -> { + p1.dismiss(); + String name = binding.name.getEditText().getText().toString().trim(); + boolean renamed = name != null && name.length() > 0 && name.length() <= 40 && FileUtils.rename(f, name); + getApp().toast(renamed ? R.string.renamed : R.string.rename_failed, renamed ? Toaster.Type.SUCCESS : Toaster.Type.ERROR); + if(renamed) { + if(mLastHolded != null) { + TreeNode parent = mLastHolded.getParent(); + parent.deleteChild(mLastHolded); + TreeNode node = new TreeNode(new File(f.getParentFile(), name)); + node.setViewHolder(new FileTreeViewHolder(EditorActivity.this)); + parent.addChild(node); + mFileTreeFragment.expandNode(parent); + } else { + mFileTreeFragment.listProjectFiles(); + } + } + }); + builder.create().show(); + } + + // ----------------------------- + // ---- Quick Actions + // ----------------------------- + + private void createQuickActions() { + ActionItem closeThis = new ActionItem(ACTIONID_CLOSE, getString(R.string.action_closeThis), R.drawable.ic_close_this); + ActionItem closeOthers = new ActionItem(ACTIONID_OTHERS, getString(R.string.action_closeOthers), R.drawable.ic_close_others); + ActionItem closeAll = new ActionItem(ACTIONID_ALL, getString(R.string.action_closeAll), R.drawable.ic_close_all); + mTabCloseAction = new QuickAction(this, QuickAction.HORIZONTAL); + mTabCloseAction.addActionItem(closeThis, closeOthers, closeAll); + mTabCloseAction.setColorRes(R.color.tabAction_background); + mTabCloseAction.setTextColorRes(R.color.tabAction_text); + + mTabCloseAction.setOnActionItemClickListener((__) -> { + ActionItem item = __; + final int id = item.getActionId(); + saveAll(); + if(id == ACTIONID_CLOSE) { + closeFile(mBinding.tabs.getSelectedTabPosition()); + } + + if(id == ACTIONID_OTHERS) { + closeOthers(); + closeOthers(); + } + + if(id == ACTIONID_ALL) { + closeAll(); + } + }); + } + + private void closeAll() { + mBinding.tabs.removeOnTabSelectedListener(this); + + mPagerAdapter = new EditorPagerAdapter(getSupportFragmentManager(), mProject); + mBinding.editorViewPager.setAdapter(mPagerAdapter); + mBinding.tabs.setupWithViewPager(mBinding.editorViewPager); + mBinding.tabs.addOnTabSelectedListener(this); + } + + private void closeOthers() { + final Fragment frag = mPagerAdapter.getFragments().get(mBinding.tabs.getSelectedTabPosition()); + final File file = mPagerAdapter.getOpenedFiles().get(mBinding.tabs.getSelectedTabPosition()); + mPagerAdapter = new EditorPagerAdapter(getSupportFragmentManager(), mProject, Arrays.asList(frag), Arrays.asList(file)); + mBinding.editorViewPager.setAdapter(mPagerAdapter); + mBinding.tabs.setupWithViewPager(mBinding.editorViewPager); + mBinding.tabs.addOnTabSelectedListener(this); + } + + private void closeFile(int index) { + closeFile(index, true); + } + + private void closeFile(int index, boolean selectOther) { + mBinding.tabs.removeOnTabSelectedListener(this); + + int pos = index; + final List frags = mPagerAdapter.getFragments(); + final List files = mPagerAdapter.getOpenedFiles(); + + frags.remove(index); + files.remove(index); + + mPagerAdapter = new EditorPagerAdapter(getSupportFragmentManager(), mProject, frags, files); + mBinding.editorViewPager.setAdapter(mPagerAdapter); + mBinding.tabs.setupWithViewPager(mBinding.editorViewPager); + mBinding.tabs.addOnTabSelectedListener(this); + + if(selectOther) { + if(pos >= 0 && pos < frags.size()) { + mBinding.editorViewPager.setCurrentItem(pos, false); + } else { + int i = pos - 1; + if(i >= 0 && i < frags.size()) + pos = i; + else { + i = pos + 1; + if(i >= 0 && i < frags.size()) + pos = i; + } + mBinding.editorViewPager.setCurrentItem(pos, false); + } + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/MainActivity.java b/app/src/main/java/com/itsaky/androidide/MainActivity.java new file mode 100644 index 000000000..660ed7335 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/MainActivity.java @@ -0,0 +1,103 @@ +package com.itsaky.androidide; + +import abhishekti7.unicorn.filepicker.UnicornFilePicker; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import com.blankj.utilcode.util.SizeUtils; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.adapters.MainPagerAdapter; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivityMainBinding; +import com.itsaky.androidide.fragments.MainFragment; +import com.itsaky.androidide.fragments.ProjectsFragment; +import com.itsaky.androidide.fragments.sheets.ProgressSheet; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.utils.FileUtil; +import com.itsaky.androidide.views.VerticalViewPager; +import com.itsaky.toaster.Toaster; +import java.io.File; +import java.util.ArrayList; +import com.itsaky.androidide.utils.Environment; + +public class MainActivity extends StudioActivity +{ + private ActivityMainBinding binding; + + private MainFragment mMainFragment; + private ProjectsFragment mProjectsFragment; + private MainPagerAdapter mPagerAdapter; + + private int currentItem = 0; + + public static final String TAG = "MainActivity"; + + @Override + protected View bindLayout() { + binding = ActivityMainBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + mPagerAdapter = new MainPagerAdapter(getSupportFragmentManager()) + .addFragment(getMainFragment()) + .addFragment(getProjectsFragment()); + binding.mainViewPager.setAdapter(mPagerAdapter); + binding.mainMoveDown.hide(); + binding.mainMoveDown.setOnClickListener(v -> showFirst()); + binding.settings.setOnClickListener(v -> gotoSettings()); + binding.mainViewPager.setOnPageChangeListener(new VerticalViewPager.OnPageChangeListener(){ + + @Override + public void onPageScrolled(int p1, float p2, int p3) { + float elevation = SizeUtils.dp2px(8) * (currentItem == 0 ? p2 : -p2); + binding.activitymainTextView1.setElevation(elevation); + } + + @Override + public void onPageSelected(int p1) { + currentItem = p1; + if(p1 == 1) + binding.mainMoveDown.show(); + else binding.mainMoveDown.hide(); + } + + @Override + public void onPageScrollStateChanged(int p1) { + } + }); + } + + private void gotoSettings() { + startActivity(new Intent(this, PreferencesActivity.class)); + } + + private void showFirst() { + if(binding.mainViewPager.getCurrentItem() != 0) + binding.mainViewPager.setCurrentItem(0, true); + } + + @Override + protected void onStorageGranted() + { + getProjectsFragment().loadProjects(); + } + + @Override + protected void onStorageDenied() + { + getApp().toast(R.string.msg_storage_denied, Toaster.Type.ERROR); + finishAffinity(); + } + + private MainFragment getMainFragment() { + return mMainFragment == null ? mMainFragment = new MainFragment().setCreateProjectListener(() -> getProjectsFragment().loadProjects()).setOnCreateProjectVisibilityListener((isVisible) -> binding.mainViewPager.setScrollEnabled(!isVisible)) : mMainFragment; + } + + private ProjectsFragment getProjectsFragment() { + return mProjectsFragment == null ? mProjectsFragment = new ProjectsFragment() : mProjectsFragment; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/PreferencesActivity.java b/app/src/main/java/com/itsaky/androidide/PreferencesActivity.java new file mode 100644 index 000000000..bfb1eab00 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/PreferencesActivity.java @@ -0,0 +1,48 @@ +package com.itsaky.androidide; + +import android.os.Bundle; +import android.view.View; +import androidx.fragment.app.Fragment; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivityPreferencesBinding; +import com.itsaky.androidide.fragments.preferences.AppearancePreferences; +import com.itsaky.androidide.fragments.preferences.BuildPreferences; +import com.itsaky.androidide.fragments.preferences.EditorPreferences; +import com.itsaky.androidide.fragments.preferences.IDEPreferences; + +public class PreferencesActivity extends StudioActivity { + + private ActivityPreferencesBinding binding; + private IDEPreferences mPref; + + @Override + protected View bindLayout() { + binding = ActivityPreferencesBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setSupportActionBar(binding.toolbar); + getSupportActionBar().setTitle(R.string.ide_preferences); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + loadFragment(getPrefsFragment()); + } + + private IDEPreferences getPrefsFragment() { + return mPref == null ? mPref = new IDEPreferences() : mPref; + } + + private void loadFragment(Fragment frag) { + super.loadFragment(frag, binding.fragmentContainer.getId()); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/SplashActivity.java b/app/src/main/java/com/itsaky/androidide/SplashActivity.java new file mode 100644 index 000000000..0af992bc7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/SplashActivity.java @@ -0,0 +1,82 @@ +package com.itsaky.androidide; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivitySplashBinding; +import com.itsaky.androidide.fragments.sheets.ProgressSheet; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.utils.Environment; +import java.io.File; + +public class SplashActivity extends StudioActivity +{ + private ActivitySplashBinding binding; + + private static final Handler mHandler = new Handler(); + private final Runnable mRunnable = new Runnable(){ + + @Override + public void run() + { + startActivity(new Intent(SplashActivity.this, MainActivity.class)); + finish(); + } + }; + + @Override + protected View bindLayout() { + binding = ActivitySplashBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + binding.splashText.setText(getString(R.string.msg_checking_storage_permissions)); + } + + @Override + protected void onStorageGranted() + { + super.onStorageGranted(); + proceed(); + } + + @Override + protected void onStorageAlreadyGranted() + { + super.onStorageAlreadyGranted(); + proceed(); + } + + private void proceed() + { + if(false && !getApp().is64Bit()) { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog); + builder.setTitle(R.string.title_device_not_supported); + builder.setMessage(R.string.msg_device_not_supported); + builder.setCancelable(false); + builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity()); + builder.create().show(); + } else { + binding.splashText.setText(getString(R.string.msg_storage_granted)); + if (getApp().isFrameworkInstalled()) { + goToMain(); + } else { + startActivity(new Intent(this, DownloadActivity.class)); + finish(); + } + } + } + + private void goToMain() { + getApp().checkAndUpdateGradle(); + mHandler.removeCallbacks(mRunnable); + mHandler.postDelayed(mRunnable, 1000); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java new file mode 100644 index 000000000..bafd6a62e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java @@ -0,0 +1,76 @@ +package com.itsaky.androidide.adapters; + +import android.content.res.Resources; +import android.graphics.Typeface; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.core.content.ContextCompat; +import com.itsaky.androidide.R; +import com.itsaky.androidide.databinding.LayoutCompletionItemBinding; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.models.CompletionListItem; +import com.itsaky.androidide.utils.Either; +import com.itsaky.androidide.utils.TypefaceUtils; +import io.github.rosemoe.editor.struct.CompletionItem; +import io.github.rosemoe.editor.widget.EditorCompletionAdapter; +import java.util.Locale; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; + +public class CompletionListAdapter extends EditorCompletionAdapter { + @Override + public int getItemHeight() { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, Resources.getSystem().getDisplayMetrics()); + } + + @Override + protected View getView(int position, View convertView, ViewGroup parent, boolean isCurrentCursorPosition) { + LayoutCompletionItemBinding binding = LayoutCompletionItemBinding.inflate(LayoutInflater.from(getContext()), parent, false); + + Either e = getItem(position); + String label = "", desc = "", type = ""; + String header = ""; + if (e != null && e.isLeft()) { + SuggestItem s = e.getLeft(); + label = s.getName(); + desc = s.getDescription(); + type = s.getReturnType(); + header = String.valueOf(s.getTypeHeader()).toUpperCase(Locale.US); + } else if (e != null && e.isRight()) { + CompletionListItem item = (CompletionListItem) e.getRight(); + header = item.getType() == null ? CompletionListItem.Type.OBJECT.getAsString() : item.getType().getAsString(); + label = item.getLabel(); + type = item.getItemType().contains(".") ? item.getItemType().substring(item.getItemType().lastIndexOf(".") + 1) : item.getItemType(); + desc = item.getType() != CompletionListItem.Type.NOT_IMPORTED_CLASS ? item.getDetail() : getContext().getString(R.string.label_not_imported, item.getDetail()); + } + type = JavaUtil.getArrayTypeIfNeeded(type); + binding.completionIconText.setText(header); + binding.completionLabel.setText(label); + binding.completionType.setText(type); + binding.completionDetail.setText(desc); + binding.completionIconText.setTypeface(TypefaceUtils.jetbrainsMono(), Typeface.BOLD); + if(desc == null || desc.isEmpty()) + binding.completionDetail.setVisibility(View.GONE); + + if (isCurrentCursorPosition) + binding.getRoot().setBackgroundColor(ContextCompat.getColor(getContext(), R.color.completionList_backgroundSelected)); + else binding.getRoot().setBackgroundColor(ContextCompat.getColor(getContext(), R.color.completionList_background)); + + return binding.getRoot(); + } + + @Override + protected String getHtmlJavadocAt(int index) { + Either item = getItem(index); + if(item.isLeft() && item.getLeft() instanceof IJavaDocCommentable) { + IJavaDocCommentable commentable = (IJavaDocCommentable) item; + String doc = commentable.getJavaDoc(); + if(doc != null && doc.trim().length() > 0) { + return doc; + } + } + return ""; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java new file mode 100644 index 000000000..484679fe0 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java @@ -0,0 +1,108 @@ +package com.itsaky.androidide.adapters; + +import android.view.ViewGroup; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; +import com.itsaky.androidide.fragments.EditorFragment; +import com.itsaky.androidide.models.AndroidProject; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class EditorPagerAdapter extends FragmentStatePagerAdapter +{ + private ArrayList mOpenedFiles; + private ArrayList mFragments; + private AndroidProject project; + + public EditorPagerAdapter(FragmentManager manager, AndroidProject project) + { + super(manager); + this.project = project; + this.mOpenedFiles = new ArrayList<>(); + this.mFragments = new ArrayList<>(); + } + + public EditorPagerAdapter(FragmentManager manager, AndroidProject project, List fragments, List files) + { + super(manager); + this.project = project; + this.mOpenedFiles = new ArrayList<>(); + this.mFragments = new ArrayList<>(); + + mOpenedFiles.addAll(files); + mFragments.addAll(fragments); + } + + public int openFile(File file) + { + int openedFileIndex = -1; + for(int i=0;i= 0 && index < mFragments.size()) { + boolean hasGradle = false; + EditorFragment frag = getFrag(index); + hasGradle = frag.isModified() && frag.getFile().getName().endsWith(EditorFragment.EXT_GRADLE); + frag.save(); + return hasGradle; + } + return false; + } + + public EditorFragment getFrag(int index) { + return (EditorFragment) getItem(index); + } + + public List getFragments() { + return mFragments; + } + + public List getOpenedFiles() { + return mOpenedFiles; + } + + @Override + public Fragment getItem(int p1) + { + return p1 < 0 || p1 >= mFragments.size() ? null : mFragments.get(p1); + } + + @Override + public int getCount() + { + return mFragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) + { + return mOpenedFiles.get(position).getName(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/MainPagerAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/MainPagerAdapter.java new file mode 100644 index 000000000..2c09f815c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/MainPagerAdapter.java @@ -0,0 +1,39 @@ +package com.itsaky.androidide.adapters; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import java.util.ArrayList; + +public class MainPagerAdapter extends FragmentPagerAdapter +{ + private ArrayList mFragmentList; + + public MainPagerAdapter(FragmentManager manager) + { + super(manager); + mFragmentList = new ArrayList<>(); + } + + @Override + public Fragment getItem(int p1) + { + return mFragmentList != null && p1 < mFragmentList.size() ? mFragmentList.get(p1) : null; + } + + @Override + public int getCount() + { + return mFragmentList != null ? mFragmentList.size() : 0; + } + + public MainPagerAdapter addFragment(Fragment frag) + { + getFragments().add(frag); + return this; + } + + public ArrayList getFragments() + { + return mFragmentList == null ? mFragmentList = new ArrayList<>() : mFragmentList; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/OptionsSheetAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/OptionsSheetAdapter.java new file mode 100644 index 000000000..e503ee5af --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/OptionsSheetAdapter.java @@ -0,0 +1,53 @@ +package com.itsaky.androidide.adapters; + +import android.view.LayoutInflater; +import android.view.ViewGroup; +import androidx.recyclerview.widget.RecyclerView; +import com.itsaky.androidide.databinding.LayoutOptionssheetItemBinding; +import com.itsaky.androidide.models.SheetOption; +import java.util.List; + +public class OptionsSheetAdapter extends RecyclerView.Adapter { + + private OnOptionsClickListener listener; + private List options; + + public OptionsSheetAdapter(List options, OnOptionsClickListener listener) { + this.options = options; + this.listener = listener; + } + + @Override + public OptionsSheetAdapter.VH onCreateViewHolder(ViewGroup p1, int p2) { + return new VH(LayoutOptionssheetItemBinding.inflate(LayoutInflater.from(p1.getContext()), p1, false)); + } + + @Override + public void onBindViewHolder(OptionsSheetAdapter.VH p1, int p2) { + final LayoutOptionssheetItemBinding binding = p1.binding; + final SheetOption option = options.get(p2); + + binding.text.setText(option.titleRes); + binding.icon.setImageResource(option.iconRes); + + binding.getRoot().setOnClickListener(v -> { if(listener != null) listener.onOptionClick(option); }); + } + + @Override + public int getItemCount() { + return options.size(); + } + + public class VH extends RecyclerView.ViewHolder { + private LayoutOptionssheetItemBinding binding; + public VH(LayoutOptionssheetItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + public static interface OnOptionsClickListener { + public void onOptionClick(SheetOption option); + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java new file mode 100644 index 000000000..e0636252c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java @@ -0,0 +1,124 @@ +package com.itsaky.androidide.adapters; + +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; +import com.itsaky.androidide.R; +import com.itsaky.androidide.databinding.LayoutProjectsItemBinding; +import com.itsaky.androidide.models.AndroidProject; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import androidx.transition.TransitionManager; +import androidx.transition.ChangeBounds; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.blankj.utilcode.util.FileUtils; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.toaster.Toaster; + +public class ProjectsListAdapter extends RecyclerView.Adapter { + private ArrayList mProjects; + private OnProjectClickListener listener; + + private final Comparator PROJECTS_SORTER = new Comparator(){ + + @Override + public int compare(AndroidProject p1, AndroidProject p2) { + return p1.getAppName().compareTo(p2.getAppName()); + } + }; + + public ProjectsListAdapter(ArrayList mProjects, OnProjectClickListener listener) { + this.mProjects = mProjects; + this.listener = listener; + Collections.sort(this.mProjects, PROJECTS_SORTER); + } + + @Override + public ProjectsListAdapter.VH onCreateViewHolder(ViewGroup p1, int p2) { + return new VH(LayoutProjectsItemBinding.inflate(LayoutInflater.from(p1.getContext()), p1, false)); + } + + @Override + public void onBindViewHolder(ProjectsListAdapter.VH holder, int p2) { + final AndroidProject project = mProjects.get(p2); + holder.binding.projecsitemName.setText(project.getAppName()); + holder.binding.projecsitemPkgName.setText(project.getPackageName()); + holder.binding.deleteMsg.setText(holder.binding.deleteMsg.getContext().getString(R.string.msg_confirm_delete, project.getAppName())); + if(!TextUtils.isEmpty(project.getIconPath())) Glide.with(holder.itemView.getContext().getApplicationContext()).load(new File(project.getIconPath())).into(holder.binding.projecsitemIcon); + else holder.binding.projecsitemIcon.setImageResource(R.drawable.ic_android); + + holder.binding.projectsitemClickableContainer.setOnClickListener(v -> sendClickEvent(project)); + holder.binding.projectsitemClickableContainer.setOnLongClickListener(v -> holder.toggleDelete()); + holder.binding.delete.setOnClickListener(v -> holder.showConfirmDelete()); + holder.binding.deleteCancel.setOnClickListener(v -> holder.hideAllDelete()); + holder.binding.deleteOk.setOnClickListener(v -> deleteProject(project, p2)); + } + + private void deleteProject(AndroidProject project, int index) { + index = index >= mProjects.size() ? mProjects.size() - 1 : index; + if(index < 0) return; + mProjects.remove(index); + notifyItemRemoved(index); + + new TaskExecutor().executeAsync(() -> FileUtils.delete(project.getProjectPath()), __ -> { + StudioApp.getInstance().toast(__ ? R.string.msg_project_deleted : R.string.msg_project_delete_failed, Toaster.Type.SUCCESS); + }); + } + + private void sendClickEvent(AndroidProject project) { + if(listener != null) listener.onProjectClick(project); + } + + @Override + public int getItemCount() { + return mProjects.size(); + } + + public class VH extends RecyclerView.ViewHolder { + LayoutProjectsItemBinding binding; + + public VH(LayoutProjectsItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + + public void showConfirmDelete() { + binding.confirmDeleteContainer.setEnabled(true); + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds().setDuration(85)); + binding.confirmDeleteContainer.setVisibility(View.VISIBLE); + } + + public void hideAllDelete() { + hideDelete(); + hideConfirmDelete(); + } + + public boolean toggleDelete() { + binding.delete.setEnabled(!binding.delete.isEnabled()); + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds().setDuration(85)); + binding.delete.setVisibility(binding.delete.isEnabled() ? View.VISIBLE : View.GONE); + return true; + } + + public void hideDelete() { + binding.delete.setEnabled(false); + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds().setDuration(85)); + binding.delete.setVisibility(View.GONE); + } + + public void hideConfirmDelete() { + binding.confirmDeleteContainer.setEnabled(false); + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds().setDuration(85)); + binding.confirmDeleteContainer.setVisibility(View.GONE); + } + } + + public interface OnProjectClickListener { + public void onProjectClick(AndroidProject project); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/SymbolInputAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/SymbolInputAdapter.java new file mode 100644 index 000000000..e450c2b88 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/SymbolInputAdapter.java @@ -0,0 +1,67 @@ +package com.itsaky.androidide.adapters; + +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import androidx.core.widget.TextViewCompat; +import androidx.recyclerview.widget.RecyclerView; +import com.itsaky.androidide.databinding.LayoutSymbolItemBinding; +import com.itsaky.androidide.views.SymbolInputView.Symbol; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.widget.SymbolChannel; +import android.util.TypedValue; + +public class SymbolInputAdapter extends RecyclerView.Adapter { + + private SymbolChannel channel; + private Symbol[] symbols; + + public SymbolInputAdapter(CodeEditor editor) { + this(editor, null); + } + + public SymbolInputAdapter(CodeEditor editor, Symbol[] symbols) { + this.channel = editor.createNewSymbolChannel(); + this.symbols = symbols == null ? new Symbol[0] : symbols; + } + + public SymbolInputAdapter setSymbols(Symbol... symbols) { + return setSymbols(false, symbols); + } + + public SymbolInputAdapter setSymbols(boolean notify, Symbol... symbols) { + this.symbols = symbols; + if(notify) { + notifyDataSetChanged(); + } + return this; + } + + @Override + public VH onCreateViewHolder(ViewGroup parent, int itemType) { + return new VH(LayoutSymbolItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(VH holder, int position) { + if(symbols == null || symbols[position] == null) return; + final Symbol symbol = symbols[position]; + holder.binding.symbol.setText(symbol.label); + TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(holder.binding.symbol, 16, 27, 1, TypedValue.COMPLEX_UNIT_SP); + holder.binding.symbol.setOnClickListener(__ -> channel.insertSymbol(symbol.commit, symbol.offset)); + } + + @Override + public int getItemCount() { + return symbols == null ? 0 : symbols.length; + } + + public class VH extends RecyclerView.ViewHolder { + LayoutSymbolItemBinding binding; + + public VH(LayoutSymbolItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/adapters/viewholders/FileTreeViewHolder.java b/app/src/main/java/com/itsaky/androidide/adapters/viewholders/FileTreeViewHolder.java new file mode 100644 index 000000000..34a8f3ae3 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/adapters/viewholders/FileTreeViewHolder.java @@ -0,0 +1,72 @@ +package com.itsaky.androidide.adapters.viewholders; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import androidx.core.content.ContextCompat; +import com.github.ybq.android.spinkit.style.Circle; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.LayoutFiletreeItemBinding; +import com.itsaky.androidide.utils.Environment; +import com.unnamed.b.atv.model.TreeNode; +import java.io.File; + +public class FileTreeViewHolder extends TreeNode.BaseNodeViewHolder { + + private Context context; + private ImageView chevron; + private LayoutFiletreeItemBinding binding; + + public FileTreeViewHolder(Context context) { + super(context); + this.context = context; + } + + @Override + public View createNodeView(TreeNode node, File file) { + binding = LayoutFiletreeItemBinding.inflate(LayoutInflater.from(context)); + int dp15 = context instanceof StudioActivity ? ((StudioActivity) context).dpToPx(15) : (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, context.getResources().getDisplayMetrics())); + int icon = 0; + if (file.isDirectory()) + icon = R.drawable.ic_folder; + else if (file.getName().endsWith(".java")) + icon = R.drawable.ic_language_java; + else if (file.getName().endsWith(".kt")) + icon = R.drawable.ic_language_kotlin; + else if (file.getName().endsWith(".xml")) + icon = R.drawable.ic_language_xml; + else if (file.getName().endsWith(".gradle")) + icon = R.drawable.ic_language_gradle; + else if (file.getName().endsWith(".json")) + icon = R.drawable.ic_language_json; + else + icon = R.drawable.ic_file_unknown; + + final boolean isGradle = file.getAbsolutePath().equals(Environment.GRADLE_PROPS_DIR.getAbsolutePath()); + chevron = binding.getRoot().findViewById(R.id.filetree_chevron); + binding.filetreeName.setText(isGradle ? "GRADLE_HOME" : file.getName()); + binding.filetreeIcon.setImageResource(icon); + binding.getRoot().setPadding(binding.getRoot().getPaddingLeft() + (dp15 * (node.getLevel() - 1)), binding.getRoot().getPaddingTop(), binding.getRoot().getPaddingRight(), binding.getRoot().getPaddingBottom()); + chevron.setVisibility(file.isFile() ? View.INVISIBLE : View.VISIBLE); + chevron.setImageResource(node.isExpanded() ? R.drawable.ic_chevron_down : R.drawable.ic_chevron_right); + chevron.getDrawable().setColorFilter(ContextCompat.getColor(context, R.color.secondaryLightColor), PorterDuff.Mode.SRC_ATOP); + binding.filetreeIcon.getDrawable().setColorFilter(ContextCompat.getColor(context, R.color.secondaryLightColor), PorterDuff.Mode.SRC_ATOP); + + return binding.getRoot(); + } + + public void setLoading() { + chevron.setImageDrawable(new Circle()); + chevron.getDrawable().setColorFilter(ContextCompat.getColor(context, R.color.secondaryLightColor), PorterDuff.Mode.SRC_ATOP); + } + + public void updateChevron(boolean isExpanded) { + chevron.setImageResource(isExpanded ? R.drawable.ic_chevron_down : R.drawable.ic_chevron_right); + chevron.getDrawable().setColorFilter(ContextCompat.getColor(context, R.color.secondaryLightColor), PorterDuff.Mode.SRC_ATOP); + } +} + diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioActivity.java b/app/src/main/java/com/itsaky/androidide/app/StudioActivity.java new file mode 100644 index 000000000..459c08433 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/app/StudioActivity.java @@ -0,0 +1,106 @@ +package com.itsaky.androidide.app; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.util.TypedValue; +import android.view.View; +import androidx.annotation.AttrRes; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; +import com.itsaky.androidide.R; +import com.itsaky.androidide.services.IDEService; + +public abstract class StudioActivity extends AppCompatActivity { + private boolean toRequestStorage = true; + + public static final String TAG = "StudioActivity"; + public static final int REQCODE_STORAGE = 1009; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(bindLayout()); + onSetContentView(); + if (toRequestStorage && !isStoragePermissionGranted()) + requestStorage(); + else if (isStoragePermissionGranted()) + onStorageAlreadyGranted(); + } + + public boolean isStoragePermissionGranted() { + return Build.VERSION.SDK_INT < 23 || + (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); + } + + protected void doNotRequestStorage() { + this.toRequestStorage = false; + } + + protected void requestStorage() { + if (isStoragePermissionGranted()) { onStorageGranted(); return; } + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, REQCODE_STORAGE); + } + + public void loadFrament(Fragment frag, View view) { + loadFragment(frag, view.getId()); + } + + public void loadFragment(Fragment fragment, int id) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(id, fragment); + transaction.commit(); + } + + public StudioApp getApp() { + return (StudioApp) getApplication(); + } + + public IDEService getBuildService() { + return getApp().getBuildService(); + } + + public TypedValue getTypedValueForAttr(@AttrRes int attrRes) { + TypedValue typedValue = new TypedValue(); + getTheme().resolveAttribute(attrRes, typedValue, true); + return typedValue; + } + + public int getColorPrimary() { + return getTypedValueForAttr(R.attr.colorPrimary).data; + } + + public int getColorPrimaryDark() { + return getTypedValueForAttr(R.attr.colorPrimaryDark).data; + } + + public int getColorAccent() { + return getTypedValueForAttr(R.attr.colorAccent).data; + } + + public int dpToPx(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQCODE_STORAGE) { + if (grantResults != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) + onStorageGranted(); + else onStorageDenied(); + } + } + + protected void onStorageAlreadyGranted() {} + protected void onStorageGranted() {} + protected void onStorageDenied() {} + protected void onSetContentView() {} + + protected abstract View bindLayout(); +} diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java new file mode 100644 index 000000000..bdae075e6 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java @@ -0,0 +1,487 @@ +package com.itsaky.androidide.app; + +import android.annotation.SuppressLint; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import androidx.core.app.NotificationManagerCompat; +import androidx.multidex.MultiDexApplication; +import com.blankj.utilcode.util.EncodeUtils; +import com.blankj.utilcode.util.ResourceUtils; +import com.blankj.utilcode.util.SPStaticUtils; +import com.blankj.utilcode.util.ThrowableUtils; +import com.elvishew.xlog.LogConfiguration; +import com.elvishew.xlog.LogLevel; +import com.elvishew.xlog.XLog; +import com.elvishew.xlog.printer.Printer; +import com.elvishew.xlog.printer.file.FilePrinter; +import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator; +import com.google.firebase.messaging.FirebaseMessaging; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.interfaces.LanguageServerListener; +import com.itsaky.androidide.language.java.manager.JavaCharacter; +import com.itsaky.androidide.language.java.provider.JavaCompletionProvider; +import com.itsaky.androidide.language.xml.completion.XMLCompletionService; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.services.MessagingService; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.androidide.utils.FileUtil; +import com.itsaky.androidide.utils.PreferenceManager; +import com.itsaky.androidide.utils.StudioUtils; +import com.itsaky.toaster.Toaster; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import com.itsaky.androidide.models.ConstantsBridge; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import java.io.FileOutputStream; +import java.io.IOException; +import com.itsaky.androidide.services.compiler.JavaCompilerService; +import com.itsaky.androidide.interfaces.CompileListener; +import com.blankj.utilcode.util.FileUtils; + +public class StudioApp extends MultiDexApplication +{ + private static StudioApp instance; + private StudioUtils mUtils; + private IDEService buildService; + private JavaCompilerService mJavaCompilerService; + private JavaCompletionProvider mCompletionProvider; + private XMLCompletionService mXmlCompletionService; + private PreferenceManager mPrefsManager; + private NotificationManager mNotificationManager; + + private boolean stopGradleDaemon = true; + private String sArch = ""; + + private List serveralisteners = new ArrayList<>(); + + public static final boolean DEBUG = com.itsaky.androidide.BuildConfig.DEBUG; + + public static final long BUSYBOX_VERSION = 1; + public static final String TAG = "StudioApp"; + public static final String ASSETS_DATA_DIR = "data/"; + public static final String PROJECTS_FOLDER = "AndroidIDEProjects"; + + public static final String NOTIFICATION_ID_UPDATE = "17571"; + public static final String NOTIFICATION_ID_DEVS = "17572"; + + public static final String TELEGRAM_GROUP_URL = "https://t.me/androidide_discussions"; + public static final String SUGGESTIONS_URL = "https://github.com/itsaky/AndroidIDE"; + + private Thread.UncaughtExceptionHandler uncaughtExceptionHandler; + + @Override + public void onCreate() { + this.instance = this; + this.uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> handleCrash(thread, ex)); + initLogger(); + super.onCreate(); + mPrefsManager = new PreferenceManager(this); + mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + JavaCharacter.initMap(); + + newShell(line -> handleLog(line)).bgAppend("logcat -v threadtime"); + setupLibsIfNeeded(); + + if(isFrameworkInstalled()) { + newShell(t -> XLog.i(t)).bgAppend("printenv > /sdcard/androidideenv.txt && java -version"); + } + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createNotificationChannels(); + } + + FirebaseMessaging.getInstance().subscribeToTopic(MessagingService.TOPIC_UPDATE); + FirebaseMessaging.getInstance().subscribeToTopic(MessagingService.TOPIC_DEV_MSGS); + } + + private void handleLog(CharSequence seq) { + if(seq == null) + return; + String line = seq.toString(); + line = line.endsWith("\n") ? line : line + "\n"; + + File log = new File(FileUtil.getExternalStorageDir(), "ide_xlog/idelog.txt"); + try { + FileOutputStream os = new FileOutputStream(log, true); + os.write(line.getBytes()); + os.close(); + } catch (IOException e) {} + } + + @SuppressLint("NewApi") + private void createNotificationChannels() { + NotificationChannel updateChannel = new NotificationChannel(NOTIFICATION_ID_UPDATE, getNotificationChannelNameForId(NOTIFICATION_ID_UPDATE), NotificationManager.IMPORTANCE_HIGH); + updateChannel.enableLights(true); + updateChannel.enableVibration(true); + updateChannel.setLightColor(Color.RED); + updateChannel.setVibrationPattern(new long[]{10, 50, 10}); + NotificationManagerCompat.from(this).createNotificationChannel(updateChannel); + + NotificationChannel devsChannels = new NotificationChannel(NOTIFICATION_ID_DEVS, getNotificationChannelNameForId(NOTIFICATION_ID_DEVS), NotificationManager.IMPORTANCE_MIN); + devsChannels.enableLights(true); + devsChannels.enableVibration(true); + devsChannels.setLightColor(Color.BLUE); + devsChannels.setVibrationPattern(new long[]{10, 50, 10}); + NotificationManagerCompat.from(this).createNotificationChannel(devsChannels); + } + + public String getNotificationChannelNameForId(String id) { + if(id.equals(NOTIFICATION_ID_UPDATE)) + return getUpdateNotificationChannelName(); + else if(id.equals(NOTIFICATION_ID_DEVS)) + return getDevNotificationChannelName(); + else return "AndroidIDE Notifications"; + } + + private String getUpdateNotificationChannelName() { + return getString(R.string.cms_channel_id_update); + } + + private String getDevNotificationChannelName() { + return getString(R.string.cms_channel_id_devs); + } + + private void initLogger() { + LogConfiguration config = new LogConfiguration.Builder() + .logLevel(DEBUG ? LogLevel.ALL : LogLevel.NONE) + .tag("Android IDE") + .enableThreadInfo() + .enableStackTrace(2) + .enableBorder() + .build(); + Printer filePrinter = new FilePrinter + .Builder(FileUtil.getExternalStorageDir() + "/ide_xlog") + .fileNameGenerator(new DateFileNameGenerator()) + .build(); + XLog.init( + config, + filePrinter); + } + + private boolean setupLibsIfNeeded() { + File lib = Environment.LIBDIR; + return extractLibs(lib); +// if(lib != null && lib.exists() && lib.isDirectory()) { +// boolean libhook, librt, libgcc, libgcc_real, libpthread, libz; +// libhook = librt = libgcc = libgcc_real = libpthread = libz = false; +// File[] list = lib.listFiles(); +// if(list != null) { +// for(File f : list) { +// libhook = libhook == false && f.getName().equals("libhook.so"); +// librt = librt == false && f.getName().equals("librt.so"); +// libpthread = libpthread == false && f.getName().equals("libpthread.so"); +// libgcc = libgcc == false && f.getName().equals("libgcc.so"); +// libgcc_real = libgcc_real = false & f.getName().equals("libgcc_real.so"); +// libz = libz == false && f.getName().equals("libz.so.1"); +// } +// } else return extractLibs(lib); +// return !(libhook && librt && libgcc && libgcc_real && libpthread && libz) ? extractLibs(lib) : true; +// } else return extractLibs(lib); + } + + private boolean extractLibs(File lib) { + if(lib.exists()) + FileUtils.delete(lib.getParentFile()); + return lib.mkdirs() && ResourceUtils.copyFileFromAssets(getAssetsDataFile("lib"), lib.getAbsolutePath()); + } + + private File getBusybox() { + File parentFile = getRootDir().getParentFile(); + File busyboxDir = new File(parentFile, "bin/busybox"); + if (busyboxDir.exists() && busyboxDir.isDirectory()) + FileUtil.deleteFile(busyboxDir.getAbsolutePath()); + + if ((!busyboxDir.exists() || SPStaticUtils.getLong("BUSYBOX_VERSION", 0) < BUSYBOX_VERSION) && Build.SUPPORTED_64_BIT_ABIS.length > 0) { + String arch = getArch(Build.SUPPORTED_64_BIT_ABIS[0]); + + if (arch == null) { + return null; + } else if (ResourceUtils.copyFileFromAssets(getAssetsDataFile(new StringBuffer().append("busybox/").append(arch).toString()), parentFile.getAbsolutePath())) { + SPStaticUtils.put("busyboxArch", arch); + busyboxDir.setExecutable(true); + SPStaticUtils.put("BUSYBOX_VERSION", BUSYBOX_VERSION); + return busyboxDir; + } else return null; + } + if (!busyboxDir.canExecute()) + busyboxDir.setExecutable(true); + + return busyboxDir; + } + + public void onGradleUpdated() { + IDEService service = getBuildService(); + if(service != null) { + service.onGradleUpdated(); + } + } + + public void startBuildService() { + if(!IDEService.isRunning()) { + startService(new Intent(this, IDEService.class)); + } + } + + public void storeBuildServiceInstance(IDEService.BuildListener listener) { + buildService = IDEService.getInstance(); + buildService.setListener(listener); + } + + public IDEService getBuildService() { + return buildService; + } + + public void createCompletionService(AndroidProject project) { + this.mXmlCompletionService = new XMLCompletionService(); + this.mCompletionProvider = new JavaCompletionProvider(); + this.mCompletionProvider.loadProject(project); + } + + public void createJavaCompiler(AndroidProject project, CompileListener listener) { + this.mJavaCompilerService = + new JavaCompilerService(project) + .setListener(listener); + } + + public JavaCompilerService getJavaCompiler() { + return mJavaCompilerService; + } + + public JavaCompletionProvider getCompletionProvider() { + return mCompletionProvider; + } + + public XMLCompletionService getXmlCompletionService() { + return mXmlCompletionService; + } + + public boolean areCompletorsStarted() { + return mCompletionProvider != null + && mXmlCompletionService != null + && mCompletionProvider.isInitiated() + && mXmlCompletionService.isInitiated() + && ConstantsBridge.CLASS_LOAD_SUCCESS; + } + + public void setStopGradleDaemon(boolean startGradleDaemon) { + this.stopGradleDaemon = startGradleDaemon; + } + + public boolean isStopGradleDaemon() { + return stopGradleDaemon; + } + + public static StudioApp getInstance() { + return instance; + } + + public ShellServer newShell(ShellServer.Callback callback) { + ShellServer shellServer = new ShellServer(callback, "sh", Environment.mkdirIfNotExits(getRootDir()).getAbsolutePath()); + if (getBusybox() != null) shellServer.append(String.format("export BUSYBOX=%s\n", getBusybox().getAbsolutePath()), false); + shellServer.start(); + return shellServer; + } + + public void addServerListener(LanguageServerListener listener) { + if(serveralisteners == null) serveralisteners = new ArrayList<>(); + if(!serveralisteners.contains(listener)) + serveralisteners.add(listener); + } + + public void removeServerListener(LanguageServerListener listener) { + if(serveralisteners == null) serveralisteners = new ArrayList<>(); + if(serveralisteners.contains(listener)) + serveralisteners.remove(listener); + } + + + public void writeException(Throwable th) { + FileUtil.writeFile(new File(FileUtil.getExternalStorageDir(), "idelog.txt").getAbsolutePath(), ThrowableUtils.getFullStackTrace(th)); + } + + public File getIndexedDir() { + return Environment.mkdirIfNotExits(new File(getRootDir(), "indexed")); + } + + public File getD8Jar() { + File f = new File(getRootDir(), "d8.jar"); + if(f.exists() && f.isFile()) + return f; + if(ResourceUtils.copyFileFromAssets("data/d8.jar", f.getAbsolutePath())) { + return f; + } + + return null; + } + + public File getRootDir() { + return new File(getIDEDataDir(), "framework"); + } + + public File getRootDirOld() { + return new File(getFilesDir(), "framework"); + } + + public File getIDEDataDir() { + return Environment.mkdirIfNotExits(new File("/data/data/com.itsaky.androidide/files")); + } + + public final File getLogSenderDir() { + return new File(getRootDir(), "logsender"); + } + + public final File getToolsDownloadDirectory() { + return new File(getRootDir(), "downloads"); + } + + public final File getTempProjectDir() { + return Environment.mkdirIfNotExits(new File(getRootDir(), "tempProject")); + } + + public final File getTempClassesDir() { + return Environment.mkdirIfNotExits(new File(FileUtil.getExternalStorageDir() /*getTempProjectDir() */, "classes")); + } + + public final String getDownloadRequestUrl() { + return new String(EncodeUtils.base64Decode("aHR0cHM6Ly9hbmRyb2lkaWRlLmNvbS9idWlsZC90b29scy9kb3dubG9hZC8=")); + } + + public boolean isFrameworkDownloaded() { + return getToolsDownloadDirectory().exists() && mPrefsManager.isFrameworkDownloaded(); + } + + public boolean isFrameworkInstalled() { + return getRootDir().exists() && mPrefsManager.isFrameworkInstalled(); + } + + public PreferenceManager getPrefManager() { + return mPrefsManager; + } + + public File getProjectsDir() { + return Environment.mkdirIfNotExits(new File(FileUtil.getExternalStorageDir(), PROJECTS_FOLDER)); + } + + public File[] listProjects() { + return getProjectsDir().listFiles(p1 -> p1.isDirectory()); + } + + public boolean is64Bit() { + if(Build.VERSION.SDK_INT >= 23) { + return android.os.Process.is64Bit(); + } else { + String[] abis = Build.SUPPORTED_64_BIT_ABIS; + return abis != null && abis.length > 0; + } + } + + public String getArch() { + if (sArch == null) { + sArch = getArch(System.getProperty("os.arch")); + } + return sArch; + } + + private void handleCrash(Thread thread, Throwable th) { + if(DEBUG) + writeException(th); + if(this.uncaughtExceptionHandler != null) { + this.uncaughtExceptionHandler.uncaughtException(thread, th); + } + try { + android.os.Process.killProcess(android.os.Process.myPid()); + } catch (Throwable ignored) {} + } + + private String getArch(String str) { + if (str.length() > 0) { + switch (str.toLowerCase(Locale.US).charAt(0)) { + case 'a': + return str.equals("amd64") ? "x86_64" : str.contains("64") ? "arm64" : "arm"; + case 'i': + case 'x': + return str.contains("64") ? "x86_64" : "x86"; + case 'm': + return str.contains("64") ? "mips64" : "mips"; + } + } + return "unknown"; + } + + public String getAssetsDataFile() { + return ASSETS_DATA_DIR; + } + + public String getAssetsDataFile(String str) { + return new StringBuffer().append(getAssetsDataFile()).append(str).toString(); + } + + public void checkAndUpdateGradle() { + File gradle = new File(Environment.GRADLE_DIR, "bin/gradle"); + if(gradle.exists()) { + String[] txt = FileUtil.readFile(gradle.getAbsolutePath()).split("\n"); + if(txt != null && txt.length > 1 && txt[0].contains("#!/usr/bin/env sh")) { + txt[0] = ""; + FileUtil.writeFile(gradle.getAbsolutePath(), TextUtils.join("\n", txt)); + if(!gradle.canExecute()) + gradle.setExecutable(true); + } + } + } + + public StudioUtils getUtils() { + return mUtils == null ? mUtils = new StudioUtils(this) : mUtils; + } + + public void toast(String msg, Toaster.Type type) { + getUtils().toast(msg, type); + } + + public void toast(int msg, Toaster.Type type) { + getUtils().toast(msg, type); + } + + public void toastLong(String msg, Toaster.Type type) { + getUtils().toastLong(msg, type); + } + + public void toastLong(int msg, Toaster.Type type) { + getUtils().toastLong(msg, type); + } + + public static File getCompilerOut() { + return new File(FileUtil.getExternalStorageDir(), "ide_xlog/compiler_out.txt"); + } + + public static File getCompilerError() { + return new File(FileUtil.getExternalStorageDir(), "ide_xlog/compiler_err.txt"); + } + + public void openTelegramGroup() { + Intent open = new Intent(); + open.setAction(Intent.ACTION_VIEW); + open.setData(Uri.parse(StudioApp.TELEGRAM_GROUP_URL)); + open.setPackage("org.telegram.messenger"); + open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(open); + } + + public void openIssueTracker() { + Intent open = new Intent(); + open.setAction(Intent.ACTION_VIEW); + open.setData(Uri.parse(StudioApp.SUGGESTIONS_URL)); + open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(open); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/BaseFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/BaseFragment.java new file mode 100644 index 000000000..0faf41097 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/BaseFragment.java @@ -0,0 +1,11 @@ +package com.itsaky.androidide.fragments; + +import androidx.fragment.app.Fragment; +import com.itsaky.androidide.app.StudioActivity; + +public class BaseFragment extends Fragment +{ + protected StudioActivity getStudioActivity() { + return (StudioActivity) getActivity(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java new file mode 100644 index 000000000..300c4b616 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java @@ -0,0 +1,276 @@ +package com.itsaky.androidide.fragments; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import com.itsaky.androidide.adapters.CompletionListAdapter; +import com.itsaky.androidide.databinding.FragmentEditorBinding; +import com.itsaky.androidide.fragments.preferences.EditorPreferences; +import com.itsaky.androidide.language.groovy.GroovyLanguage; +import com.itsaky.androidide.language.java.JavaLanguage; +import com.itsaky.androidide.language.xml.XMLLanguage; +import com.itsaky.androidide.language.xml.lexer.XMLLexer; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.models.ConstantsBridge; +import com.itsaky.androidide.services.compiler.model.CompilerDiagnostic; +import com.itsaky.androidide.syntax.colorschemes.SchemeWombat; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.tasks.callables.ReadFileTask; +import com.itsaky.androidide.utils.FileUtil; +import com.itsaky.androidide.utils.PreferenceManager; +import com.itsaky.androidide.utils.TypefaceUtils; +import io.github.rosemoe.editor.interfaces.EditorEventListener; +import io.github.rosemoe.editor.langs.EmptyLanguage; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.widget.schemes.SchemeVS2019; +import java.io.File; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; +import com.elvishew.xlog.XLog; +import android.text.TextUtils; +import com.itsaky.androidide.services.compiler.JavaCompilerService; + +public class EditorFragment extends BaseFragment implements EditorEventListener { + + public FragmentEditorBinding binding; + private File mFile; + private boolean isRead = false; + private boolean isModified = false; + private boolean isFirstCreate = false; + + private static AndroidProject project; + + private List diags; + + public static final String KEY_FILE_PATH = "file_path"; + public static final String KEY_PROJECT = "project"; + public static final String EXT_JAVA = ".java"; + public static final String EXT_XML = ".xml"; + public static final String EXT_HTML = ".html"; + public static final String EXT_GRADLE = ".gradle"; + public static final String EXT_GROOVY = ".groovy"; + public static final String EXT_KOTLIN = ".kt"; + public static final String EXT_JSON = ".json"; + + public static EditorFragment newInstance(File file, AndroidProject project) { + Bundle bundle = new Bundle(); + bundle.putString(KEY_FILE_PATH, file.getAbsolutePath()); + bundle.putParcelable(KEY_PROJECT, project); + EditorFragment frag = new EditorFragment(); + frag.setArguments(bundle); + return frag; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + isFirstCreate = true; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = FragmentEditorBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getActivity() == null || getArguments() == null || !getArguments().containsKey(KEY_FILE_PATH) || !getArguments().containsKey(KEY_PROJECT)) return; + mFile = new File(getArguments().getString(KEY_FILE_PATH)); + project = getArguments().getParcelable(KEY_PROJECT); + + binding.editorCodeEditor.setOverScrollEnabled(false); + binding.editorCodeEditor.setTypefaceText(TypefaceUtils.jetbrainsMono()); + binding.editorCodeEditor.setTextActionMode(CodeEditor.TextActionMode.ACTION_MODE); + binding.editorCodeEditor.setHighlightCurrentBlock(true); + binding.editorCodeEditor.setEventListener(this); + binding.editorCodeEditor.setAutoCompletionOnComposing(true); + binding.editorCodeEditor.setAutoCompletionItemAdapter(new CompletionListAdapter()); + binding.editorCodeEditor.setLineColorsEnabled(true); + + configureEditorIfNeeded(); + + new TaskExecutor().executeAsync(new ReadFileTask(mFile), result -> { + binding.editorCodeEditor.setText(result); + postRead(); + }); + } + + public void setDiagnostics(List diags) { + this.diags = diags; + XLog.i("[EditorFragment] Diagnostics for file: " + getFile().getAbsolutePath() + + "\ndiagnostics: " + TextUtils.join("\n", diags)); + } + + private void configureEditorIfNeeded() { + boolean sizeChanged = isFirstCreate || ConstantsBridge.EDITORPREF_SIZE_CHANGED; + boolean flagsChanged = isFirstCreate || ConstantsBridge.EDITORPREF_FLAGS_CHANGED; + boolean drawHexChanged = isFirstCreate || ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED; + final PreferenceManager prefs = getStudioActivity().getApp().getPrefManager(); + if(sizeChanged) { + float textSize = prefs.getFloat(EditorPreferences.KEY_EDITOR_FONT_SIZE); + if(textSize < 6 || textSize > 32) + textSize = 14; + binding.editorCodeEditor.setTextSize(textSize); + ConstantsBridge.EDITORPREF_SIZE_CHANGED = false; + } + + if(flagsChanged) { + int flags = 0; + if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_LEADING, true)) + flags |= CodeEditor.FLAG_DRAW_WHITESPACE_LEADING; + if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_TRAILING, false)) + flags |= CodeEditor.FLAG_DRAW_WHITESPACE_TRAILING; + if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_INNER, true)) + flags |= CodeEditor.FLAG_DRAW_WHITESPACE_INNER; + if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_EMPTY_LINE, true)) + flags |= CodeEditor.FLAG_DRAW_WHITESPACE_FOR_EMPTY_LINE; + if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_LINE_BREAK, true)) + flags |= CodeEditor.FLAG_DRAW_LINE_SEPARATOR; + + binding.editorCodeEditor.setNonPrintablePaintingFlags(flags); + ConstantsBridge.EDITORPREF_FLAGS_CHANGED = false; + } + + if(drawHexChanged) { + binding.editorCodeEditor.setLineColorsEnabled(prefs.getBoolean(PreferenceManager.KEY_EDITOR_DRAW_HEX, true)); + ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED = false; + } + + isFirstCreate = false; + } + + public boolean isModified() { + return isModified; + } + + public void undo() { + if(binding.editorCodeEditor.canUndo()) + binding.editorCodeEditor.undo(); + } + + public void redo() { + if(binding.editorCodeEditor.canRedo()) + binding.editorCodeEditor.redo(); + } + + public void save() { + FileUtil.writeFile(mFile.getAbsolutePath(), binding.editorCodeEditor.getText().toString()); + isModified = false; + } + + public File getFile() { + return mFile; + } + + @Override + public void onResume() { + super.onResume(); + configureEditorIfNeeded(); + } + + private void postRead() { + if (mFile.isFile() && mFile.getName().endsWith(EXT_JAVA)) { + binding.editorCodeEditor.setEditorLanguage(new JavaLanguage(binding.editorCodeEditor, project)); + binding.editorCodeEditor.setColorScheme(new SchemeVS2019()); + } else if (mFile.isFile() && mFile.getName().endsWith(EXT_XML)) { + binding.editorCodeEditor.setEditorLanguage(new XMLLanguage(binding.editorCodeEditor)); + binding.editorCodeEditor.setColorScheme(new SchemeWombat()); + } else if (mFile.isFile() && mFile.getName().endsWith(EXT_GRADLE)) { + binding.editorCodeEditor.setEditorLanguage(new GroovyLanguage()); + binding.editorCodeEditor.setColorScheme(new SchemeVS2019()); + } else { + binding.editorCodeEditor.setEditorLanguage(new EmptyLanguage()); + } + isRead = true; + } + + private void closeCurrentTag(String text, int line, int col) { + try { + XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(text))); + Token token; + boolean wasSlash = false, wasOpen = false; + ArrayList currentNames = new ArrayList<>(); + while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) { + final int type = token.getType(); + if(type == XMLLexer.OPEN) { + wasOpen = true; + } else if(type == XMLLexer.Name) { + if(wasOpen && wasSlash && currentNames.size() > 0) { + currentNames.remove(0); + } else if(wasOpen){ + currentNames.add(0, token.getText()); + wasOpen = false; + } + } else if(type == XMLLexer.OPEN_SLASH) { + int l = token.getLine() - 1; + int c = token.getCharPositionInLine(); + if(l == line && c == col) { + break; + } + else if(currentNames.size() > 0) + currentNames.remove(0); + } else if(type == XMLLexer.SLASH_CLOSE + || type == XMLLexer.SPECIAL_CLOSE) { + if(currentNames.size() > 0 && token.getText().trim().endsWith("/>")) + currentNames.remove(0); + } else if(type == XMLLexer.SLASH) { + wasSlash = true; + } else wasOpen = wasSlash = false; + } + if(currentNames.size() > 0) { + binding.editorCodeEditor.getText().insert(line, col + 2, currentNames.get(0)); + } + } catch (Throwable th) {} + } + + @Override + public boolean onRequestFormat(CodeEditor editor, boolean async) { + return false; + } + + @Override + public boolean onFormatFail(CodeEditor editor, Throwable cause) { + return false; + } + + @Override + public void onFormatSucceed(CodeEditor editor) { + } + + @Override + public void onNewTextSet(CodeEditor editor) { + isModified = true; + } + + @Override + public void afterDelete(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence deletedContent) { + isModified = true; + } + + @Override + public void afterInsert(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence insertedContent) { + isModified = true; + boolean isOpen = false; + try { + isOpen = editor.getText().charAt(editor.getCursor().getLeft() - 2) == '<'; + } catch (Throwable th) {} + if(isOpen && insertedContent.toString().equals("/")) { + closeCurrentTag(editor.getText().toString(), endLine, endColumn); + } + + JavaCompilerService compiler = getStudioActivity().getApp().getJavaCompiler(); + if(compiler != null) { + compiler.compileAll(); + } + } + + @Override + public void beforeReplace(CodeEditor editor, CharSequence content) { + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java new file mode 100644 index 000000000..406a877f9 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java @@ -0,0 +1,240 @@ +package com.itsaky.androidide.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.ProgressBar; +import androidx.transition.ChangeBounds; +import androidx.transition.TransitionManager; +import com.blankj.utilcode.util.FileIOUtils; +import com.bumptech.glide.Glide; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.itsaky.androidide.R; +import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.databinding.LayoutEditorFileTreeBinding; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.tasks.callables.FileTreeCallable; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.toaster.Toaster; +import com.unnamed.b.atv.model.TreeNode; +import com.unnamed.b.atv.view.AndroidTreeView; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; + +public class FileTreeFragment extends BottomSheetDialogFragment implements TreeNode.TreeNodeClickListener, TreeNode.TreeNodeLongClickListener { + + private LayoutEditorFileTreeBinding binding; + private AndroidTreeView mFileTreeView; + private FileActionListener mFileActionListener; + private AndroidProject mProject; + private TreeNode mRoot; + private ArrayList compatibleExtensions = new ArrayList<>(); + + public FileTreeFragment() { + compatibleExtensions = new ArrayList<>(); + compatibleExtensions.add(".java"); // Java + compatibleExtensions.add(".kt"); // Kotlin + compatibleExtensions.add(".xml"); // XML + compatibleExtensions.add(".json"); // JSON + compatibleExtensions.add(".gradle"); // Gradle + compatibleExtensions.add(".txt"); // Text + compatibleExtensions.add(".properties"); // properties (User may need to edit gradle.properties) + compatibleExtensions.add(".md"); // MarkDown (to edit README.md and other files) + } + + public FileTreeFragment setFileActionListener(FileActionListener listener) { + this.mFileActionListener = listener; + return this; + } + + public static FileTreeFragment newInstance(AndroidProject project) { + Bundle bundle = new Bundle(); + bundle.putParcelable("project", project); + FileTreeFragment frag = new FileTreeFragment(); + frag.setArguments(bundle); + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = LayoutEditorFileTreeBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getActivity() == null || getArguments() == null || !getArguments().containsKey("project")) return; + mProject = getArguments().getParcelable("project"); + + if(mProject.getIconPath() == null || mProject.getIconPath().trim().length() <= 0) { + StudioApp.getInstance().toast(R.string.msg_failed_load_icon_path, Toaster.Type.ERROR); + } else { + Glide.with(getActivity().getApplicationContext()).load(new File(mProject.getIconPath())).into(binding.filetreenavigationAppIcon); + } + binding.filetreenavigationProjectDetails.setText(getResources().getString(R.string.project_with_package, mProject.getAppName(), mProject.getPackageName())); + listProjectFiles(); + } + + @Override + public void onClick(TreeNode node, Object p2) { + final File f = (File) p2; + if(f.isFile()) { + if (mFileActionListener != null && f.isFile()) { + for(String ext : compatibleExtensions) { + if(f.getName().endsWith(ext)) { + mFileActionListener.openFile(f); + break; + } + } + } + } else if(f.isDirectory() && f.exists()) { + if(node.isExpanded()) { + collapseNode(node); + } else if(f.getAbsolutePath().equals(Environment.GRADLE_PROPS_DIR.getAbsolutePath()) && !node.isExpanded()) { + expandNode(node); + } else { + setLoading(node); + listNode(node, true); + } + } + } + + private void listNode(TreeNode node, boolean wasClicked) { + node.getChildren().clear(); + node.setExpanded(false); + new TaskExecutor().executeAsync(() -> { + getNodeFromFiles(node.getValue().listFiles(/* new FileTreeCallable.HiddenFilesFilter() */), node); + TreeNode temp = node; + while(temp.size() == 1) { + temp = temp.childAt(0); + if(!temp.getValue().isDirectory()) break; + getNodeFromFiles(temp.getValue().listFiles(/* new FileTreeCallable.HiddenFilesFilter() */), temp); + temp.setExpanded(true); + } + return null; + }, __ -> { + updateChevron(node); + expandNode(node); + }); + } + + private void getNodeFromFiles(File[] files, TreeNode parent) { + Arrays.sort(files, new FileTreeCallable.SortFileName()); + Arrays.sort(files, new FileTreeCallable.SortFolder()); + for (File file : files) { + TreeNode node = new TreeNode(file); + node.setViewHolder(new FileTreeViewHolder(getContext())); + parent.addChild(node); + } + } + + private void setLoading(TreeNode node) { + if (node.getViewHolder() instanceof FileTreeViewHolder) { + ((FileTreeViewHolder) node.getViewHolder()).setLoading(); + } + } + + private void updateChevron(TreeNode node) { + if (node.getViewHolder() instanceof FileTreeViewHolder) { + ((FileTreeViewHolder) node.getViewHolder()).updateChevron(!node.isExpanded()); + } + } + + @Override + public boolean onLongClick(TreeNode node, Object value) { + if(mFileActionListener != null) + mFileActionListener.showFileOptions((File) value, node); + return true; + } + + public void expandNode(TreeNode node) { + if(mFileTreeView == null) { + return; + } + + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); + mFileTreeView.expandNode(node); + } + + public void collapseNode(TreeNode node) { + if(mFileTreeView == null) { + return; + } + + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); + mFileTreeView.collapseNode(node); + } + + + public void listProjectFiles() { + if (mProject == null) + return; + + final File gradleProps = Environment.GRADLE_PROPS; + final File gradleHome = Environment.GRADLE_PROPS_DIR; + final File root = StudioApp.getInstance().getRootDir().getParentFile(); + File projectDir = new File(mProject.getProjectPath()); + projectDir = root; + mRoot = TreeNode.root(projectDir); + if(gradleHome.exists() && gradleHome.isDirectory()) { + if(!gradleProps.exists()) + FileIOUtils.writeFileFromString(gradleProps, Environment.SAMPLE_GRADLE_PROP_CONTENTS); + TreeNode home = new TreeNode(gradleHome); + home.setViewHolder(new FileTreeViewHolder(getContext())); + TreeNode prop = new TreeNode(gradleProps); + prop.setViewHolder(new FileTreeViewHolder(getContext())); + home.addChild(prop); + mRoot.addChild(home); + } + mRoot.setViewHolder(new FileTreeViewHolder(getContext())); + + getScrollView().setVisibility(View.GONE); + getLoadingProgress().setVisibility(View.VISIBLE); + new TaskExecutor().executeAsync(new FileTreeCallable(getContext(), mRoot, projectDir), (result) -> { + getScrollView().setVisibility(View.VISIBLE); + getLoadingProgress().setVisibility(View.GONE); + AndroidTreeView tree = createTreeView(mRoot); + if(tree != null) { + tree.setUseAutoToggle(false); + tree.setDefaultNodeClickListener(FileTreeFragment.this); + tree.setDefaultNodeLongClickListener(FileTreeFragment.this); + getScrollView().removeAllViews(); + getScrollView().addView(tree.getView()); + } + }); + } + + public AndroidTreeView createTreeView(TreeNode node) { + Context ctx = null; + if(getActivity() != null) + ctx = getActivity(); + else if(getContext() != null) { + ctx = getContext(); + } + + if(ctx == null) + return null; + + return mFileTreeView = new AndroidTreeView(ctx, node, R.drawable.bg_ripple); + } + + public HorizontalScrollView getScrollView() { + return binding.filetreeHorizontalScrollView; + } + + public ProgressBar getLoadingProgress() { + return binding.fileTreeLoadingProgress; + } + + public interface FileActionListener { + public void openFile(File file); + public void showFileOptions(File file, TreeNode node); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/MainFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/MainFragment.java new file mode 100644 index 000000000..b22b78ad7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/MainFragment.java @@ -0,0 +1,340 @@ +package com.itsaky.androidide.fragments; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.transition.ChangeBounds; +import androidx.transition.Transition; +import androidx.transition.TransitionManager; +import com.itsaky.androidide.R; +import com.itsaky.androidide.databinding.LayoutCreateProjectBinding; +import com.itsaky.androidide.databinding.LayoutCreateProjectContentBinding; +import com.itsaky.androidide.databinding.LayoutMainBinding; +import com.itsaky.androidide.interfaces.ProjectWriterCallback; +import com.itsaky.androidide.models.ProjectTemplate; +import com.itsaky.androidide.views.transition.ArcMotionPlus; +import com.itsaky.toaster.Toaster; +import java.util.ArrayList; +import java.util.concurrent.Callable; +import com.itsaky.androidide.utils.ProjectWriter; +import com.itsaky.androidide.models.NewProjectDetails; +import com.itsaky.androidide.fragments.sheets.ProgressSheet; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.tasks.callables.ProjectCreatorCallable; + +public class MainFragment extends BaseFragment implements OnClickListener, ProjectWriterCallback +{ + private LayoutMainBinding binding; + private LayoutCreateProjectBinding createBinding; + private LayoutCreateProjectContentBinding createLayoutBinding; + + private OnCreateProjectListener createProjectListener; + private ProgressSheet mWritingProgressSheet; + + private ArrayList mTemplates = new ArrayList(); + private OnCreateProjectVisibilityListener visibilityChangeListener; + + public static final String TAG = "MainFragment"; + private int currentTemplateIndex = 0; + + public MainFragment setCreateProjectListener(OnCreateProjectListener createProjectListener) { + this.createProjectListener = createProjectListener; + return this; + } + + public MainFragment setOnCreateProjectVisibilityListener(OnCreateProjectVisibilityListener visibilityChangeListener) { + this.visibilityChangeListener = visibilityChangeListener; + return this; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = LayoutMainBinding.inflate(inflater, container, false); + createBinding = binding.createLayout; + createLayoutBinding = createBinding.createProjectContent; + return binding.getRoot(); + } + + @Override + public void onViewCreated(final View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + binding.createNew.setOnClickListener(this); + createBinding.createprojectClose.setOnClickListener(this); + createLayoutBinding.createprojectCreate.setOnClickListener(this); + createLayoutBinding.previousCard.setOnClickListener(this); + createLayoutBinding.nextCard.setOnClickListener(this); + binding.createNewCard.setVisibility(View.GONE); + + currentTemplateIndex = 0; + createTemplates(); + createProgressSheet(); + showTemplate(currentTemplateIndex); + } + + @Override + public void onClick(View p1) { + if(p1.getId() == binding.createNew.getId()) + showCreateProject(); + else if(p1.getId() == createBinding.createprojectClose.getId()) + hideCreateProject(); + else if(p1.getId() == createLayoutBinding.nextCard.getId()) { + currentTemplateIndex++; + if(currentTemplateIndex >= mTemplates.size()) currentTemplateIndex = 0; + showTemplate(currentTemplateIndex); + } else if(p1.getId() == createLayoutBinding.previousCard.getId()) { + currentTemplateIndex--; + if(currentTemplateIndex < 0) currentTemplateIndex = mTemplates.size() - 1; + showTemplate(currentTemplateIndex); + } else if(p1.getId() == createLayoutBinding.createprojectCreate.getId()) + createNewProject(); + } + + @Override + public void beforeBegin() { + if(mWritingProgressSheet == null) + createProgressSheet(); + + setMessage(R.string.msg_begin_project_write); + } + + @Override + public void onProcessTask(String taskName) { + setMessage(taskName); + } + + @Override + public void onSuccess() { + if(mWritingProgressSheet != null) + createProgressSheet(); + + if(mWritingProgressSheet.isShowing()) + mWritingProgressSheet.dismiss(); + getStudioActivity().getApp().toast(R.string.project_created_successfully, Toaster.Type.SUCCESS); + if(createProjectListener != null) + createProjectListener.onNewProjectCreated(); + } + + @Override + public void onFailed(String reason) { + if(mWritingProgressSheet != null) + createProgressSheet(); + + if(mWritingProgressSheet.isShowing()) + mWritingProgressSheet.dismiss(); + getStudioActivity().getApp().toast(reason, Toaster.Type.ERROR); + } + + private void showTemplate(int index) { + if(index < 0 || index >= mTemplates.size()) return; + final ProjectTemplate template = mTemplates.get(index); + createLayoutBinding.createprojectTemplateLabel.setText(template.getName()); + createLayoutBinding.createprojectTemplateDescription.setText(template.getDescription()); + createLayoutBinding.createprojectTemplateImage.setImageResource(template.getImageId()); + } + + /** + * Must be called in/after onViewCreated + */ + private void createTemplates() { + mTemplates = new ArrayList<>(); + + ProjectTemplate + empty = new ProjectTemplate() + .setId(0) + .setName(getContext(), R.string.template_empty) + .setDescription(getContext(), R.string.template_description_empty) + .setImageId(R.drawable.template_empty), + basic = new ProjectTemplate() + .setId(1) + .setName(getContext(), R.string.template_basic) + .setDescription(getContext(), R.string.template_description_basic) + .setImageId(R.drawable.template_basic), + drawer = new ProjectTemplate() + .setId(2) + .setName(getContext(), R.string.template_navigation_drawer) + .setDescription(getContext(), R.string.template_description_navigation_drawer) + .setImageId(R.drawable.template_navigation_drawer); +// navigation = new ProjectTemplate() +// .setId(3) +// .setName(getContext(), R.string.template_bottom_navigation) +// .setDescription(getContext(), R.string.template_description_bottom_navigation) +// .setImageId(R.drawable.template_bottom_navigation), +// kotlin = new ProjectTemplate() +// .setId(4) +// .setName(getContext(), R.string.template_basic_kotlin) +// .setDescription(getContext(), R.string.template_description_kotlin) +// .setImageId(R.drawable.template_kotlin); + + mTemplates.add(empty); + mTemplates.add(basic); + mTemplates.add(drawer); +// mTemplates.add(navigation); +// mTemplates.add(kotlin); + } + + private void createProgressSheet() { + mWritingProgressSheet = new ProgressSheet(); + } + + private void setMessage(int msg) { + if(getContext() != null) { + setMessage(getContext().getString(msg)); + } + } + + private void setMessage(String msg) { + mWritingProgressSheet.setMessage(msg); + } + + private void createNewProject() { + final String appName = createLayoutBinding.createprojectTextAppName.getEditText().getText().toString().trim(); + final String packageName = createLayoutBinding.createprojectTextPackageName.getEditText().getText().toString().trim(); + final int minSdk = getMinSdk(); + final int targetSdk = getTargetSdk(); + + if(!isValid(appName, packageName, minSdk, targetSdk)) { + getStudioActivity().getApp().toast(R.string.invalid_values, Toaster.Type.ERROR); + return; + } + + createProject(appName, packageName, minSdk, targetSdk); + } + + private void createProject(String appName, String packageName, int minSdk, int targetSdk) { + new TaskExecutor().executeAsync(new ProjectCreatorCallable(mTemplates.get(currentTemplateIndex), new NewProjectDetails(appName, packageName, minSdk, targetSdk), this), r -> {}); + } + + private boolean isValid(String appName, String packageName, int minSdk, int targetSdk) + { + return appName != null && appName.length() > 0 + && packageName != null && packageName.length() > 0 + && minSdk > 1 && minSdk < 99 + && targetSdk > 1 && minSdk < 99; + } + + private int getMinSdk() + { + try + { + return Integer.parseInt(createLayoutBinding.createprojectTextMinSdk.getEditText().getText().toString()); + } catch (Exception e) + { getStudioActivity().getApp().toast(e.getMessage(), Toaster.Type.ERROR); } + return -1; + } + + private int getTargetSdk() + { + try + { + return Integer.parseInt(createLayoutBinding.createprojectTextTargetSdk.getEditText().getText().toString()); + } catch (Exception e) + { getStudioActivity().getApp().toast(e.getMessage(), Toaster.Type.ERROR); } + return -1; + } + + private void showCreateProject() + { + ChangeBounds bounds = new ChangeBounds(); + bounds.setPathMotion(new ArcMotionPlus().setArcAngle(90)); + bounds.setDuration(300); + bounds.addListener(new OnEndTransitionListener(() -> { + final int x = (int) binding.createNew.getX() + (binding.createNew.getWidth() / 2); + final int y = (int) binding.createNew.getY() + (binding.createNew.getHeight() / 2); + binding.createNewCard.setVisibility(View.VISIBLE); + int startRadius = binding.createNew.getWidth() / 2; + int endRadius = Math.max(binding.getRoot().getWidth(), binding.getRoot().getHeight()); + Animator anim = ViewAnimationUtils.createCircularReveal(binding.createNewCard, x, y, startRadius, endRadius); + anim.setDuration(600); + anim.start(); + if(visibilityChangeListener != null) + visibilityChangeListener.onVisibilityChanged(true); + return null; + })); + TransitionManager.beginDelayedTransition(binding.getRoot(), bounds); + + ConstraintLayout.LayoutParams p = (ConstraintLayout.LayoutParams) binding.createNew.getLayoutParams(); + p.topToTop = p.PARENT_ID; + p.rightToRight = p.PARENT_ID; + p.leftToLeft = p.UNSET; + binding.createNew.setLayoutParams(p); + } + + private void hideCreateProject() + { + int x = (int) binding.createNew.getX() + (binding.createNew.getWidth() / 2); + int y = (int) binding.createNew.getY() + (binding.createNew.getHeight() / 2); + int startRadius = Math.max(binding.getRoot().getWidth(), binding.getRoot().getHeight()); + int endRadius = binding.createNew.getWidth() / 2; + Animator anim = ViewAnimationUtils.createCircularReveal(binding.createNewCard, x, y, startRadius, endRadius); + anim.setDuration(500); + anim.addListener(new AnimatorListenerAdapter() + { + @Override + public void onAnimationEnd(Animator anim) + { + binding.createNewCard.setVisibility(View.GONE); + if(visibilityChangeListener != null) + visibilityChangeListener.onVisibilityChanged(false); + + ChangeBounds bounds = new ChangeBounds(); + bounds.setPathMotion(new ArcMotionPlus().setArcAngle(90)); + bounds.setDuration(300); + TransitionManager.beginDelayedTransition(binding.getRoot(), bounds); + + ConstraintLayout.LayoutParams p = (ConstraintLayout.LayoutParams) binding.createNew.getLayoutParams(); + p.topToTop = p.UNSET; + p.topToBottom = binding.greetingText.getId(); + p.rightToRight = p.PARENT_ID; + p.leftToLeft = p.PARENT_ID; + binding.createNew.setLayoutParams(p); + } + }); + anim.start(); + } + + private final class OnEndTransitionListener implements Transition.TransitionListener { + + Callable c; + public OnEndTransitionListener(Callable c) { + this.c = c; + } + + @Override + public void onTransitionStart(Transition p1) { + } + + @Override + public void onTransitionEnd(Transition p1) { + try { + c.call(); + } catch (Exception e) {} + } + + @Override + public void onTransitionCancel(Transition p1) { + } + + @Override + public void onTransitionPause(Transition p1) { + } + + @Override + public void onTransitionResume(Transition p1) { + } + } + + public interface OnCreateProjectVisibilityListener { + public void onVisibilityChanged(boolean isVisible); + } + + public static interface OnCreateProjectListener { + public void onNewProjectCreated(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/ProjectsFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/ProjectsFragment.java new file mode 100644 index 000000000..d3e20614c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/ProjectsFragment.java @@ -0,0 +1,239 @@ +package com.itsaky.androidide.fragments; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import com.itsaky.androidide.EditorActivity; +import com.itsaky.androidide.adapters.ProjectsListAdapter; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.databinding.LayoutProjectsBinding; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.utils.FileUtil; +import fr.arnaudguyon.xmltojsonlib.XmlToJson; +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import org.json.JSONException; +import org.json.JSONObject; +import com.blankj.utilcode.util.FileUtils; +import java.util.stream.Collectors; + +public class ProjectsFragment extends BaseFragment { + + private LayoutProjectsBinding binding; + private ArrayList mProjects; + private boolean isLoading = false; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = LayoutProjectsBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getActivity() == null) return; + + loadProjects(); + } + + public void loadProjects() { + if (!isLoading && getStudioActivity().isStoragePermissionGranted()) { + getProgressBar().setVisibility(View.VISIBLE); + getRecyclerView().setVisibility(View.GONE); + setLoading(true); + final ProjectsFragment frag = this; + new TaskExecutor().executeAsync(new GetProjectsTask(), (result) -> { + frag.setLoading(false); + + if (frag.getProjectsList() == null || frag.getProjectsList().size() == 0) { + frag.getProgressBar().setVisibility(View.GONE); + frag.getRecyclerView().setVisibility(View.GONE); + frag.getNothingLayout().setVisibility(View.VISIBLE); + } else { + frag.getNothingLayout().setVisibility(View.GONE); + frag.getProgressBar().setVisibility(View.GONE); + frag.getRecyclerView().setVisibility(View.VISIBLE); + frag.getRecyclerView().setLayoutManager(new LinearLayoutManager(getActivity())); + frag.getRecyclerView().setAdapter(new ProjectsListAdapter(mProjects, (project) -> openProject(project))); + } + }); + } + } + + private void openProject(AndroidProject project) { + startActivity(new Intent(getActivity(), EditorActivity.class) + .putExtra("project", project)); + } + + public void getProjects() throws Exception { + mProjects = new ArrayList<>(); + File[] files = StudioApp.getInstance().listProjects(); + for (File file : files) { + if (!file.isDirectory() || file.isHidden()) continue; + File settings = new File(file, "settings.gradle"); + if (!settings.exists()) continue; + String content = FileUtil.readFile(settings.getAbsolutePath()); + if (TextUtils.isEmpty(content)) continue; + boolean foundIcon = false; + AndroidProject project = new AndroidProject(); + for (File module : file.listFiles()) { + String[] result; + if (module.isDirectory() + && !module.isHidden() + && (result = proceedModule(file, module, project)) != null + && result.length == 2 + && result[0] != null + && result[1] != null + && !foundIcon) { + foundIcon = true; + String packageName = result[0]; + String icon = result[1]; + project.setPackageName(packageName) + .setIconPath(icon) + .setMainModule(module.getName()) + .setMainSourcePath(new File(module, "src/main/java").getAbsolutePath()); + } + } + + project.setAppName(file.getName()); + project.setProjectPath(file.getAbsolutePath()); + mProjects.add(project); + } + } + + private String[] proceedModule(File file, File module, AndroidProject project) throws JSONException { + File projectGradle = new File(file, "build.gradle"); + File moduleGradle = new File(module, "build.gradle"); + File manifest = new File(module, "src/main/AndroidManifest.xml"); + File res = new File(module, "src/main/res"); + if (!module.exists() || !projectGradle.exists() || !moduleGradle.exists() || !manifest.exists()) return null; + if (!module.isDirectory() || !moduleGradle.isFile() || !projectGradle.isFile() || !manifest.isFile()) return null; + + File java = new File(module, "src/main/java"); + if (java.exists() && java.isDirectory()) + project.addSource(java.getAbsolutePath()) + .addModule(module.getAbsolutePath()); + + File libsFolder = new File(module, "libs"); + if (libsFolder.exists() && libsFolder.isDirectory()) { + File[] libs = libsFolder.listFiles(); + if (libs != null && libs.length > 0) { + for (File lib : libs) + if (lib.getName().endsWith(".jar")) + project.addClasspath(lib.getAbsolutePath()); + } + } + + project.addSource(new File(module, "build/generated/source/buildConfig/debug").getAbsolutePath()); + project.addSource(new File(module, "build/generated/data_binding_base_class_source_out/debug/out").getAbsolutePath()); + + JSONObject obj = new XmlToJson.Builder(FileUtil.readFile(manifest.getAbsolutePath())).build().toJson(); + if (!obj.has("manifest")) return null; + String iconPath = null; + if (obj.has("manifest") && obj.getJSONObject("manifest").has("application") && obj.getJSONObject("manifest").getJSONObject("application").has("android:icon")) { + String iconRes = obj.getJSONObject("manifest").getJSONObject("application").getString("android:icon"); + if (iconRes.startsWith("@drawable")) { + final String iconName = iconRes.replace("@drawable/", ""); + File[] drawables = listDrawables(res); + for (File drawable : drawables) { + File[] icons = listFilesNotEndingWith(drawable, ".xml"); + for (File icon : icons) { + String nameWithoutExtension = icon.getName().substring(0, icon.getName().lastIndexOf(".")); + if (nameWithoutExtension.equals(iconName)) { + iconPath = icon.getAbsolutePath(); + break; + } + } + } + } else if (iconRes.startsWith("@mipmap")) { + final String iconName = iconRes.replace("@mipmap/", ""); + File[] drawables = listMipmaps(res); + for (File drawable : drawables) { + File[] icons = listFilesNotEndingWith(drawable, ".xml"); + for (File icon : icons) { + String nameWithoutExtension = icon.getName().substring(0, icon.getName().lastIndexOf(".")); + if (nameWithoutExtension.equals(iconName)) { + iconPath = icon.getAbsolutePath(); + break; + } + } + } + } + } + final String packageName = obj.getJSONObject("manifest").getString("package"); + if (iconPath == null) return null; + return new String[]{ packageName, iconPath }; + } + + private File[] listDrawables(File file) { + return listFolderStartingWith(file, "drawable"); + } + + private File[] listMipmaps(File file) { + return listFolderStartingWith(file, "mipmap"); + } + + private File[] listFolderStartingWith(File file, final String prefix) { + return file.listFiles(new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isDirectory() && p1.getName().startsWith(prefix); + } + }); + } + + private File[] listFilesNotEndingWith(File file, final String suffix) { + return file.listFiles(new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isFile() && !p1.getName().endsWith(suffix); + } + }); + } + + public ProgressBar getProgressBar() { + return binding.projectsProgressBar; + } + + public RecyclerView getRecyclerView() { + return binding.mainProjectsRecyclerView; + } + + public boolean isLoading() { + return isLoading; + } + + public void setLoading(boolean isLoading) { + this.isLoading = isLoading; + } + + public ArrayList getProjectsList() { + return mProjects; + } + + public View getNothingLayout() { + return binding.projectsNothingLayout; + } + + private class GetProjectsTask implements Callable> { + @Override + public List call() throws Exception { + getProjects(); + return null; + } + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/AppearancePreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/AppearancePreferences.java new file mode 100644 index 000000000..9ca6d916f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/AppearancePreferences.java @@ -0,0 +1,12 @@ +package com.itsaky.androidide.fragments.preferences; + +import android.os.Bundle; +import com.itsaky.androidide.R; + +public class AppearancePreferences extends BasePreferenceFragment { + + @Override + public void onCreatePreferences(Bundle p1, String p2) { + super.onCreatePreferences(p1, p2); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/BasePreferenceFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BasePreferenceFragment.java new file mode 100644 index 000000000..759bdbcac --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BasePreferenceFragment.java @@ -0,0 +1,31 @@ +package com.itsaky.androidide.fragments.preferences; + +import androidx.preference.PreferenceFragmentCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.os.Bundle; +import android.view.ViewGroup; +import androidx.core.content.ContextCompat; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.utils.PreferenceManager; + +public abstract class BasePreferenceFragment extends PreferenceFragmentCompat { + + protected PreferenceManager mPrefManager; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = super.onCreateView(inflater, container, savedInstanceState); + v.setBackgroundColor(ContextCompat.getColor(StudioApp.getInstance(), com.itsaky.androidide.R.color.content_background)); + return v; + } + + @Override + public void onCreatePreferences(Bundle p1, String p2) { + setPreferencesFromResource(com.itsaky.androidide.R.xml.ide_prefs, p2); + } + + protected PreferenceManager getPrefManager() { + return mPrefManager == null ? mPrefManager = new PreferenceManager(getContext()) : mPrefManager; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java new file mode 100644 index 000000000..2a5552286 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/BuildPreferences.java @@ -0,0 +1,226 @@ +package com.itsaky.androidide.fragments.preferences; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; +import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.ZipUtils; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.databinding.LayoutDialogTextInputBinding; +import com.itsaky.androidide.fragments.sheets.ProgressSheet; +import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.toaster.Toaster; +import java.io.File; +import java.util.List; +import java.util.Set; + +import static com.itsaky.androidide.utils.PreferenceManager.*; + +public class BuildPreferences extends BasePreferenceFragment implements Preference.OnPreferenceClickListener { + + public static final String KEY_GRADLE_INSTALL = "idepref_build_gradleInstall"; + public static final String KEY_GRADLE_COMMAMDS = "idepref_build_gradleCommands"; + public static final String KEY_GRADLE_CLEAR_CACHE = "idepref_build_gradleClearCache"; + public static final String KEY_CHOOSE_GRADLE = "idepref_build_chooseGradle"; + + private ProgressSheet progressSheet; + + @Override + public void onCreatePreferences(Bundle p1, String p2) { + super.onCreatePreferences(p1, p2); + if(getContext() == null) return; + final PreferenceScreen screen = getPreferenceScreen(); + final PreferenceCategory categoryGradle = new PreferenceCategory(getContext()); + final Preference customGradle = new Preference(getContext()); + final Preference chooseGradle = new Preference(getContext()); + final Preference customCommands = new Preference(getContext()); + final Preference clearCache = new Preference(getContext()); + + screen.addPreference(categoryGradle); + + customGradle.setKey(KEY_GRADLE_INSTALL); + customGradle.setIcon(R.drawable.ic_language_gradle); + customGradle.setTitle(R.string.idepref_build_installgradle_title); + customGradle.setSummary(R.string.idepref_build_installgradle_summary); + + chooseGradle.setKey(KEY_CHOOSE_GRADLE); + chooseGradle.setIcon(R.drawable.ic_file_rename); + chooseGradle.setTitle(R.string.idepref_build_choosegradle_title); + chooseGradle.setSummary(R.string.idepref_build_choosegradle_summary); + + customCommands.setKey(KEY_GRADLE_COMMAMDS); + customCommands.setIcon(R.drawable.ic_bash_commands); + customCommands.setTitle(R.string.idepref_build_customgradlecommands_title); + customCommands.setSummary(R.string.idepref_build_customgradlecommands_summary); + + clearCache.setKey(KEY_GRADLE_CLEAR_CACHE); + clearCache.setIcon(R.drawable.ic_file_delete); + clearCache.setTitle(R.string.idepref_build_clearCache_title); + clearCache.setSummary(R.string.idepref_build_clearCache_summary); + + categoryGradle.setTitle(R.string.gradle); +// categoryGradle.addPreference(customGradle); +// categoryGradle.addPreference(chooseGradle); + categoryGradle.addPreference(customCommands); + categoryGradle.addPreference(clearCache); + + setPreferenceScreen(screen); + + customGradle.setOnPreferenceClickListener(this); + chooseGradle.setOnPreferenceClickListener(this); + customCommands.setOnPreferenceClickListener(this); + clearCache.setOnPreferenceClickListener(this); + } + + @Override + public boolean onPreferenceClick(Preference p1) { + final String key = p1.getKey(); + if(key.equals(KEY_GRADLE_INSTALL)) { + showInstallGradleDialog(); + } else if(key.equals(KEY_GRADLE_COMMAMDS)) { + showGradleCommandsDialog(); + } else if(key.equals(KEY_GRADLE_CLEAR_CACHE)) { + showClearCacheDialog(); + } else if(key.equals(KEY_CHOOSE_GRADLE)) { + showChooseGradle(); + } + return true; + } + + private void showChooseGradle() { + final Set installed = getPrefManager().getGradleFolderNames(); + final String[] labels = installed.toArray(new String[installed.size()]); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); + builder.setTitle(R.string.idepref_build_choosegradle_title); + builder.setSingleChoiceItems(labels, 0, (p1, p2) -> { + DialogInterface iface = p1; + int pos = p2; + }); + builder.create().show(); + } + + private void showInstallGradleDialog() { + final LayoutDialogTextInputBinding binding = LayoutDialogTextInputBinding.inflate(LayoutInflater.from(getContext())); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); + binding.name.setHint(R.string.zip_file_path); + builder.setTitle(R.string.idepref_build_installgradle_title); + builder.setMessage(R.string.msg_custom_gradle); + builder.setView(binding.getRoot()); + builder.setPositiveButton(android.R.string.ok, (p1, p2) -> { + final String path = binding.name.getEditText().getText().toString(); + if(path.trim().length() <= 0) { + StudioApp.getInstance().toast(R.string.invalid_zip, Toaster.Type.ERROR); + return; + } + File file = new File(path.trim()); + if(!(file.exists() && file.isFile() && file.getName().endsWith(".zip"))) { + StudioApp.getInstance().toast(R.string.msg_file_should_be_zip, Toaster.Type.ERROR); + return; + } + p1.dismiss(); + getProgressSheet().setCancelable(false); + getProgressSheet().setShowShadow(false); + getProgressSheet().setSubMessageEnabled(false); + getProgressSheet().setWelcomeTextEnabled(false); + getProgressSheet().show(getChildFragmentManager(), "custom_gradle_progress"); + new TaskExecutor().executeAsync(() -> { + try { + List extracted = ZipUtils.unzipFile(file, Environment.HOME); + if(extracted != null && extracted.size() > 0) { + File newestFolder = null; + for(File f : extracted) { + if((newestFolder = f.getParentFile()).getAbsolutePath().equals(Environment.HOME.getAbsolutePath())) { + break; + } + } + if(newestFolder != null) { + getPrefManager().setCurentGradleFolderName(newestFolder.getName()); + Environment.GRADLE_FOLDER_NAME = newestFolder.getName(); + Environment.updateGradleDir(); + StudioApp.getInstance().toast(R.string.msg_gradle_installed, Toaster.Type.SUCCESS); + getProgressSheet().dismiss(); + } + } else { + StudioApp.getInstance().toast(R.string.failed_unzip, Toaster.Type.ERROR); + } + } catch (Throwable th) { + StudioApp.getInstance().toast(R.string.failed_unzip, Toaster.Type.ERROR); + } + return null; + }, __ -> {}); + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.create().show(); + } + + private void showGradleCommandsDialog() { + final String[] labels = { + "--stacktrace", + "--info", + "--debug", + "--scan", + "--warning-mode all" + }; + final boolean[] checked = { + getPrefManager().isStracktraceEnabled(), + getPrefManager().isGradleInfoEnabled(), + getPrefManager().isGradleDebugEnabled(), + getPrefManager().isGradleScanEnabled(), + getPrefManager().isGradleWarningEnabled() + }; + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); + builder.setTitle(R.string.idepref_build_customgradlecommands_title); + builder.setMultiChoiceItems(labels, checked, (p1, p2, p3) -> { + boolean isChecked = p3; + int pos = p2; + if(pos == 0) { + getPrefManager().setGradleStacktraceEnabled(isChecked); + } else if(pos == 1) { + getPrefManager().setGradleInfoEnabled(isChecked); + } else if(pos == 2) { + getPrefManager().setGradleDebugEnabled(isChecked); + } else if(pos == 3) { + getPrefManager().setGradleScanEnabled(isChecked); + } else if(pos == 4) { + getPrefManager().setGradleWarningEnabled(isChecked); + } + }); + builder.setPositiveButton(android.R.string.ok, null); + builder.setCancelable(false); + builder.create().show(); + } + + private void showClearCacheDialog() { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); + builder.setTitle(R.string.idepref_build_clearCache_title); + builder.setMessage(R.string.msg_clear_cache); + builder.setCancelable(false); + builder.setPositiveButton(android.R.string.yes, (p1, p2) -> { + p1.dismiss(); + getProgressSheet().show(getChildFragmentManager(), "progress_sheet"); + new TaskExecutor().executeAsync(() -> deleteCaches(), __ -> { + getProgressSheet().dismiss(); + }); + }); + builder.setNegativeButton(android.R.string.no, null); + builder.create().show(); + } + + private Object deleteCaches() { + File file = new File(Environment.HOME, ".gradle/caches"); + if(file.exists()) { + FileUtils.delete(file); + } + return null; + } + + private ProgressSheet getProgressSheet() { + return progressSheet == null ? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait)) : progressSheet; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java new file mode 100644 index 000000000..47515d9a7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java @@ -0,0 +1,153 @@ +package com.itsaky.androidide.fragments.preferences; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.R; +import com.itsaky.androidide.databinding.LayoutTextSizeSliderBinding; + +import static com.itsaky.androidide.utils.PreferenceManager.*; +import com.itsaky.androidide.models.ConstantsBridge; +import com.google.android.material.slider.LabelFormatter; +import java.text.NumberFormat; +import java.util.Locale; + +public class EditorPreferences extends BasePreferenceFragment implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { + + public static final String KEY_EDITOR_FONT_SIZE = "idepref_editor_fontSize"; + public static final String KEY_EDITOR_PRINTABLE_CHARS = "idepref_editor_nonPrintableFlags"; + public static final String KEY_EDITOR_DRAW_HEX = "idepref_editor_drawHexColors"; + + @Override + public void onCreatePreferences(Bundle p1, String p2) { + super.onCreatePreferences(p1, p2); + if(getContext() == null) return; + + final PreferenceScreen screen = getPreferenceScreen(); + final Preference fontSize = new Preference(getContext()); + final Preference nonPrintable = new Preference(getContext()); + final SwitchPreference drawHex = new SwitchPreference(getContext()); + + fontSize.setIcon(R.drawable.ic_text_size); + fontSize.setKey(KEY_EDITOR_FONT_SIZE); + fontSize.setTitle(R.string.idepref_editor_fontsize_title); + fontSize.setSummary(R.string.idepref_editor_fontsize_summary); + + nonPrintable.setIcon(R.drawable.ic_drawing); + nonPrintable.setKey(KEY_EDITOR_PRINTABLE_CHARS); + nonPrintable.setTitle(R.string.idepref_editor_paintingflags_title); + nonPrintable.setSummary(R.string.idepref_editor_paintingflags_summary); + + drawHex.setIcon(R.drawable.ic_hexadecimal); + drawHex.setKey(KEY_EDITOR_DRAW_HEX); + drawHex.setTitle(R.string.idepref_editor_drawhexcolors_title); + drawHex.setSummary(R.string.idepref_editor_drawhexcolors_summary); + + screen.addPreference(fontSize); + screen.addPreference(nonPrintable); + screen.addPreference(drawHex); + setPreferenceScreen(screen); + + fontSize.setOnPreferenceClickListener(this); + nonPrintable.setOnPreferenceClickListener(this); + drawHex.setOnPreferenceChangeListener(this); + + drawHex.setChecked(getPrefManager().getBoolean(KEY_EDITOR_DRAW_HEX, true)); + } + + @Override + public boolean onPreferenceChange(Preference p1, Object p2) { + if(p1.getKey().equals(KEY_EDITOR_DRAW_HEX)) { + boolean drawHex = (boolean) p2; + getPrefManager().putBoolean(KEY_EDITOR_DRAW_HEX, drawHex); + ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED = true; + } + return true; + } + + @Override + public boolean onPreferenceClick(Preference p1) { + final String key = p1.getKey(); + if(key.equals(KEY_EDITOR_FONT_SIZE)) { + showTextSizeDialog(); + } else if(key.equals(KEY_EDITOR_PRINTABLE_CHARS)) { + showPrintableCharsDialog(); + } + return true; + } + + private void showTextSizeDialog() { + final LayoutTextSizeSliderBinding binding = LayoutTextSizeSliderBinding.inflate(LayoutInflater.from(getContext())); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext(), R.style.AppTheme_MaterialAlertDialog); + float size = getPrefManager().getFloat(KEY_EDITOR_FONT_SIZE, 14); + if(size < 6 || size > 32) { + size = 14; + changeTextSize(binding, size); + } + binding.slider.setLabelFormatter(p1 -> String.valueOf((int) p1)); + builder.setTitle(R.string.title_change_text_size); + builder.setMessage(R.string.msg_editor_font_size); + builder.setView(binding.getRoot()); + builder.setPositiveButton(android.R.string.ok, (p1, p2) -> { + p1.dismiss(); + float s = binding.slider.getValue(); + changeTextSize(binding, s); + }); + builder.setNeutralButton(R.string.reset, (p1, p2) -> { + changeTextSize(binding, 14); + }); + builder.setCancelable(false); + builder.create().show(); + } + + private void changeTextSize(LayoutTextSizeSliderBinding binding, float size) { + getPrefManager().putFloat(KEY_EDITOR_FONT_SIZE, size); + binding.slider.setValue(size); + ConstantsBridge.EDITORPREF_SIZE_CHANGED = true; + } + + private void showPrintableCharsDialog() { + String[] labels = { + "Leading whitespaces", + "Trailing whitespaces", + "Inner whitespaces", + "Whitespaces in empty lines", + "Line breaks" + }; + final boolean[] checked = { + getPrefManager().getBoolean(KEY_EDITORFLAG_WS_LEADING, true), + getPrefManager().getBoolean(KEY_EDITORFLAG_WS_TRAILING, false), + getPrefManager().getBoolean(KEY_EDITORFLAG_WS_INNER, true), + getPrefManager().getBoolean(KEY_EDITORFLAG_WS_EMPTY_LINE, true), + getPrefManager().getBoolean(KEY_EDITORFLAG_LINE_BREAK, true) + }; + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext(), R.style.AppTheme_MaterialAlertDialog); + builder.setTitle(R.string.idepref_editor_paintingflags_title); + builder.setMultiChoiceItems(labels, checked, (p1, p2, p3) -> { + DialogInterface iface = p1; + int pos = p2; + boolean isChecked = p3; + + if(pos == 0) { + getPrefManager().putBoolean(KEY_EDITORFLAG_WS_LEADING, isChecked); + } else if(pos == 1) { + getPrefManager().putBoolean(KEY_EDITORFLAG_WS_TRAILING, isChecked); + } else if(pos == 2) { + getPrefManager().putBoolean(KEY_EDITORFLAG_WS_INNER, isChecked); + } else if(pos == 3) { + getPrefManager().putBoolean(KEY_EDITORFLAG_WS_EMPTY_LINE, isChecked); + } else if(pos == 4) { + getPrefManager().putBoolean(KEY_EDITORFLAG_LINE_BREAK, isChecked); + } + + ConstantsBridge.EDITORPREF_FLAGS_CHANGED = true; + }); + builder.setPositiveButton(android.R.string.ok, null); + builder.setCancelable(false); + builder.create().show(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/IDEPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/IDEPreferences.java new file mode 100644 index 000000000..f55a045ed --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/IDEPreferences.java @@ -0,0 +1,169 @@ +package com.itsaky.androidide.fragments.preferences; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.StyleSpan; +import android.util.TypedValue; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import com.blankj.utilcode.util.ResourceUtils; +import com.blankj.utilcode.util.ThrowableUtils; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import org.json.JSONArray; +import org.json.JSONObject; +import com.blankj.utilcode.util.SizeUtils; + +public class IDEPreferences extends BasePreferenceFragment { + + private AppearancePreferences mAppearancePrefs; + private BuildPreferences mBuildPreferences; + private EditorPreferences mEditorPreferences; + + private String CHANGELOG = null; + + public static final String KEY_APPEARANCE = "idepref_appearance"; + public static final String KEY_EDITOR = "idepref_editor"; + public static final String KEY_BUILD = "idepref_build"; + public static final String KEY_TELEGRAM = "idepref_telegram"; + public static final String KEY_ISSUES = "idepref_issues"; + public static final String KEY_CHANGELOG = "idepref_changelog"; + + @Override + public void onCreatePreferences(Bundle savedState, String rootKey) { + super.onCreatePreferences(savedState, rootKey); + if(getContext() == null) return; + + final PreferenceScreen screen = getPreferenceScreen(); + final Preference appearance = new Preference(getContext()); + final Preference editor = new Preference(getContext()); + final Preference build = new Preference(getContext()); + final Preference telegram = new Preference(getContext()); + final Preference issueTracker = new Preference(getContext()); + final Preference changelog = new Preference(getContext()); + + appearance.setKey(KEY_APPEARANCE); + appearance.setIconSpaceReserved(false); + appearance.setFragment(getAppearanceFrag().getClass().getName()); + appearance.setTitle(R.string.idepref_appearance_title); + appearance.setSummary(R.string.idepref_appearance_summary); + + editor.setKey(KEY_EDITOR); + editor.setIconSpaceReserved(false); + editor.setFragment(getEditorFrag().getClass().getName()); + editor.setTitle(R.string.idepref_editor_title); + editor.setSummary(R.string.idepref_editor_summary); + + build.setKey(KEY_BUILD); + build.setIconSpaceReserved(false); + build.setFragment(getBuildFrag().getClass().getName()); + build.setTitle(R.string.idepref_build_title); + build.setSummary(R.string.idepref_build_summary); + + issueTracker.setKey(KEY_ISSUES); + issueTracker.setIconSpaceReserved(false); + issueTracker.setTitle(R.string.user_suggestions); + issueTracker.setSummary(R.string.issue_tracker_summary); + + telegram.setKey(KEY_TELEGRAM); + telegram.setIconSpaceReserved(false); + telegram.setTitle(R.string.discussions_on_telegram); + telegram.setSummary(R.string.discussions_on_telegram_summary); + + changelog.setKey(KEY_CHANGELOG); + changelog.setIconSpaceReserved(false); + changelog.setTitle(R.string.pref_changelog); + changelog.setSummary(R.string.pref_changelog_summary); + + screen.addPreference(editor); + screen.addPreference(build); +// screen.addPreference(issueTracker); + screen.addPreference(telegram); + screen.addPreference(changelog); + + final Preference.OnPreferenceClickListener listener = getListener(); + issueTracker.setOnPreferenceClickListener(listener); + telegram.setOnPreferenceClickListener(listener); + changelog.setOnPreferenceClickListener(listener); + } + + private AppearancePreferences getAppearanceFrag() { + return mAppearancePrefs == null ? mAppearancePrefs = new AppearancePreferences() : mAppearancePrefs; + } + + private EditorPreferences getEditorFrag() { + return mEditorPreferences == null ? mEditorPreferences = new EditorPreferences() : mEditorPreferences; + } + + private BuildPreferences getBuildFrag() { + return mBuildPreferences == null ? mBuildPreferences = new BuildPreferences() : mBuildPreferences; + } + + private void showChangelog() { + final int dp8 = SizeUtils.dp2px(8); + final int dp16 = SizeUtils.dp2px(16); + final HorizontalScrollView scroll = new HorizontalScrollView(getContext()); + scroll.setLayoutParams(new ViewGroup.LayoutParams(-1, -2)); + scroll.setFillViewport(true); + scroll.setPadding(dp16, dp8, dp16, dp8); + scroll.setPaddingRelative(dp16, dp8, dp16, dp8); + + final TextView text = new TextView(getContext()); + text.setText(CHANGELOG == null ? CHANGELOG = changelogAsString() : CHANGELOG); + text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + text.setTextColor(ContextCompat.getColor(getContext(), R.color.primaryTextColor)); + scroll.removeAllViews(); + scroll.addView(text, new ViewGroup.LayoutParams(-1, -1)); + + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext(), R.style.AppTheme_MaterialAlertDialog); + builder.setTitle(R.string.pref_changelog); + builder.setView(scroll); + builder.setPositiveButton(android.R.string.ok, null); + builder.create().show(); + } + + private String changelogAsString() { + try { + final SpannableStringBuilder sb = new SpannableStringBuilder(); + JSONArray arr = new JSONArray(ResourceUtils.readAssets2String("changelog.json")); + for(int i =0;i onShow()); + return mDialog; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = LayoutSheetBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + bind(binding.container); + binding.title.setText(getTitle()); + binding.title.setOnClickListener(v -> handleTitleClick()); + + if(shouldHideTitle()) { + binding.getRoot().removeView(binding.title); + } + + if(!shadowEnabled) { + binding.shadow.setVisibility(View.GONE); + } + } + + private void handleTitleClick() { + if(isCancelable()) { + dismiss(); + } + } + + public boolean isShowing() { + return mDialog != null && mDialog.isShowing(); + } + + public BaseBottomSheetFragment setTitle(int title) { + if(binding != null && binding.title != null) { + binding.title.setText(title); + } + return this; + } + + public BaseBottomSheetFragment setTitle(String title) { + if(binding != null && binding.title != null) { + binding.title.setText(title); + } + return this; + } + + protected boolean shouldHideTitle() { + return false; + } + + protected String getTitle() { + return ""; + } + + public void setShowShadow(boolean enabled) { + this.shadowEnabled = enabled; + } + + protected void onShow() {} + protected abstract void bind(LinearLayout container); +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java b/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java new file mode 100644 index 000000000..219c4dc3e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java @@ -0,0 +1,65 @@ +package com.itsaky.androidide.fragments.sheets; + +import android.graphics.Typeface; +import android.util.TypedValue; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; +import com.blankj.utilcode.util.ThrowableUtils; +import com.elvishew.xlog.XLog; +import com.itsaky.androidide.R; +import com.itsaky.androidide.models.LogLine; + +public class LogSheet extends BaseBottomSheetFragment { + + private ScrollView verticalScroll; + private LinearLayout mContainer; + + @Override + protected void bind(LinearLayout container) { + mContainer = new LinearLayout(getContext()); + mContainer.setOrientation(LinearLayout.VERTICAL); + + verticalScroll = new ScrollView(getContext()); + verticalScroll.setFillViewport(true); + + HorizontalScrollView scroll = new HorizontalScrollView(getContext()); + scroll.setFillViewport(true); + + container.removeAllViews(); + verticalScroll.removeAllViews(); + mContainer.removeAllViews(); + scroll.removeAllViews(); + + container.addView(verticalScroll); + verticalScroll.addView(scroll, new ScrollView.LayoutParams(-1, -1)); + scroll.addView(mContainer, new HorizontalScrollView.LayoutParams(-1, -1)); + } + + @Override + protected String getTitle() { + return getString(R.string.logs); + } + + public void addLine(LogLine line) { + if(line != null) { + try { + mContainer.addView(createLogTextView(line), new ViewGroup.LayoutParams(-1, -2)); + verticalScroll.scrollTo(0, mContainer.getChildAt(mContainer.getChildCount() - 1).getBottom()); + } catch (Throwable th) {} + } + } + + protected TextView createLogTextView(LogLine line) { + TextView text = new TextView(getContext()); + text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + text.setTextColor(line.getColor(getContext())); + text.setText(line + ""); + text.setSingleLine(true); + text.setMaxLines(1); + text.setTypeface(Typeface.MONOSPACE); + return text; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sheets/OptionsListFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/sheets/OptionsListFragment.java new file mode 100644 index 000000000..2390ea04d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/sheets/OptionsListFragment.java @@ -0,0 +1,64 @@ +package com.itsaky.androidide.fragments.sheets; + +import android.os.Bundle; +import android.view.View; +import android.widget.LinearLayout; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import com.itsaky.androidide.adapters.OptionsSheetAdapter; +import com.itsaky.androidide.models.SheetOption; +import java.util.ArrayList; +import java.util.List; + +public class OptionsListFragment extends BaseBottomSheetFragment { + + private RecyclerView mList; + private OnOptionsClickListener listener; + private final List mOptions = new ArrayList<>(); + + @Override + protected void bind(LinearLayout container) { + mList = new RecyclerView(getContext()); + container.removeAllViews(); + container.addView(mList, new LinearLayout.LayoutParams(-1, -1)); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mList.setLayoutManager(new LinearLayoutManager(getContext())); + mList.setAdapter(new OptionsSheetAdapter(mOptions, __ -> { dismiss(); if(listener != null) listener.onOptionsClick(__);})); + } + + public OptionsListFragment setOnOptionsClickListener(OnOptionsClickListener listener) { + this.listener = listener; + return this; + } + + public OptionsListFragment addOption(SheetOption option) { + if(!mOptions.contains(option)) { + mOptions.add(option); + } + + return this; + } + + public OptionsListFragment removeOption(int optionIndex) { + return removeOption(mOptions.get(optionIndex)); + } + + public OptionsListFragment removeOption(SheetOption option) { + mOptions.remove(option); + return this; + } + + @Override + protected String getTitle() { + return getString(com.itsaky.androidide.R.string.file_options); + } + + public static interface OnOptionsClickListener { + void onOptionsClick(SheetOption option); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sheets/ProgressSheet.java b/app/src/main/java/com/itsaky/androidide/fragments/sheets/ProgressSheet.java new file mode 100644 index 000000000..9c5b1f782 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/sheets/ProgressSheet.java @@ -0,0 +1,101 @@ +package com.itsaky.androidide.fragments.sheets; + +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import com.github.ybq.android.spinkit.style.FoldingCube; +import com.itsaky.androidide.databinding.LayoutProgressSheetBinding; +import com.blankj.utilcode.util.SizeUtils; +import android.widget.RelativeLayout; + +public class ProgressSheet extends BaseBottomSheetFragment { + + private LayoutProgressSheetBinding binding; + private Drawable drawable = new FoldingCube(); + private String message = ""; + private String subMessage = ""; + private boolean subMessageEnabled = false; + private boolean welcomTextEnabled = false; + + @Override + protected void bind(LinearLayout container) { + binding = LayoutProgressSheetBinding.inflate(LayoutInflater.from(getContext())); + container.addView(binding.getRoot()); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + binding.progress.setIndeterminateDrawable(new FoldingCube()); + binding.message.setText(message); + if(subMessageEnabled) { + binding.subMessage.setText(subMessage); + binding.subMessage.setVisibility(View.VISIBLE); + RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) binding.message.getLayoutParams(); + try { + p.removeRule(RelativeLayout.CENTER_VERTICAL); + } catch (Throwable th) {} + binding.message.setLayoutParams(p); + } else { + binding.subMessage.setVisibility(View.GONE); + RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) binding.message.getLayoutParams(); + try { + p.addRule(RelativeLayout.CENTER_VERTICAL); + } catch (Throwable th) {} + binding.message.setLayoutParams(p); + } + + if(!welcomTextEnabled) { + binding.welcomeText.setVisibility(View.GONE); + } + } + + @Override + protected boolean shouldHideTitle() { + return true; + } + + public ProgressSheet setWelcomeTextEnabled(boolean enabled) { + this.welcomTextEnabled = enabled; + return this; + } + + public ProgressSheet setSubMessageEnabled(boolean enabled) { + this.subMessageEnabled = enabled; + return this; + } + + public ProgressSheet setSubMessage(String msg) { + this.subMessage = msg; + if(isShowing()) { + binding.subMessage.setText(msg); + } + return this; + } + + public ProgressSheet setMessage(String message) { + this.message = message; + if(isShowing()) { + binding.message.setText(message); + } + + return this; + } + + public ProgressSheet setProgressDrawable(Drawable drawable) { + this.drawable = drawable; + if(isShowing()) { + binding.progress.setIndeterminateDrawable(drawable); + } + + return this; + } + + @Override + public void dismiss() { + if(isShowing()) + super.dismiss(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sheets/TextSheetFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/sheets/TextSheetFragment.java new file mode 100644 index 000000000..6a5564eda --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/fragments/sheets/TextSheetFragment.java @@ -0,0 +1,117 @@ +package com.itsaky.androidide.fragments.sheets; + +import android.graphics.Color; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.itsaky.androidide.R; +import com.itsaky.androidide.utils.TypefaceUtils; +import io.github.rosemoe.editor.langs.EmptyLanguage; +import io.github.rosemoe.editor.widget.CodeEditor; + +public class TextSheetFragment extends BaseBottomSheetFragment { + + private SpannableStringBuilder outputBuilder; + private CodeEditor editor; + private boolean textSelectable; + + public TextSheetFragment setTextSelectable(boolean textSelectable) { + this.textSelectable = textSelectable; + return this; + } + + @Override + protected void bind(LinearLayout container) { + final CodeEditor e = getEditor(); + container.setPadding(0, 0, 0, 0); + container.setPaddingRelative(0, 0, 0, 0); + LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(-1, 0); + p.weight = 1.0f; + if(e.getParent() != null && e.getParent() instanceof ViewGroup) { + ((ViewGroup) e.getParent()).removeView(e); + } + container.addView(getEditor(), p); + } + + @Override + protected String getTitle() { + return getString(R.string.build_output); + } + + @Override + protected void onShow() { + super.onShow(); + setToEditor(SpannableString.valueOf(getOutputBuilder())); + } + + private Void scrollToBottom() { + if(getActivity() != null) + getActivity().runOnUiThread(() -> { + editor.goToEnd(); + }); + return null; + } + + public TextSheetFragment setTitleText(int res) { + super.setTitle(res); + return this; + } + + public TextSheetFragment setTitleText(String res) { + super.setTitle(res); + return this; + } + + public void append(String text) { + append(text, -1, true); + } + + public void append(String text, int spanColor, boolean appendLine) { + if(text != null && text.trim().length() > 0) { + appendInternal(appendLine && !text.endsWith("\n") ? text.concat("\n") : text, spanColor); + } + } + + private void appendInternal(String text, int spanColor) { + SpannableString str = new SpannableString(text); + str.setSpan(new ForegroundColorSpan(spanColor == -1 ? Color.WHITE : spanColor), 0, text.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + getOutputBuilder().append(str); + if(mDialog != null && mDialog.isShowing()) { + setToEditor(str); + } + } + + private void setToEditor(SpannableString line) { + if(getActivity() != null) + getActivity().runOnUiThread(() -> { + editor.getText().append(line); + scrollToBottom(); + }); + } + + private CodeEditor getEditor() { + return editor == null ? createEditor() : editor; + } + + private CodeEditor createEditor() { + editor = new CodeEditor(getContext()); + editor.setEditable(false); + editor.setDividerWidth(0); + editor.setEditorLanguage(new EmptyLanguage()); + editor.setOverScrollEnabled(false); + editor.setTextActionMode(CodeEditor.TextActionMode.ACTION_MODE); + editor.setWordwrap(false); + editor.setUndoEnabled(false); + editor.setTypefaceLineNumber(TypefaceUtils.jetbrainsMono()); + editor.setTypefaceText(TypefaceUtils.jetbrainsMono()); + editor.setTextSize(12); + return editor; + } + + private SpannableStringBuilder getOutputBuilder() { + return outputBuilder == null ? outputBuilder = new SpannableStringBuilder() : outputBuilder; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/CompileListener.java b/app/src/main/java/com/itsaky/androidide/interfaces/CompileListener.java new file mode 100644 index 000000000..3919e7aa7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/interfaces/CompileListener.java @@ -0,0 +1,10 @@ +package com.itsaky.androidide.interfaces; + +import com.itsaky.androidide.services.compiler.model.CompilerDiagnostic; +import java.io.File; +import java.util.List; +import java.util.Map; + +public interface CompileListener { + void onCompilationResult(boolean success, Map> diagnostics); +} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/DexResultListener.java b/app/src/main/java/com/itsaky/androidide/interfaces/DexResultListener.java new file mode 100644 index 000000000..bd0fb564d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/interfaces/DexResultListener.java @@ -0,0 +1,10 @@ +package com.itsaky.androidide.interfaces; + +import androidx.core.util.Pair; +import java.util.List; + +public interface DexResultListener { + public void onDex(String name); + public void onDexSuccess(List dexes); + public void onDexFailed(String message); +} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/Filter.java b/app/src/main/java/com/itsaky/androidide/interfaces/Filter.java new file mode 100644 index 000000000..ea980430f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/interfaces/Filter.java @@ -0,0 +1,6 @@ +package com.itsaky.androidide.interfaces; + +public interface Filter { + + boolean accept(T t); +} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java b/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java new file mode 100644 index 000000000..a9b298305 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java @@ -0,0 +1,5 @@ +package com.itsaky.androidide.interfaces; + +public interface LanguageServerListener +{ +} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/ProjectWriterCallback.java b/app/src/main/java/com/itsaky/androidide/interfaces/ProjectWriterCallback.java new file mode 100644 index 000000000..1642923b5 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/interfaces/ProjectWriterCallback.java @@ -0,0 +1,8 @@ +package com.itsaky.androidide.interfaces; + +public interface ProjectWriterCallback { + public void beforeBegin(); + public void onProcessTask(String taskName); + public void onSuccess(); + public void onFailed(String reason); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java new file mode 100644 index 000000000..fc545bd67 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java @@ -0,0 +1,39 @@ +package com.itsaky.androidide.language.groovy; + +import android.graphics.Color; +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.syntax.lexer.impls.groovy.GroovyLexerImpl; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.struct.HexColor; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.text.TextAnalyzer; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.antlr.v4.runtime.Token; + +public class GroovyAnalyzer implements CodeAnalyzer { + + @Override + public void analyze(CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { + try { + GroovyLexerImpl lexer = new GroovyLexerImpl(content.toString(), colors); + lexer.init(); + + // Adding spans, hex colors, block lines and all is handled by JavaLexerImpl + while (delegate.shouldAnalyze()) { + // null = EOF + if(lexer.nextToken() == null) + break; + } + if (lexer.stack.isEmpty() && lexer.currSwitch > lexer.maxSwitch) + lexer.maxSwitch = lexer.currSwitch; + + colors.determine(lexer.lastLine); + colors.setSuppressSwitch(lexer.maxSwitch + 10); + colors.setHexColors(lexer.lineColors); + } catch (Throwable e) { + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java new file mode 100644 index 000000000..c70ba0d5d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java @@ -0,0 +1,356 @@ +package com.itsaky.androidide.language.groovy; + +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.models.GradleSuggestItem; +import com.itsaky.androidide.utils.Either; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.struct.CompletionItem; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class GroovyAutoComplete implements AutoCompleteProvider { + + private static final List ANDROIDX_ARTIFACTS = createArtifacts(); + private static final List CONFIGURATIONS = createConfigs(); + private static final List OTHERS = createOtherCompletions(); + + @Override + public List> getAutoCompleteItems(String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int line) { + List> result = new ArrayList<>(); + + for(String artifact : ANDROIDX_ARTIFACTS) { + if(!artifact.toLowerCase(Locale.US).startsWith(prefix.toLowerCase(Locale.US))) continue; + SuggestItem item = createCompletionItem(artifact, prefix, true); + Either either = Either.forLeft(item); + result.add(either); + } + + for(String config : CONFIGURATIONS) { + if(!config.toLowerCase(Locale.US).startsWith(prefix.toLowerCase(Locale.US))) continue; + SuggestItem item = createCompletionItem(config, prefix, false); + Either either = Either.forLeft(item); + result.add(either); + } + + for(String other : OTHERS) { + if(!other.toLowerCase(Locale.US).startsWith(prefix.toLowerCase(Locale.US))) continue; + SuggestItem item = createCompletionItem(other, prefix, false); + Either either = Either.forLeft(item); + result.add(either); + } + + return result; + } + + private SuggestItem createCompletionItem(String itemLabel, String prefix, boolean artifact) { + return new GradleSuggestItem(itemLabel, "", prefix, artifact); + } + + private static List createArtifacts() { + List artifacts = new ArrayList(); + artifacts.add("androidx.arch.core:core-common"); + artifacts.add("androidx.arch.core:core"); + artifacts.add("androidx.arch.core:core-testing"); + artifacts.add("androidx.arch.core:core-runtime"); + artifacts.add("androidx.lifecycle:lifecycle-common"); + artifacts.add("androidx.lifecycle:lifecycle-common-java8"); + artifacts.add("androidx.lifecycle:lifecycle-compiler"); + artifacts.add("androidx.lifecycle:lifecycle-extensions"); + artifacts.add("androidx.lifecycle:lifecycle-livedata"); + artifacts.add("androidx.lifecycle:lifecycle-livedata-core"); + artifacts.add("androidx.lifecycle:lifecycle-reactivestreams"); + artifacts.add("androidx.lifecycle:lifecycle-runtime"); + artifacts.add("androidx.lifecycle:lifecycle-viewmodel"); + artifacts.add("androidx.paging:paging-common"); + artifacts.add("androidx.paging:paging-runtime"); + artifacts.add("androidx.paging:paging-rxjava2"); + artifacts.add("androidx.room:room-common"); + artifacts.add("androidx.room:room-compiler"); + artifacts.add("androidx.room:room-guava"); + artifacts.add("androidx.room:room-migration"); + artifacts.add("androidx.room:room-runtime"); + artifacts.add("androidx.room:room-rxjava2"); + artifacts.add("androidx.room:room-testing"); + artifacts.add("androidx.sqlite:sqlite"); + artifacts.add("androidx.sqlite:sqlite-framework"); + artifacts.add("androidx.constraintlayout:constraintlayout"); + artifacts.add("androidx.constraintlayout:constraintlayout-solver"); + artifacts.add("androidx.test.espresso.idling:idling-concurrent"); + artifacts.add("androidx.test.espresso.idling:idling-net"); + artifacts.add("androidx.test.espresso:espresso-accessibility"); + artifacts.add("androidx.test.espresso:espresso-contrib"); + artifacts.add("androidx.test.espresso:espresso-core"); + artifacts.add("androidx.test.espresso:espresso-idling-resource"); + artifacts.add("androidx.test.espresso:espresso-intents"); + artifacts.add("androidx.test.espresso:espresso-remote"); + artifacts.add("androidx.test.espresso:espresso-web"); + artifacts.add("androidx.test.jank:janktesthelper"); + artifacts.add("androidx.test:test-services"); + artifacts.add("androidx.test.uiautomator:uiautomator"); + artifacts.add("androidx.test:monitor"); + artifacts.add("androidx.test:orchestrator"); + artifacts.add("androidx.test:rules"); + artifacts.add("androidx.test:runner"); + artifacts.add("androidx.vectordrawable:vectordrawable-animated"); + artifacts.add("androidx.appcompat:appcompat"); + artifacts.add("androidx.asynclayoutinflater:asynclayoutinflater"); + artifacts.add("androidx.car:car"); + artifacts.add("androidx.cardview:cardview"); + artifacts.add("androidx.collection:collection"); + artifacts.add("androidx.coordinatorlayout:coordinatorlayout"); + artifacts.add("androidx.cursoradapter:cursoradapter"); + artifacts.add("androidx.browser:browser"); + artifacts.add("androidx.customview:customview"); + artifacts.add("com.google.android.material:material"); + artifacts.add("androidx.documentfile:documentfile"); + artifacts.add("androidx.drawerlayout:drawerlayout"); + artifacts.add("androidx.exifinterface:exifinterface"); + artifacts.add("androidx.gridlayout:gridlayout"); + artifacts.add("androidx.heifwriter:heifwriter"); + artifacts.add("androidx.interpolator:interpolator"); + artifacts.add("androidx.leanback:leanback"); + artifacts.add("androidx.loader:loader"); + artifacts.add("androidx.localbroadcastmanager:localbroadcastmanager"); + artifacts.add("androidx.media2:media2"); + artifacts.add("androidx.media2:media2-exoplayer"); + artifacts.add("androidx.mediarouter:mediarouter"); + artifacts.add("androidx.multidex:multidex"); + artifacts.add("androidx.multidex:multidex-instrumentation"); + artifacts.add("androidx.palette:palette"); + artifacts.add("androidx.percentlayout:percentlayout"); + artifacts.add("androidx.leanback:leanback-preference"); + artifacts.add("androidx.legacy:legacy-preference-v14"); + artifacts.add("androidx.preference:preference"); + artifacts.add("androidx.print:print"); + artifacts.add("androidx.recommendation:recommendation"); + artifacts.add("androidx.recyclerview:recyclerview-selection"); + artifacts.add("androidx.recyclerview:recyclerview"); + artifacts.add("androidx.slice:slice-builders"); + artifacts.add("androidx.slice:slice-core"); + artifacts.add("androidx.slice:slice-view"); + artifacts.add("androidx.slidingpanelayout:slidingpanelayout"); + artifacts.add("androidx.annotation:annotation"); + artifacts.add("androidx.core:core"); + artifacts.add("androidx.contentpager:contentpager"); + artifacts.add("androidx.legacy:legacy-support-core-ui"); + artifacts.add("androidx.legacy:legacy-support-core-utils"); + artifacts.add("androidx.dynamicanimation:dynamicanimation"); + artifacts.add("androidx.emoji:emoji"); + artifacts.add("androidx.emoji:emoji-appcompat"); + artifacts.add("androidx.emoji:emoji-bundled"); + artifacts.add("androidx.fragment:fragment"); + artifacts.add("androidx.media:media"); + artifacts.add("androidx.tvprovider:tvprovider"); + artifacts.add("androidx.legacy:legacy-support-v13"); + artifacts.add("androidx.legacy:legacy-support-v4"); + artifacts.add("androidx.vectordrawable:vectordrawable"); + artifacts.add("androidx.swiperefreshlayout:swiperefreshlayout"); + artifacts.add("androidx.textclassifier:textclassifier"); + artifacts.add("androidx.transition:transition"); + artifacts.add("androidx.versionedparcelable:versionedparcelable"); + artifacts.add("androidx.viewpager:viewpager"); + artifacts.add("androidx.wear:wear"); + artifacts.add("androidx.webkit:webkit"); + + artifacts.add("fileTree(dir: 'libs', include: ['*.jar'])"); + return artifacts; + } + + private static List createConfigs() { + List configs = new ArrayList(); + configs.add("androidApis"); + configs.add("androidTestAnnotationProcessor"); + configs.add("androidTestApi"); + configs.add("androidTestApk"); + configs.add("androidTestCompile"); + configs.add("androidTestCompileOnly"); + configs.add("androidTestDebugAnnotationProcessor"); + configs.add("androidTestDebugApi"); + configs.add("androidTestDebugApk"); + configs.add("androidTestDebugCompile"); + configs.add("androidTestDebugCompileOnly"); + configs.add("androidTestDebugImplementation"); + configs.add("androidTestDebugProvided"); + configs.add("androidTestDebugRuntimeOnly"); + configs.add("androidTestDebugWearApp"); + configs.add("androidTestImplementation"); + configs.add("androidTestProvided"); + configs.add("androidTestRuntimeOnly"); + configs.add("androidTestUtil"); + configs.add("androidTestWearApp"); + configs.add("annotationProcessor"); + configs.add("api"); + configs.add("apk"); + configs.add("archives"); + configs.add("compile"); + configs.add("compileOnly"); + configs.add("coreLibraryDesugaring"); + configs.add("debugAnnotationProcessor"); + configs.add("debugApi"); + configs.add("debugApk"); + configs.add("debugCompile"); + configs.add("debugCompileOnly"); + configs.add("debugImplementation"); + configs.add("debugProvided"); + configs.add("debugRuntimeOnly"); + configs.add("debugWearApp"); + configs.add("default"); + configs.add("implementation"); + configs.add("implementation platform()"); + configs.add("lintChecks"); + configs.add("lintClassPath"); + configs.add("lintPublish"); + configs.add("provided"); + configs.add("releaseAnnotationProcessor"); + configs.add("releaseApi"); + configs.add("releaseApk"); + configs.add("releaseCompile"); + configs.add("releaseCompileOnly"); + configs.add("releaseImplementation"); + configs.add("releaseProvided"); + configs.add("releaseRuntimeOnly"); + configs.add("releaseWearApp"); + configs.add("runtimeOnly"); + configs.add("testAnnotationProcessor"); + configs.add("testApi"); + configs.add("testApk"); + configs.add("testCompile"); + configs.add("testCompileOnly"); + configs.add("testDebugAnnotationProcessor"); + configs.add("testDebugApi"); + configs.add("testDebugApk"); + configs.add("testDebugCompile"); + configs.add("testDebugCompileOnly"); + configs.add("testDebugImplementation"); + configs.add("testDebugProvided"); + configs.add("testDebugRuntimeOnly"); + configs.add("testDebugWearApp"); + configs.add("testImplementation"); + configs.add("testProvided"); + configs.add("testReleaseAnnotationProcessor"); + configs.add("testReleaseApi"); + configs.add("testReleaseApk"); + configs.add("testReleaseCompile"); + configs.add("testReleaseCompileOnly"); + configs.add("testReleaseImplementation"); + configs.add("testReleaseProvided"); + configs.add("testReleaseRuntimeOnly"); + configs.add("testReleaseWearApp"); + configs.add("testRuntimeOnly"); + configs.add("testWearApp"); + configs.add("wearApp"); + return configs; + } + + private static List createOtherCompletions() { + List others = new ArrayList(); + + // Common words that user may use + others.add("android"); + others.add("applicationVariants"); + others.add("compileSdkVersion"); + others.add("buildToolsVersion"); + others.add("defaultConfig"); + others.add("applicationId"); + others.add("minSdkVersion"); + others.add("targetSdkVersion"); + others.add("versionCode"); + others.add("versionName"); + others.add("multiDexEnabled"); + others.add("vectorDrawables.useSupportLibrary"); + others.add("compileOptions"); + others.add("coreLibraryDesugaringEnabled"); + others.add("sourceCompatibility"); + others.add("targetCompatibility"); + others.add("JavaVersion.VERSION_1_8"); + others.add("JavaVersion.VERSION_1_7"); + + // Lint options + others.add("lintOptions"); + others.add("quiet"); + others.add("abortOnError"); + others.add("checkReleaseBuilds"); + others.add("ignoreWarnings"); + others.add("checkAllWarnings"); + others.add("warningsAsErrors"); + others.add("disable"); + others.add("enable"); + others.add("check"); + others.add("noLines"); + others.add("showAll"); + others.add("explainIssues"); + others.add("lintConfig"); + others.add("textReport"); + others.add("textOutput"); + others.add("xmlReport"); + others.add("xmlOutput"); + others.add("htmlReport"); + others.add("htmlOutput"); + others.add("fatal"); + others.add("error"); + others.add("warning"); + others.add("ignore"); + others.add("informational"); + others.add("baseline"); + others.add("checkTestSources"); + others.add("ignoreTestSources"); + others.add("checkGeneratedSources"); + others.add("checkDependencies"); + + // buildFeatures options + others.add("buildFeatures"); + others.add("aidl"); + others.add("buildConfig"); + others.add("compose"); + others.add("prefab"); + others.add("renderScript"); + others.add("resValues"); + others.add("shaders"); + others.add("viewBinding"); + + // Signing configs and all + others.add("signingConfigs"); + others.add("debug"); + others.add("storeFile"); + others.add("storePassword"); + others.add("keyAlias"); + others.add("keyPassword"); + others.add("release"); + others.add("storeFile"); + others.add("storePassword"); + others.add("keyAlias"); + others.add("keyPassword"); + others.add("buildTypes"); + others.add("debug"); + others.add("minifyEnabled"); + others.add("proguardFiles"); + others.add("signingConfig"); + others.add("stringfog.enable"); + others.add("release"); + others.add("minifyEnabled"); + others.add("proguardFiles"); + others.add("signingConfig"); + others.add("stringfog.enable"); + others.add("packagingOptions"); + others.add("exclude"); + + // Maybe used in root project's build.gradle + others.add("buildscript"); + others.add("ext"); + others.add("project.ext"); + others.add("repositories"); + others.add("maven"); + others.add("url"); + others.add("google()"); + others.add("mavenLocal()"); + others.add("mavenCentral()"); + others.add("jcenter()"); + others.add("classpath"); + others.add("allprojects"); + others.add("subprojects"); + return others; + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyLanguage.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyLanguage.java new file mode 100644 index 000000000..5c1da52bf --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyLanguage.java @@ -0,0 +1,109 @@ +package com.itsaky.androidide.language.groovy; + +import com.itsaky.androidide.language.groovy.lexer.GroovyLexer; +import com.itsaky.androidide.language.java.manager.JavaCharacter; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.interfaces.EditorLanguage; +import io.github.rosemoe.editor.interfaces.NewlineHandler; +import io.github.rosemoe.editor.text.TextUtils; +import io.github.rosemoe.editor.widget.SymbolPairMatch; +import java.io.StringReader; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; + +public class GroovyLanguage implements EditorLanguage { + + private GroovyAnalyzer analyzer; + private GroovyAutoComplete completor; + + public GroovyLanguage() { + analyzer = new GroovyAnalyzer(); + completor = new GroovyAutoComplete(); + } + + @Override + public CodeAnalyzer getAnalyzer() { + return analyzer; + } + + @Override + public AutoCompleteProvider getAutoCompleteProvider() { + return completor; + } + + @Override + public boolean isAutoCompleteChar(char ch) { + return JavaCharacter.isJavaIdentifierPart(ch) || ch == '.'; + } + + @Override + public int getIndentAdvance(String p1) + { + try + { + GroovyLexer lexer = new GroovyLexer(CharStreams.fromReader(new StringReader(p1))); + Token token = null; + int advance = 0; + while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) + { + switch (token.getType()) + { + case GroovyLexer.LBRACE: + advance++; + break; + case GroovyLexer.RBRACE: + advance --; + break; + } + } + advance = Math.max(0, advance); + return advance * 4; + } catch (Throwable e) + {} + return 0; + } + + @Override + public SymbolPairMatch getSymbolPairs() { + return new SymbolPairMatch.DefaultSymbolPairs(); + } + + @Override + public boolean useTab() { + return true; + } + + @Override + public CharSequence format(CharSequence content) { + return content; + } + + private NewlineHandler[] newlineHandlers = new NewlineHandler[] { new BraceHandler() }; + + @Override + public NewlineHandler[] getNewlineHandlers() { + return newlineHandlers; + } + + class BraceHandler implements NewlineHandler { + + @Override + public boolean matchesRequirement(String beforeText, String afterText) { + beforeText = beforeText.trim(); + afterText = afterText.trim(); + return beforeText.endsWith("{") && afterText.startsWith("}"); + } + + @Override + public HandleResult handleNewline(String beforeText, String afterText, int tabSize) { + int count = TextUtils.countLeadingSpaceCount(beforeText, tabSize); + int advanceBefore = getIndentAdvance(beforeText); + int advanceAfter = getIndentAdvance(afterText); + String text; + StringBuilder sb = new StringBuilder("\n").append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab())).append('\n').append(text = TextUtils.createIndent(count + advanceAfter, tabSize, useTab())); + int shiftLeft = text.length() + 1; + return new HandleResult(sb, shiftLeft); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.g4 b/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.g4 new file mode 100644 index 000000000..e8182209b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.g4 @@ -0,0 +1,212 @@ +/* + [The "BSD licence"] + Copyright (c) 2013 Terence Parr, Sam Harwell + Copyright (c) 2017 Ivan Kochurkin (upgrade to Java 8) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +lexer grammar GroovyLexer; + +// Keywords + +ABSTRACT: 'abstract'; +ASSERT: 'assert'; +BOOLEAN: 'boolean'; +BREAK: 'break'; +BYTE: 'byte'; +CASE: 'case'; +CATCH: 'catch'; +CHAR: 'char'; +CLASS: 'class'; +CONST: 'const'; +CONTINUE: 'continue'; +DEFAULT: 'default'; +DO: 'do'; +DOUBLE: 'double'; +ELSE: 'else'; +ENUM: 'enum'; +EXTENDS: 'extends'; +FINAL: 'final'; +FINALLY: 'finally'; +FLOAT: 'float'; +FOR: 'for'; +IF: 'if'; +GOTO: 'goto'; +IMPLEMENTS: 'implements'; +IMPORT: 'import'; +INSTANCEOF: 'instanceof'; +INT: 'int'; +INTERFACE: 'interface'; +LONG: 'long'; +NATIVE: 'native'; +NEW: 'new'; +PACKAGE: 'package'; +PRIVATE: 'private'; +PROTECTED: 'protected'; +PUBLIC: 'public'; +RETURN: 'return'; +SHORT: 'short'; +STATIC: 'static'; +STRICTFP: 'strictfp'; +SUPER: 'super'; +SWITCH: 'switch'; +SYNCHRONIZED: 'synchronized'; +THIS: 'this'; +THROW: 'throw'; +THROWS: 'throws'; +TRANSIENT: 'transient'; +TRY: 'try'; +VOID: 'void'; +VOLATILE: 'volatile'; +WHILE: 'while'; + +// Literals + +DECIMAL_LITERAL: ('0' | [1-9] (Digits? | '_'+ Digits)) [lL]?; +HEX_LITERAL: '0' [xX] [0-9a-fA-F] ([0-9a-fA-F_]* [0-9a-fA-F])? [lL]?; +OCT_LITERAL: '0' '_'* [0-7] ([0-7_]* [0-7])? [lL]?; +BINARY_LITERAL: '0' [bB] [01] ([01_]* [01])? [lL]?; + +FLOAT_LITERAL: (Digits '.' Digits? | '.' Digits) ExponentPart? [fFdD]? + | Digits (ExponentPart [fFdD]? | [fFdD]) + ; + +HEX_FLOAT_LITERAL: '0' [xX] (HexDigits '.'? | HexDigits? '.' HexDigits) [pP] [+-]? Digits [fFdD]?; + +BOOL_LITERAL: 'true' + | 'false' + ; + +CHAR_LITERAL: '\'' (~['\\\r\n] | EscapeSequence) '\''; + +SINGLE_QUOTE_STRING: '\'' (~['\\\r\n] | EscapeSequence)* '\''; +STRING_LITERAL: '"' (~["\\\r\n] | EscapeSequence)* '"'; + +NULL_LITERAL: 'null'; + +// Separators + +LPAREN: '('; +RPAREN: ')'; +LBRACE: '{'; +RBRACE: '}'; +LBRACK: '['; +RBRACK: ']'; +SEMI: ';'; +COMMA: ','; +DOT: '.'; + +// Operators + +ASSIGN: '='; +GT: '>'; +LT: '<'; +BANG: '!'; +TILDE: '~'; +QUESTION: '?'; +COLON: ':'; +EQUAL: '=='; +LE: '<='; +GE: '>='; +NOTEQUAL: '!='; +AND: '&&'; +OR: '||'; +INC: '++'; +DEC: '--'; +ADD: '+'; +SUB: '-'; +MUL: '*'; +DIV: '/'; +BITAND: '&'; +BITOR: '|'; +CARET: '^'; +MOD: '%'; + +ADD_ASSIGN: '+='; +SUB_ASSIGN: '-='; +MUL_ASSIGN: '*='; +DIV_ASSIGN: '/='; +AND_ASSIGN: '&='; +OR_ASSIGN: '|='; +XOR_ASSIGN: '^='; +MOD_ASSIGN: '%='; +LSHIFT_ASSIGN: '<<='; +RSHIFT_ASSIGN: '>>='; +URSHIFT_ASSIGN: '>>>='; + +// Java 8 tokens + +ARROW: '->'; +COLONCOLON: '::'; + +// Additional symbols not defined in the lexical specification + +AT: '@'; +ELLIPSIS: '...'; + +// Whitespace and comments + +WS: [ \t\r\n\u000C]+ -> channel(HIDDEN); +COMMENT: '/*' .*? '*/' -> channel(HIDDEN); +LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN); + +// Identifiers + +IDENTIFIER: Letter LetterOrDigit*; + +// Fragment rules + +fragment ExponentPart + : [eE] [+-]? Digits + ; + +fragment EscapeSequence + : '\\' [btnfr"'\\] + | '\\' ([0-3]? [0-7])? [0-7] + | '\\' 'u'+ HexDigit HexDigit HexDigit HexDigit + ; + +fragment HexDigits + : HexDigit ((HexDigit | '_')* HexDigit)? + ; + +fragment HexDigit + : [0-9a-fA-F] + ; + +fragment Digits + : [0-9] ([0-9_]* [0-9])? + ; + +fragment LetterOrDigit + : Letter + | [0-9] + ; + +fragment Letter + : [a-zA-Z$_] // these are the "java letters" below 0x7F + | ~[\u0000-\u007F\uD800-\uDBFF] // covers all characters above 0x7F which are not a surrogate + | [\uD800-\uDBFF] [\uDC00-\uDFFF] // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF + ; diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.java b/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.java new file mode 100644 index 000000000..d891af434 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/lexer/GroovyLexer.java @@ -0,0 +1,514 @@ +// Generated from GroovyLexer.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.groovy.lexer; + +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class GroovyLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + ABSTRACT=1, ASSERT=2, BOOLEAN=3, BREAK=4, BYTE=5, CASE=6, CATCH=7, CHAR=8, + CLASS=9, CONST=10, CONTINUE=11, DEFAULT=12, DO=13, DOUBLE=14, ELSE=15, + ENUM=16, EXTENDS=17, FINAL=18, FINALLY=19, FLOAT=20, FOR=21, IF=22, GOTO=23, + IMPLEMENTS=24, IMPORT=25, INSTANCEOF=26, INT=27, INTERFACE=28, LONG=29, + NATIVE=30, NEW=31, PACKAGE=32, PRIVATE=33, PROTECTED=34, PUBLIC=35, RETURN=36, + SHORT=37, STATIC=38, STRICTFP=39, SUPER=40, SWITCH=41, SYNCHRONIZED=42, + THIS=43, THROW=44, THROWS=45, TRANSIENT=46, TRY=47, VOID=48, VOLATILE=49, + WHILE=50, DECIMAL_LITERAL=51, HEX_LITERAL=52, OCT_LITERAL=53, BINARY_LITERAL=54, + FLOAT_LITERAL=55, HEX_FLOAT_LITERAL=56, BOOL_LITERAL=57, CHAR_LITERAL=58, + SINGLE_QUOTE_STRING=59, STRING_LITERAL=60, NULL_LITERAL=61, LPAREN=62, + RPAREN=63, LBRACE=64, RBRACE=65, LBRACK=66, RBRACK=67, SEMI=68, COMMA=69, + DOT=70, ASSIGN=71, GT=72, LT=73, BANG=74, TILDE=75, QUESTION=76, COLON=77, + EQUAL=78, LE=79, GE=80, NOTEQUAL=81, AND=82, OR=83, INC=84, DEC=85, ADD=86, + SUB=87, MUL=88, DIV=89, BITAND=90, BITOR=91, CARET=92, MOD=93, ADD_ASSIGN=94, + SUB_ASSIGN=95, MUL_ASSIGN=96, DIV_ASSIGN=97, AND_ASSIGN=98, OR_ASSIGN=99, + XOR_ASSIGN=100, MOD_ASSIGN=101, LSHIFT_ASSIGN=102, RSHIFT_ASSIGN=103, + URSHIFT_ASSIGN=104, ARROW=105, COLONCOLON=106, AT=107, ELLIPSIS=108, WS=109, + COMMENT=110, LINE_COMMENT=111, IDENTIFIER=112; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", "CHAR", + "CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", "ENUM", + "EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "IF", "GOTO", "IMPLEMENTS", + "IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", "NEW", + "PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", "STATIC", + "STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", "THROWS", + "TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE", "DECIMAL_LITERAL", "HEX_LITERAL", + "OCT_LITERAL", "BINARY_LITERAL", "FLOAT_LITERAL", "HEX_FLOAT_LITERAL", + "BOOL_LITERAL", "CHAR_LITERAL", "SINGLE_QUOTE_STRING", "STRING_LITERAL", + "NULL_LITERAL", "LPAREN", "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", + "SEMI", "COMMA", "DOT", "ASSIGN", "GT", "LT", "BANG", "TILDE", "QUESTION", + "COLON", "EQUAL", "LE", "GE", "NOTEQUAL", "AND", "OR", "INC", "DEC", + "ADD", "SUB", "MUL", "DIV", "BITAND", "BITOR", "CARET", "MOD", "ADD_ASSIGN", + "SUB_ASSIGN", "MUL_ASSIGN", "DIV_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", + "XOR_ASSIGN", "MOD_ASSIGN", "LSHIFT_ASSIGN", "RSHIFT_ASSIGN", "URSHIFT_ASSIGN", + "ARROW", "COLONCOLON", "AT", "ELLIPSIS", "WS", "COMMENT", "LINE_COMMENT", + "IDENTIFIER", "ExponentPart", "EscapeSequence", "HexDigits", "HexDigit", + "Digits", "LetterOrDigit", "Letter" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'abstract'", "'assert'", "'boolean'", "'break'", "'byte'", "'case'", + "'catch'", "'char'", "'class'", "'const'", "'continue'", "'default'", + "'do'", "'double'", "'else'", "'enum'", "'extends'", "'final'", "'finally'", + "'float'", "'for'", "'if'", "'goto'", "'implements'", "'import'", "'instanceof'", + "'int'", "'interface'", "'long'", "'native'", "'new'", "'package'", "'private'", + "'protected'", "'public'", "'return'", "'short'", "'static'", "'strictfp'", + "'super'", "'switch'", "'synchronized'", "'this'", "'throw'", "'throws'", + "'transient'", "'try'", "'void'", "'volatile'", "'while'", null, null, + null, null, null, null, null, null, null, null, "'null'", "'('", "')'", + "'{'", "'}'", "'['", "']'", "';'", "','", "'.'", "'='", "'>'", "'<'", + "'!'", "'~'", "'?'", "':'", "'=='", "'<='", "'>='", "'!='", "'&&'", "'||'", + "'++'", "'--'", "'+'", "'-'", "'*'", "'/'", "'&'", "'|'", "'^'", "'%'", + "'+='", "'-='", "'*='", "'/='", "'&='", "'|='", "'^='", "'%='", "'<<='", + "'>>='", "'>>>='", "'->'", "'::'", "'@'", "'...'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", + "CHAR", "CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", + "ENUM", "EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "IF", "GOTO", + "IMPLEMENTS", "IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", + "NEW", "PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", + "STATIC", "STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", + "THROWS", "TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE", "DECIMAL_LITERAL", + "HEX_LITERAL", "OCT_LITERAL", "BINARY_LITERAL", "FLOAT_LITERAL", "HEX_FLOAT_LITERAL", + "BOOL_LITERAL", "CHAR_LITERAL", "SINGLE_QUOTE_STRING", "STRING_LITERAL", + "NULL_LITERAL", "LPAREN", "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", + "SEMI", "COMMA", "DOT", "ASSIGN", "GT", "LT", "BANG", "TILDE", "QUESTION", + "COLON", "EQUAL", "LE", "GE", "NOTEQUAL", "AND", "OR", "INC", "DEC", + "ADD", "SUB", "MUL", "DIV", "BITAND", "BITOR", "CARET", "MOD", "ADD_ASSIGN", + "SUB_ASSIGN", "MUL_ASSIGN", "DIV_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", + "XOR_ASSIGN", "MOD_ASSIGN", "LSHIFT_ASSIGN", "RSHIFT_ASSIGN", "URSHIFT_ASSIGN", + "ARROW", "COLONCOLON", "AT", "ELLIPSIS", "WS", "COMMENT", "LINE_COMMENT", + "IDENTIFIER" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public GroovyLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "GroovyLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2r\u03bf\b\1\4\2\t"+ + "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+ + "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ + "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+ + "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+ + ",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+ + "\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+ + "\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+ + "\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+ + "\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+ + "`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k\t"+ + "k\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\4q\tq\4r\tr\4s\ts\4t\tt\4u\tu\4v\tv\4"+ + "w\tw\4x\tx\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3"+ + "\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3"+ + "\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t"+ + "\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f"+ + "\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16"+ + "\3\17\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21"+ + "\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23"+ + "\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25"+ + "\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\30\3\30\3\30\3\30"+ + "\3\30\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32"+ + "\3\32\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33"+ + "\3\33\3\33\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35"+ + "\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3\37\3\37"+ + "\3 \3 \3 \3 \3!\3!\3!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3"+ + "#\3#\3#\3#\3#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\3%\3"+ + "%\3&\3&\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3(\3(\3(\3"+ + "(\3(\3)\3)\3)\3)\3)\3)\3*\3*\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3+\3"+ + "+\3+\3+\3+\3+\3,\3,\3,\3,\3,\3-\3-\3-\3-\3-\3-\3.\3.\3.\3.\3.\3.\3.\3"+ + "/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3\60\3\60\3\60\3\60\3\61\3\61\3\61\3\61\3"+ + "\61\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\63\3\63\3\63\3\63\3"+ + "\63\3\63\3\64\3\64\3\64\5\64\u0248\n\64\3\64\6\64\u024b\n\64\r\64\16\64"+ + "\u024c\3\64\5\64\u0250\n\64\5\64\u0252\n\64\3\64\5\64\u0255\n\64\3\65"+ + "\3\65\3\65\3\65\7\65\u025b\n\65\f\65\16\65\u025e\13\65\3\65\5\65\u0261"+ + "\n\65\3\65\5\65\u0264\n\65\3\66\3\66\7\66\u0268\n\66\f\66\16\66\u026b"+ + "\13\66\3\66\3\66\7\66\u026f\n\66\f\66\16\66\u0272\13\66\3\66\5\66\u0275"+ + "\n\66\3\66\5\66\u0278\n\66\3\67\3\67\3\67\3\67\7\67\u027e\n\67\f\67\16"+ + "\67\u0281\13\67\3\67\5\67\u0284\n\67\3\67\5\67\u0287\n\67\38\38\38\58"+ + "\u028c\n8\38\38\58\u0290\n8\38\58\u0293\n8\38\58\u0296\n8\38\38\38\58"+ + "\u029b\n8\38\58\u029e\n8\58\u02a0\n8\39\39\39\39\59\u02a6\n9\39\59\u02a9"+ + "\n9\39\39\59\u02ad\n9\39\39\59\u02b1\n9\39\39\59\u02b5\n9\3:\3:\3:\3:"+ + "\3:\3:\3:\3:\3:\5:\u02c0\n:\3;\3;\3;\5;\u02c5\n;\3;\3;\3<\3<\3<\7<\u02cc"+ + "\n<\f<\16<\u02cf\13<\3<\3<\3=\3=\3=\7=\u02d6\n=\f=\16=\u02d9\13=\3=\3"+ + "=\3>\3>\3>\3>\3>\3?\3?\3@\3@\3A\3A\3B\3B\3C\3C\3D\3D\3E\3E\3F\3F\3G\3"+ + "G\3H\3H\3I\3I\3J\3J\3K\3K\3L\3L\3M\3M\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3"+ + "Q\3R\3R\3R\3S\3S\3S\3T\3T\3T\3U\3U\3U\3V\3V\3V\3W\3W\3X\3X\3Y\3Y\3Z\3"+ + "Z\3[\3[\3\\\3\\\3]\3]\3^\3^\3_\3_\3_\3`\3`\3`\3a\3a\3a\3b\3b\3b\3c\3c"+ + "\3c\3d\3d\3d\3e\3e\3e\3f\3f\3f\3g\3g\3g\3g\3h\3h\3h\3h\3i\3i\3i\3i\3i"+ + "\3j\3j\3j\3k\3k\3k\3l\3l\3m\3m\3m\3m\3n\6n\u035c\nn\rn\16n\u035d\3n\3"+ + "n\3o\3o\3o\3o\7o\u0366\no\fo\16o\u0369\13o\3o\3o\3o\3o\3o\3p\3p\3p\3p"+ + "\7p\u0374\np\fp\16p\u0377\13p\3p\3p\3q\3q\7q\u037d\nq\fq\16q\u0380\13"+ + "q\3r\3r\5r\u0384\nr\3r\3r\3s\3s\3s\3s\5s\u038c\ns\3s\5s\u038f\ns\3s\3"+ + "s\3s\6s\u0394\ns\rs\16s\u0395\3s\3s\3s\3s\3s\5s\u039d\ns\3t\3t\3t\7t\u03a2"+ + "\nt\ft\16t\u03a5\13t\3t\5t\u03a8\nt\3u\3u\3v\3v\7v\u03ae\nv\fv\16v\u03b1"+ + "\13v\3v\5v\u03b4\nv\3w\3w\5w\u03b8\nw\3x\3x\3x\3x\5x\u03be\nx\3\u0367"+ + "\2y\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35"+ + "\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36"+ + ";\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67"+ + "m8o9q:s;u{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008d"+ + "H\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1"+ + "R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00afY\u00b1Z\u00b3[\u00b5"+ + "\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3c\u00c5d\u00c7e\u00c9"+ + "f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3k\u00d5l\u00d7m\u00d9n\u00dbo\u00dd"+ + "p\u00dfq\u00e1r\u00e3\2\u00e5\2\u00e7\2\u00e9\2\u00eb\2\u00ed\2\u00ef"+ + "\2\3\2\34\3\2\63;\4\2NNnn\4\2ZZzz\5\2\62;CHch\6\2\62;CHaach\3\2\629\4"+ + "\2\629aa\4\2DDdd\3\2\62\63\4\2\62\63aa\6\2FFHHffhh\4\2RRrr\4\2--//\6\2"+ + "\f\f\17\17))^^\6\2\f\f\17\17$$^^\5\2\13\f\16\17\"\"\4\2\f\f\17\17\4\2"+ + "GGgg\n\2$$))^^ddhhppttvv\3\2\62\65\3\2\62;\4\2\62;aa\6\2&&C\\aac|\4\2"+ + "\2\u0081\ud802\udc01\3\2\ud802\udc01\3\2\udc02\ue001\2\u03ea\2\3\3\2\2"+ + "\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3"+ + "\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2"+ + "\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2"+ + "\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2"+ + "\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3"+ + "\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2"+ + "\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2"+ + "W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3"+ + "\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2"+ + "\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2"+ + "}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2"+ + "\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f"+ + "\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2"+ + "\2\2\u0099\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1"+ + "\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2"+ + "\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3"+ + "\3\2\2\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb\3\2\2"+ + "\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5"+ + "\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd\3\2\2"+ + "\2\2\u00cf\3\2\2\2\2\u00d1\3\2\2\2\2\u00d3\3\2\2\2\2\u00d5\3\2\2\2\2\u00d7"+ + "\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\2\u00df\3\2\2"+ + "\2\2\u00e1\3\2\2\2\3\u00f1\3\2\2\2\5\u00fa\3\2\2\2\7\u0101\3\2\2\2\t\u0109"+ + "\3\2\2\2\13\u010f\3\2\2\2\r\u0114\3\2\2\2\17\u0119\3\2\2\2\21\u011f\3"+ + "\2\2\2\23\u0124\3\2\2\2\25\u012a\3\2\2\2\27\u0130\3\2\2\2\31\u0139\3\2"+ + "\2\2\33\u0141\3\2\2\2\35\u0144\3\2\2\2\37\u014b\3\2\2\2!\u0150\3\2\2\2"+ + "#\u0155\3\2\2\2%\u015d\3\2\2\2\'\u0163\3\2\2\2)\u016b\3\2\2\2+\u0171\3"+ + "\2\2\2-\u0175\3\2\2\2/\u0178\3\2\2\2\61\u017d\3\2\2\2\63\u0188\3\2\2\2"+ + "\65\u018f\3\2\2\2\67\u019a\3\2\2\29\u019e\3\2\2\2;\u01a8\3\2\2\2=\u01ad"+ + "\3\2\2\2?\u01b4\3\2\2\2A\u01b8\3\2\2\2C\u01c0\3\2\2\2E\u01c8\3\2\2\2G"+ + "\u01d2\3\2\2\2I\u01d9\3\2\2\2K\u01e0\3\2\2\2M\u01e6\3\2\2\2O\u01ed\3\2"+ + "\2\2Q\u01f6\3\2\2\2S\u01fc\3\2\2\2U\u0203\3\2\2\2W\u0210\3\2\2\2Y\u0215"+ + "\3\2\2\2[\u021b\3\2\2\2]\u0222\3\2\2\2_\u022c\3\2\2\2a\u0230\3\2\2\2c"+ + "\u0235\3\2\2\2e\u023e\3\2\2\2g\u0251\3\2\2\2i\u0256\3\2\2\2k\u0265\3\2"+ + "\2\2m\u0279\3\2\2\2o\u029f\3\2\2\2q\u02a1\3\2\2\2s\u02bf\3\2\2\2u\u02c1"+ + "\3\2\2\2w\u02c8\3\2\2\2y\u02d2\3\2\2\2{\u02dc\3\2\2\2}\u02e1\3\2\2\2\177"+ + "\u02e3\3\2\2\2\u0081\u02e5\3\2\2\2\u0083\u02e7\3\2\2\2\u0085\u02e9\3\2"+ + "\2\2\u0087\u02eb\3\2\2\2\u0089\u02ed\3\2\2\2\u008b\u02ef\3\2\2\2\u008d"+ + "\u02f1\3\2\2\2\u008f\u02f3\3\2\2\2\u0091\u02f5\3\2\2\2\u0093\u02f7\3\2"+ + "\2\2\u0095\u02f9\3\2\2\2\u0097\u02fb\3\2\2\2\u0099\u02fd\3\2\2\2\u009b"+ + "\u02ff\3\2\2\2\u009d\u0301\3\2\2\2\u009f\u0304\3\2\2\2\u00a1\u0307\3\2"+ + "\2\2\u00a3\u030a\3\2\2\2\u00a5\u030d\3\2\2\2\u00a7\u0310\3\2\2\2\u00a9"+ + "\u0313\3\2\2\2\u00ab\u0316\3\2\2\2\u00ad\u0319\3\2\2\2\u00af\u031b\3\2"+ + "\2\2\u00b1\u031d\3\2\2\2\u00b3\u031f\3\2\2\2\u00b5\u0321\3\2\2\2\u00b7"+ + "\u0323\3\2\2\2\u00b9\u0325\3\2\2\2\u00bb\u0327\3\2\2\2\u00bd\u0329\3\2"+ + "\2\2\u00bf\u032c\3\2\2\2\u00c1\u032f\3\2\2\2\u00c3\u0332\3\2\2\2\u00c5"+ + "\u0335\3\2\2\2\u00c7\u0338\3\2\2\2\u00c9\u033b\3\2\2\2\u00cb\u033e\3\2"+ + "\2\2\u00cd\u0341\3\2\2\2\u00cf\u0345\3\2\2\2\u00d1\u0349\3\2\2\2\u00d3"+ + "\u034e\3\2\2\2\u00d5\u0351\3\2\2\2\u00d7\u0354\3\2\2\2\u00d9\u0356\3\2"+ + "\2\2\u00db\u035b\3\2\2\2\u00dd\u0361\3\2\2\2\u00df\u036f\3\2\2\2\u00e1"+ + "\u037a\3\2\2\2\u00e3\u0381\3\2\2\2\u00e5\u039c\3\2\2\2\u00e7\u039e\3\2"+ + "\2\2\u00e9\u03a9\3\2\2\2\u00eb\u03ab\3\2\2\2\u00ed\u03b7\3\2\2\2\u00ef"+ + "\u03bd\3\2\2\2\u00f1\u00f2\7c\2\2\u00f2\u00f3\7d\2\2\u00f3\u00f4\7u\2"+ + "\2\u00f4\u00f5\7v\2\2\u00f5\u00f6\7t\2\2\u00f6\u00f7\7c\2\2\u00f7\u00f8"+ + "\7e\2\2\u00f8\u00f9\7v\2\2\u00f9\4\3\2\2\2\u00fa\u00fb\7c\2\2\u00fb\u00fc"+ + "\7u\2\2\u00fc\u00fd\7u\2\2\u00fd\u00fe\7g\2\2\u00fe\u00ff\7t\2\2\u00ff"+ + "\u0100\7v\2\2\u0100\6\3\2\2\2\u0101\u0102\7d\2\2\u0102\u0103\7q\2\2\u0103"+ + "\u0104\7q\2\2\u0104\u0105\7n\2\2\u0105\u0106\7g\2\2\u0106\u0107\7c\2\2"+ + "\u0107\u0108\7p\2\2\u0108\b\3\2\2\2\u0109\u010a\7d\2\2\u010a\u010b\7t"+ + "\2\2\u010b\u010c\7g\2\2\u010c\u010d\7c\2\2\u010d\u010e\7m\2\2\u010e\n"+ + "\3\2\2\2\u010f\u0110\7d\2\2\u0110\u0111\7{\2\2\u0111\u0112\7v\2\2\u0112"+ + "\u0113\7g\2\2\u0113\f\3\2\2\2\u0114\u0115\7e\2\2\u0115\u0116\7c\2\2\u0116"+ + "\u0117\7u\2\2\u0117\u0118\7g\2\2\u0118\16\3\2\2\2\u0119\u011a\7e\2\2\u011a"+ + "\u011b\7c\2\2\u011b\u011c\7v\2\2\u011c\u011d\7e\2\2\u011d\u011e\7j\2\2"+ + "\u011e\20\3\2\2\2\u011f\u0120\7e\2\2\u0120\u0121\7j\2\2\u0121\u0122\7"+ + "c\2\2\u0122\u0123\7t\2\2\u0123\22\3\2\2\2\u0124\u0125\7e\2\2\u0125\u0126"+ + "\7n\2\2\u0126\u0127\7c\2\2\u0127\u0128\7u\2\2\u0128\u0129\7u\2\2\u0129"+ + "\24\3\2\2\2\u012a\u012b\7e\2\2\u012b\u012c\7q\2\2\u012c\u012d\7p\2\2\u012d"+ + "\u012e\7u\2\2\u012e\u012f\7v\2\2\u012f\26\3\2\2\2\u0130\u0131\7e\2\2\u0131"+ + "\u0132\7q\2\2\u0132\u0133\7p\2\2\u0133\u0134\7v\2\2\u0134\u0135\7k\2\2"+ + "\u0135\u0136\7p\2\2\u0136\u0137\7w\2\2\u0137\u0138\7g\2\2\u0138\30\3\2"+ + "\2\2\u0139\u013a\7f\2\2\u013a\u013b\7g\2\2\u013b\u013c\7h\2\2\u013c\u013d"+ + "\7c\2\2\u013d\u013e\7w\2\2\u013e\u013f\7n\2\2\u013f\u0140\7v\2\2\u0140"+ + "\32\3\2\2\2\u0141\u0142\7f\2\2\u0142\u0143\7q\2\2\u0143\34\3\2\2\2\u0144"+ + "\u0145\7f\2\2\u0145\u0146\7q\2\2\u0146\u0147\7w\2\2\u0147\u0148\7d\2\2"+ + "\u0148\u0149\7n\2\2\u0149\u014a\7g\2\2\u014a\36\3\2\2\2\u014b\u014c\7"+ + "g\2\2\u014c\u014d\7n\2\2\u014d\u014e\7u\2\2\u014e\u014f\7g\2\2\u014f "+ + "\3\2\2\2\u0150\u0151\7g\2\2\u0151\u0152\7p\2\2\u0152\u0153\7w\2\2\u0153"+ + "\u0154\7o\2\2\u0154\"\3\2\2\2\u0155\u0156\7g\2\2\u0156\u0157\7z\2\2\u0157"+ + "\u0158\7v\2\2\u0158\u0159\7g\2\2\u0159\u015a\7p\2\2\u015a\u015b\7f\2\2"+ + "\u015b\u015c\7u\2\2\u015c$\3\2\2\2\u015d\u015e\7h\2\2\u015e\u015f\7k\2"+ + "\2\u015f\u0160\7p\2\2\u0160\u0161\7c\2\2\u0161\u0162\7n\2\2\u0162&\3\2"+ + "\2\2\u0163\u0164\7h\2\2\u0164\u0165\7k\2\2\u0165\u0166\7p\2\2\u0166\u0167"+ + "\7c\2\2\u0167\u0168\7n\2\2\u0168\u0169\7n\2\2\u0169\u016a\7{\2\2\u016a"+ + "(\3\2\2\2\u016b\u016c\7h\2\2\u016c\u016d\7n\2\2\u016d\u016e\7q\2\2\u016e"+ + "\u016f\7c\2\2\u016f\u0170\7v\2\2\u0170*\3\2\2\2\u0171\u0172\7h\2\2\u0172"+ + "\u0173\7q\2\2\u0173\u0174\7t\2\2\u0174,\3\2\2\2\u0175\u0176\7k\2\2\u0176"+ + "\u0177\7h\2\2\u0177.\3\2\2\2\u0178\u0179\7i\2\2\u0179\u017a\7q\2\2\u017a"+ + "\u017b\7v\2\2\u017b\u017c\7q\2\2\u017c\60\3\2\2\2\u017d\u017e\7k\2\2\u017e"+ + "\u017f\7o\2\2\u017f\u0180\7r\2\2\u0180\u0181\7n\2\2\u0181\u0182\7g\2\2"+ + "\u0182\u0183\7o\2\2\u0183\u0184\7g\2\2\u0184\u0185\7p\2\2\u0185\u0186"+ + "\7v\2\2\u0186\u0187\7u\2\2\u0187\62\3\2\2\2\u0188\u0189\7k\2\2\u0189\u018a"+ + "\7o\2\2\u018a\u018b\7r\2\2\u018b\u018c\7q\2\2\u018c\u018d\7t\2\2\u018d"+ + "\u018e\7v\2\2\u018e\64\3\2\2\2\u018f\u0190\7k\2\2\u0190\u0191\7p\2\2\u0191"+ + "\u0192\7u\2\2\u0192\u0193\7v\2\2\u0193\u0194\7c\2\2\u0194\u0195\7p\2\2"+ + "\u0195\u0196\7e\2\2\u0196\u0197\7g\2\2\u0197\u0198\7q\2\2\u0198\u0199"+ + "\7h\2\2\u0199\66\3\2\2\2\u019a\u019b\7k\2\2\u019b\u019c\7p\2\2\u019c\u019d"+ + "\7v\2\2\u019d8\3\2\2\2\u019e\u019f\7k\2\2\u019f\u01a0\7p\2\2\u01a0\u01a1"+ + "\7v\2\2\u01a1\u01a2\7g\2\2\u01a2\u01a3\7t\2\2\u01a3\u01a4\7h\2\2\u01a4"+ + "\u01a5\7c\2\2\u01a5\u01a6\7e\2\2\u01a6\u01a7\7g\2\2\u01a7:\3\2\2\2\u01a8"+ + "\u01a9\7n\2\2\u01a9\u01aa\7q\2\2\u01aa\u01ab\7p\2\2\u01ab\u01ac\7i\2\2"+ + "\u01ac<\3\2\2\2\u01ad\u01ae\7p\2\2\u01ae\u01af\7c\2\2\u01af\u01b0\7v\2"+ + "\2\u01b0\u01b1\7k\2\2\u01b1\u01b2\7x\2\2\u01b2\u01b3\7g\2\2\u01b3>\3\2"+ + "\2\2\u01b4\u01b5\7p\2\2\u01b5\u01b6\7g\2\2\u01b6\u01b7\7y\2\2\u01b7@\3"+ + "\2\2\2\u01b8\u01b9\7r\2\2\u01b9\u01ba\7c\2\2\u01ba\u01bb\7e\2\2\u01bb"+ + "\u01bc\7m\2\2\u01bc\u01bd\7c\2\2\u01bd\u01be\7i\2\2\u01be\u01bf\7g\2\2"+ + "\u01bfB\3\2\2\2\u01c0\u01c1\7r\2\2\u01c1\u01c2\7t\2\2\u01c2\u01c3\7k\2"+ + "\2\u01c3\u01c4\7x\2\2\u01c4\u01c5\7c\2\2\u01c5\u01c6\7v\2\2\u01c6\u01c7"+ + "\7g\2\2\u01c7D\3\2\2\2\u01c8\u01c9\7r\2\2\u01c9\u01ca\7t\2\2\u01ca\u01cb"+ + "\7q\2\2\u01cb\u01cc\7v\2\2\u01cc\u01cd\7g\2\2\u01cd\u01ce\7e\2\2\u01ce"+ + "\u01cf\7v\2\2\u01cf\u01d0\7g\2\2\u01d0\u01d1\7f\2\2\u01d1F\3\2\2\2\u01d2"+ + "\u01d3\7r\2\2\u01d3\u01d4\7w\2\2\u01d4\u01d5\7d\2\2\u01d5\u01d6\7n\2\2"+ + "\u01d6\u01d7\7k\2\2\u01d7\u01d8\7e\2\2\u01d8H\3\2\2\2\u01d9\u01da\7t\2"+ + "\2\u01da\u01db\7g\2\2\u01db\u01dc\7v\2\2\u01dc\u01dd\7w\2\2\u01dd\u01de"+ + "\7t\2\2\u01de\u01df\7p\2\2\u01dfJ\3\2\2\2\u01e0\u01e1\7u\2\2\u01e1\u01e2"+ + "\7j\2\2\u01e2\u01e3\7q\2\2\u01e3\u01e4\7t\2\2\u01e4\u01e5\7v\2\2\u01e5"+ + "L\3\2\2\2\u01e6\u01e7\7u\2\2\u01e7\u01e8\7v\2\2\u01e8\u01e9\7c\2\2\u01e9"+ + "\u01ea\7v\2\2\u01ea\u01eb\7k\2\2\u01eb\u01ec\7e\2\2\u01ecN\3\2\2\2\u01ed"+ + "\u01ee\7u\2\2\u01ee\u01ef\7v\2\2\u01ef\u01f0\7t\2\2\u01f0\u01f1\7k\2\2"+ + "\u01f1\u01f2\7e\2\2\u01f2\u01f3\7v\2\2\u01f3\u01f4\7h\2\2\u01f4\u01f5"+ + "\7r\2\2\u01f5P\3\2\2\2\u01f6\u01f7\7u\2\2\u01f7\u01f8\7w\2\2\u01f8\u01f9"+ + "\7r\2\2\u01f9\u01fa\7g\2\2\u01fa\u01fb\7t\2\2\u01fbR\3\2\2\2\u01fc\u01fd"+ + "\7u\2\2\u01fd\u01fe\7y\2\2\u01fe\u01ff\7k\2\2\u01ff\u0200\7v\2\2\u0200"+ + "\u0201\7e\2\2\u0201\u0202\7j\2\2\u0202T\3\2\2\2\u0203\u0204\7u\2\2\u0204"+ + "\u0205\7{\2\2\u0205\u0206\7p\2\2\u0206\u0207\7e\2\2\u0207\u0208\7j\2\2"+ + "\u0208\u0209\7t\2\2\u0209\u020a\7q\2\2\u020a\u020b\7p\2\2\u020b\u020c"+ + "\7k\2\2\u020c\u020d\7|\2\2\u020d\u020e\7g\2\2\u020e\u020f\7f\2\2\u020f"+ + "V\3\2\2\2\u0210\u0211\7v\2\2\u0211\u0212\7j\2\2\u0212\u0213\7k\2\2\u0213"+ + "\u0214\7u\2\2\u0214X\3\2\2\2\u0215\u0216\7v\2\2\u0216\u0217\7j\2\2\u0217"+ + "\u0218\7t\2\2\u0218\u0219\7q\2\2\u0219\u021a\7y\2\2\u021aZ\3\2\2\2\u021b"+ + "\u021c\7v\2\2\u021c\u021d\7j\2\2\u021d\u021e\7t\2\2\u021e\u021f\7q\2\2"+ + "\u021f\u0220\7y\2\2\u0220\u0221\7u\2\2\u0221\\\3\2\2\2\u0222\u0223\7v"+ + "\2\2\u0223\u0224\7t\2\2\u0224\u0225\7c\2\2\u0225\u0226\7p\2\2\u0226\u0227"+ + "\7u\2\2\u0227\u0228\7k\2\2\u0228\u0229\7g\2\2\u0229\u022a\7p\2\2\u022a"+ + "\u022b\7v\2\2\u022b^\3\2\2\2\u022c\u022d\7v\2\2\u022d\u022e\7t\2\2\u022e"+ + "\u022f\7{\2\2\u022f`\3\2\2\2\u0230\u0231\7x\2\2\u0231\u0232\7q\2\2\u0232"+ + "\u0233\7k\2\2\u0233\u0234\7f\2\2\u0234b\3\2\2\2\u0235\u0236\7x\2\2\u0236"+ + "\u0237\7q\2\2\u0237\u0238\7n\2\2\u0238\u0239\7c\2\2\u0239\u023a\7v\2\2"+ + "\u023a\u023b\7k\2\2\u023b\u023c\7n\2\2\u023c\u023d\7g\2\2\u023dd\3\2\2"+ + "\2\u023e\u023f\7y\2\2\u023f\u0240\7j\2\2\u0240\u0241\7k\2\2\u0241\u0242"+ + "\7n\2\2\u0242\u0243\7g\2\2\u0243f\3\2\2\2\u0244\u0252\7\62\2\2\u0245\u024f"+ + "\t\2\2\2\u0246\u0248\5\u00ebv\2\u0247\u0246\3\2\2\2\u0247\u0248\3\2\2"+ + "\2\u0248\u0250\3\2\2\2\u0249\u024b\7a\2\2\u024a\u0249\3\2\2\2\u024b\u024c"+ + "\3\2\2\2\u024c\u024a\3\2\2\2\u024c\u024d\3\2\2\2\u024d\u024e\3\2\2\2\u024e"+ + "\u0250\5\u00ebv\2\u024f\u0247\3\2\2\2\u024f\u024a\3\2\2\2\u0250\u0252"+ + "\3\2\2\2\u0251\u0244\3\2\2\2\u0251\u0245\3\2\2\2\u0252\u0254\3\2\2\2\u0253"+ + "\u0255\t\3\2\2\u0254\u0253\3\2\2\2\u0254\u0255\3\2\2\2\u0255h\3\2\2\2"+ + "\u0256\u0257\7\62\2\2\u0257\u0258\t\4\2\2\u0258\u0260\t\5\2\2\u0259\u025b"+ + "\t\6\2\2\u025a\u0259\3\2\2\2\u025b\u025e\3\2\2\2\u025c\u025a\3\2\2\2\u025c"+ + "\u025d\3\2\2\2\u025d\u025f\3\2\2\2\u025e\u025c\3\2\2\2\u025f\u0261\t\5"+ + "\2\2\u0260\u025c\3\2\2\2\u0260\u0261\3\2\2\2\u0261\u0263\3\2\2\2\u0262"+ + "\u0264\t\3\2\2\u0263\u0262\3\2\2\2\u0263\u0264\3\2\2\2\u0264j\3\2\2\2"+ + "\u0265\u0269\7\62\2\2\u0266\u0268\7a\2\2\u0267\u0266\3\2\2\2\u0268\u026b"+ + "\3\2\2\2\u0269\u0267\3\2\2\2\u0269\u026a\3\2\2\2\u026a\u026c\3\2\2\2\u026b"+ + "\u0269\3\2\2\2\u026c\u0274\t\7\2\2\u026d\u026f\t\b\2\2\u026e\u026d\3\2"+ + "\2\2\u026f\u0272\3\2\2\2\u0270\u026e\3\2\2\2\u0270\u0271\3\2\2\2\u0271"+ + "\u0273\3\2\2\2\u0272\u0270\3\2\2\2\u0273\u0275\t\7\2\2\u0274\u0270\3\2"+ + "\2\2\u0274\u0275\3\2\2\2\u0275\u0277\3\2\2\2\u0276\u0278\t\3\2\2\u0277"+ + "\u0276\3\2\2\2\u0277\u0278\3\2\2\2\u0278l\3\2\2\2\u0279\u027a\7\62\2\2"+ + "\u027a\u027b\t\t\2\2\u027b\u0283\t\n\2\2\u027c\u027e\t\13\2\2\u027d\u027c"+ + "\3\2\2\2\u027e\u0281\3\2\2\2\u027f\u027d\3\2\2\2\u027f\u0280\3\2\2\2\u0280"+ + "\u0282\3\2\2\2\u0281\u027f\3\2\2\2\u0282\u0284\t\n\2\2\u0283\u027f\3\2"+ + "\2\2\u0283\u0284\3\2\2\2\u0284\u0286\3\2\2\2\u0285\u0287\t\3\2\2\u0286"+ + "\u0285\3\2\2\2\u0286\u0287\3\2\2\2\u0287n\3\2\2\2\u0288\u0289\5\u00eb"+ + "v\2\u0289\u028b\7\60\2\2\u028a\u028c\5\u00ebv\2\u028b\u028a\3\2\2\2\u028b"+ + "\u028c\3\2\2\2\u028c\u0290\3\2\2\2\u028d\u028e\7\60\2\2\u028e\u0290\5"+ + "\u00ebv\2\u028f\u0288\3\2\2\2\u028f\u028d\3\2\2\2\u0290\u0292\3\2\2\2"+ + "\u0291\u0293\5\u00e3r\2\u0292\u0291\3\2\2\2\u0292\u0293\3\2\2\2\u0293"+ + "\u0295\3\2\2\2\u0294\u0296\t\f\2\2\u0295\u0294\3\2\2\2\u0295\u0296\3\2"+ + "\2\2\u0296\u02a0\3\2\2\2\u0297\u029d\5\u00ebv\2\u0298\u029a\5\u00e3r\2"+ + "\u0299\u029b\t\f\2\2\u029a\u0299\3\2\2\2\u029a\u029b\3\2\2\2\u029b\u029e"+ + "\3\2\2\2\u029c\u029e\t\f\2\2\u029d\u0298\3\2\2\2\u029d\u029c\3\2\2\2\u029e"+ + "\u02a0\3\2\2\2\u029f\u028f\3\2\2\2\u029f\u0297\3\2\2\2\u02a0p\3\2\2\2"+ + "\u02a1\u02a2\7\62\2\2\u02a2\u02ac\t\4\2\2\u02a3\u02a5\5\u00e7t\2\u02a4"+ + "\u02a6\7\60\2\2\u02a5\u02a4\3\2\2\2\u02a5\u02a6\3\2\2\2\u02a6\u02ad\3"+ + "\2\2\2\u02a7\u02a9\5\u00e7t\2\u02a8\u02a7\3\2\2\2\u02a8\u02a9\3\2\2\2"+ + "\u02a9\u02aa\3\2\2\2\u02aa\u02ab\7\60\2\2\u02ab\u02ad\5\u00e7t\2\u02ac"+ + "\u02a3\3\2\2\2\u02ac\u02a8\3\2\2\2\u02ad\u02ae\3\2\2\2\u02ae\u02b0\t\r"+ + "\2\2\u02af\u02b1\t\16\2\2\u02b0\u02af\3\2\2\2\u02b0\u02b1\3\2\2\2\u02b1"+ + "\u02b2\3\2\2\2\u02b2\u02b4\5\u00ebv\2\u02b3\u02b5\t\f\2\2\u02b4\u02b3"+ + "\3\2\2\2\u02b4\u02b5\3\2\2\2\u02b5r\3\2\2\2\u02b6\u02b7\7v\2\2\u02b7\u02b8"+ + "\7t\2\2\u02b8\u02b9\7w\2\2\u02b9\u02c0\7g\2\2\u02ba\u02bb\7h\2\2\u02bb"+ + "\u02bc\7c\2\2\u02bc\u02bd\7n\2\2\u02bd\u02be\7u\2\2\u02be\u02c0\7g\2\2"+ + "\u02bf\u02b6\3\2\2\2\u02bf\u02ba\3\2\2\2\u02c0t\3\2\2\2\u02c1\u02c4\7"+ + ")\2\2\u02c2\u02c5\n\17\2\2\u02c3\u02c5\5\u00e5s\2\u02c4\u02c2\3\2\2\2"+ + "\u02c4\u02c3\3\2\2\2\u02c5\u02c6\3\2\2\2\u02c6\u02c7\7)\2\2\u02c7v\3\2"+ + "\2\2\u02c8\u02cd\7)\2\2\u02c9\u02cc\n\17\2\2\u02ca\u02cc\5\u00e5s\2\u02cb"+ + "\u02c9\3\2\2\2\u02cb\u02ca\3\2\2\2\u02cc\u02cf\3\2\2\2\u02cd\u02cb\3\2"+ + "\2\2\u02cd\u02ce\3\2\2\2\u02ce\u02d0\3\2\2\2\u02cf\u02cd\3\2\2\2\u02d0"+ + "\u02d1\7)\2\2\u02d1x\3\2\2\2\u02d2\u02d7\7$\2\2\u02d3\u02d6\n\20\2\2\u02d4"+ + "\u02d6\5\u00e5s\2\u02d5\u02d3\3\2\2\2\u02d5\u02d4\3\2\2\2\u02d6\u02d9"+ + "\3\2\2\2\u02d7\u02d5\3\2\2\2\u02d7\u02d8\3\2\2\2\u02d8\u02da\3\2\2\2\u02d9"+ + "\u02d7\3\2\2\2\u02da\u02db\7$\2\2\u02dbz\3\2\2\2\u02dc\u02dd\7p\2\2\u02dd"+ + "\u02de\7w\2\2\u02de\u02df\7n\2\2\u02df\u02e0\7n\2\2\u02e0|\3\2\2\2\u02e1"+ + "\u02e2\7*\2\2\u02e2~\3\2\2\2\u02e3\u02e4\7+\2\2\u02e4\u0080\3\2\2\2\u02e5"+ + "\u02e6\7}\2\2\u02e6\u0082\3\2\2\2\u02e7\u02e8\7\177\2\2\u02e8\u0084\3"+ + "\2\2\2\u02e9\u02ea\7]\2\2\u02ea\u0086\3\2\2\2\u02eb\u02ec\7_\2\2\u02ec"+ + "\u0088\3\2\2\2\u02ed\u02ee\7=\2\2\u02ee\u008a\3\2\2\2\u02ef\u02f0\7.\2"+ + "\2\u02f0\u008c\3\2\2\2\u02f1\u02f2\7\60\2\2\u02f2\u008e\3\2\2\2\u02f3"+ + "\u02f4\7?\2\2\u02f4\u0090\3\2\2\2\u02f5\u02f6\7@\2\2\u02f6\u0092\3\2\2"+ + "\2\u02f7\u02f8\7>\2\2\u02f8\u0094\3\2\2\2\u02f9\u02fa\7#\2\2\u02fa\u0096"+ + "\3\2\2\2\u02fb\u02fc\7\u0080\2\2\u02fc\u0098\3\2\2\2\u02fd\u02fe\7A\2"+ + "\2\u02fe\u009a\3\2\2\2\u02ff\u0300\7<\2\2\u0300\u009c\3\2\2\2\u0301\u0302"+ + "\7?\2\2\u0302\u0303\7?\2\2\u0303\u009e\3\2\2\2\u0304\u0305\7>\2\2\u0305"+ + "\u0306\7?\2\2\u0306\u00a0\3\2\2\2\u0307\u0308\7@\2\2\u0308\u0309\7?\2"+ + "\2\u0309\u00a2\3\2\2\2\u030a\u030b\7#\2\2\u030b\u030c\7?\2\2\u030c\u00a4"+ + "\3\2\2\2\u030d\u030e\7(\2\2\u030e\u030f\7(\2\2\u030f\u00a6\3\2\2\2\u0310"+ + "\u0311\7~\2\2\u0311\u0312\7~\2\2\u0312\u00a8\3\2\2\2\u0313\u0314\7-\2"+ + "\2\u0314\u0315\7-\2\2\u0315\u00aa\3\2\2\2\u0316\u0317\7/\2\2\u0317\u0318"+ + "\7/\2\2\u0318\u00ac\3\2\2\2\u0319\u031a\7-\2\2\u031a\u00ae\3\2\2\2\u031b"+ + "\u031c\7/\2\2\u031c\u00b0\3\2\2\2\u031d\u031e\7,\2\2\u031e\u00b2\3\2\2"+ + "\2\u031f\u0320\7\61\2\2\u0320\u00b4\3\2\2\2\u0321\u0322\7(\2\2\u0322\u00b6"+ + "\3\2\2\2\u0323\u0324\7~\2\2\u0324\u00b8\3\2\2\2\u0325\u0326\7`\2\2\u0326"+ + "\u00ba\3\2\2\2\u0327\u0328\7\'\2\2\u0328\u00bc\3\2\2\2\u0329\u032a\7-"+ + "\2\2\u032a\u032b\7?\2\2\u032b\u00be\3\2\2\2\u032c\u032d\7/\2\2\u032d\u032e"+ + "\7?\2\2\u032e\u00c0\3\2\2\2\u032f\u0330\7,\2\2\u0330\u0331\7?\2\2\u0331"+ + "\u00c2\3\2\2\2\u0332\u0333\7\61\2\2\u0333\u0334\7?\2\2\u0334\u00c4\3\2"+ + "\2\2\u0335\u0336\7(\2\2\u0336\u0337\7?\2\2\u0337\u00c6\3\2\2\2\u0338\u0339"+ + "\7~\2\2\u0339\u033a\7?\2\2\u033a\u00c8\3\2\2\2\u033b\u033c\7`\2\2\u033c"+ + "\u033d\7?\2\2\u033d\u00ca\3\2\2\2\u033e\u033f\7\'\2\2\u033f\u0340\7?\2"+ + "\2\u0340\u00cc\3\2\2\2\u0341\u0342\7>\2\2\u0342\u0343\7>\2\2\u0343\u0344"+ + "\7?\2\2\u0344\u00ce\3\2\2\2\u0345\u0346\7@\2\2\u0346\u0347\7@\2\2\u0347"+ + "\u0348\7?\2\2\u0348\u00d0\3\2\2\2\u0349\u034a\7@\2\2\u034a\u034b\7@\2"+ + "\2\u034b\u034c\7@\2\2\u034c\u034d\7?\2\2\u034d\u00d2\3\2\2\2\u034e\u034f"+ + "\7/\2\2\u034f\u0350\7@\2\2\u0350\u00d4\3\2\2\2\u0351\u0352\7<\2\2\u0352"+ + "\u0353\7<\2\2\u0353\u00d6\3\2\2\2\u0354\u0355\7B\2\2\u0355\u00d8\3\2\2"+ + "\2\u0356\u0357\7\60\2\2\u0357\u0358\7\60\2\2\u0358\u0359\7\60\2\2\u0359"+ + "\u00da\3\2\2\2\u035a\u035c\t\21\2\2\u035b\u035a\3\2\2\2\u035c\u035d\3"+ + "\2\2\2\u035d\u035b\3\2\2\2\u035d\u035e\3\2\2\2\u035e\u035f\3\2\2\2\u035f"+ + "\u0360\bn\2\2\u0360\u00dc\3\2\2\2\u0361\u0362\7\61\2\2\u0362\u0363\7,"+ + "\2\2\u0363\u0367\3\2\2\2\u0364\u0366\13\2\2\2\u0365\u0364\3\2\2\2\u0366"+ + "\u0369\3\2\2\2\u0367\u0368\3\2\2\2\u0367\u0365\3\2\2\2\u0368\u036a\3\2"+ + "\2\2\u0369\u0367\3\2\2\2\u036a\u036b\7,\2\2\u036b\u036c\7\61\2\2\u036c"+ + "\u036d\3\2\2\2\u036d\u036e\bo\2\2\u036e\u00de\3\2\2\2\u036f\u0370\7\61"+ + "\2\2\u0370\u0371\7\61\2\2\u0371\u0375\3\2\2\2\u0372\u0374\n\22\2\2\u0373"+ + "\u0372\3\2\2\2\u0374\u0377\3\2\2\2\u0375\u0373\3\2\2\2\u0375\u0376\3\2"+ + "\2\2\u0376\u0378\3\2\2\2\u0377\u0375\3\2\2\2\u0378\u0379\bp\2\2\u0379"+ + "\u00e0\3\2\2\2\u037a\u037e\5\u00efx\2\u037b\u037d\5\u00edw\2\u037c\u037b"+ + "\3\2\2\2\u037d\u0380\3\2\2\2\u037e\u037c\3\2\2\2\u037e\u037f\3\2\2\2\u037f"+ + "\u00e2\3\2\2\2\u0380\u037e\3\2\2\2\u0381\u0383\t\23\2\2\u0382\u0384\t"+ + "\16\2\2\u0383\u0382\3\2\2\2\u0383\u0384\3\2\2\2\u0384\u0385\3\2\2\2\u0385"+ + "\u0386\5\u00ebv\2\u0386\u00e4\3\2\2\2\u0387\u0388\7^\2\2\u0388\u039d\t"+ + "\24\2\2\u0389\u038e\7^\2\2\u038a\u038c\t\25\2\2\u038b\u038a\3\2\2\2\u038b"+ + "\u038c\3\2\2\2\u038c\u038d\3\2\2\2\u038d\u038f\t\7\2\2\u038e\u038b\3\2"+ + "\2\2\u038e\u038f\3\2\2\2\u038f\u0390\3\2\2\2\u0390\u039d\t\7\2\2\u0391"+ + "\u0393\7^\2\2\u0392\u0394\7w\2\2\u0393\u0392\3\2\2\2\u0394\u0395\3\2\2"+ + "\2\u0395\u0393\3\2\2\2\u0395\u0396\3\2\2\2\u0396\u0397\3\2\2\2\u0397\u0398"+ + "\5\u00e9u\2\u0398\u0399\5\u00e9u\2\u0399\u039a\5\u00e9u\2\u039a\u039b"+ + "\5\u00e9u\2\u039b\u039d\3\2\2\2\u039c\u0387\3\2\2\2\u039c\u0389\3\2\2"+ + "\2\u039c\u0391\3\2\2\2\u039d\u00e6\3\2\2\2\u039e\u03a7\5\u00e9u\2\u039f"+ + "\u03a2\5\u00e9u\2\u03a0\u03a2\7a\2\2\u03a1\u039f\3\2\2\2\u03a1\u03a0\3"+ + "\2\2\2\u03a2\u03a5\3\2\2\2\u03a3\u03a1\3\2\2\2\u03a3\u03a4\3\2\2\2\u03a4"+ + "\u03a6\3\2\2\2\u03a5\u03a3\3\2\2\2\u03a6\u03a8\5\u00e9u\2\u03a7\u03a3"+ + "\3\2\2\2\u03a7\u03a8\3\2\2\2\u03a8\u00e8\3\2\2\2\u03a9\u03aa\t\5\2\2\u03aa"+ + "\u00ea\3\2\2\2\u03ab\u03b3\t\26\2\2\u03ac\u03ae\t\27\2\2\u03ad\u03ac\3"+ + "\2\2\2\u03ae\u03b1\3\2\2\2\u03af\u03ad\3\2\2\2\u03af\u03b0\3\2\2\2\u03b0"+ + "\u03b2\3\2\2\2\u03b1\u03af\3\2\2\2\u03b2\u03b4\t\26\2\2\u03b3\u03af\3"+ + "\2\2\2\u03b3\u03b4\3\2\2\2\u03b4\u00ec\3\2\2\2\u03b5\u03b8\5\u00efx\2"+ + "\u03b6\u03b8\t\26\2\2\u03b7\u03b5\3\2\2\2\u03b7\u03b6\3\2\2\2\u03b8\u00ee"+ + "\3\2\2\2\u03b9\u03be\t\30\2\2\u03ba\u03be\n\31\2\2\u03bb\u03bc\t\32\2"+ + "\2\u03bc\u03be\t\33\2\2\u03bd\u03b9\3\2\2\2\u03bd\u03ba\3\2\2\2\u03bd"+ + "\u03bb\3\2\2\2\u03be\u00f0\3\2\2\2\64\2\u0247\u024c\u024f\u0251\u0254"+ + "\u025c\u0260\u0263\u0269\u0270\u0274\u0277\u027f\u0283\u0286\u028b\u028f"+ + "\u0292\u0295\u029a\u029d\u029f\u02a5\u02a8\u02ac\u02b0\u02b4\u02bf\u02c4"+ + "\u02cb\u02cd\u02d5\u02d7\u035d\u0367\u0375\u037e\u0383\u038b\u038e\u0395"+ + "\u039c\u03a1\u03a3\u03a7\u03af\u03b3\u03b7\u03bd\3\2\3\2"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java new file mode 100644 index 000000000..ff330bb8a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java @@ -0,0 +1,43 @@ +package com.itsaky.androidide.language.java; + +import android.text.TextUtils; +import androidx.core.util.Pair; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.language.java.JavaLanguageAnalyzer; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.utils.Either; +import com.itsaky.androidide.utils.EitherOfResult; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.struct.CompletionItem; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +public class JavaAutoComplete implements AutoCompleteProvider { + + private CodeEditor editor; + private JavaLanguageAnalyzer analyzer; + + public JavaAutoComplete(CodeEditor editor, JavaLanguageAnalyzer analyzer) { + this.editor = editor; + this.analyzer = analyzer; + } + + @Override + public List> getAutoCompleteItems(String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int line) { + Pair, List>> pair = StudioApp.getInstance().getCompletionProvider().getSuggestions(editor); + final ArrayList suggestions = pair.first; + final List> diags = pair.second; + if(suggestions != null) { + List> result = new ArrayList<>(); + for(SuggestItem item : suggestions) { + result.add(new EitherOfResult(item, null)); + } + return result; + } + return new ArrayList>(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java new file mode 100644 index 000000000..cef9260b5 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java @@ -0,0 +1,135 @@ +package com.itsaky.androidide.language.java; + +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.language.java.manager.JavaCharacter; +import com.itsaky.androidide.language.java.parser.JavaLexer; +import com.itsaky.androidide.language.java.parser.JavaParser; +import com.itsaky.androidide.models.AndroidProject; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.interfaces.EditorLanguage; +import io.github.rosemoe.editor.interfaces.NewlineHandler; +import io.github.rosemoe.editor.text.TextUtils; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.widget.SymbolPairMatch; +import java.io.StringReader; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; + +public class JavaLanguage implements EditorLanguage +{ + private JavaLanguageAnalyzer analyzer; + private JavaAutoComplete complete; + private AndroidProject project; + private CodeEditor editor; + + public JavaLanguage(CodeEditor editor, AndroidProject project) + { + this.analyzer = new JavaLanguageAnalyzer(); + this.complete = new JavaAutoComplete(editor, analyzer); + this.project = project; + this.editor = editor; + } + + @Override + public CodeAnalyzer getAnalyzer() + { + return analyzer; + } + + @Override + public AutoCompleteProvider getAutoCompleteProvider() + { + return complete; + } + + @Override + public boolean isAutoCompleteChar(char p1) + { + return JavaCharacter.isJavaIdentifierPart(p1) || p1 == '.'; + } + + @Override + public int getIndentAdvance(String p1) + { + try + { + JavaLexer lexer = new JavaLexer(CharStreams.fromReader(new StringReader(p1))); + Token token = null; + int advance = 0; + while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) + { + switch (token.getType()) + { + case JavaLexer.LBRACE: + advance++; + break; + case JavaParser.RBRACE: + advance --; + break; + } + } + advance = Math.max(0, advance); + return advance * 4; + } catch (Throwable e) + {} + return 0; + } + + @Override + public SymbolPairMatch getSymbolPairs() { + return new SymbolPairMatch.DefaultSymbolPairs(); + } + + @Override + public boolean useTab() { + return true; + } + + @Override + public CharSequence format(CharSequence content) { + return content; + } + + private NewlineHandler[] newlineHandlers = new NewlineHandler[] { new BraceHandler() }; + + @Override + public NewlineHandler[] getNewlineHandlers() { + return newlineHandlers; + } + + class BraceHandler implements NewlineHandler { + + @Override + public boolean matchesRequirement(String beforeText, String afterText) { + beforeText = beforeText.trim(); + afterText = afterText.trim(); + return beforeText.endsWith("{") && afterText.startsWith("}"); + } + + @Override + public HandleResult handleNewline(String beforeText, String afterText, int tabSize) { + int count = TextUtils.countLeadingSpaceCount(beforeText, tabSize); + int advanceBefore = getIndentAdvance(beforeText); + int advanceAfter = getIndentAdvance(afterText); + String text; + StringBuilder sb = new StringBuilder("\n").append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab())).append('\n').append(text = TextUtils.createIndent(count + advanceAfter, tabSize, useTab())); + int shiftLeft = text.length() + 1; + return new HandleResult(sb, shiftLeft); + } + } + + public static String[] getKeywords() + { + return new String[] { + "abstract", "assert", "boolean", "break", "byte", "case", + "catch", "char", "class", "const", "continue", "default", + "do", "double", "else", "enum", "extends", "final", "finally", + "float", "for", "if", "goto", "implements", "import", "instanceof", + "int", "interface", "long", "native", "new", "package", "private", + "protected", "public", "return", "short", "static", "strictfp", + "super", "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "void", "volatile", "while", "null" + }; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java new file mode 100644 index 000000000..e6ee269aa --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java @@ -0,0 +1,36 @@ +package com.itsaky.androidide.language.java; + +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.syntax.lexer.Lexer; +import com.itsaky.androidide.syntax.lexer.impls.java.JavaLexerImpl; +import com.itsaky.androidide.syntax.lexer.tokens.Token; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.text.TextAnalyzer; +import java.util.ArrayList; +import com.blankj.utilcode.util.ThrowableUtils; + +public class JavaLanguageAnalyzer implements CodeAnalyzer { + + @Override + public void analyze(CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { + try { + JavaLexerImpl lexer = new JavaLexerImpl(content.toString(), colors); + lexer.init(); + + // Adding spans, hex colors, block lines and all is handled by JavaLexerImpl + while (delegate.shouldAnalyze()) { + // null = EOF + if(lexer.nextToken() == null) + break; + } + if (lexer.stack.isEmpty() && lexer.currSwitch > lexer.maxSwitch) + lexer.maxSwitch = lexer.currSwitch; + + colors.determine(lexer.lastLine); + colors.setSuppressSwitch(lexer.maxSwitch + 10); + colors.setHexColors(lexer.lineColors); + } catch (Throwable e) { + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/manager/JavaCharacter.java b/app/src/main/java/com/itsaky/androidide/language/java/manager/JavaCharacter.java new file mode 100644 index 000000000..04bfd9543 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/manager/JavaCharacter.java @@ -0,0 +1,83 @@ +package com.itsaky.androidide.language.java.manager; + +import java.util.Arrays; + +/** + * @author Rose + * Get whether Identifier part/start quickly + */ +public class JavaCharacter { + + /** + * Compressed bit set for isJavaIdentifierStart() + */ + private static int[] state_start; + + /** + * Compressed bit set for isJavaIdentifierPart() + */ + private static int[] state_part; + + /** + * Get bit in compressed bit set + * + * @param values Compressed bit set + * @param bitIndex Target index + * @return Boolean value at the index + */ + private static boolean get(int[] values, int bitIndex) { + return ((values[bitIndex / 32] & (1 << (bitIndex % 32))) != 0); + } + + /** + * Make the given position's bit true + * + * @param values Compressed bit set + * @param bitIndex Index of bit + */ + private static void set(int[] values, int bitIndex) { + values[bitIndex / 32] |= (1 << (bitIndex % 32)); + } + + /** + * Init maps + */ + public static void initMap() { + if (state_start != null) { + return; + } + state_part = new int[2048]; + state_start = new int[2048]; + Arrays.fill(state_part, 0); + Arrays.fill(state_start, 0); + for (int i = 0; i <= 65535; i++) { + if (Character.isJavaIdentifierPart((char) i)) { + set(state_part, i); + } + if (Character.isJavaIdentifierStart((char) i)) { + set(state_start, i); + } + } + } + + /** + * @param key Character + * @return Whether a identifier part + * @see Character#isJavaIdentifierPart(char) + */ + public static boolean isJavaIdentifierPart(int key) { + return get(state_part, key); + } + + /** + * @param key Character + * @return Whether a identifier start + * @see Character#isJavaIdentifierStart(char) + */ + public static boolean isJavaIdentifierStart(int key) { + return get(state_start, key); + } + +} + + diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/DiagnosticCollector.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/DiagnosticCollector.java new file mode 100644 index 000000000..1d21d3904 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/DiagnosticCollector.java @@ -0,0 +1,27 @@ +package com.itsaky.androidide.language.java.parser; + +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import java.util.Collections; +import java.util.ArrayList; +import javax.tools.JavaFileObject; + +public class DiagnosticCollector implements DiagnosticListener { + + private List> diagnostics = Collections.synchronizedList(new ArrayList>()); + + @Override + public void report(Diagnostic diagnostic) { + diagnostic.getClass(); + diagnostics.add(diagnostic); + } + + public void clearDiagnostics() { + diagnostics.clear(); + } + + public List> getDiagnostics() { + return Collections.unmodifiableList(diagnostics); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/Expression.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/Expression.java new file mode 100644 index 000000000..be8eae748 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/Expression.java @@ -0,0 +1,60 @@ +package com.itsaky.androidide.language.java.parser; + +import com.sun.tools.javac.tree.JCTree; +import java.util.LinkedList; +import java.util.List; + +import static com.sun.tools.javac.tree.JCTree.JCExpression; + +public class Expression { + /** + * Parent scope of statement, from higher to lower + * parentOfStatement.get(0) will be contains parentOfStatement.get(1) + */ + public final LinkedList parentOfStatement = new LinkedList<>(); + + /** + * Expression at cursor + */ + public JCExpression expression; + + public Expression(JCExpression expression) { + this.expression = expression; + } + + public Expression(JCTree root, JCExpression expression) { + this.expression = expression; + } + + public void addRoot(JCTree tree) { + if (tree != null) { + parentOfStatement.addFirst(tree); + } + } + + public JCTree getRootAt(int level) { + return parentOfStatement.get(level); + } + + public JCExpression getExpression() { + return expression; + } + + public int getParentLevelCount() { + return parentOfStatement.size(); + } + + public LinkedList getParentOfExpression() { + return parentOfStatement; + } + + @Override + public String toString() { + if (expression instanceof JCTree.JCErroneous) { + List errorTrees + = ((JCTree.JCErroneous) expression).getErrorTrees(); + return errorTrees.toString(); + } + return expression.toString(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/ExpressionResolver.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/ExpressionResolver.java new file mode 100644 index 000000000..262ede94f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/ExpressionResolver.java @@ -0,0 +1,411 @@ +package com.itsaky.androidide.language.java.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCLambda; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.List; +import java.util.Map; +import com.sun.tools.javac.tree.EndPosTable; + +public class ExpressionResolver { + private int mCursor; + private EndPosTable mEndPositions; + private JCTree.JCCompilationUnit mAst; + + public ExpressionResolver(@NonNull JCTree.JCCompilationUnit unit, @NonNull CodeEditor editor) { + unit.getClass(); + editor.getClass(); + mAst = unit; + mCursor = editor.getCursor().getLeft(); + mEndPositions = unit.endPositions; + } + + @Nullable + public Expression getExpressionAtCursor() { + for (JCTree jcTree : mAst.getTypeDecls()) { + Expression expression = getExpressionContainsCursor(jcTree); + if (expression != null) { + return expression; + } + } + return null; + } + + @Nullable + private Expression getExpressionContainsCursor(JCTree tree) { + if (!isCursorInsideTree(tree)) { + return null; + } + if (tree instanceof JCClassDecl) { + return getExpressionFromClass((JCClassDecl) tree); + } + return null; + } + + private Expression getExpressionFromStatement(JCTree.JCStatement statement) { + if (!isCursorInsideTree(statement)) { + return null; + } + Expression result; + if (statement instanceof JCBlock) { + JCBlock jcBlock = (JCBlock) statement; + List statements = jcBlock.getStatements(); + return addRootIfNeeded(jcBlock/*root*/, + getExpressionFromStatements(statements)); + + } else if (statement instanceof JCClassDecl) { + return getExpressionFromClass((JCClassDecl) statement); + + } else if (statement instanceof JCDoWhileLoop) { + JCDoWhileLoop jcDoWhileLoop = (JCDoWhileLoop) statement; + JCExpression cond = jcDoWhileLoop.cond; + if (isCursorInsideTree(cond)) { + return resolveExactlyExpression(statement, cond); + } + + JCStatement body = jcDoWhileLoop.getStatement(); + result = getExpressionFromStatement(body); + return addRootIfNeeded(statement, result); + + } else if (statement instanceof JCEnhancedForLoop) { + JCEnhancedForLoop jcEnhancedForLoop = (JCEnhancedForLoop) statement; + JCExpression expression = jcEnhancedForLoop.getExpression(); + if (isCursorInsideTree(expression)) { + return resolveExactlyExpression(jcEnhancedForLoop, expression); + } + + JCVariableDecl variable = jcEnhancedForLoop.getVariable(); + return addRootIfNeeded( + jcEnhancedForLoop/*root*/, + getExpressionFromStatement(variable)); + + } else if (statement instanceof JCExpressionStatement) { + JCExpression expression = ((JCExpressionStatement) statement).getExpression(); + if (isCursorInsideTree(expression)) { + return resolveExactlyExpression(statement, expression); + } + + } else if (statement instanceof JCForLoop) { + JCForLoop jcForLoop = (JCForLoop) statement; + List initializer = jcForLoop.getInitializer(); + result = getExpressionFromStatements(initializer); + if (result != null) { + return addRootIfNeeded(jcForLoop, result); + } + + JCExpression condition = jcForLoop.getCondition(); + if (isCursorInsideTree(condition)) { + return resolveExactlyExpression(jcForLoop, condition); + } + + List update = jcForLoop.getUpdate(); + result = getExpressionFromStatements(update); + if (result != null) { + return addRootIfNeeded(jcForLoop, result); + } + + result = getExpressionFromStatement(jcForLoop.getStatement()); + if (result != null) { + return addRootIfNeeded(jcForLoop, result); + } + } else if (statement instanceof JCIf) { + JCIf jcIf = (JCIf) statement; + JCExpression condition = jcIf.getCondition(); + if (isCursorInsideTree(condition)) { + return resolveExactlyExpression(jcIf, condition); + } + + JCStatement thenStatement = jcIf.getThenStatement(); + result = getExpressionFromStatement(thenStatement); + if (result != null) { + return addRootIfNeeded(jcIf, result); + } + + JCStatement elseStatement = jcIf.getElseStatement(); + if (elseStatement != null) { + result = getExpressionFromStatement(thenStatement); + if (result != null) { + return addRootIfNeeded(jcIf, result); + } + + } + } else if (statement instanceof JCLabeledStatement) { + JCLabeledStatement jcLabeledStatement = (JCLabeledStatement) statement; + return addRootIfNeeded(jcLabeledStatement, + getExpressionFromStatement(jcLabeledStatement.getStatement())); + + } else if (statement instanceof JCReturn) { + JCReturn jcReturn = (JCReturn) statement; + JCExpression expression = jcReturn.getExpression(); + if (isCursorInsideTree(expression)) { + return resolveExactlyExpression(jcReturn, expression); + } + } else if (statement instanceof JCSwitch) { + JCSwitch jcSwitch = (JCSwitch) statement; + JCExpression jcExpression = jcSwitch.getExpression(); + if (isCursorInsideTree(jcExpression)) { + return resolveExactlyExpression(jcSwitch, jcExpression); + } + + List jcCases = jcSwitch.getCases(); + for (JCCase jcCase : jcCases) { + JCExpression jcCaseExpression = jcCase.getExpression(); + if (isCursorInsideTree(jcCaseExpression)) { + return resolveExactlyExpression(jcCase, jcCaseExpression); + } + List statements = jcCase.getStatements(); + result = getExpressionFromStatements(statements); + if (result != null) { + return result; + } + } + } else if (statement instanceof JCSynchronized) { + JCSynchronized jcSynchronized = (JCSynchronized) statement; + JCExpression jcExpression = jcSynchronized.getExpression(); + if (isCursorInsideTree(jcExpression)) { + return resolveExactlyExpression(jcSynchronized, jcExpression); + } + + JCBlock block = jcSynchronized.getBlock(); + return addRootIfNeeded( + jcSynchronized/*root*/, + getExpressionFromStatement(block)); + + } else if (statement instanceof JCThrow) { + JCThrow jcThrow = (JCThrow) statement; + if (isCursorInsideTree(jcThrow.getExpression())) { + return resolveExactlyExpression(jcThrow, jcThrow.getExpression()); + } + + } else if (statement instanceof JCTry) { + JCTry jcTry = (JCTry) statement; + JCBlock block = jcTry.getBlock(); + result = getExpressionFromStatement(block); + if (result != null) { + return addRootIfNeeded(jcTry, result); + } + + List catches = jcTry.getCatches(); + for (JCCatch aCatch : catches) { + JCVariableDecl parameter = aCatch.getParameter(); + result = getExpressionFromStatement(parameter); + if (result == null) { + block = aCatch.getBlock(); + result = getExpressionFromStatement(block); + } + if (result != null) { + result.addRoot(aCatch); + result.addRoot(jcTry); + return result; + } + } + + block = jcTry.getFinallyBlock(); + result = getExpressionFromStatement(block); + return addRootIfNeeded(jcTry, result); + + } else if (statement instanceof JCVariableDecl) { + JCVariableDecl jcVariableDecl = (JCVariableDecl) statement; + JCExpression initializer = jcVariableDecl.getInitializer(); + if (isCursorInsideTree(initializer)) { + return resolveExactlyExpression(jcVariableDecl, initializer); + } + JCExpression vartype = jcVariableDecl.vartype; + if (isCursorInsideTree(vartype)) { + return resolveExactlyExpression(jcVariableDecl, vartype); + } + } else if (statement instanceof JCWhileLoop) { + JCWhileLoop jcWhileLoop = (JCWhileLoop) statement; + JCExpression condition = jcWhileLoop.getCondition(); + if (isCursorInsideTree(condition)) { + return resolveExactlyExpression(jcWhileLoop, condition); + } + + JCStatement body = jcWhileLoop.getStatement(); + return addRootIfNeeded( + jcWhileLoop, + getExpressionFromStatement(body)); + } + + return null; + } + + private Expression resolveExactlyExpression(JCTree parent, JCExpression expression) { + if (expression instanceof JCAssign) { + JCAssign jcAssign = (JCAssign) expression; + JCExpression lhs = jcAssign.getVariable(); + if (isCursorInsideTree(lhs)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcAssign, lhs)); + } + JCExpression rhs = jcAssign.getExpression(); + if (isCursorInsideTree(rhs)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcAssign, rhs)); + } + } else if (expression instanceof JCAssignOp) { + JCAssignOp jcAssign = (JCAssignOp) expression; + JCExpression lhs = jcAssign.getVariable(); + if (isCursorInsideTree(lhs)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcAssign, lhs)); + } + JCExpression rhs = jcAssign.getExpression(); + if (isCursorInsideTree(rhs)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcAssign, rhs)); + } + } else if (expression instanceof JCBinary) { + JCBinary jcBinary = (JCBinary) expression; + JCExpression leftOperand = jcBinary.getLeftOperand(); + if (isCursorInsideTree(leftOperand)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcBinary, leftOperand)); + } + JCExpression rightOperand = jcBinary.getRightOperand(); + if (isCursorInsideTree(rightOperand)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcBinary, rightOperand)); + } + } else if (expression instanceof JCConditional) { + JCConditional jcConditional = (JCConditional) expression; + JCExpression condition = jcConditional.getCondition(); + if (isCursorInsideTree(condition)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcConditional, condition)); + } + + JCExpression trueExpression = jcConditional.getTrueExpression(); + if (isCursorInsideTree(trueExpression)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcConditional, trueExpression)); + } + + JCExpression falseExpression = jcConditional.getFalseExpression(); + if (isCursorInsideTree(falseExpression)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcConditional, falseExpression)); + } + + } else if (expression instanceof JCInstanceOf) { + JCInstanceOf jcInstanceOf = (JCInstanceOf) expression; + JCExpression lhs = jcInstanceOf.getExpression(); + if (isCursorInsideTree(lhs)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcInstanceOf, lhs)); + } + } else if (expression instanceof JCUnary) { + JCUnary jcUnary = (JCUnary) expression; + JCExpression jcExpression = jcUnary.getExpression(); + if (isCursorInsideTree(jcExpression)) { + return addRootIfNeeded( + parent, resolveExactlyExpression(jcUnary, jcExpression)); + } + } + + return new Expression(parent, expression); + } + + @Nullable + private Expression getExpressionFromClass(JCClassDecl tree) { + + if (!isCursorInsideTree(tree)) { + return null; + } + Expression expression = null; + List members = tree.getMembers(); + for (JCTree member : members) { + if (member instanceof JCMethodDecl) { + expression = getExpressionFromMethod((JCMethodDecl) member); + + } else if (member instanceof JCVariableDecl) { + expression = getExpressionFromStatement((JCVariableDecl) member); + + } else if (member instanceof JCClassDecl) { + + expression = getExpressionFromClass((JCClassDecl) member); + } + + if (expression != null) { + return addRootIfNeeded(tree, expression); + } + } + return null; + } + + @Nullable + private Expression getExpressionFromMethod(JCMethodDecl method) { + + Expression expression; + List parameters = method.getParameters(); + + for (JCVariableDecl parameter : parameters) { + expression = getExpressionFromStatement(parameter); + if (expression != null) { + expression.addRoot(method); + return expression; + } + } + + expression = getExpressionFromStatement(method.getBody()); + + return addRootIfNeeded(method, expression); + } + + @Nullable + private Expression getExpressionFromStatements( + @NonNull List statements) { + for (JCStatement statement : statements) { + Expression expression = getExpressionFromStatement(statement); + if (expression != null) { + return expression; + } + } + return null; + } + + private Expression addRootIfNeeded(JCTree root, Expression expression) { + if (expression != null) { + expression.addRoot(root); + return expression; + } + return null; + } + + private boolean isCursorInsideTree(JCTree tree) { + if (tree == null) { + return false; + } + int startPosition = tree.getStartPosition(); + int endPosition = tree.getEndPosition(mEndPositions); + return startPosition <= mCursor && mCursor <= endPosition; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaLexer.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaLexer.java new file mode 100644 index 000000000..c3aba1162 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaLexer.java @@ -0,0 +1,506 @@ +// Generated from JavaLexer.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class JavaLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + ABSTRACT=1, ASSERT=2, BOOLEAN=3, BREAK=4, BYTE=5, CASE=6, CATCH=7, CHAR=8, + CLASS=9, CONST=10, CONTINUE=11, DEFAULT=12, DO=13, DOUBLE=14, ELSE=15, + ENUM=16, EXTENDS=17, FINAL=18, FINALLY=19, FLOAT=20, FOR=21, IF=22, GOTO=23, + IMPLEMENTS=24, IMPORT=25, INSTANCEOF=26, INT=27, INTERFACE=28, LONG=29, + NATIVE=30, NEW=31, PACKAGE=32, PRIVATE=33, PROTECTED=34, PUBLIC=35, RETURN=36, + SHORT=37, STATIC=38, STRICTFP=39, SUPER=40, SWITCH=41, SYNCHRONIZED=42, + THIS=43, THROW=44, THROWS=45, TRANSIENT=46, TRY=47, VOID=48, VOLATILE=49, + WHILE=50, DECIMAL_LITERAL=51, HEX_LITERAL=52, OCT_LITERAL=53, BINARY_LITERAL=54, + FLOAT_LITERAL=55, HEX_FLOAT_LITERAL=56, BOOL_LITERAL=57, CHAR_LITERAL=58, + STRING_LITERAL=59, NULL_LITERAL=60, LPAREN=61, RPAREN=62, LBRACE=63, RBRACE=64, + LBRACK=65, RBRACK=66, SEMI=67, COMMA=68, DOT=69, ASSIGN=70, GT=71, LT=72, + BANG=73, TILDE=74, QUESTION=75, COLON=76, EQUAL=77, LE=78, GE=79, NOTEQUAL=80, + AND=81, OR=82, INC=83, DEC=84, ADD=85, SUB=86, MUL=87, DIV=88, BITAND=89, + BITOR=90, CARET=91, MOD=92, ADD_ASSIGN=93, SUB_ASSIGN=94, MUL_ASSIGN=95, + DIV_ASSIGN=96, AND_ASSIGN=97, OR_ASSIGN=98, XOR_ASSIGN=99, MOD_ASSIGN=100, + LSHIFT_ASSIGN=101, RSHIFT_ASSIGN=102, URSHIFT_ASSIGN=103, ARROW=104, COLONCOLON=105, + AT=106, ELLIPSIS=107, WS=108, COMMENT=109, LINE_COMMENT=110, IDENTIFIER=111; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", "CHAR", + "CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", "ENUM", + "EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "IF", "GOTO", "IMPLEMENTS", + "IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", "NEW", + "PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", "STATIC", + "STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", "THROWS", + "TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE", "DECIMAL_LITERAL", "HEX_LITERAL", + "OCT_LITERAL", "BINARY_LITERAL", "FLOAT_LITERAL", "HEX_FLOAT_LITERAL", + "BOOL_LITERAL", "CHAR_LITERAL", "STRING_LITERAL", "NULL_LITERAL", "LPAREN", + "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", "SEMI", "COMMA", "DOT", + "ASSIGN", "GT", "LT", "BANG", "TILDE", "QUESTION", "COLON", "EQUAL", + "LE", "GE", "NOTEQUAL", "AND", "OR", "INC", "DEC", "ADD", "SUB", "MUL", + "DIV", "BITAND", "BITOR", "CARET", "MOD", "ADD_ASSIGN", "SUB_ASSIGN", + "MUL_ASSIGN", "DIV_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", + "MOD_ASSIGN", "LSHIFT_ASSIGN", "RSHIFT_ASSIGN", "URSHIFT_ASSIGN", "ARROW", + "COLONCOLON", "AT", "ELLIPSIS", "WS", "COMMENT", "LINE_COMMENT", "IDENTIFIER", + "ExponentPart", "EscapeSequence", "HexDigits", "HexDigit", "Digits", + "LetterOrDigit", "Letter" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'abstract'", "'assert'", "'boolean'", "'break'", "'byte'", "'case'", + "'catch'", "'char'", "'class'", "'const'", "'continue'", "'default'", + "'do'", "'double'", "'else'", "'enum'", "'extends'", "'final'", "'finally'", + "'float'", "'for'", "'if'", "'goto'", "'implements'", "'import'", "'instanceof'", + "'int'", "'interface'", "'long'", "'native'", "'new'", "'package'", "'private'", + "'protected'", "'public'", "'return'", "'short'", "'static'", "'strictfp'", + "'super'", "'switch'", "'synchronized'", "'this'", "'throw'", "'throws'", + "'transient'", "'try'", "'void'", "'volatile'", "'while'", null, null, + null, null, null, null, null, null, null, "'null'", "'('", "')'", "'{'", + "'}'", "'['", "']'", "';'", "','", "'.'", "'='", "'>'", "'<'", "'!'", + "'~'", "'?'", "':'", "'=='", "'<='", "'>='", "'!='", "'&&'", "'||'", + "'++'", "'--'", "'+'", "'-'", "'*'", "'/'", "'&'", "'|'", "'^'", "'%'", + "'+='", "'-='", "'*='", "'/='", "'&='", "'|='", "'^='", "'%='", "'<<='", + "'>>='", "'>>>='", "'->'", "'::'", "'@'", "'...'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", + "CHAR", "CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", + "ENUM", "EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "IF", "GOTO", + "IMPLEMENTS", "IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", + "NEW", "PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", + "STATIC", "STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", + "THROWS", "TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE", "DECIMAL_LITERAL", + "HEX_LITERAL", "OCT_LITERAL", "BINARY_LITERAL", "FLOAT_LITERAL", "HEX_FLOAT_LITERAL", + "BOOL_LITERAL", "CHAR_LITERAL", "STRING_LITERAL", "NULL_LITERAL", "LPAREN", + "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", "SEMI", "COMMA", "DOT", + "ASSIGN", "GT", "LT", "BANG", "TILDE", "QUESTION", "COLON", "EQUAL", + "LE", "GE", "NOTEQUAL", "AND", "OR", "INC", "DEC", "ADD", "SUB", "MUL", + "DIV", "BITAND", "BITOR", "CARET", "MOD", "ADD_ASSIGN", "SUB_ASSIGN", + "MUL_ASSIGN", "DIV_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", + "MOD_ASSIGN", "LSHIFT_ASSIGN", "RSHIFT_ASSIGN", "URSHIFT_ASSIGN", "ARROW", + "COLONCOLON", "AT", "ELLIPSIS", "WS", "COMMENT", "LINE_COMMENT", "IDENTIFIER" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public JavaLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "JavaLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2q\u03b3\b\1\4\2\t"+ + "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+ + "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ + "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+ + "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+ + ",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+ + "\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+ + "\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+ + "\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+ + "\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+ + "`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k\t"+ + "k\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\4q\tq\4r\tr\4s\ts\4t\tt\4u\tu\4v\tv\4"+ + "w\tw\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3"+ + "\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6"+ + "\3\6\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3"+ + "\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3"+ + "\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\17"+ + "\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21"+ + "\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23"+ + "\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25"+ + "\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30"+ + "\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32"+ + "\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33"+ + "\3\33\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35"+ + "\3\35\3\36\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3 \3"+ + " \3 \3 \3!\3!\3!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#"+ + "\3#\3#\3#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\3%\3%\3&"+ + "\3&\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3(\3(\3(\3(\3"+ + "(\3)\3)\3)\3)\3)\3)\3*\3*\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3+\3+\3"+ + "+\3+\3+\3+\3,\3,\3,\3,\3,\3-\3-\3-\3-\3-\3-\3.\3.\3.\3.\3.\3.\3.\3/\3"+ + "/\3/\3/\3/\3/\3/\3/\3/\3/\3\60\3\60\3\60\3\60\3\61\3\61\3\61\3\61\3\61"+ + "\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\62\3\63\3\63\3\63\3\63\3\63"+ + "\3\63\3\64\3\64\3\64\5\64\u0246\n\64\3\64\6\64\u0249\n\64\r\64\16\64\u024a"+ + "\3\64\5\64\u024e\n\64\5\64\u0250\n\64\3\64\5\64\u0253\n\64\3\65\3\65\3"+ + "\65\3\65\7\65\u0259\n\65\f\65\16\65\u025c\13\65\3\65\5\65\u025f\n\65\3"+ + "\65\5\65\u0262\n\65\3\66\3\66\7\66\u0266\n\66\f\66\16\66\u0269\13\66\3"+ + "\66\3\66\7\66\u026d\n\66\f\66\16\66\u0270\13\66\3\66\5\66\u0273\n\66\3"+ + "\66\5\66\u0276\n\66\3\67\3\67\3\67\3\67\7\67\u027c\n\67\f\67\16\67\u027f"+ + "\13\67\3\67\5\67\u0282\n\67\3\67\5\67\u0285\n\67\38\38\38\58\u028a\n8"+ + "\38\38\58\u028e\n8\38\58\u0291\n8\38\58\u0294\n8\38\38\38\58\u0299\n8"+ + "\38\58\u029c\n8\58\u029e\n8\39\39\39\39\59\u02a4\n9\39\59\u02a7\n9\39"+ + "\39\59\u02ab\n9\39\39\59\u02af\n9\39\39\59\u02b3\n9\3:\3:\3:\3:\3:\3:"+ + "\3:\3:\3:\5:\u02be\n:\3;\3;\3;\5;\u02c3\n;\3;\3;\3<\3<\3<\7<\u02ca\n<"+ + "\f<\16<\u02cd\13<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3B\3B\3"+ + "C\3C\3D\3D\3E\3E\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K\3K\3L\3L\3M\3M\3N\3"+ + "N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R\3S\3S\3S\3T\3T\3T\3U\3U\3U\3"+ + "V\3V\3W\3W\3X\3X\3Y\3Y\3Z\3Z\3[\3[\3\\\3\\\3]\3]\3^\3^\3^\3_\3_\3_\3`"+ + "\3`\3`\3a\3a\3a\3b\3b\3b\3c\3c\3c\3d\3d\3d\3e\3e\3e\3f\3f\3f\3f\3g\3g"+ + "\3g\3g\3h\3h\3h\3h\3h\3i\3i\3i\3j\3j\3j\3k\3k\3l\3l\3l\3l\3m\6m\u0350"+ + "\nm\rm\16m\u0351\3m\3m\3n\3n\3n\3n\7n\u035a\nn\fn\16n\u035d\13n\3n\3n"+ + "\3n\3n\3n\3o\3o\3o\3o\7o\u0368\no\fo\16o\u036b\13o\3o\3o\3p\3p\7p\u0371"+ + "\np\fp\16p\u0374\13p\3q\3q\5q\u0378\nq\3q\3q\3r\3r\3r\3r\5r\u0380\nr\3"+ + "r\5r\u0383\nr\3r\3r\3r\6r\u0388\nr\rr\16r\u0389\3r\3r\3r\3r\3r\5r\u0391"+ + "\nr\3s\3s\3s\7s\u0396\ns\fs\16s\u0399\13s\3s\5s\u039c\ns\3t\3t\3u\3u\7"+ + "u\u03a2\nu\fu\16u\u03a5\13u\3u\5u\u03a8\nu\3v\3v\5v\u03ac\nv\3w\3w\3w"+ + "\3w\5w\u03b2\nw\3\u035b\2x\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25"+ + "\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32"+ + "\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a"+ + "\62c\63e\64g\65i\66k\67m8o9q:s;u{?}@\177A\u0081B\u0083C\u0085D\u0087"+ + "E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009b"+ + "O\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00af"+ + "Y\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3"+ + "c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3k\u00d5l\u00d7"+ + "m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1\2\u00e3\2\u00e5\2\u00e7\2\u00e9\2"+ + "\u00eb\2\u00ed\2\3\2\34\3\2\63;\4\2NNnn\4\2ZZzz\5\2\62;CHch\6\2\62;CH"+ + "aach\3\2\629\4\2\629aa\4\2DDdd\3\2\62\63\4\2\62\63aa\6\2FFHHffhh\4\2R"+ + "Rrr\4\2--//\6\2\f\f\17\17))^^\6\2\f\f\17\17$$^^\5\2\13\f\16\17\"\"\4\2"+ + "\f\f\17\17\4\2GGgg\n\2$$))^^ddhhppttvv\3\2\62\65\3\2\62;\4\2\62;aa\6\2"+ + "&&C\\aac|\4\2\2\u0081\ud802\udc01\3\2\ud802\udc01\3\2\udc02\ue001\2\u03dc"+ + "\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2"+ + "\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2"+ + "\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2"+ + "\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2"+ + "\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3"+ + "\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2"+ + "\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2"+ + "U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3"+ + "\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2"+ + "\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2"+ + "{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085"+ + "\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2"+ + "\2\2\u008f\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097"+ + "\3\2\2\2\2\u0099\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2"+ + "\2\2\u00a1\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9"+ + "\3\2\2\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2"+ + "\2\2\u00b3\3\2\2\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb"+ + "\3\2\2\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2"+ + "\2\2\u00c5\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd"+ + "\3\2\2\2\2\u00cf\3\2\2\2\2\u00d1\3\2\2\2\2\u00d3\3\2\2\2\2\u00d5\3\2\2"+ + "\2\2\u00d7\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\2\u00df"+ + "\3\2\2\2\3\u00ef\3\2\2\2\5\u00f8\3\2\2\2\7\u00ff\3\2\2\2\t\u0107\3\2\2"+ + "\2\13\u010d\3\2\2\2\r\u0112\3\2\2\2\17\u0117\3\2\2\2\21\u011d\3\2\2\2"+ + "\23\u0122\3\2\2\2\25\u0128\3\2\2\2\27\u012e\3\2\2\2\31\u0137\3\2\2\2\33"+ + "\u013f\3\2\2\2\35\u0142\3\2\2\2\37\u0149\3\2\2\2!\u014e\3\2\2\2#\u0153"+ + "\3\2\2\2%\u015b\3\2\2\2\'\u0161\3\2\2\2)\u0169\3\2\2\2+\u016f\3\2\2\2"+ + "-\u0173\3\2\2\2/\u0176\3\2\2\2\61\u017b\3\2\2\2\63\u0186\3\2\2\2\65\u018d"+ + "\3\2\2\2\67\u0198\3\2\2\29\u019c\3\2\2\2;\u01a6\3\2\2\2=\u01ab\3\2\2\2"+ + "?\u01b2\3\2\2\2A\u01b6\3\2\2\2C\u01be\3\2\2\2E\u01c6\3\2\2\2G\u01d0\3"+ + "\2\2\2I\u01d7\3\2\2\2K\u01de\3\2\2\2M\u01e4\3\2\2\2O\u01eb\3\2\2\2Q\u01f4"+ + "\3\2\2\2S\u01fa\3\2\2\2U\u0201\3\2\2\2W\u020e\3\2\2\2Y\u0213\3\2\2\2["+ + "\u0219\3\2\2\2]\u0220\3\2\2\2_\u022a\3\2\2\2a\u022e\3\2\2\2c\u0233\3\2"+ + "\2\2e\u023c\3\2\2\2g\u024f\3\2\2\2i\u0254\3\2\2\2k\u0263\3\2\2\2m\u0277"+ + "\3\2\2\2o\u029d\3\2\2\2q\u029f\3\2\2\2s\u02bd\3\2\2\2u\u02bf\3\2\2\2w"+ + "\u02c6\3\2\2\2y\u02d0\3\2\2\2{\u02d5\3\2\2\2}\u02d7\3\2\2\2\177\u02d9"+ + "\3\2\2\2\u0081\u02db\3\2\2\2\u0083\u02dd\3\2\2\2\u0085\u02df\3\2\2\2\u0087"+ + "\u02e1\3\2\2\2\u0089\u02e3\3\2\2\2\u008b\u02e5\3\2\2\2\u008d\u02e7\3\2"+ + "\2\2\u008f\u02e9\3\2\2\2\u0091\u02eb\3\2\2\2\u0093\u02ed\3\2\2\2\u0095"+ + "\u02ef\3\2\2\2\u0097\u02f1\3\2\2\2\u0099\u02f3\3\2\2\2\u009b\u02f5\3\2"+ + "\2\2\u009d\u02f8\3\2\2\2\u009f\u02fb\3\2\2\2\u00a1\u02fe\3\2\2\2\u00a3"+ + "\u0301\3\2\2\2\u00a5\u0304\3\2\2\2\u00a7\u0307\3\2\2\2\u00a9\u030a\3\2"+ + "\2\2\u00ab\u030d\3\2\2\2\u00ad\u030f\3\2\2\2\u00af\u0311\3\2\2\2\u00b1"+ + "\u0313\3\2\2\2\u00b3\u0315\3\2\2\2\u00b5\u0317\3\2\2\2\u00b7\u0319\3\2"+ + "\2\2\u00b9\u031b\3\2\2\2\u00bb\u031d\3\2\2\2\u00bd\u0320\3\2\2\2\u00bf"+ + "\u0323\3\2\2\2\u00c1\u0326\3\2\2\2\u00c3\u0329\3\2\2\2\u00c5\u032c\3\2"+ + "\2\2\u00c7\u032f\3\2\2\2\u00c9\u0332\3\2\2\2\u00cb\u0335\3\2\2\2\u00cd"+ + "\u0339\3\2\2\2\u00cf\u033d\3\2\2\2\u00d1\u0342\3\2\2\2\u00d3\u0345\3\2"+ + "\2\2\u00d5\u0348\3\2\2\2\u00d7\u034a\3\2\2\2\u00d9\u034f\3\2\2\2\u00db"+ + "\u0355\3\2\2\2\u00dd\u0363\3\2\2\2\u00df\u036e\3\2\2\2\u00e1\u0375\3\2"+ + "\2\2\u00e3\u0390\3\2\2\2\u00e5\u0392\3\2\2\2\u00e7\u039d\3\2\2\2\u00e9"+ + "\u039f\3\2\2\2\u00eb\u03ab\3\2\2\2\u00ed\u03b1\3\2\2\2\u00ef\u00f0\7c"+ + "\2\2\u00f0\u00f1\7d\2\2\u00f1\u00f2\7u\2\2\u00f2\u00f3\7v\2\2\u00f3\u00f4"+ + "\7t\2\2\u00f4\u00f5\7c\2\2\u00f5\u00f6\7e\2\2\u00f6\u00f7\7v\2\2\u00f7"+ + "\4\3\2\2\2\u00f8\u00f9\7c\2\2\u00f9\u00fa\7u\2\2\u00fa\u00fb\7u\2\2\u00fb"+ + "\u00fc\7g\2\2\u00fc\u00fd\7t\2\2\u00fd\u00fe\7v\2\2\u00fe\6\3\2\2\2\u00ff"+ + "\u0100\7d\2\2\u0100\u0101\7q\2\2\u0101\u0102\7q\2\2\u0102\u0103\7n\2\2"+ + "\u0103\u0104\7g\2\2\u0104\u0105\7c\2\2\u0105\u0106\7p\2\2\u0106\b\3\2"+ + "\2\2\u0107\u0108\7d\2\2\u0108\u0109\7t\2\2\u0109\u010a\7g\2\2\u010a\u010b"+ + "\7c\2\2\u010b\u010c\7m\2\2\u010c\n\3\2\2\2\u010d\u010e\7d\2\2\u010e\u010f"+ + "\7{\2\2\u010f\u0110\7v\2\2\u0110\u0111\7g\2\2\u0111\f\3\2\2\2\u0112\u0113"+ + "\7e\2\2\u0113\u0114\7c\2\2\u0114\u0115\7u\2\2\u0115\u0116\7g\2\2\u0116"+ + "\16\3\2\2\2\u0117\u0118\7e\2\2\u0118\u0119\7c\2\2\u0119\u011a\7v\2\2\u011a"+ + "\u011b\7e\2\2\u011b\u011c\7j\2\2\u011c\20\3\2\2\2\u011d\u011e\7e\2\2\u011e"+ + "\u011f\7j\2\2\u011f\u0120\7c\2\2\u0120\u0121\7t\2\2\u0121\22\3\2\2\2\u0122"+ + "\u0123\7e\2\2\u0123\u0124\7n\2\2\u0124\u0125\7c\2\2\u0125\u0126\7u\2\2"+ + "\u0126\u0127\7u\2\2\u0127\24\3\2\2\2\u0128\u0129\7e\2\2\u0129\u012a\7"+ + "q\2\2\u012a\u012b\7p\2\2\u012b\u012c\7u\2\2\u012c\u012d\7v\2\2\u012d\26"+ + "\3\2\2\2\u012e\u012f\7e\2\2\u012f\u0130\7q\2\2\u0130\u0131\7p\2\2\u0131"+ + "\u0132\7v\2\2\u0132\u0133\7k\2\2\u0133\u0134\7p\2\2\u0134\u0135\7w\2\2"+ + "\u0135\u0136\7g\2\2\u0136\30\3\2\2\2\u0137\u0138\7f\2\2\u0138\u0139\7"+ + "g\2\2\u0139\u013a\7h\2\2\u013a\u013b\7c\2\2\u013b\u013c\7w\2\2\u013c\u013d"+ + "\7n\2\2\u013d\u013e\7v\2\2\u013e\32\3\2\2\2\u013f\u0140\7f\2\2\u0140\u0141"+ + "\7q\2\2\u0141\34\3\2\2\2\u0142\u0143\7f\2\2\u0143\u0144\7q\2\2\u0144\u0145"+ + "\7w\2\2\u0145\u0146\7d\2\2\u0146\u0147\7n\2\2\u0147\u0148\7g\2\2\u0148"+ + "\36\3\2\2\2\u0149\u014a\7g\2\2\u014a\u014b\7n\2\2\u014b\u014c\7u\2\2\u014c"+ + "\u014d\7g\2\2\u014d \3\2\2\2\u014e\u014f\7g\2\2\u014f\u0150\7p\2\2\u0150"+ + "\u0151\7w\2\2\u0151\u0152\7o\2\2\u0152\"\3\2\2\2\u0153\u0154\7g\2\2\u0154"+ + "\u0155\7z\2\2\u0155\u0156\7v\2\2\u0156\u0157\7g\2\2\u0157\u0158\7p\2\2"+ + "\u0158\u0159\7f\2\2\u0159\u015a\7u\2\2\u015a$\3\2\2\2\u015b\u015c\7h\2"+ + "\2\u015c\u015d\7k\2\2\u015d\u015e\7p\2\2\u015e\u015f\7c\2\2\u015f\u0160"+ + "\7n\2\2\u0160&\3\2\2\2\u0161\u0162\7h\2\2\u0162\u0163\7k\2\2\u0163\u0164"+ + "\7p\2\2\u0164\u0165\7c\2\2\u0165\u0166\7n\2\2\u0166\u0167\7n\2\2\u0167"+ + "\u0168\7{\2\2\u0168(\3\2\2\2\u0169\u016a\7h\2\2\u016a\u016b\7n\2\2\u016b"+ + "\u016c\7q\2\2\u016c\u016d\7c\2\2\u016d\u016e\7v\2\2\u016e*\3\2\2\2\u016f"+ + "\u0170\7h\2\2\u0170\u0171\7q\2\2\u0171\u0172\7t\2\2\u0172,\3\2\2\2\u0173"+ + "\u0174\7k\2\2\u0174\u0175\7h\2\2\u0175.\3\2\2\2\u0176\u0177\7i\2\2\u0177"+ + "\u0178\7q\2\2\u0178\u0179\7v\2\2\u0179\u017a\7q\2\2\u017a\60\3\2\2\2\u017b"+ + "\u017c\7k\2\2\u017c\u017d\7o\2\2\u017d\u017e\7r\2\2\u017e\u017f\7n\2\2"+ + "\u017f\u0180\7g\2\2\u0180\u0181\7o\2\2\u0181\u0182\7g\2\2\u0182\u0183"+ + "\7p\2\2\u0183\u0184\7v\2\2\u0184\u0185\7u\2\2\u0185\62\3\2\2\2\u0186\u0187"+ + "\7k\2\2\u0187\u0188\7o\2\2\u0188\u0189\7r\2\2\u0189\u018a\7q\2\2\u018a"+ + "\u018b\7t\2\2\u018b\u018c\7v\2\2\u018c\64\3\2\2\2\u018d\u018e\7k\2\2\u018e"+ + "\u018f\7p\2\2\u018f\u0190\7u\2\2\u0190\u0191\7v\2\2\u0191\u0192\7c\2\2"+ + "\u0192\u0193\7p\2\2\u0193\u0194\7e\2\2\u0194\u0195\7g\2\2\u0195\u0196"+ + "\7q\2\2\u0196\u0197\7h\2\2\u0197\66\3\2\2\2\u0198\u0199\7k\2\2\u0199\u019a"+ + "\7p\2\2\u019a\u019b\7v\2\2\u019b8\3\2\2\2\u019c\u019d\7k\2\2\u019d\u019e"+ + "\7p\2\2\u019e\u019f\7v\2\2\u019f\u01a0\7g\2\2\u01a0\u01a1\7t\2\2\u01a1"+ + "\u01a2\7h\2\2\u01a2\u01a3\7c\2\2\u01a3\u01a4\7e\2\2\u01a4\u01a5\7g\2\2"+ + "\u01a5:\3\2\2\2\u01a6\u01a7\7n\2\2\u01a7\u01a8\7q\2\2\u01a8\u01a9\7p\2"+ + "\2\u01a9\u01aa\7i\2\2\u01aa<\3\2\2\2\u01ab\u01ac\7p\2\2\u01ac\u01ad\7"+ + "c\2\2\u01ad\u01ae\7v\2\2\u01ae\u01af\7k\2\2\u01af\u01b0\7x\2\2\u01b0\u01b1"+ + "\7g\2\2\u01b1>\3\2\2\2\u01b2\u01b3\7p\2\2\u01b3\u01b4\7g\2\2\u01b4\u01b5"+ + "\7y\2\2\u01b5@\3\2\2\2\u01b6\u01b7\7r\2\2\u01b7\u01b8\7c\2\2\u01b8\u01b9"+ + "\7e\2\2\u01b9\u01ba\7m\2\2\u01ba\u01bb\7c\2\2\u01bb\u01bc\7i\2\2\u01bc"+ + "\u01bd\7g\2\2\u01bdB\3\2\2\2\u01be\u01bf\7r\2\2\u01bf\u01c0\7t\2\2\u01c0"+ + "\u01c1\7k\2\2\u01c1\u01c2\7x\2\2\u01c2\u01c3\7c\2\2\u01c3\u01c4\7v\2\2"+ + "\u01c4\u01c5\7g\2\2\u01c5D\3\2\2\2\u01c6\u01c7\7r\2\2\u01c7\u01c8\7t\2"+ + "\2\u01c8\u01c9\7q\2\2\u01c9\u01ca\7v\2\2\u01ca\u01cb\7g\2\2\u01cb\u01cc"+ + "\7e\2\2\u01cc\u01cd\7v\2\2\u01cd\u01ce\7g\2\2\u01ce\u01cf\7f\2\2\u01cf"+ + "F\3\2\2\2\u01d0\u01d1\7r\2\2\u01d1\u01d2\7w\2\2\u01d2\u01d3\7d\2\2\u01d3"+ + "\u01d4\7n\2\2\u01d4\u01d5\7k\2\2\u01d5\u01d6\7e\2\2\u01d6H\3\2\2\2\u01d7"+ + "\u01d8\7t\2\2\u01d8\u01d9\7g\2\2\u01d9\u01da\7v\2\2\u01da\u01db\7w\2\2"+ + "\u01db\u01dc\7t\2\2\u01dc\u01dd\7p\2\2\u01ddJ\3\2\2\2\u01de\u01df\7u\2"+ + "\2\u01df\u01e0\7j\2\2\u01e0\u01e1\7q\2\2\u01e1\u01e2\7t\2\2\u01e2\u01e3"+ + "\7v\2\2\u01e3L\3\2\2\2\u01e4\u01e5\7u\2\2\u01e5\u01e6\7v\2\2\u01e6\u01e7"+ + "\7c\2\2\u01e7\u01e8\7v\2\2\u01e8\u01e9\7k\2\2\u01e9\u01ea\7e\2\2\u01ea"+ + "N\3\2\2\2\u01eb\u01ec\7u\2\2\u01ec\u01ed\7v\2\2\u01ed\u01ee\7t\2\2\u01ee"+ + "\u01ef\7k\2\2\u01ef\u01f0\7e\2\2\u01f0\u01f1\7v\2\2\u01f1\u01f2\7h\2\2"+ + "\u01f2\u01f3\7r\2\2\u01f3P\3\2\2\2\u01f4\u01f5\7u\2\2\u01f5\u01f6\7w\2"+ + "\2\u01f6\u01f7\7r\2\2\u01f7\u01f8\7g\2\2\u01f8\u01f9\7t\2\2\u01f9R\3\2"+ + "\2\2\u01fa\u01fb\7u\2\2\u01fb\u01fc\7y\2\2\u01fc\u01fd\7k\2\2\u01fd\u01fe"+ + "\7v\2\2\u01fe\u01ff\7e\2\2\u01ff\u0200\7j\2\2\u0200T\3\2\2\2\u0201\u0202"+ + "\7u\2\2\u0202\u0203\7{\2\2\u0203\u0204\7p\2\2\u0204\u0205\7e\2\2\u0205"+ + "\u0206\7j\2\2\u0206\u0207\7t\2\2\u0207\u0208\7q\2\2\u0208\u0209\7p\2\2"+ + "\u0209\u020a\7k\2\2\u020a\u020b\7|\2\2\u020b\u020c\7g\2\2\u020c\u020d"+ + "\7f\2\2\u020dV\3\2\2\2\u020e\u020f\7v\2\2\u020f\u0210\7j\2\2\u0210\u0211"+ + "\7k\2\2\u0211\u0212\7u\2\2\u0212X\3\2\2\2\u0213\u0214\7v\2\2\u0214\u0215"+ + "\7j\2\2\u0215\u0216\7t\2\2\u0216\u0217\7q\2\2\u0217\u0218\7y\2\2\u0218"+ + "Z\3\2\2\2\u0219\u021a\7v\2\2\u021a\u021b\7j\2\2\u021b\u021c\7t\2\2\u021c"+ + "\u021d\7q\2\2\u021d\u021e\7y\2\2\u021e\u021f\7u\2\2\u021f\\\3\2\2\2\u0220"+ + "\u0221\7v\2\2\u0221\u0222\7t\2\2\u0222\u0223\7c\2\2\u0223\u0224\7p\2\2"+ + "\u0224\u0225\7u\2\2\u0225\u0226\7k\2\2\u0226\u0227\7g\2\2\u0227\u0228"+ + "\7p\2\2\u0228\u0229\7v\2\2\u0229^\3\2\2\2\u022a\u022b\7v\2\2\u022b\u022c"+ + "\7t\2\2\u022c\u022d\7{\2\2\u022d`\3\2\2\2\u022e\u022f\7x\2\2\u022f\u0230"+ + "\7q\2\2\u0230\u0231\7k\2\2\u0231\u0232\7f\2\2\u0232b\3\2\2\2\u0233\u0234"+ + "\7x\2\2\u0234\u0235\7q\2\2\u0235\u0236\7n\2\2\u0236\u0237\7c\2\2\u0237"+ + "\u0238\7v\2\2\u0238\u0239\7k\2\2\u0239\u023a\7n\2\2\u023a\u023b\7g\2\2"+ + "\u023bd\3\2\2\2\u023c\u023d\7y\2\2\u023d\u023e\7j\2\2\u023e\u023f\7k\2"+ + "\2\u023f\u0240\7n\2\2\u0240\u0241\7g\2\2\u0241f\3\2\2\2\u0242\u0250\7"+ + "\62\2\2\u0243\u024d\t\2\2\2\u0244\u0246\5\u00e9u\2\u0245\u0244\3\2\2\2"+ + "\u0245\u0246\3\2\2\2\u0246\u024e\3\2\2\2\u0247\u0249\7a\2\2\u0248\u0247"+ + "\3\2\2\2\u0249\u024a\3\2\2\2\u024a\u0248\3\2\2\2\u024a\u024b\3\2\2\2\u024b"+ + "\u024c\3\2\2\2\u024c\u024e\5\u00e9u\2\u024d\u0245\3\2\2\2\u024d\u0248"+ + "\3\2\2\2\u024e\u0250\3\2\2\2\u024f\u0242\3\2\2\2\u024f\u0243\3\2\2\2\u0250"+ + "\u0252\3\2\2\2\u0251\u0253\t\3\2\2\u0252\u0251\3\2\2\2\u0252\u0253\3\2"+ + "\2\2\u0253h\3\2\2\2\u0254\u0255\7\62\2\2\u0255\u0256\t\4\2\2\u0256\u025e"+ + "\t\5\2\2\u0257\u0259\t\6\2\2\u0258\u0257\3\2\2\2\u0259\u025c\3\2\2\2\u025a"+ + "\u0258\3\2\2\2\u025a\u025b\3\2\2\2\u025b\u025d\3\2\2\2\u025c\u025a\3\2"+ + "\2\2\u025d\u025f\t\5\2\2\u025e\u025a\3\2\2\2\u025e\u025f\3\2\2\2\u025f"+ + "\u0261\3\2\2\2\u0260\u0262\t\3\2\2\u0261\u0260\3\2\2\2\u0261\u0262\3\2"+ + "\2\2\u0262j\3\2\2\2\u0263\u0267\7\62\2\2\u0264\u0266\7a\2\2\u0265\u0264"+ + "\3\2\2\2\u0266\u0269\3\2\2\2\u0267\u0265\3\2\2\2\u0267\u0268\3\2\2\2\u0268"+ + "\u026a\3\2\2\2\u0269\u0267\3\2\2\2\u026a\u0272\t\7\2\2\u026b\u026d\t\b"+ + "\2\2\u026c\u026b\3\2\2\2\u026d\u0270\3\2\2\2\u026e\u026c\3\2\2\2\u026e"+ + "\u026f\3\2\2\2\u026f\u0271\3\2\2\2\u0270\u026e\3\2\2\2\u0271\u0273\t\7"+ + "\2\2\u0272\u026e\3\2\2\2\u0272\u0273\3\2\2\2\u0273\u0275\3\2\2\2\u0274"+ + "\u0276\t\3\2\2\u0275\u0274\3\2\2\2\u0275\u0276\3\2\2\2\u0276l\3\2\2\2"+ + "\u0277\u0278\7\62\2\2\u0278\u0279\t\t\2\2\u0279\u0281\t\n\2\2\u027a\u027c"+ + "\t\13\2\2\u027b\u027a\3\2\2\2\u027c\u027f\3\2\2\2\u027d\u027b\3\2\2\2"+ + "\u027d\u027e\3\2\2\2\u027e\u0280\3\2\2\2\u027f\u027d\3\2\2\2\u0280\u0282"+ + "\t\n\2\2\u0281\u027d\3\2\2\2\u0281\u0282\3\2\2\2\u0282\u0284\3\2\2\2\u0283"+ + "\u0285\t\3\2\2\u0284\u0283\3\2\2\2\u0284\u0285\3\2\2\2\u0285n\3\2\2\2"+ + "\u0286\u0287\5\u00e9u\2\u0287\u0289\7\60\2\2\u0288\u028a\5\u00e9u\2\u0289"+ + "\u0288\3\2\2\2\u0289\u028a\3\2\2\2\u028a\u028e\3\2\2\2\u028b\u028c\7\60"+ + "\2\2\u028c\u028e\5\u00e9u\2\u028d\u0286\3\2\2\2\u028d\u028b\3\2\2\2\u028e"+ + "\u0290\3\2\2\2\u028f\u0291\5\u00e1q\2\u0290\u028f\3\2\2\2\u0290\u0291"+ + "\3\2\2\2\u0291\u0293\3\2\2\2\u0292\u0294\t\f\2\2\u0293\u0292\3\2\2\2\u0293"+ + "\u0294\3\2\2\2\u0294\u029e\3\2\2\2\u0295\u029b\5\u00e9u\2\u0296\u0298"+ + "\5\u00e1q\2\u0297\u0299\t\f\2\2\u0298\u0297\3\2\2\2\u0298\u0299\3\2\2"+ + "\2\u0299\u029c\3\2\2\2\u029a\u029c\t\f\2\2\u029b\u0296\3\2\2\2\u029b\u029a"+ + "\3\2\2\2\u029c\u029e\3\2\2\2\u029d\u028d\3\2\2\2\u029d\u0295\3\2\2\2\u029e"+ + "p\3\2\2\2\u029f\u02a0\7\62\2\2\u02a0\u02aa\t\4\2\2\u02a1\u02a3\5\u00e5"+ + "s\2\u02a2\u02a4\7\60\2\2\u02a3\u02a2\3\2\2\2\u02a3\u02a4\3\2\2\2\u02a4"+ + "\u02ab\3\2\2\2\u02a5\u02a7\5\u00e5s\2\u02a6\u02a5\3\2\2\2\u02a6\u02a7"+ + "\3\2\2\2\u02a7\u02a8\3\2\2\2\u02a8\u02a9\7\60\2\2\u02a9\u02ab\5\u00e5"+ + "s\2\u02aa\u02a1\3\2\2\2\u02aa\u02a6\3\2\2\2\u02ab\u02ac\3\2\2\2\u02ac"+ + "\u02ae\t\r\2\2\u02ad\u02af\t\16\2\2\u02ae\u02ad\3\2\2\2\u02ae\u02af\3"+ + "\2\2\2\u02af\u02b0\3\2\2\2\u02b0\u02b2\5\u00e9u\2\u02b1\u02b3\t\f\2\2"+ + "\u02b2\u02b1\3\2\2\2\u02b2\u02b3\3\2\2\2\u02b3r\3\2\2\2\u02b4\u02b5\7"+ + "v\2\2\u02b5\u02b6\7t\2\2\u02b6\u02b7\7w\2\2\u02b7\u02be\7g\2\2\u02b8\u02b9"+ + "\7h\2\2\u02b9\u02ba\7c\2\2\u02ba\u02bb\7n\2\2\u02bb\u02bc\7u\2\2\u02bc"+ + "\u02be\7g\2\2\u02bd\u02b4\3\2\2\2\u02bd\u02b8\3\2\2\2\u02bet\3\2\2\2\u02bf"+ + "\u02c2\7)\2\2\u02c0\u02c3\n\17\2\2\u02c1\u02c3\5\u00e3r\2\u02c2\u02c0"+ + "\3\2\2\2\u02c2\u02c1\3\2\2\2\u02c3\u02c4\3\2\2\2\u02c4\u02c5\7)\2\2\u02c5"+ + "v\3\2\2\2\u02c6\u02cb\7$\2\2\u02c7\u02ca\n\20\2\2\u02c8\u02ca\5\u00e3"+ + "r\2\u02c9\u02c7\3\2\2\2\u02c9\u02c8\3\2\2\2\u02ca\u02cd\3\2\2\2\u02cb"+ + "\u02c9\3\2\2\2\u02cb\u02cc\3\2\2\2\u02cc\u02ce\3\2\2\2\u02cd\u02cb\3\2"+ + "\2\2\u02ce\u02cf\7$\2\2\u02cfx\3\2\2\2\u02d0\u02d1\7p\2\2\u02d1\u02d2"+ + "\7w\2\2\u02d2\u02d3\7n\2\2\u02d3\u02d4\7n\2\2\u02d4z\3\2\2\2\u02d5\u02d6"+ + "\7*\2\2\u02d6|\3\2\2\2\u02d7\u02d8\7+\2\2\u02d8~\3\2\2\2\u02d9\u02da\7"+ + "}\2\2\u02da\u0080\3\2\2\2\u02db\u02dc\7\177\2\2\u02dc\u0082\3\2\2\2\u02dd"+ + "\u02de\7]\2\2\u02de\u0084\3\2\2\2\u02df\u02e0\7_\2\2\u02e0\u0086\3\2\2"+ + "\2\u02e1\u02e2\7=\2\2\u02e2\u0088\3\2\2\2\u02e3\u02e4\7.\2\2\u02e4\u008a"+ + "\3\2\2\2\u02e5\u02e6\7\60\2\2\u02e6\u008c\3\2\2\2\u02e7\u02e8\7?\2\2\u02e8"+ + "\u008e\3\2\2\2\u02e9\u02ea\7@\2\2\u02ea\u0090\3\2\2\2\u02eb\u02ec\7>\2"+ + "\2\u02ec\u0092\3\2\2\2\u02ed\u02ee\7#\2\2\u02ee\u0094\3\2\2\2\u02ef\u02f0"+ + "\7\u0080\2\2\u02f0\u0096\3\2\2\2\u02f1\u02f2\7A\2\2\u02f2\u0098\3\2\2"+ + "\2\u02f3\u02f4\7<\2\2\u02f4\u009a\3\2\2\2\u02f5\u02f6\7?\2\2\u02f6\u02f7"+ + "\7?\2\2\u02f7\u009c\3\2\2\2\u02f8\u02f9\7>\2\2\u02f9\u02fa\7?\2\2\u02fa"+ + "\u009e\3\2\2\2\u02fb\u02fc\7@\2\2\u02fc\u02fd\7?\2\2\u02fd\u00a0\3\2\2"+ + "\2\u02fe\u02ff\7#\2\2\u02ff\u0300\7?\2\2\u0300\u00a2\3\2\2\2\u0301\u0302"+ + "\7(\2\2\u0302\u0303\7(\2\2\u0303\u00a4\3\2\2\2\u0304\u0305\7~\2\2\u0305"+ + "\u0306\7~\2\2\u0306\u00a6\3\2\2\2\u0307\u0308\7-\2\2\u0308\u0309\7-\2"+ + "\2\u0309\u00a8\3\2\2\2\u030a\u030b\7/\2\2\u030b\u030c\7/\2\2\u030c\u00aa"+ + "\3\2\2\2\u030d\u030e\7-\2\2\u030e\u00ac\3\2\2\2\u030f\u0310\7/\2\2\u0310"+ + "\u00ae\3\2\2\2\u0311\u0312\7,\2\2\u0312\u00b0\3\2\2\2\u0313\u0314\7\61"+ + "\2\2\u0314\u00b2\3\2\2\2\u0315\u0316\7(\2\2\u0316\u00b4\3\2\2\2\u0317"+ + "\u0318\7~\2\2\u0318\u00b6\3\2\2\2\u0319\u031a\7`\2\2\u031a\u00b8\3\2\2"+ + "\2\u031b\u031c\7\'\2\2\u031c\u00ba\3\2\2\2\u031d\u031e\7-\2\2\u031e\u031f"+ + "\7?\2\2\u031f\u00bc\3\2\2\2\u0320\u0321\7/\2\2\u0321\u0322\7?\2\2\u0322"+ + "\u00be\3\2\2\2\u0323\u0324\7,\2\2\u0324\u0325\7?\2\2\u0325\u00c0\3\2\2"+ + "\2\u0326\u0327\7\61\2\2\u0327\u0328\7?\2\2\u0328\u00c2\3\2\2\2\u0329\u032a"+ + "\7(\2\2\u032a\u032b\7?\2\2\u032b\u00c4\3\2\2\2\u032c\u032d\7~\2\2\u032d"+ + "\u032e\7?\2\2\u032e\u00c6\3\2\2\2\u032f\u0330\7`\2\2\u0330\u0331\7?\2"+ + "\2\u0331\u00c8\3\2\2\2\u0332\u0333\7\'\2\2\u0333\u0334\7?\2\2\u0334\u00ca"+ + "\3\2\2\2\u0335\u0336\7>\2\2\u0336\u0337\7>\2\2\u0337\u0338\7?\2\2\u0338"+ + "\u00cc\3\2\2\2\u0339\u033a\7@\2\2\u033a\u033b\7@\2\2\u033b\u033c\7?\2"+ + "\2\u033c\u00ce\3\2\2\2\u033d\u033e\7@\2\2\u033e\u033f\7@\2\2\u033f\u0340"+ + "\7@\2\2\u0340\u0341\7?\2\2\u0341\u00d0\3\2\2\2\u0342\u0343\7/\2\2\u0343"+ + "\u0344\7@\2\2\u0344\u00d2\3\2\2\2\u0345\u0346\7<\2\2\u0346\u0347\7<\2"+ + "\2\u0347\u00d4\3\2\2\2\u0348\u0349\7B\2\2\u0349\u00d6\3\2\2\2\u034a\u034b"+ + "\7\60\2\2\u034b\u034c\7\60\2\2\u034c\u034d\7\60\2\2\u034d\u00d8\3\2\2"+ + "\2\u034e\u0350\t\21\2\2\u034f\u034e\3\2\2\2\u0350\u0351\3\2\2\2\u0351"+ + "\u034f\3\2\2\2\u0351\u0352\3\2\2\2\u0352\u0353\3\2\2\2\u0353\u0354\bm"+ + "\2\2\u0354\u00da\3\2\2\2\u0355\u0356\7\61\2\2\u0356\u0357\7,\2\2\u0357"+ + "\u035b\3\2\2\2\u0358\u035a\13\2\2\2\u0359\u0358\3\2\2\2\u035a\u035d\3"+ + "\2\2\2\u035b\u035c\3\2\2\2\u035b\u0359\3\2\2\2\u035c\u035e\3\2\2\2\u035d"+ + "\u035b\3\2\2\2\u035e\u035f\7,\2\2\u035f\u0360\7\61\2\2\u0360\u0361\3\2"+ + "\2\2\u0361\u0362\bn\2\2\u0362\u00dc\3\2\2\2\u0363\u0364\7\61\2\2\u0364"+ + "\u0365\7\61\2\2\u0365\u0369\3\2\2\2\u0366\u0368\n\22\2\2\u0367\u0366\3"+ + "\2\2\2\u0368\u036b\3\2\2\2\u0369\u0367\3\2\2\2\u0369\u036a\3\2\2\2\u036a"+ + "\u036c\3\2\2\2\u036b\u0369\3\2\2\2\u036c\u036d\bo\2\2\u036d\u00de\3\2"+ + "\2\2\u036e\u0372\5\u00edw\2\u036f\u0371\5\u00ebv\2\u0370\u036f\3\2\2\2"+ + "\u0371\u0374\3\2\2\2\u0372\u0370\3\2\2\2\u0372\u0373\3\2\2\2\u0373\u00e0"+ + "\3\2\2\2\u0374\u0372\3\2\2\2\u0375\u0377\t\23\2\2\u0376\u0378\t\16\2\2"+ + "\u0377\u0376\3\2\2\2\u0377\u0378\3\2\2\2\u0378\u0379\3\2\2\2\u0379\u037a"+ + "\5\u00e9u\2\u037a\u00e2\3\2\2\2\u037b\u037c\7^\2\2\u037c\u0391\t\24\2"+ + "\2\u037d\u0382\7^\2\2\u037e\u0380\t\25\2\2\u037f\u037e\3\2\2\2\u037f\u0380"+ + "\3\2\2\2\u0380\u0381\3\2\2\2\u0381\u0383\t\7\2\2\u0382\u037f\3\2\2\2\u0382"+ + "\u0383\3\2\2\2\u0383\u0384\3\2\2\2\u0384\u0391\t\7\2\2\u0385\u0387\7^"+ + "\2\2\u0386\u0388\7w\2\2\u0387\u0386\3\2\2\2\u0388\u0389\3\2\2\2\u0389"+ + "\u0387\3\2\2\2\u0389\u038a\3\2\2\2\u038a\u038b\3\2\2\2\u038b\u038c\5\u00e7"+ + "t\2\u038c\u038d\5\u00e7t\2\u038d\u038e\5\u00e7t\2\u038e\u038f\5\u00e7"+ + "t\2\u038f\u0391\3\2\2\2\u0390\u037b\3\2\2\2\u0390\u037d\3\2\2\2\u0390"+ + "\u0385\3\2\2\2\u0391\u00e4\3\2\2\2\u0392\u039b\5\u00e7t\2\u0393\u0396"+ + "\5\u00e7t\2\u0394\u0396\7a\2\2\u0395\u0393\3\2\2\2\u0395\u0394\3\2\2\2"+ + "\u0396\u0399\3\2\2\2\u0397\u0395\3\2\2\2\u0397\u0398\3\2\2\2\u0398\u039a"+ + "\3\2\2\2\u0399\u0397\3\2\2\2\u039a\u039c\5\u00e7t\2\u039b\u0397\3\2\2"+ + "\2\u039b\u039c\3\2\2\2\u039c\u00e6\3\2\2\2\u039d\u039e\t\5\2\2\u039e\u00e8"+ + "\3\2\2\2\u039f\u03a7\t\26\2\2\u03a0\u03a2\t\27\2\2\u03a1\u03a0\3\2\2\2"+ + "\u03a2\u03a5\3\2\2\2\u03a3\u03a1\3\2\2\2\u03a3\u03a4\3\2\2\2\u03a4\u03a6"+ + "\3\2\2\2\u03a5\u03a3\3\2\2\2\u03a6\u03a8\t\26\2\2\u03a7\u03a3\3\2\2\2"+ + "\u03a7\u03a8\3\2\2\2\u03a8\u00ea\3\2\2\2\u03a9\u03ac\5\u00edw\2\u03aa"+ + "\u03ac\t\26\2\2\u03ab\u03a9\3\2\2\2\u03ab\u03aa\3\2\2\2\u03ac\u00ec\3"+ + "\2\2\2\u03ad\u03b2\t\30\2\2\u03ae\u03b2\n\31\2\2\u03af\u03b0\t\32\2\2"+ + "\u03b0\u03b2\t\33\2\2\u03b1\u03ad\3\2\2\2\u03b1\u03ae\3\2\2\2\u03b1\u03af"+ + "\3\2\2\2\u03b2\u00ee\3\2\2\2\62\2\u0245\u024a\u024d\u024f\u0252\u025a"+ + "\u025e\u0261\u0267\u026e\u0272\u0275\u027d\u0281\u0284\u0289\u028d\u0290"+ + "\u0293\u0298\u029b\u029d\u02a3\u02a6\u02aa\u02ae\u02b2\u02bd\u02c2\u02c9"+ + "\u02cb\u0351\u035b\u0369\u0372\u0377\u037f\u0382\u0389\u0390\u0395\u0397"+ + "\u039b\u03a3\u03a7\u03ab\u03b1\3\2\3\2"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParser.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParser.java new file mode 100644 index 000000000..7058c344d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParser.java @@ -0,0 +1,10204 @@ +// Generated from JavaParser.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; + +import java.util.List; +import org.antlr.v4.runtime.FailedPredicateException; +import org.antlr.v4.runtime.NoViableAltException; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.RuntimeMetaData; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.Vocabulary; +import org.antlr.v4.runtime.VocabularyImpl; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.TerminalNode; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class JavaParser extends Parser { + static { RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + ABSTRACT=1, ASSERT=2, BOOLEAN=3, BREAK=4, BYTE=5, CASE=6, CATCH=7, CHAR=8, + CLASS=9, CONST=10, CONTINUE=11, DEFAULT=12, DO=13, DOUBLE=14, ELSE=15, + ENUM=16, EXTENDS=17, FINAL=18, FINALLY=19, FLOAT=20, FOR=21, IF=22, GOTO=23, + IMPLEMENTS=24, IMPORT=25, INSTANCEOF=26, INT=27, INTERFACE=28, LONG=29, + NATIVE=30, NEW=31, PACKAGE=32, PRIVATE=33, PROTECTED=34, PUBLIC=35, RETURN=36, + SHORT=37, STATIC=38, STRICTFP=39, SUPER=40, SWITCH=41, SYNCHRONIZED=42, + THIS=43, THROW=44, THROWS=45, TRANSIENT=46, TRY=47, VOID=48, VOLATILE=49, + WHILE=50, DECIMAL_LITERAL=51, HEX_LITERAL=52, OCT_LITERAL=53, BINARY_LITERAL=54, + FLOAT_LITERAL=55, HEX_FLOAT_LITERAL=56, BOOL_LITERAL=57, CHAR_LITERAL=58, + STRING_LITERAL=59, NULL_LITERAL=60, LPAREN=61, RPAREN=62, LBRACE=63, RBRACE=64, + LBRACK=65, RBRACK=66, SEMI=67, COMMA=68, DOT=69, ASSIGN=70, GT=71, LT=72, + BANG=73, TILDE=74, QUESTION=75, COLON=76, EQUAL=77, LE=78, GE=79, NOTEQUAL=80, + AND=81, OR=82, INC=83, DEC=84, ADD=85, SUB=86, MUL=87, DIV=88, BITAND=89, + BITOR=90, CARET=91, MOD=92, ADD_ASSIGN=93, SUB_ASSIGN=94, MUL_ASSIGN=95, + DIV_ASSIGN=96, AND_ASSIGN=97, OR_ASSIGN=98, XOR_ASSIGN=99, MOD_ASSIGN=100, + LSHIFT_ASSIGN=101, RSHIFT_ASSIGN=102, URSHIFT_ASSIGN=103, ARROW=104, COLONCOLON=105, + AT=106, ELLIPSIS=107, WS=108, COMMENT=109, LINE_COMMENT=110, IDENTIFIER=111; + public static final int + RULE_compilationUnit = 0, RULE_packageDeclaration = 1, RULE_importDeclaration = 2, + RULE_typeDeclaration = 3, RULE_modifier = 4, RULE_classOrInterfaceModifier = 5, + RULE_variableModifier = 6, RULE_classDeclaration = 7, RULE_typeParameters = 8, + RULE_typeParameter = 9, RULE_typeBound = 10, RULE_enumDeclaration = 11, + RULE_enumConstants = 12, RULE_enumConstant = 13, RULE_enumBodyDeclarations = 14, + RULE_interfaceDeclaration = 15, RULE_classBody = 16, RULE_interfaceBody = 17, + RULE_classBodyDeclaration = 18, RULE_memberDeclaration = 19, RULE_methodDeclaration = 20, + RULE_methodBody = 21, RULE_typeTypeOrVoid = 22, RULE_genericMethodDeclaration = 23, + RULE_genericConstructorDeclaration = 24, RULE_constructorDeclaration = 25, + RULE_fieldDeclaration = 26, RULE_interfaceBodyDeclaration = 27, RULE_interfaceMemberDeclaration = 28, + RULE_constDeclaration = 29, RULE_constantDeclarator = 30, RULE_interfaceMethodDeclaration = 31, + RULE_interfaceMethodModifier = 32, RULE_genericInterfaceMethodDeclaration = 33, + RULE_variableDeclarators = 34, RULE_variableDeclarator = 35, RULE_variableDeclaratorId = 36, + RULE_variableInitializer = 37, RULE_arrayInitializer = 38, RULE_classOrInterfaceType = 39, + RULE_typeArgument = 40, RULE_qualifiedNameList = 41, RULE_formalParameters = 42, + RULE_formalParameterList = 43, RULE_formalParameter = 44, RULE_lastFormalParameter = 45, + RULE_qualifiedName = 46, RULE_literal = 47, RULE_integerLiteral = 48, + RULE_floatLiteral = 49, RULE_altAnnotationQualifiedName = 50, RULE_annotation = 51, + RULE_elementValuePairs = 52, RULE_elementValuePair = 53, RULE_elementValue = 54, + RULE_elementValueArrayInitializer = 55, RULE_annotationTypeDeclaration = 56, + RULE_annotationTypeBody = 57, RULE_annotationTypeElementDeclaration = 58, + RULE_annotationTypeElementRest = 59, RULE_annotationMethodOrConstantRest = 60, + RULE_annotationMethodRest = 61, RULE_annotationConstantRest = 62, RULE_defaultValue = 63, + RULE_block = 64, RULE_blockStatement = 65, RULE_localVariableDeclaration = 66, + RULE_localTypeDeclaration = 67, RULE_statement = 68, RULE_catchClause = 69, + RULE_catchType = 70, RULE_finallyBlock = 71, RULE_resourceSpecification = 72, + RULE_resources = 73, RULE_resource = 74, RULE_switchBlockStatementGroup = 75, + RULE_switchLabel = 76, RULE_forControl = 77, RULE_forInit = 78, RULE_enhancedForControl = 79, + RULE_parExpression = 80, RULE_expressionList = 81, RULE_methodCall = 82, + RULE_expression = 83, RULE_lambdaExpression = 84, RULE_lambdaParameters = 85, + RULE_lambdaBody = 86, RULE_primary = 87, RULE_classType = 88, RULE_creator = 89, + RULE_createdName = 90, RULE_innerCreator = 91, RULE_arrayCreatorRest = 92, + RULE_classCreatorRest = 93, RULE_explicitGenericInvocation = 94, RULE_typeArgumentsOrDiamond = 95, + RULE_nonWildcardTypeArgumentsOrDiamond = 96, RULE_nonWildcardTypeArguments = 97, + RULE_typeList = 98, RULE_typeType = 99, RULE_primitiveType = 100, RULE_typeArguments = 101, + RULE_superSuffix = 102, RULE_explicitGenericInvocationSuffix = 103, RULE_arguments = 104; + private static String[] makeRuleNames() { + return new String[] { + "compilationUnit", "packageDeclaration", "importDeclaration", "typeDeclaration", + "modifier", "classOrInterfaceModifier", "variableModifier", "classDeclaration", + "typeParameters", "typeParameter", "typeBound", "enumDeclaration", "enumConstants", + "enumConstant", "enumBodyDeclarations", "interfaceDeclaration", "classBody", + "interfaceBody", "classBodyDeclaration", "memberDeclaration", "methodDeclaration", + "methodBody", "typeTypeOrVoid", "genericMethodDeclaration", "genericConstructorDeclaration", + "constructorDeclaration", "fieldDeclaration", "interfaceBodyDeclaration", + "interfaceMemberDeclaration", "constDeclaration", "constantDeclarator", + "interfaceMethodDeclaration", "interfaceMethodModifier", "genericInterfaceMethodDeclaration", + "variableDeclarators", "variableDeclarator", "variableDeclaratorId", + "variableInitializer", "arrayInitializer", "classOrInterfaceType", "typeArgument", + "qualifiedNameList", "formalParameters", "formalParameterList", "formalParameter", + "lastFormalParameter", "qualifiedName", "literal", "integerLiteral", + "floatLiteral", "altAnnotationQualifiedName", "annotation", "elementValuePairs", + "elementValuePair", "elementValue", "elementValueArrayInitializer", "annotationTypeDeclaration", + "annotationTypeBody", "annotationTypeElementDeclaration", "annotationTypeElementRest", + "annotationMethodOrConstantRest", "annotationMethodRest", "annotationConstantRest", + "defaultValue", "block", "blockStatement", "localVariableDeclaration", + "localTypeDeclaration", "statement", "catchClause", "catchType", "finallyBlock", + "resourceSpecification", "resources", "resource", "switchBlockStatementGroup", + "switchLabel", "forControl", "forInit", "enhancedForControl", "parExpression", + "expressionList", "methodCall", "expression", "lambdaExpression", "lambdaParameters", + "lambdaBody", "primary", "classType", "creator", "createdName", "innerCreator", + "arrayCreatorRest", "classCreatorRest", "explicitGenericInvocation", + "typeArgumentsOrDiamond", "nonWildcardTypeArgumentsOrDiamond", "nonWildcardTypeArguments", + "typeList", "typeType", "primitiveType", "typeArguments", "superSuffix", + "explicitGenericInvocationSuffix", "arguments" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'abstract'", "'assert'", "'boolean'", "'break'", "'byte'", "'case'", + "'catch'", "'char'", "'class'", "'const'", "'continue'", "'default'", + "'do'", "'double'", "'else'", "'enum'", "'extends'", "'final'", "'finally'", + "'float'", "'for'", "'if'", "'goto'", "'implements'", "'import'", "'instanceof'", + "'int'", "'interface'", "'long'", "'native'", "'new'", "'package'", "'private'", + "'protected'", "'public'", "'return'", "'short'", "'static'", "'strictfp'", + "'super'", "'switch'", "'synchronized'", "'this'", "'throw'", "'throws'", + "'transient'", "'try'", "'void'", "'volatile'", "'while'", null, null, + null, null, null, null, null, null, null, "'null'", "'('", "')'", "'{'", + "'}'", "'['", "']'", "';'", "','", "'.'", "'='", "'>'", "'<'", "'!'", + "'~'", "'?'", "':'", "'=='", "'<='", "'>='", "'!='", "'&&'", "'||'", + "'++'", "'--'", "'+'", "'-'", "'*'", "'/'", "'&'", "'|'", "'^'", "'%'", + "'+='", "'-='", "'*='", "'/='", "'&='", "'|='", "'^='", "'%='", "'<<='", + "'>>='", "'>>>='", "'->'", "'::'", "'@'", "'...'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "ABSTRACT", "ASSERT", "BOOLEAN", "BREAK", "BYTE", "CASE", "CATCH", + "CHAR", "CLASS", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", + "ENUM", "EXTENDS", "FINAL", "FINALLY", "FLOAT", "FOR", "IF", "GOTO", + "IMPLEMENTS", "IMPORT", "INSTANCEOF", "INT", "INTERFACE", "LONG", "NATIVE", + "NEW", "PACKAGE", "PRIVATE", "PROTECTED", "PUBLIC", "RETURN", "SHORT", + "STATIC", "STRICTFP", "SUPER", "SWITCH", "SYNCHRONIZED", "THIS", "THROW", + "THROWS", "TRANSIENT", "TRY", "VOID", "VOLATILE", "WHILE", "DECIMAL_LITERAL", + "HEX_LITERAL", "OCT_LITERAL", "BINARY_LITERAL", "FLOAT_LITERAL", "HEX_FLOAT_LITERAL", + "BOOL_LITERAL", "CHAR_LITERAL", "STRING_LITERAL", "NULL_LITERAL", "LPAREN", + "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", "SEMI", "COMMA", "DOT", + "ASSIGN", "GT", "LT", "BANG", "TILDE", "QUESTION", "COLON", "EQUAL", + "LE", "GE", "NOTEQUAL", "AND", "OR", "INC", "DEC", "ADD", "SUB", "MUL", + "DIV", "BITAND", "BITOR", "CARET", "MOD", "ADD_ASSIGN", "SUB_ASSIGN", + "MUL_ASSIGN", "DIV_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", + "MOD_ASSIGN", "LSHIFT_ASSIGN", "RSHIFT_ASSIGN", "URSHIFT_ASSIGN", "ARROW", + "COLONCOLON", "AT", "ELLIPSIS", "WS", "COMMENT", "LINE_COMMENT", "IDENTIFIER" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + @Override + public String getGrammarFileName() { return "JavaParser.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public ATN getATN() { return _ATN; } + + public JavaParser(TokenStream input) { + super(input); + _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + public static class CompilationUnitContext extends ParserRuleContext { + public TerminalNode EOF() { return getToken(JavaParser.EOF, 0); } + public PackageDeclarationContext packageDeclaration() { + return getRuleContext(PackageDeclarationContext.class,0); + } + public List importDeclaration() { + return getRuleContexts(ImportDeclarationContext.class); + } + public ImportDeclarationContext importDeclaration(int i) { + return getRuleContext(ImportDeclarationContext.class,i); + } + public List typeDeclaration() { + return getRuleContexts(TypeDeclarationContext.class); + } + public TypeDeclarationContext typeDeclaration(int i) { + return getRuleContext(TypeDeclarationContext.class,i); + } + public CompilationUnitContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_compilationUnit; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterCompilationUnit(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitCompilationUnit(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitCompilationUnit(this); + else return visitor.visitChildren(this); + } + } + + public final CompilationUnitContext compilationUnit() throws RecognitionException { + CompilationUnitContext _localctx = new CompilationUnitContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_compilationUnit); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(211); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) { + case 1: + { + setState(210); + packageDeclaration(); + } + break; + } + setState(216); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==IMPORT) { + { + { + setState(213); + importDeclaration(); + } + } + setState(218); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(222); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << CLASS) | (1L << ENUM) | (1L << FINAL) | (1L << INTERFACE) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << STATIC) | (1L << STRICTFP))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(219); + typeDeclaration(); + } + } + setState(224); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(225); + match(EOF); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class PackageDeclarationContext extends ParserRuleContext { + public TerminalNode PACKAGE() { return getToken(JavaParser.PACKAGE, 0); } + public QualifiedNameContext qualifiedName() { + return getRuleContext(QualifiedNameContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public PackageDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_packageDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterPackageDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitPackageDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitPackageDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final PackageDeclarationContext packageDeclaration() throws RecognitionException { + PackageDeclarationContext _localctx = new PackageDeclarationContext(_ctx, getState()); + enterRule(_localctx, 2, RULE_packageDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(230); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==AT || _la==IDENTIFIER) { + { + { + setState(227); + annotation(); + } + } + setState(232); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(233); + match(PACKAGE); + setState(234); + qualifiedName(); + setState(235); + match(SEMI); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ImportDeclarationContext extends ParserRuleContext { + public TerminalNode IMPORT() { return getToken(JavaParser.IMPORT, 0); } + public QualifiedNameContext qualifiedName() { + return getRuleContext(QualifiedNameContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public TerminalNode STATIC() { return getToken(JavaParser.STATIC, 0); } + public TerminalNode DOT() { return getToken(JavaParser.DOT, 0); } + public TerminalNode MUL() { return getToken(JavaParser.MUL, 0); } + public ImportDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_importDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterImportDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitImportDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitImportDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final ImportDeclarationContext importDeclaration() throws RecognitionException { + ImportDeclarationContext _localctx = new ImportDeclarationContext(_ctx, getState()); + enterRule(_localctx, 4, RULE_importDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(237); + match(IMPORT); + setState(239); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==STATIC) { + { + setState(238); + match(STATIC); + } + } + + setState(241); + qualifiedName(); + setState(244); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==DOT) { + { + setState(242); + match(DOT); + setState(243); + match(MUL); + } + } + + setState(246); + match(SEMI); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeDeclarationContext extends ParserRuleContext { + public ClassDeclarationContext classDeclaration() { + return getRuleContext(ClassDeclarationContext.class,0); + } + public EnumDeclarationContext enumDeclaration() { + return getRuleContext(EnumDeclarationContext.class,0); + } + public InterfaceDeclarationContext interfaceDeclaration() { + return getRuleContext(InterfaceDeclarationContext.class,0); + } + public AnnotationTypeDeclarationContext annotationTypeDeclaration() { + return getRuleContext(AnnotationTypeDeclarationContext.class,0); + } + public List classOrInterfaceModifier() { + return getRuleContexts(ClassOrInterfaceModifierContext.class); + } + public ClassOrInterfaceModifierContext classOrInterfaceModifier(int i) { + return getRuleContext(ClassOrInterfaceModifierContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public TypeDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final TypeDeclarationContext typeDeclaration() throws RecognitionException { + TypeDeclarationContext _localctx = new TypeDeclarationContext(_ctx, getState()); + enterRule(_localctx, 6, RULE_typeDeclaration); + try { + int _alt; + setState(261); + _errHandler.sync(this); + switch (_input.LA(1)) { + case ABSTRACT: + case CLASS: + case ENUM: + case FINAL: + case INTERFACE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(251); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(248); + classOrInterfaceModifier(); + } + } + } + setState(253); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); + } + setState(258); + _errHandler.sync(this); + switch (_input.LA(1)) { + case CLASS: + { + setState(254); + classDeclaration(); + } + break; + case ENUM: + { + setState(255); + enumDeclaration(); + } + break; + case INTERFACE: + { + setState(256); + interfaceDeclaration(); + } + break; + case AT: + { + setState(257); + annotationTypeDeclaration(); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + case SEMI: + enterOuterAlt(_localctx, 2); + { + setState(260); + match(SEMI); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ModifierContext extends ParserRuleContext { + public ClassOrInterfaceModifierContext classOrInterfaceModifier() { + return getRuleContext(ClassOrInterfaceModifierContext.class,0); + } + public TerminalNode NATIVE() { return getToken(JavaParser.NATIVE, 0); } + public TerminalNode SYNCHRONIZED() { return getToken(JavaParser.SYNCHRONIZED, 0); } + public TerminalNode TRANSIENT() { return getToken(JavaParser.TRANSIENT, 0); } + public TerminalNode VOLATILE() { return getToken(JavaParser.VOLATILE, 0); } + public ModifierContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_modifier; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterModifier(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitModifier(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitModifier(this); + else return visitor.visitChildren(this); + } + } + + public final ModifierContext modifier() throws RecognitionException { + ModifierContext _localctx = new ModifierContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_modifier); + try { + setState(268); + _errHandler.sync(this); + switch (_input.LA(1)) { + case ABSTRACT: + case FINAL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(263); + classOrInterfaceModifier(); + } + break; + case NATIVE: + enterOuterAlt(_localctx, 2); + { + setState(264); + match(NATIVE); + } + break; + case SYNCHRONIZED: + enterOuterAlt(_localctx, 3); + { + setState(265); + match(SYNCHRONIZED); + } + break; + case TRANSIENT: + enterOuterAlt(_localctx, 4); + { + setState(266); + match(TRANSIENT); + } + break; + case VOLATILE: + enterOuterAlt(_localctx, 5); + { + setState(267); + match(VOLATILE); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassOrInterfaceModifierContext extends ParserRuleContext { + public AnnotationContext annotation() { + return getRuleContext(AnnotationContext.class,0); + } + public TerminalNode PUBLIC() { return getToken(JavaParser.PUBLIC, 0); } + public TerminalNode PROTECTED() { return getToken(JavaParser.PROTECTED, 0); } + public TerminalNode PRIVATE() { return getToken(JavaParser.PRIVATE, 0); } + public TerminalNode STATIC() { return getToken(JavaParser.STATIC, 0); } + public TerminalNode ABSTRACT() { return getToken(JavaParser.ABSTRACT, 0); } + public TerminalNode FINAL() { return getToken(JavaParser.FINAL, 0); } + public TerminalNode STRICTFP() { return getToken(JavaParser.STRICTFP, 0); } + public ClassOrInterfaceModifierContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classOrInterfaceModifier; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassOrInterfaceModifier(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassOrInterfaceModifier(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassOrInterfaceModifier(this); + else return visitor.visitChildren(this); + } + } + + public final ClassOrInterfaceModifierContext classOrInterfaceModifier() throws RecognitionException { + ClassOrInterfaceModifierContext _localctx = new ClassOrInterfaceModifierContext(_ctx, getState()); + enterRule(_localctx, 10, RULE_classOrInterfaceModifier); + try { + setState(278); + _errHandler.sync(this); + switch (_input.LA(1)) { + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(270); + annotation(); + } + break; + case PUBLIC: + enterOuterAlt(_localctx, 2); + { + setState(271); + match(PUBLIC); + } + break; + case PROTECTED: + enterOuterAlt(_localctx, 3); + { + setState(272); + match(PROTECTED); + } + break; + case PRIVATE: + enterOuterAlt(_localctx, 4); + { + setState(273); + match(PRIVATE); + } + break; + case STATIC: + enterOuterAlt(_localctx, 5); + { + setState(274); + match(STATIC); + } + break; + case ABSTRACT: + enterOuterAlt(_localctx, 6); + { + setState(275); + match(ABSTRACT); + } + break; + case FINAL: + enterOuterAlt(_localctx, 7); + { + setState(276); + match(FINAL); + } + break; + case STRICTFP: + enterOuterAlt(_localctx, 8); + { + setState(277); + match(STRICTFP); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class VariableModifierContext extends ParserRuleContext { + public TerminalNode FINAL() { return getToken(JavaParser.FINAL, 0); } + public AnnotationContext annotation() { + return getRuleContext(AnnotationContext.class,0); + } + public VariableModifierContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_variableModifier; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterVariableModifier(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitVariableModifier(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitVariableModifier(this); + else return visitor.visitChildren(this); + } + } + + public final VariableModifierContext variableModifier() throws RecognitionException { + VariableModifierContext _localctx = new VariableModifierContext(_ctx, getState()); + enterRule(_localctx, 12, RULE_variableModifier); + try { + setState(282); + _errHandler.sync(this); + switch (_input.LA(1)) { + case FINAL: + enterOuterAlt(_localctx, 1); + { + setState(280); + match(FINAL); + } + break; + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 2); + { + setState(281); + annotation(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassDeclarationContext extends ParserRuleContext { + public TerminalNode CLASS() { return getToken(JavaParser.CLASS, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public ClassBodyContext classBody() { + return getRuleContext(ClassBodyContext.class,0); + } + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public TerminalNode EXTENDS() { return getToken(JavaParser.EXTENDS, 0); } + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public TerminalNode IMPLEMENTS() { return getToken(JavaParser.IMPLEMENTS, 0); } + public TypeListContext typeList() { + return getRuleContext(TypeListContext.class,0); + } + public ClassDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final ClassDeclarationContext classDeclaration() throws RecognitionException { + ClassDeclarationContext _localctx = new ClassDeclarationContext(_ctx, getState()); + enterRule(_localctx, 14, RULE_classDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(284); + match(CLASS); + setState(285); + match(IDENTIFIER); + setState(287); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(286); + typeParameters(); + } + } + + setState(291); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==EXTENDS) { + { + setState(289); + match(EXTENDS); + setState(290); + typeType(); + } + } + + setState(295); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==IMPLEMENTS) { + { + setState(293); + match(IMPLEMENTS); + setState(294); + typeList(); + } + } + + setState(297); + classBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeParametersContext extends ParserRuleContext { + public TerminalNode LT() { return getToken(JavaParser.LT, 0); } + public List typeParameter() { + return getRuleContexts(TypeParameterContext.class); + } + public TypeParameterContext typeParameter(int i) { + return getRuleContext(TypeParameterContext.class,i); + } + public TerminalNode GT() { return getToken(JavaParser.GT, 0); } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public TypeParametersContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeParameters; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeParameters(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeParameters(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeParameters(this); + else return visitor.visitChildren(this); + } + } + + public final TypeParametersContext typeParameters() throws RecognitionException { + TypeParametersContext _localctx = new TypeParametersContext(_ctx, getState()); + enterRule(_localctx, 16, RULE_typeParameters); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(299); + match(LT); + setState(300); + typeParameter(); + setState(305); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(301); + match(COMMA); + setState(302); + typeParameter(); + } + } + setState(307); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(308); + match(GT); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeParameterContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public TerminalNode EXTENDS() { return getToken(JavaParser.EXTENDS, 0); } + public TypeBoundContext typeBound() { + return getRuleContext(TypeBoundContext.class,0); + } + public TypeParameterContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeParameter; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeParameter(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeParameter(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeParameter(this); + else return visitor.visitChildren(this); + } + } + + public final TypeParameterContext typeParameter() throws RecognitionException { + TypeParameterContext _localctx = new TypeParameterContext(_ctx, getState()); + enterRule(_localctx, 18, RULE_typeParameter); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(313); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,16,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(310); + annotation(); + } + } + } + setState(315); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,16,_ctx); + } + setState(316); + match(IDENTIFIER); + setState(325); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==EXTENDS) { + { + setState(317); + match(EXTENDS); + setState(321); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,17,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(318); + annotation(); + } + } + } + setState(323); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,17,_ctx); + } + setState(324); + typeBound(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeBoundContext extends ParserRuleContext { + public List typeType() { + return getRuleContexts(TypeTypeContext.class); + } + public TypeTypeContext typeType(int i) { + return getRuleContext(TypeTypeContext.class,i); + } + public List BITAND() { return getTokens(JavaParser.BITAND); } + public TerminalNode BITAND(int i) { + return getToken(JavaParser.BITAND, i); + } + public TypeBoundContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeBound; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeBound(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeBound(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeBound(this); + else return visitor.visitChildren(this); + } + } + + public final TypeBoundContext typeBound() throws RecognitionException { + TypeBoundContext _localctx = new TypeBoundContext(_ctx, getState()); + enterRule(_localctx, 20, RULE_typeBound); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(327); + typeType(); + setState(332); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==BITAND) { + { + { + setState(328); + match(BITAND); + setState(329); + typeType(); + } + } + setState(334); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EnumDeclarationContext extends ParserRuleContext { + public TerminalNode ENUM() { return getToken(JavaParser.ENUM, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public TerminalNode IMPLEMENTS() { return getToken(JavaParser.IMPLEMENTS, 0); } + public TypeListContext typeList() { + return getRuleContext(TypeListContext.class,0); + } + public EnumConstantsContext enumConstants() { + return getRuleContext(EnumConstantsContext.class,0); + } + public TerminalNode COMMA() { return getToken(JavaParser.COMMA, 0); } + public EnumBodyDeclarationsContext enumBodyDeclarations() { + return getRuleContext(EnumBodyDeclarationsContext.class,0); + } + public EnumDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_enumDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterEnumDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitEnumDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitEnumDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final EnumDeclarationContext enumDeclaration() throws RecognitionException { + EnumDeclarationContext _localctx = new EnumDeclarationContext(_ctx, getState()); + enterRule(_localctx, 22, RULE_enumDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(335); + match(ENUM); + setState(336); + match(IDENTIFIER); + setState(339); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==IMPLEMENTS) { + { + setState(337); + match(IMPLEMENTS); + setState(338); + typeList(); + } + } + + setState(341); + match(LBRACE); + setState(343); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==AT || _la==IDENTIFIER) { + { + setState(342); + enumConstants(); + } + } + + setState(346); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==COMMA) { + { + setState(345); + match(COMMA); + } + } + + setState(349); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==SEMI) { + { + setState(348); + enumBodyDeclarations(); + } + } + + setState(351); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EnumConstantsContext extends ParserRuleContext { + public List enumConstant() { + return getRuleContexts(EnumConstantContext.class); + } + public EnumConstantContext enumConstant(int i) { + return getRuleContext(EnumConstantContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public EnumConstantsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_enumConstants; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterEnumConstants(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitEnumConstants(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitEnumConstants(this); + else return visitor.visitChildren(this); + } + } + + public final EnumConstantsContext enumConstants() throws RecognitionException { + EnumConstantsContext _localctx = new EnumConstantsContext(_ctx, getState()); + enterRule(_localctx, 24, RULE_enumConstants); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(353); + enumConstant(); + setState(358); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,24,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(354); + match(COMMA); + setState(355); + enumConstant(); + } + } + } + setState(360); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,24,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EnumConstantContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public ArgumentsContext arguments() { + return getRuleContext(ArgumentsContext.class,0); + } + public ClassBodyContext classBody() { + return getRuleContext(ClassBodyContext.class,0); + } + public EnumConstantContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_enumConstant; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterEnumConstant(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitEnumConstant(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitEnumConstant(this); + else return visitor.visitChildren(this); + } + } + + public final EnumConstantContext enumConstant() throws RecognitionException { + EnumConstantContext _localctx = new EnumConstantContext(_ctx, getState()); + enterRule(_localctx, 26, RULE_enumConstant); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(364); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,25,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(361); + annotation(); + } + } + } + setState(366); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,25,_ctx); + } + setState(367); + match(IDENTIFIER); + setState(369); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LPAREN) { + { + setState(368); + arguments(); + } + } + + setState(372); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LBRACE) { + { + setState(371); + classBody(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EnumBodyDeclarationsContext extends ParserRuleContext { + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public List classBodyDeclaration() { + return getRuleContexts(ClassBodyDeclarationContext.class); + } + public ClassBodyDeclarationContext classBodyDeclaration(int i) { + return getRuleContext(ClassBodyDeclarationContext.class,i); + } + public EnumBodyDeclarationsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_enumBodyDeclarations; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterEnumBodyDeclarations(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitEnumBodyDeclarations(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitEnumBodyDeclarations(this); + else return visitor.visitChildren(this); + } + } + + public final EnumBodyDeclarationsContext enumBodyDeclarations() throws RecognitionException { + EnumBodyDeclarationsContext _localctx = new EnumBodyDeclarationsContext(_ctx, getState()); + enterRule(_localctx, 28, RULE_enumBodyDeclarations); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(374); + match(SEMI); + setState(378); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << DOUBLE) | (1L << ENUM) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NATIVE) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SYNCHRONIZED) | (1L << TRANSIENT) | (1L << VOID) | (1L << VOLATILE) | (1L << LBRACE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (LT - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(375); + classBodyDeclaration(); + } + } + setState(380); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceDeclarationContext extends ParserRuleContext { + public TerminalNode INTERFACE() { return getToken(JavaParser.INTERFACE, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public InterfaceBodyContext interfaceBody() { + return getRuleContext(InterfaceBodyContext.class,0); + } + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public TerminalNode EXTENDS() { return getToken(JavaParser.EXTENDS, 0); } + public TypeListContext typeList() { + return getRuleContext(TypeListContext.class,0); + } + public InterfaceDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceDeclarationContext interfaceDeclaration() throws RecognitionException { + InterfaceDeclarationContext _localctx = new InterfaceDeclarationContext(_ctx, getState()); + enterRule(_localctx, 30, RULE_interfaceDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(381); + match(INTERFACE); + setState(382); + match(IDENTIFIER); + setState(384); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(383); + typeParameters(); + } + } + + setState(388); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==EXTENDS) { + { + setState(386); + match(EXTENDS); + setState(387); + typeList(); + } + } + + setState(390); + interfaceBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassBodyContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List classBodyDeclaration() { + return getRuleContexts(ClassBodyDeclarationContext.class); + } + public ClassBodyDeclarationContext classBodyDeclaration(int i) { + return getRuleContext(ClassBodyDeclarationContext.class,i); + } + public ClassBodyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classBody; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassBody(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassBody(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassBody(this); + else return visitor.visitChildren(this); + } + } + + public final ClassBodyContext classBody() throws RecognitionException { + ClassBodyContext _localctx = new ClassBodyContext(_ctx, getState()); + enterRule(_localctx, 32, RULE_classBody); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(392); + match(LBRACE); + setState(396); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << DOUBLE) | (1L << ENUM) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NATIVE) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SYNCHRONIZED) | (1L << TRANSIENT) | (1L << VOID) | (1L << VOLATILE) | (1L << LBRACE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (LT - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(393); + classBodyDeclaration(); + } + } + setState(398); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(399); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceBodyContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List interfaceBodyDeclaration() { + return getRuleContexts(InterfaceBodyDeclarationContext.class); + } + public InterfaceBodyDeclarationContext interfaceBodyDeclaration(int i) { + return getRuleContext(InterfaceBodyDeclarationContext.class,i); + } + public InterfaceBodyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceBody; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceBody(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceBody(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceBody(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceBodyContext interfaceBody() throws RecognitionException { + InterfaceBodyContext _localctx = new InterfaceBodyContext(_ctx, getState()); + enterRule(_localctx, 34, RULE_interfaceBody); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(401); + match(LBRACE); + setState(405); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << DEFAULT) | (1L << DOUBLE) | (1L << ENUM) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NATIVE) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SYNCHRONIZED) | (1L << TRANSIENT) | (1L << VOID) | (1L << VOLATILE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (LT - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(402); + interfaceBodyDeclaration(); + } + } + setState(407); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(408); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassBodyDeclarationContext extends ParserRuleContext { + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public TerminalNode STATIC() { return getToken(JavaParser.STATIC, 0); } + public MemberDeclarationContext memberDeclaration() { + return getRuleContext(MemberDeclarationContext.class,0); + } + public List modifier() { + return getRuleContexts(ModifierContext.class); + } + public ModifierContext modifier(int i) { + return getRuleContext(ModifierContext.class,i); + } + public ClassBodyDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classBodyDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassBodyDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassBodyDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassBodyDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final ClassBodyDeclarationContext classBodyDeclaration() throws RecognitionException { + ClassBodyDeclarationContext _localctx = new ClassBodyDeclarationContext(_ctx, getState()); + enterRule(_localctx, 36, RULE_classBodyDeclaration); + int _la; + try { + int _alt; + setState(422); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,35,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(410); + match(SEMI); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(412); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==STATIC) { + { + setState(411); + match(STATIC); + } + } + + setState(414); + block(); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(418); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,34,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(415); + modifier(); + } + } + } + setState(420); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,34,_ctx); + } + setState(421); + memberDeclaration(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class MemberDeclarationContext extends ParserRuleContext { + public MethodDeclarationContext methodDeclaration() { + return getRuleContext(MethodDeclarationContext.class,0); + } + public GenericMethodDeclarationContext genericMethodDeclaration() { + return getRuleContext(GenericMethodDeclarationContext.class,0); + } + public FieldDeclarationContext fieldDeclaration() { + return getRuleContext(FieldDeclarationContext.class,0); + } + public ConstructorDeclarationContext constructorDeclaration() { + return getRuleContext(ConstructorDeclarationContext.class,0); + } + public GenericConstructorDeclarationContext genericConstructorDeclaration() { + return getRuleContext(GenericConstructorDeclarationContext.class,0); + } + public InterfaceDeclarationContext interfaceDeclaration() { + return getRuleContext(InterfaceDeclarationContext.class,0); + } + public AnnotationTypeDeclarationContext annotationTypeDeclaration() { + return getRuleContext(AnnotationTypeDeclarationContext.class,0); + } + public ClassDeclarationContext classDeclaration() { + return getRuleContext(ClassDeclarationContext.class,0); + } + public EnumDeclarationContext enumDeclaration() { + return getRuleContext(EnumDeclarationContext.class,0); + } + public MemberDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_memberDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterMemberDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitMemberDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitMemberDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final MemberDeclarationContext memberDeclaration() throws RecognitionException { + MemberDeclarationContext _localctx = new MemberDeclarationContext(_ctx, getState()); + enterRule(_localctx, 38, RULE_memberDeclaration); + try { + setState(433); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,36,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(424); + methodDeclaration(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(425); + genericMethodDeclaration(); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(426); + fieldDeclaration(); + } + break; + case 4: + enterOuterAlt(_localctx, 4); + { + setState(427); + constructorDeclaration(); + } + break; + case 5: + enterOuterAlt(_localctx, 5); + { + setState(428); + genericConstructorDeclaration(); + } + break; + case 6: + enterOuterAlt(_localctx, 6); + { + setState(429); + interfaceDeclaration(); + } + break; + case 7: + enterOuterAlt(_localctx, 7); + { + setState(430); + annotationTypeDeclaration(); + } + break; + case 8: + enterOuterAlt(_localctx, 8); + { + setState(431); + classDeclaration(); + } + break; + case 9: + enterOuterAlt(_localctx, 9); + { + setState(432); + enumDeclaration(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class MethodDeclarationContext extends ParserRuleContext { + public TypeTypeOrVoidContext typeTypeOrVoid() { + return getRuleContext(TypeTypeOrVoidContext.class,0); + } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public FormalParametersContext formalParameters() { + return getRuleContext(FormalParametersContext.class,0); + } + public MethodBodyContext methodBody() { + return getRuleContext(MethodBodyContext.class,0); + } + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public TerminalNode THROWS() { return getToken(JavaParser.THROWS, 0); } + public QualifiedNameListContext qualifiedNameList() { + return getRuleContext(QualifiedNameListContext.class,0); + } + public MethodDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_methodDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterMethodDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitMethodDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitMethodDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final MethodDeclarationContext methodDeclaration() throws RecognitionException { + MethodDeclarationContext _localctx = new MethodDeclarationContext(_ctx, getState()); + enterRule(_localctx, 40, RULE_methodDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(435); + typeTypeOrVoid(); + setState(436); + match(IDENTIFIER); + setState(437); + formalParameters(); + setState(442); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LBRACK) { + { + { + setState(438); + match(LBRACK); + setState(439); + match(RBRACK); + } + } + setState(444); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(447); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==THROWS) { + { + setState(445); + match(THROWS); + setState(446); + qualifiedNameList(); + } + } + + setState(449); + methodBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class MethodBodyContext extends ParserRuleContext { + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public MethodBodyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_methodBody; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterMethodBody(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitMethodBody(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitMethodBody(this); + else return visitor.visitChildren(this); + } + } + + public final MethodBodyContext methodBody() throws RecognitionException { + MethodBodyContext _localctx = new MethodBodyContext(_ctx, getState()); + enterRule(_localctx, 42, RULE_methodBody); + try { + setState(453); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LBRACE: + enterOuterAlt(_localctx, 1); + { + setState(451); + block(); + } + break; + case SEMI: + enterOuterAlt(_localctx, 2); + { + setState(452); + match(SEMI); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeTypeOrVoidContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public TerminalNode VOID() { return getToken(JavaParser.VOID, 0); } + public TypeTypeOrVoidContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeTypeOrVoid; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeTypeOrVoid(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeTypeOrVoid(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeTypeOrVoid(this); + else return visitor.visitChildren(this); + } + } + + public final TypeTypeOrVoidContext typeTypeOrVoid() throws RecognitionException { + TypeTypeOrVoidContext _localctx = new TypeTypeOrVoidContext(_ctx, getState()); + enterRule(_localctx, 44, RULE_typeTypeOrVoid); + try { + setState(457); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(455); + typeType(); + } + break; + case VOID: + enterOuterAlt(_localctx, 2); + { + setState(456); + match(VOID); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class GenericMethodDeclarationContext extends ParserRuleContext { + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public MethodDeclarationContext methodDeclaration() { + return getRuleContext(MethodDeclarationContext.class,0); + } + public GenericMethodDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_genericMethodDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterGenericMethodDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitGenericMethodDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitGenericMethodDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final GenericMethodDeclarationContext genericMethodDeclaration() throws RecognitionException { + GenericMethodDeclarationContext _localctx = new GenericMethodDeclarationContext(_ctx, getState()); + enterRule(_localctx, 46, RULE_genericMethodDeclaration); + try { + enterOuterAlt(_localctx, 1); + { + setState(459); + typeParameters(); + setState(460); + methodDeclaration(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class GenericConstructorDeclarationContext extends ParserRuleContext { + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public ConstructorDeclarationContext constructorDeclaration() { + return getRuleContext(ConstructorDeclarationContext.class,0); + } + public GenericConstructorDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_genericConstructorDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterGenericConstructorDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitGenericConstructorDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitGenericConstructorDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final GenericConstructorDeclarationContext genericConstructorDeclaration() throws RecognitionException { + GenericConstructorDeclarationContext _localctx = new GenericConstructorDeclarationContext(_ctx, getState()); + enterRule(_localctx, 48, RULE_genericConstructorDeclaration); + try { + enterOuterAlt(_localctx, 1); + { + setState(462); + typeParameters(); + setState(463); + constructorDeclaration(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ConstructorDeclarationContext extends ParserRuleContext { + public BlockContext constructorBody; + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public FormalParametersContext formalParameters() { + return getRuleContext(FormalParametersContext.class,0); + } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public TerminalNode THROWS() { return getToken(JavaParser.THROWS, 0); } + public QualifiedNameListContext qualifiedNameList() { + return getRuleContext(QualifiedNameListContext.class,0); + } + public ConstructorDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_constructorDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterConstructorDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitConstructorDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitConstructorDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final ConstructorDeclarationContext constructorDeclaration() throws RecognitionException { + ConstructorDeclarationContext _localctx = new ConstructorDeclarationContext(_ctx, getState()); + enterRule(_localctx, 50, RULE_constructorDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(465); + match(IDENTIFIER); + setState(466); + formalParameters(); + setState(469); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==THROWS) { + { + setState(467); + match(THROWS); + setState(468); + qualifiedNameList(); + } + } + + setState(471); + ((ConstructorDeclarationContext)_localctx).constructorBody = block(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FieldDeclarationContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public VariableDeclaratorsContext variableDeclarators() { + return getRuleContext(VariableDeclaratorsContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public FieldDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_fieldDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFieldDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFieldDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFieldDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final FieldDeclarationContext fieldDeclaration() throws RecognitionException { + FieldDeclarationContext _localctx = new FieldDeclarationContext(_ctx, getState()); + enterRule(_localctx, 52, RULE_fieldDeclaration); + try { + enterOuterAlt(_localctx, 1); + { + setState(473); + typeType(); + setState(474); + variableDeclarators(); + setState(475); + match(SEMI); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceBodyDeclarationContext extends ParserRuleContext { + public InterfaceMemberDeclarationContext interfaceMemberDeclaration() { + return getRuleContext(InterfaceMemberDeclarationContext.class,0); + } + public List modifier() { + return getRuleContexts(ModifierContext.class); + } + public ModifierContext modifier(int i) { + return getRuleContext(ModifierContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public InterfaceBodyDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceBodyDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceBodyDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceBodyDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceBodyDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceBodyDeclarationContext interfaceBodyDeclaration() throws RecognitionException { + InterfaceBodyDeclarationContext _localctx = new InterfaceBodyDeclarationContext(_ctx, getState()); + enterRule(_localctx, 54, RULE_interfaceBodyDeclaration); + try { + int _alt; + setState(485); + _errHandler.sync(this); + switch (_input.LA(1)) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DEFAULT: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOID: + case VOLATILE: + case LT: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(480); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,42,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(477); + modifier(); + } + } + } + setState(482); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,42,_ctx); + } + setState(483); + interfaceMemberDeclaration(); + } + break; + case SEMI: + enterOuterAlt(_localctx, 2); + { + setState(484); + match(SEMI); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceMemberDeclarationContext extends ParserRuleContext { + public ConstDeclarationContext constDeclaration() { + return getRuleContext(ConstDeclarationContext.class,0); + } + public InterfaceMethodDeclarationContext interfaceMethodDeclaration() { + return getRuleContext(InterfaceMethodDeclarationContext.class,0); + } + public GenericInterfaceMethodDeclarationContext genericInterfaceMethodDeclaration() { + return getRuleContext(GenericInterfaceMethodDeclarationContext.class,0); + } + public InterfaceDeclarationContext interfaceDeclaration() { + return getRuleContext(InterfaceDeclarationContext.class,0); + } + public AnnotationTypeDeclarationContext annotationTypeDeclaration() { + return getRuleContext(AnnotationTypeDeclarationContext.class,0); + } + public ClassDeclarationContext classDeclaration() { + return getRuleContext(ClassDeclarationContext.class,0); + } + public EnumDeclarationContext enumDeclaration() { + return getRuleContext(EnumDeclarationContext.class,0); + } + public InterfaceMemberDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceMemberDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceMemberDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceMemberDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceMemberDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceMemberDeclarationContext interfaceMemberDeclaration() throws RecognitionException { + InterfaceMemberDeclarationContext _localctx = new InterfaceMemberDeclarationContext(_ctx, getState()); + enterRule(_localctx, 56, RULE_interfaceMemberDeclaration); + try { + setState(494); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,44,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(487); + constDeclaration(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(488); + interfaceMethodDeclaration(); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(489); + genericInterfaceMethodDeclaration(); + } + break; + case 4: + enterOuterAlt(_localctx, 4); + { + setState(490); + interfaceDeclaration(); + } + break; + case 5: + enterOuterAlt(_localctx, 5); + { + setState(491); + annotationTypeDeclaration(); + } + break; + case 6: + enterOuterAlt(_localctx, 6); + { + setState(492); + classDeclaration(); + } + break; + case 7: + enterOuterAlt(_localctx, 7); + { + setState(493); + enumDeclaration(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ConstDeclarationContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public List constantDeclarator() { + return getRuleContexts(ConstantDeclaratorContext.class); + } + public ConstantDeclaratorContext constantDeclarator(int i) { + return getRuleContext(ConstantDeclaratorContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public ConstDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_constDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterConstDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitConstDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitConstDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final ConstDeclarationContext constDeclaration() throws RecognitionException { + ConstDeclarationContext _localctx = new ConstDeclarationContext(_ctx, getState()); + enterRule(_localctx, 58, RULE_constDeclaration); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(496); + typeType(); + setState(497); + constantDeclarator(); + setState(502); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(498); + match(COMMA); + setState(499); + constantDeclarator(); + } + } + setState(504); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(505); + match(SEMI); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ConstantDeclaratorContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode ASSIGN() { return getToken(JavaParser.ASSIGN, 0); } + public VariableInitializerContext variableInitializer() { + return getRuleContext(VariableInitializerContext.class,0); + } + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public ConstantDeclaratorContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_constantDeclarator; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterConstantDeclarator(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitConstantDeclarator(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitConstantDeclarator(this); + else return visitor.visitChildren(this); + } + } + + public final ConstantDeclaratorContext constantDeclarator() throws RecognitionException { + ConstantDeclaratorContext _localctx = new ConstantDeclaratorContext(_ctx, getState()); + enterRule(_localctx, 60, RULE_constantDeclarator); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(507); + match(IDENTIFIER); + setState(512); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LBRACK) { + { + { + setState(508); + match(LBRACK); + setState(509); + match(RBRACK); + } + } + setState(514); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(515); + match(ASSIGN); + setState(516); + variableInitializer(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceMethodDeclarationContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public FormalParametersContext formalParameters() { + return getRuleContext(FormalParametersContext.class,0); + } + public MethodBodyContext methodBody() { + return getRuleContext(MethodBodyContext.class,0); + } + public TypeTypeOrVoidContext typeTypeOrVoid() { + return getRuleContext(TypeTypeOrVoidContext.class,0); + } + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public List interfaceMethodModifier() { + return getRuleContexts(InterfaceMethodModifierContext.class); + } + public InterfaceMethodModifierContext interfaceMethodModifier(int i) { + return getRuleContext(InterfaceMethodModifierContext.class,i); + } + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public TerminalNode THROWS() { return getToken(JavaParser.THROWS, 0); } + public QualifiedNameListContext qualifiedNameList() { + return getRuleContext(QualifiedNameListContext.class,0); + } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public InterfaceMethodDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceMethodDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceMethodDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceMethodDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceMethodDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceMethodDeclarationContext interfaceMethodDeclaration() throws RecognitionException { + InterfaceMethodDeclarationContext _localctx = new InterfaceMethodDeclarationContext(_ctx, getState()); + enterRule(_localctx, 62, RULE_interfaceMethodDeclaration); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(521); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,47,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(518); + interfaceMethodModifier(); + } + } + } + setState(523); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,47,_ctx); + } + setState(534); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case VOID: + case AT: + case IDENTIFIER: + { + setState(524); + typeTypeOrVoid(); + } + break; + case LT: + { + setState(525); + typeParameters(); + setState(529); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,48,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(526); + annotation(); + } + } + } + setState(531); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,48,_ctx); + } + setState(532); + typeTypeOrVoid(); + } + break; + default: + throw new NoViableAltException(this); + } + setState(536); + match(IDENTIFIER); + setState(537); + formalParameters(); + setState(542); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LBRACK) { + { + { + setState(538); + match(LBRACK); + setState(539); + match(RBRACK); + } + } + setState(544); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(547); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==THROWS) { + { + setState(545); + match(THROWS); + setState(546); + qualifiedNameList(); + } + } + + setState(549); + methodBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InterfaceMethodModifierContext extends ParserRuleContext { + public AnnotationContext annotation() { + return getRuleContext(AnnotationContext.class,0); + } + public TerminalNode PUBLIC() { return getToken(JavaParser.PUBLIC, 0); } + public TerminalNode ABSTRACT() { return getToken(JavaParser.ABSTRACT, 0); } + public TerminalNode DEFAULT() { return getToken(JavaParser.DEFAULT, 0); } + public TerminalNode STATIC() { return getToken(JavaParser.STATIC, 0); } + public TerminalNode STRICTFP() { return getToken(JavaParser.STRICTFP, 0); } + public InterfaceMethodModifierContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_interfaceMethodModifier; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInterfaceMethodModifier(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInterfaceMethodModifier(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInterfaceMethodModifier(this); + else return visitor.visitChildren(this); + } + } + + public final InterfaceMethodModifierContext interfaceMethodModifier() throws RecognitionException { + InterfaceMethodModifierContext _localctx = new InterfaceMethodModifierContext(_ctx, getState()); + enterRule(_localctx, 64, RULE_interfaceMethodModifier); + try { + setState(557); + _errHandler.sync(this); + switch (_input.LA(1)) { + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(551); + annotation(); + } + break; + case PUBLIC: + enterOuterAlt(_localctx, 2); + { + setState(552); + match(PUBLIC); + } + break; + case ABSTRACT: + enterOuterAlt(_localctx, 3); + { + setState(553); + match(ABSTRACT); + } + break; + case DEFAULT: + enterOuterAlt(_localctx, 4); + { + setState(554); + match(DEFAULT); + } + break; + case STATIC: + enterOuterAlt(_localctx, 5); + { + setState(555); + match(STATIC); + } + break; + case STRICTFP: + enterOuterAlt(_localctx, 6); + { + setState(556); + match(STRICTFP); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class GenericInterfaceMethodDeclarationContext extends ParserRuleContext { + public TypeParametersContext typeParameters() { + return getRuleContext(TypeParametersContext.class,0); + } + public InterfaceMethodDeclarationContext interfaceMethodDeclaration() { + return getRuleContext(InterfaceMethodDeclarationContext.class,0); + } + public GenericInterfaceMethodDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_genericInterfaceMethodDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterGenericInterfaceMethodDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitGenericInterfaceMethodDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitGenericInterfaceMethodDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final GenericInterfaceMethodDeclarationContext genericInterfaceMethodDeclaration() throws RecognitionException { + GenericInterfaceMethodDeclarationContext _localctx = new GenericInterfaceMethodDeclarationContext(_ctx, getState()); + enterRule(_localctx, 66, RULE_genericInterfaceMethodDeclaration); + try { + enterOuterAlt(_localctx, 1); + { + setState(559); + typeParameters(); + setState(560); + interfaceMethodDeclaration(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class VariableDeclaratorsContext extends ParserRuleContext { + public List variableDeclarator() { + return getRuleContexts(VariableDeclaratorContext.class); + } + public VariableDeclaratorContext variableDeclarator(int i) { + return getRuleContext(VariableDeclaratorContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public VariableDeclaratorsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_variableDeclarators; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterVariableDeclarators(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitVariableDeclarators(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitVariableDeclarators(this); + else return visitor.visitChildren(this); + } + } + + public final VariableDeclaratorsContext variableDeclarators() throws RecognitionException { + VariableDeclaratorsContext _localctx = new VariableDeclaratorsContext(_ctx, getState()); + enterRule(_localctx, 68, RULE_variableDeclarators); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(562); + variableDeclarator(); + setState(567); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(563); + match(COMMA); + setState(564); + variableDeclarator(); + } + } + setState(569); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class VariableDeclaratorContext extends ParserRuleContext { + public VariableDeclaratorIdContext variableDeclaratorId() { + return getRuleContext(VariableDeclaratorIdContext.class,0); + } + public TerminalNode ASSIGN() { return getToken(JavaParser.ASSIGN, 0); } + public VariableInitializerContext variableInitializer() { + return getRuleContext(VariableInitializerContext.class,0); + } + public VariableDeclaratorContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_variableDeclarator; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterVariableDeclarator(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitVariableDeclarator(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitVariableDeclarator(this); + else return visitor.visitChildren(this); + } + } + + public final VariableDeclaratorContext variableDeclarator() throws RecognitionException { + VariableDeclaratorContext _localctx = new VariableDeclaratorContext(_ctx, getState()); + enterRule(_localctx, 70, RULE_variableDeclarator); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(570); + variableDeclaratorId(); + setState(573); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==ASSIGN) { + { + setState(571); + match(ASSIGN); + setState(572); + variableInitializer(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class VariableDeclaratorIdContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public VariableDeclaratorIdContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_variableDeclaratorId; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterVariableDeclaratorId(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitVariableDeclaratorId(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitVariableDeclaratorId(this); + else return visitor.visitChildren(this); + } + } + + public final VariableDeclaratorIdContext variableDeclaratorId() throws RecognitionException { + VariableDeclaratorIdContext _localctx = new VariableDeclaratorIdContext(_ctx, getState()); + enterRule(_localctx, 72, RULE_variableDeclaratorId); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(575); + match(IDENTIFIER); + setState(580); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LBRACK) { + { + { + setState(576); + match(LBRACK); + setState(577); + match(RBRACK); + } + } + setState(582); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class VariableInitializerContext extends ParserRuleContext { + public ArrayInitializerContext arrayInitializer() { + return getRuleContext(ArrayInitializerContext.class,0); + } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public VariableInitializerContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_variableInitializer; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterVariableInitializer(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitVariableInitializer(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitVariableInitializer(this); + else return visitor.visitChildren(this); + } + } + + public final VariableInitializerContext variableInitializer() throws RecognitionException { + VariableInitializerContext _localctx = new VariableInitializerContext(_ctx, getState()); + enterRule(_localctx, 74, RULE_variableInitializer); + try { + setState(585); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LBRACE: + enterOuterAlt(_localctx, 1); + { + setState(583); + arrayInitializer(); + } + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case NEW: + case SHORT: + case SUPER: + case THIS: + case VOID: + case DECIMAL_LITERAL: + case HEX_LITERAL: + case OCT_LITERAL: + case BINARY_LITERAL: + case FLOAT_LITERAL: + case HEX_FLOAT_LITERAL: + case BOOL_LITERAL: + case CHAR_LITERAL: + case STRING_LITERAL: + case NULL_LITERAL: + case LPAREN: + case LT: + case BANG: + case TILDE: + case INC: + case DEC: + case ADD: + case SUB: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 2); + { + setState(584); + expression(0); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ArrayInitializerContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List variableInitializer() { + return getRuleContexts(VariableInitializerContext.class); + } + public VariableInitializerContext variableInitializer(int i) { + return getRuleContext(VariableInitializerContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public ArrayInitializerContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arrayInitializer; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterArrayInitializer(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitArrayInitializer(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitArrayInitializer(this); + else return visitor.visitChildren(this); + } + } + + public final ArrayInitializerContext arrayInitializer() throws RecognitionException { + ArrayInitializerContext _localctx = new ArrayInitializerContext(_ctx, getState()); + enterRule(_localctx, 76, RULE_arrayInitializer); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(587); + match(LBRACE); + setState(599); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN) | (1L << LBRACE))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(588); + variableInitializer(); + setState(593); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,57,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(589); + match(COMMA); + setState(590); + variableInitializer(); + } + } + } + setState(595); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,57,_ctx); + } + setState(597); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==COMMA) { + { + setState(596); + match(COMMA); + } + } + + } + } + + setState(601); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassOrInterfaceTypeContext extends ParserRuleContext { + public List IDENTIFIER() { return getTokens(JavaParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(JavaParser.IDENTIFIER, i); + } + public List typeArguments() { + return getRuleContexts(TypeArgumentsContext.class); + } + public TypeArgumentsContext typeArguments(int i) { + return getRuleContext(TypeArgumentsContext.class,i); + } + public List DOT() { return getTokens(JavaParser.DOT); } + public TerminalNode DOT(int i) { + return getToken(JavaParser.DOT, i); + } + public ClassOrInterfaceTypeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classOrInterfaceType; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassOrInterfaceType(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassOrInterfaceType(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassOrInterfaceType(this); + else return visitor.visitChildren(this); + } + } + + public final ClassOrInterfaceTypeContext classOrInterfaceType() throws RecognitionException { + ClassOrInterfaceTypeContext _localctx = new ClassOrInterfaceTypeContext(_ctx, getState()); + enterRule(_localctx, 78, RULE_classOrInterfaceType); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(603); + match(IDENTIFIER); + setState(605); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,60,_ctx) ) { + case 1: + { + setState(604); + typeArguments(); + } + break; + } + setState(614); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,62,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(607); + match(DOT); + setState(608); + match(IDENTIFIER); + setState(610); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,61,_ctx) ) { + case 1: + { + setState(609); + typeArguments(); + } + break; + } + } + } + } + setState(616); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,62,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeArgumentContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public TerminalNode QUESTION() { return getToken(JavaParser.QUESTION, 0); } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public TerminalNode EXTENDS() { return getToken(JavaParser.EXTENDS, 0); } + public TerminalNode SUPER() { return getToken(JavaParser.SUPER, 0); } + public TypeArgumentContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeArgument; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeArgument(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeArgument(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeArgument(this); + else return visitor.visitChildren(this); + } + } + + public final TypeArgumentContext typeArgument() throws RecognitionException { + TypeArgumentContext _localctx = new TypeArgumentContext(_ctx, getState()); + enterRule(_localctx, 80, RULE_typeArgument); + int _la; + try { + setState(629); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,65,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(617); + typeType(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(621); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==AT || _la==IDENTIFIER) { + { + { + setState(618); + annotation(); + } + } + setState(623); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(624); + match(QUESTION); + setState(627); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==EXTENDS || _la==SUPER) { + { + setState(625); + _la = _input.LA(1); + if ( !(_la==EXTENDS || _la==SUPER) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(626); + typeType(); + } + } + + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class QualifiedNameListContext extends ParserRuleContext { + public List qualifiedName() { + return getRuleContexts(QualifiedNameContext.class); + } + public QualifiedNameContext qualifiedName(int i) { + return getRuleContext(QualifiedNameContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public QualifiedNameListContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_qualifiedNameList; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterQualifiedNameList(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitQualifiedNameList(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitQualifiedNameList(this); + else return visitor.visitChildren(this); + } + } + + public final QualifiedNameListContext qualifiedNameList() throws RecognitionException { + QualifiedNameListContext _localctx = new QualifiedNameListContext(_ctx, getState()); + enterRule(_localctx, 82, RULE_qualifiedNameList); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(631); + qualifiedName(); + setState(636); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(632); + match(COMMA); + setState(633); + qualifiedName(); + } + } + setState(638); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FormalParametersContext extends ParserRuleContext { + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public FormalParameterListContext formalParameterList() { + return getRuleContext(FormalParameterListContext.class,0); + } + public FormalParametersContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_formalParameters; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFormalParameters(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFormalParameters(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFormalParameters(this); + else return visitor.visitChildren(this); + } + } + + public final FormalParametersContext formalParameters() throws RecognitionException { + FormalParametersContext _localctx = new FormalParametersContext(_ctx, getState()); + enterRule(_localctx, 84, RULE_formalParameters); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(639); + match(LPAREN); + setState(641); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << SHORT))) != 0) || _la==AT || _la==IDENTIFIER) { + { + setState(640); + formalParameterList(); + } + } + + setState(643); + match(RPAREN); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FormalParameterListContext extends ParserRuleContext { + public List formalParameter() { + return getRuleContexts(FormalParameterContext.class); + } + public FormalParameterContext formalParameter(int i) { + return getRuleContext(FormalParameterContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public LastFormalParameterContext lastFormalParameter() { + return getRuleContext(LastFormalParameterContext.class,0); + } + public FormalParameterListContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_formalParameterList; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFormalParameterList(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFormalParameterList(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFormalParameterList(this); + else return visitor.visitChildren(this); + } + } + + public final FormalParameterListContext formalParameterList() throws RecognitionException { + FormalParameterListContext _localctx = new FormalParameterListContext(_ctx, getState()); + enterRule(_localctx, 86, RULE_formalParameterList); + int _la; + try { + int _alt; + setState(658); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,70,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(645); + formalParameter(); + setState(650); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,68,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(646); + match(COMMA); + setState(647); + formalParameter(); + } + } + } + setState(652); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,68,_ctx); + } + setState(655); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==COMMA) { + { + setState(653); + match(COMMA); + setState(654); + lastFormalParameter(); + } + } + + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(657); + lastFormalParameter(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FormalParameterContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public VariableDeclaratorIdContext variableDeclaratorId() { + return getRuleContext(VariableDeclaratorIdContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public FormalParameterContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_formalParameter; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFormalParameter(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFormalParameter(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFormalParameter(this); + else return visitor.visitChildren(this); + } + } + + public final FormalParameterContext formalParameter() throws RecognitionException { + FormalParameterContext _localctx = new FormalParameterContext(_ctx, getState()); + enterRule(_localctx, 88, RULE_formalParameter); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(663); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,71,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(660); + variableModifier(); + } + } + } + setState(665); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,71,_ctx); + } + setState(666); + typeType(); + setState(667); + variableDeclaratorId(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LastFormalParameterContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public TerminalNode ELLIPSIS() { return getToken(JavaParser.ELLIPSIS, 0); } + public VariableDeclaratorIdContext variableDeclaratorId() { + return getRuleContext(VariableDeclaratorIdContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public LastFormalParameterContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_lastFormalParameter; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLastFormalParameter(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLastFormalParameter(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLastFormalParameter(this); + else return visitor.visitChildren(this); + } + } + + public final LastFormalParameterContext lastFormalParameter() throws RecognitionException { + LastFormalParameterContext _localctx = new LastFormalParameterContext(_ctx, getState()); + enterRule(_localctx, 90, RULE_lastFormalParameter); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(672); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,72,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(669); + variableModifier(); + } + } + } + setState(674); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,72,_ctx); + } + setState(675); + typeType(); + setState(679); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==AT || _la==IDENTIFIER) { + { + { + setState(676); + annotation(); + } + } + setState(681); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(682); + match(ELLIPSIS); + setState(683); + variableDeclaratorId(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class QualifiedNameContext extends ParserRuleContext { + public List IDENTIFIER() { return getTokens(JavaParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(JavaParser.IDENTIFIER, i); + } + public List DOT() { return getTokens(JavaParser.DOT); } + public TerminalNode DOT(int i) { + return getToken(JavaParser.DOT, i); + } + public QualifiedNameContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_qualifiedName; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterQualifiedName(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitQualifiedName(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitQualifiedName(this); + else return visitor.visitChildren(this); + } + } + + public final QualifiedNameContext qualifiedName() throws RecognitionException { + QualifiedNameContext _localctx = new QualifiedNameContext(_ctx, getState()); + enterRule(_localctx, 92, RULE_qualifiedName); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(685); + match(IDENTIFIER); + setState(690); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,74,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(686); + match(DOT); + setState(687); + match(IDENTIFIER); + } + } + } + setState(692); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,74,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LiteralContext extends ParserRuleContext { + public IntegerLiteralContext integerLiteral() { + return getRuleContext(IntegerLiteralContext.class,0); + } + public FloatLiteralContext floatLiteral() { + return getRuleContext(FloatLiteralContext.class,0); + } + public TerminalNode CHAR_LITERAL() { return getToken(JavaParser.CHAR_LITERAL, 0); } + public TerminalNode STRING_LITERAL() { return getToken(JavaParser.STRING_LITERAL, 0); } + public TerminalNode BOOL_LITERAL() { return getToken(JavaParser.BOOL_LITERAL, 0); } + public TerminalNode NULL_LITERAL() { return getToken(JavaParser.NULL_LITERAL, 0); } + public LiteralContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_literal; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLiteral(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLiteral(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLiteral(this); + else return visitor.visitChildren(this); + } + } + + public final LiteralContext literal() throws RecognitionException { + LiteralContext _localctx = new LiteralContext(_ctx, getState()); + enterRule(_localctx, 94, RULE_literal); + try { + setState(699); + _errHandler.sync(this); + switch (_input.LA(1)) { + case DECIMAL_LITERAL: + case HEX_LITERAL: + case OCT_LITERAL: + case BINARY_LITERAL: + enterOuterAlt(_localctx, 1); + { + setState(693); + integerLiteral(); + } + break; + case FLOAT_LITERAL: + case HEX_FLOAT_LITERAL: + enterOuterAlt(_localctx, 2); + { + setState(694); + floatLiteral(); + } + break; + case CHAR_LITERAL: + enterOuterAlt(_localctx, 3); + { + setState(695); + match(CHAR_LITERAL); + } + break; + case STRING_LITERAL: + enterOuterAlt(_localctx, 4); + { + setState(696); + match(STRING_LITERAL); + } + break; + case BOOL_LITERAL: + enterOuterAlt(_localctx, 5); + { + setState(697); + match(BOOL_LITERAL); + } + break; + case NULL_LITERAL: + enterOuterAlt(_localctx, 6); + { + setState(698); + match(NULL_LITERAL); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class IntegerLiteralContext extends ParserRuleContext { + public TerminalNode DECIMAL_LITERAL() { return getToken(JavaParser.DECIMAL_LITERAL, 0); } + public TerminalNode HEX_LITERAL() { return getToken(JavaParser.HEX_LITERAL, 0); } + public TerminalNode OCT_LITERAL() { return getToken(JavaParser.OCT_LITERAL, 0); } + public TerminalNode BINARY_LITERAL() { return getToken(JavaParser.BINARY_LITERAL, 0); } + public IntegerLiteralContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_integerLiteral; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterIntegerLiteral(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitIntegerLiteral(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitIntegerLiteral(this); + else return visitor.visitChildren(this); + } + } + + public final IntegerLiteralContext integerLiteral() throws RecognitionException { + IntegerLiteralContext _localctx = new IntegerLiteralContext(_ctx, getState()); + enterRule(_localctx, 96, RULE_integerLiteral); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(701); + _la = _input.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL))) != 0)) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FloatLiteralContext extends ParserRuleContext { + public TerminalNode FLOAT_LITERAL() { return getToken(JavaParser.FLOAT_LITERAL, 0); } + public TerminalNode HEX_FLOAT_LITERAL() { return getToken(JavaParser.HEX_FLOAT_LITERAL, 0); } + public FloatLiteralContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_floatLiteral; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFloatLiteral(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFloatLiteral(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFloatLiteral(this); + else return visitor.visitChildren(this); + } + } + + public final FloatLiteralContext floatLiteral() throws RecognitionException { + FloatLiteralContext _localctx = new FloatLiteralContext(_ctx, getState()); + enterRule(_localctx, 98, RULE_floatLiteral); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(703); + _la = _input.LA(1); + if ( !(_la==FLOAT_LITERAL || _la==HEX_FLOAT_LITERAL) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AltAnnotationQualifiedNameContext extends ParserRuleContext { + public TerminalNode AT() { return getToken(JavaParser.AT, 0); } + public List IDENTIFIER() { return getTokens(JavaParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(JavaParser.IDENTIFIER, i); + } + public List DOT() { return getTokens(JavaParser.DOT); } + public TerminalNode DOT(int i) { + return getToken(JavaParser.DOT, i); + } + public AltAnnotationQualifiedNameContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_altAnnotationQualifiedName; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAltAnnotationQualifiedName(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAltAnnotationQualifiedName(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAltAnnotationQualifiedName(this); + else return visitor.visitChildren(this); + } + } + + public final AltAnnotationQualifiedNameContext altAnnotationQualifiedName() throws RecognitionException { + AltAnnotationQualifiedNameContext _localctx = new AltAnnotationQualifiedNameContext(_ctx, getState()); + enterRule(_localctx, 100, RULE_altAnnotationQualifiedName); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(709); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==IDENTIFIER) { + { + { + setState(705); + match(IDENTIFIER); + setState(706); + match(DOT); + } + } + setState(711); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(712); + match(AT); + setState(713); + match(IDENTIFIER); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationContext extends ParserRuleContext { + public TerminalNode AT() { return getToken(JavaParser.AT, 0); } + public QualifiedNameContext qualifiedName() { + return getRuleContext(QualifiedNameContext.class,0); + } + public AltAnnotationQualifiedNameContext altAnnotationQualifiedName() { + return getRuleContext(AltAnnotationQualifiedNameContext.class,0); + } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public ElementValuePairsContext elementValuePairs() { + return getRuleContext(ElementValuePairsContext.class,0); + } + public ElementValueContext elementValue() { + return getRuleContext(ElementValueContext.class,0); + } + public AnnotationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotation; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotation(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotation(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotation(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationContext annotation() throws RecognitionException { + AnnotationContext _localctx = new AnnotationContext(_ctx, getState()); + enterRule(_localctx, 102, RULE_annotation); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(718); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,77,_ctx) ) { + case 1: + { + setState(715); + match(AT); + setState(716); + qualifiedName(); + } + break; + case 2: + { + setState(717); + altAnnotationQualifiedName(); + } + break; + } + setState(726); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LPAREN) { + { + setState(720); + match(LPAREN); + setState(723); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,78,_ctx) ) { + case 1: + { + setState(721); + elementValuePairs(); + } + break; + case 2: + { + setState(722); + elementValue(); + } + break; + } + setState(725); + match(RPAREN); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ElementValuePairsContext extends ParserRuleContext { + public List elementValuePair() { + return getRuleContexts(ElementValuePairContext.class); + } + public ElementValuePairContext elementValuePair(int i) { + return getRuleContext(ElementValuePairContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public ElementValuePairsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_elementValuePairs; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterElementValuePairs(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitElementValuePairs(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitElementValuePairs(this); + else return visitor.visitChildren(this); + } + } + + public final ElementValuePairsContext elementValuePairs() throws RecognitionException { + ElementValuePairsContext _localctx = new ElementValuePairsContext(_ctx, getState()); + enterRule(_localctx, 104, RULE_elementValuePairs); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(728); + elementValuePair(); + setState(733); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(729); + match(COMMA); + setState(730); + elementValuePair(); + } + } + setState(735); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ElementValuePairContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode ASSIGN() { return getToken(JavaParser.ASSIGN, 0); } + public ElementValueContext elementValue() { + return getRuleContext(ElementValueContext.class,0); + } + public ElementValuePairContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_elementValuePair; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterElementValuePair(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitElementValuePair(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitElementValuePair(this); + else return visitor.visitChildren(this); + } + } + + public final ElementValuePairContext elementValuePair() throws RecognitionException { + ElementValuePairContext _localctx = new ElementValuePairContext(_ctx, getState()); + enterRule(_localctx, 106, RULE_elementValuePair); + try { + enterOuterAlt(_localctx, 1); + { + setState(736); + match(IDENTIFIER); + setState(737); + match(ASSIGN); + setState(738); + elementValue(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ElementValueContext extends ParserRuleContext { + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public AnnotationContext annotation() { + return getRuleContext(AnnotationContext.class,0); + } + public ElementValueArrayInitializerContext elementValueArrayInitializer() { + return getRuleContext(ElementValueArrayInitializerContext.class,0); + } + public ElementValueContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_elementValue; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterElementValue(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitElementValue(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitElementValue(this); + else return visitor.visitChildren(this); + } + } + + public final ElementValueContext elementValue() throws RecognitionException { + ElementValueContext _localctx = new ElementValueContext(_ctx, getState()); + enterRule(_localctx, 108, RULE_elementValue); + try { + setState(743); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,81,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(740); + expression(0); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(741); + annotation(); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(742); + elementValueArrayInitializer(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ElementValueArrayInitializerContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List elementValue() { + return getRuleContexts(ElementValueContext.class); + } + public ElementValueContext elementValue(int i) { + return getRuleContext(ElementValueContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public ElementValueArrayInitializerContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_elementValueArrayInitializer; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterElementValueArrayInitializer(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitElementValueArrayInitializer(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitElementValueArrayInitializer(this); + else return visitor.visitChildren(this); + } + } + + public final ElementValueArrayInitializerContext elementValueArrayInitializer() throws RecognitionException { + ElementValueArrayInitializerContext _localctx = new ElementValueArrayInitializerContext(_ctx, getState()); + enterRule(_localctx, 110, RULE_elementValueArrayInitializer); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(745); + match(LBRACE); + setState(754); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN) | (1L << LBRACE))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(746); + elementValue(); + setState(751); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,82,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(747); + match(COMMA); + setState(748); + elementValue(); + } + } + } + setState(753); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,82,_ctx); + } + } + } + + setState(757); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==COMMA) { + { + setState(756); + match(COMMA); + } + } + + setState(759); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationTypeDeclarationContext extends ParserRuleContext { + public TerminalNode AT() { return getToken(JavaParser.AT, 0); } + public TerminalNode INTERFACE() { return getToken(JavaParser.INTERFACE, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public AnnotationTypeBodyContext annotationTypeBody() { + return getRuleContext(AnnotationTypeBodyContext.class,0); + } + public AnnotationTypeDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationTypeDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationTypeDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationTypeDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationTypeDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationTypeDeclarationContext annotationTypeDeclaration() throws RecognitionException { + AnnotationTypeDeclarationContext _localctx = new AnnotationTypeDeclarationContext(_ctx, getState()); + enterRule(_localctx, 112, RULE_annotationTypeDeclaration); + try { + enterOuterAlt(_localctx, 1); + { + setState(761); + match(AT); + setState(762); + match(INTERFACE); + setState(763); + match(IDENTIFIER); + setState(764); + annotationTypeBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationTypeBodyContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List annotationTypeElementDeclaration() { + return getRuleContexts(AnnotationTypeElementDeclarationContext.class); + } + public AnnotationTypeElementDeclarationContext annotationTypeElementDeclaration(int i) { + return getRuleContext(AnnotationTypeElementDeclarationContext.class,i); + } + public AnnotationTypeBodyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationTypeBody; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationTypeBody(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationTypeBody(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationTypeBody(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationTypeBodyContext annotationTypeBody() throws RecognitionException { + AnnotationTypeBodyContext _localctx = new AnnotationTypeBodyContext(_ctx, getState()); + enterRule(_localctx, 114, RULE_annotationTypeBody); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(766); + match(LBRACE); + setState(770); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << DOUBLE) | (1L << ENUM) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NATIVE) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SYNCHRONIZED) | (1L << TRANSIENT) | (1L << VOLATILE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(767); + annotationTypeElementDeclaration(); + } + } + setState(772); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(773); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationTypeElementDeclarationContext extends ParserRuleContext { + public AnnotationTypeElementRestContext annotationTypeElementRest() { + return getRuleContext(AnnotationTypeElementRestContext.class,0); + } + public List modifier() { + return getRuleContexts(ModifierContext.class); + } + public ModifierContext modifier(int i) { + return getRuleContext(ModifierContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public AnnotationTypeElementDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationTypeElementDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationTypeElementDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationTypeElementDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationTypeElementDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationTypeElementDeclarationContext annotationTypeElementDeclaration() throws RecognitionException { + AnnotationTypeElementDeclarationContext _localctx = new AnnotationTypeElementDeclarationContext(_ctx, getState()); + enterRule(_localctx, 116, RULE_annotationTypeElementDeclaration); + try { + int _alt; + setState(783); + _errHandler.sync(this); + switch (_input.LA(1)) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(778); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,86,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(775); + modifier(); + } + } + } + setState(780); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,86,_ctx); + } + setState(781); + annotationTypeElementRest(); + } + break; + case SEMI: + enterOuterAlt(_localctx, 2); + { + setState(782); + match(SEMI); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationTypeElementRestContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public AnnotationMethodOrConstantRestContext annotationMethodOrConstantRest() { + return getRuleContext(AnnotationMethodOrConstantRestContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public ClassDeclarationContext classDeclaration() { + return getRuleContext(ClassDeclarationContext.class,0); + } + public InterfaceDeclarationContext interfaceDeclaration() { + return getRuleContext(InterfaceDeclarationContext.class,0); + } + public EnumDeclarationContext enumDeclaration() { + return getRuleContext(EnumDeclarationContext.class,0); + } + public AnnotationTypeDeclarationContext annotationTypeDeclaration() { + return getRuleContext(AnnotationTypeDeclarationContext.class,0); + } + public AnnotationTypeElementRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationTypeElementRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationTypeElementRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationTypeElementRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationTypeElementRest(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationTypeElementRestContext annotationTypeElementRest() throws RecognitionException { + AnnotationTypeElementRestContext _localctx = new AnnotationTypeElementRestContext(_ctx, getState()); + enterRule(_localctx, 118, RULE_annotationTypeElementRest); + try { + setState(805); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,92,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(785); + typeType(); + setState(786); + annotationMethodOrConstantRest(); + setState(787); + match(SEMI); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(789); + classDeclaration(); + setState(791); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,88,_ctx) ) { + case 1: + { + setState(790); + match(SEMI); + } + break; + } + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(793); + interfaceDeclaration(); + setState(795); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,89,_ctx) ) { + case 1: + { + setState(794); + match(SEMI); + } + break; + } + } + break; + case 4: + enterOuterAlt(_localctx, 4); + { + setState(797); + enumDeclaration(); + setState(799); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,90,_ctx) ) { + case 1: + { + setState(798); + match(SEMI); + } + break; + } + } + break; + case 5: + enterOuterAlt(_localctx, 5); + { + setState(801); + annotationTypeDeclaration(); + setState(803); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,91,_ctx) ) { + case 1: + { + setState(802); + match(SEMI); + } + break; + } + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationMethodOrConstantRestContext extends ParserRuleContext { + public AnnotationMethodRestContext annotationMethodRest() { + return getRuleContext(AnnotationMethodRestContext.class,0); + } + public AnnotationConstantRestContext annotationConstantRest() { + return getRuleContext(AnnotationConstantRestContext.class,0); + } + public AnnotationMethodOrConstantRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationMethodOrConstantRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationMethodOrConstantRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationMethodOrConstantRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationMethodOrConstantRest(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationMethodOrConstantRestContext annotationMethodOrConstantRest() throws RecognitionException { + AnnotationMethodOrConstantRestContext _localctx = new AnnotationMethodOrConstantRestContext(_ctx, getState()); + enterRule(_localctx, 120, RULE_annotationMethodOrConstantRest); + try { + setState(809); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,93,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(807); + annotationMethodRest(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(808); + annotationConstantRest(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationMethodRestContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public DefaultValueContext defaultValue() { + return getRuleContext(DefaultValueContext.class,0); + } + public AnnotationMethodRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationMethodRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationMethodRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationMethodRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationMethodRest(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationMethodRestContext annotationMethodRest() throws RecognitionException { + AnnotationMethodRestContext _localctx = new AnnotationMethodRestContext(_ctx, getState()); + enterRule(_localctx, 122, RULE_annotationMethodRest); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(811); + match(IDENTIFIER); + setState(812); + match(LPAREN); + setState(813); + match(RPAREN); + setState(815); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==DEFAULT) { + { + setState(814); + defaultValue(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class AnnotationConstantRestContext extends ParserRuleContext { + public VariableDeclaratorsContext variableDeclarators() { + return getRuleContext(VariableDeclaratorsContext.class,0); + } + public AnnotationConstantRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_annotationConstantRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterAnnotationConstantRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitAnnotationConstantRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitAnnotationConstantRest(this); + else return visitor.visitChildren(this); + } + } + + public final AnnotationConstantRestContext annotationConstantRest() throws RecognitionException { + AnnotationConstantRestContext _localctx = new AnnotationConstantRestContext(_ctx, getState()); + enterRule(_localctx, 124, RULE_annotationConstantRest); + try { + enterOuterAlt(_localctx, 1); + { + setState(817); + variableDeclarators(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class DefaultValueContext extends ParserRuleContext { + public TerminalNode DEFAULT() { return getToken(JavaParser.DEFAULT, 0); } + public ElementValueContext elementValue() { + return getRuleContext(ElementValueContext.class,0); + } + public DefaultValueContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_defaultValue; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterDefaultValue(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitDefaultValue(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitDefaultValue(this); + else return visitor.visitChildren(this); + } + } + + public final DefaultValueContext defaultValue() throws RecognitionException { + DefaultValueContext _localctx = new DefaultValueContext(_ctx, getState()); + enterRule(_localctx, 126, RULE_defaultValue); + try { + enterOuterAlt(_localctx, 1); + { + setState(819); + match(DEFAULT); + setState(820); + elementValue(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class BlockContext extends ParserRuleContext { + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List blockStatement() { + return getRuleContexts(BlockStatementContext.class); + } + public BlockStatementContext blockStatement(int i) { + return getRuleContext(BlockStatementContext.class,i); + } + public BlockContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_block; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterBlock(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitBlock(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitBlock(this); + else return visitor.visitChildren(this); + } + } + + public final BlockContext block() throws RecognitionException { + BlockContext _localctx = new BlockContext(_ctx, getState()); + enterRule(_localctx, 128, RULE_block); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(822); + match(LBRACE); + setState(826); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << ASSERT) | (1L << BOOLEAN) | (1L << BREAK) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << CONTINUE) | (1L << DO) | (1L << DOUBLE) | (1L << FINAL) | (1L << FLOAT) | (1L << FOR) | (1L << IF) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NEW) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << RETURN) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SUPER) | (1L << SWITCH) | (1L << SYNCHRONIZED) | (1L << THIS) | (1L << THROW) | (1L << TRY) | (1L << VOID) | (1L << WHILE) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN) | (1L << LBRACE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (LT - 67)) | (1L << (BANG - 67)) | (1L << (TILDE - 67)) | (1L << (INC - 67)) | (1L << (DEC - 67)) | (1L << (ADD - 67)) | (1L << (SUB - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0)) { + { + { + setState(823); + blockStatement(); + } + } + setState(828); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(829); + match(RBRACE); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class BlockStatementContext extends ParserRuleContext { + public LocalVariableDeclarationContext localVariableDeclaration() { + return getRuleContext(LocalVariableDeclarationContext.class,0); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public StatementContext statement() { + return getRuleContext(StatementContext.class,0); + } + public LocalTypeDeclarationContext localTypeDeclaration() { + return getRuleContext(LocalTypeDeclarationContext.class,0); + } + public BlockStatementContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_blockStatement; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterBlockStatement(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitBlockStatement(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitBlockStatement(this); + else return visitor.visitChildren(this); + } + } + + public final BlockStatementContext blockStatement() throws RecognitionException { + BlockStatementContext _localctx = new BlockStatementContext(_ctx, getState()); + enterRule(_localctx, 130, RULE_blockStatement); + try { + setState(836); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,96,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(831); + localVariableDeclaration(); + setState(832); + match(SEMI); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(834); + statement(); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(835); + localTypeDeclaration(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LocalVariableDeclarationContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public VariableDeclaratorsContext variableDeclarators() { + return getRuleContext(VariableDeclaratorsContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public LocalVariableDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_localVariableDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLocalVariableDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLocalVariableDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLocalVariableDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final LocalVariableDeclarationContext localVariableDeclaration() throws RecognitionException { + LocalVariableDeclarationContext _localctx = new LocalVariableDeclarationContext(_ctx, getState()); + enterRule(_localctx, 132, RULE_localVariableDeclaration); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(841); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,97,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(838); + variableModifier(); + } + } + } + setState(843); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,97,_ctx); + } + setState(844); + typeType(); + setState(845); + variableDeclarators(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LocalTypeDeclarationContext extends ParserRuleContext { + public ClassDeclarationContext classDeclaration() { + return getRuleContext(ClassDeclarationContext.class,0); + } + public InterfaceDeclarationContext interfaceDeclaration() { + return getRuleContext(InterfaceDeclarationContext.class,0); + } + public List classOrInterfaceModifier() { + return getRuleContexts(ClassOrInterfaceModifierContext.class); + } + public ClassOrInterfaceModifierContext classOrInterfaceModifier(int i) { + return getRuleContext(ClassOrInterfaceModifierContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public LocalTypeDeclarationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_localTypeDeclaration; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLocalTypeDeclaration(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLocalTypeDeclaration(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLocalTypeDeclaration(this); + else return visitor.visitChildren(this); + } + } + + public final LocalTypeDeclarationContext localTypeDeclaration() throws RecognitionException { + LocalTypeDeclarationContext _localctx = new LocalTypeDeclarationContext(_ctx, getState()); + enterRule(_localctx, 134, RULE_localTypeDeclaration); + int _la; + try { + setState(858); + _errHandler.sync(this); + switch (_input.LA(1)) { + case ABSTRACT: + case CLASS: + case FINAL: + case INTERFACE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(850); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << FINAL) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << STATIC) | (1L << STRICTFP))) != 0) || _la==AT || _la==IDENTIFIER) { + { + { + setState(847); + classOrInterfaceModifier(); + } + } + setState(852); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(855); + _errHandler.sync(this); + switch (_input.LA(1)) { + case CLASS: + { + setState(853); + classDeclaration(); + } + break; + case INTERFACE: + { + setState(854); + interfaceDeclaration(); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + case SEMI: + enterOuterAlt(_localctx, 2); + { + setState(857); + match(SEMI); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class StatementContext extends ParserRuleContext { + public BlockContext blockLabel; + public ExpressionContext statementExpression; + public Token identifierLabel; + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public TerminalNode ASSERT() { return getToken(JavaParser.ASSERT, 0); } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public TerminalNode COLON() { return getToken(JavaParser.COLON, 0); } + public TerminalNode IF() { return getToken(JavaParser.IF, 0); } + public ParExpressionContext parExpression() { + return getRuleContext(ParExpressionContext.class,0); + } + public List statement() { + return getRuleContexts(StatementContext.class); + } + public StatementContext statement(int i) { + return getRuleContext(StatementContext.class,i); + } + public TerminalNode ELSE() { return getToken(JavaParser.ELSE, 0); } + public TerminalNode FOR() { return getToken(JavaParser.FOR, 0); } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public ForControlContext forControl() { + return getRuleContext(ForControlContext.class,0); + } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public TerminalNode WHILE() { return getToken(JavaParser.WHILE, 0); } + public TerminalNode DO() { return getToken(JavaParser.DO, 0); } + public TerminalNode TRY() { return getToken(JavaParser.TRY, 0); } + public FinallyBlockContext finallyBlock() { + return getRuleContext(FinallyBlockContext.class,0); + } + public List catchClause() { + return getRuleContexts(CatchClauseContext.class); + } + public CatchClauseContext catchClause(int i) { + return getRuleContext(CatchClauseContext.class,i); + } + public ResourceSpecificationContext resourceSpecification() { + return getRuleContext(ResourceSpecificationContext.class,0); + } + public TerminalNode SWITCH() { return getToken(JavaParser.SWITCH, 0); } + public TerminalNode LBRACE() { return getToken(JavaParser.LBRACE, 0); } + public TerminalNode RBRACE() { return getToken(JavaParser.RBRACE, 0); } + public List switchBlockStatementGroup() { + return getRuleContexts(SwitchBlockStatementGroupContext.class); + } + public SwitchBlockStatementGroupContext switchBlockStatementGroup(int i) { + return getRuleContext(SwitchBlockStatementGroupContext.class,i); + } + public List switchLabel() { + return getRuleContexts(SwitchLabelContext.class); + } + public SwitchLabelContext switchLabel(int i) { + return getRuleContext(SwitchLabelContext.class,i); + } + public TerminalNode SYNCHRONIZED() { return getToken(JavaParser.SYNCHRONIZED, 0); } + public TerminalNode RETURN() { return getToken(JavaParser.RETURN, 0); } + public TerminalNode THROW() { return getToken(JavaParser.THROW, 0); } + public TerminalNode BREAK() { return getToken(JavaParser.BREAK, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode CONTINUE() { return getToken(JavaParser.CONTINUE, 0); } + public StatementContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_statement; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterStatement(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitStatement(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitStatement(this); + else return visitor.visitChildren(this); + } + } + + public final StatementContext statement() throws RecognitionException { + StatementContext _localctx = new StatementContext(_ctx, getState()); + enterRule(_localctx, 136, RULE_statement); + int _la; + try { + int _alt; + setState(964); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,113,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(860); + ((StatementContext)_localctx).blockLabel = block(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(861); + match(ASSERT); + setState(862); + expression(0); + setState(865); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==COLON) { + { + setState(863); + match(COLON); + setState(864); + expression(0); + } + } + + setState(867); + match(SEMI); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(869); + match(IF); + setState(870); + parExpression(); + setState(871); + statement(); + setState(874); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,102,_ctx) ) { + case 1: + { + setState(872); + match(ELSE); + setState(873); + statement(); + } + break; + } + } + break; + case 4: + enterOuterAlt(_localctx, 4); + { + setState(876); + match(FOR); + setState(877); + match(LPAREN); + setState(878); + forControl(); + setState(879); + match(RPAREN); + setState(880); + statement(); + } + break; + case 5: + enterOuterAlt(_localctx, 5); + { + setState(882); + match(WHILE); + setState(883); + parExpression(); + setState(884); + statement(); + } + break; + case 6: + enterOuterAlt(_localctx, 6); + { + setState(886); + match(DO); + setState(887); + statement(); + setState(888); + match(WHILE); + setState(889); + parExpression(); + setState(890); + match(SEMI); + } + break; + case 7: + enterOuterAlt(_localctx, 7); + { + setState(892); + match(TRY); + setState(893); + block(); + setState(903); + _errHandler.sync(this); + switch (_input.LA(1)) { + case CATCH: + { + setState(895); + _errHandler.sync(this); + _la = _input.LA(1); + do { + { + { + setState(894); + catchClause(); + } + } + setState(897); + _errHandler.sync(this); + _la = _input.LA(1); + } while ( _la==CATCH ); + setState(900); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==FINALLY) { + { + setState(899); + finallyBlock(); + } + } + + } + break; + case FINALLY: + { + setState(902); + finallyBlock(); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + case 8: + enterOuterAlt(_localctx, 8); + { + setState(905); + match(TRY); + setState(906); + resourceSpecification(); + setState(907); + block(); + setState(911); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==CATCH) { + { + { + setState(908); + catchClause(); + } + } + setState(913); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(915); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==FINALLY) { + { + setState(914); + finallyBlock(); + } + } + + } + break; + case 9: + enterOuterAlt(_localctx, 9); + { + setState(917); + match(SWITCH); + setState(918); + parExpression(); + setState(919); + match(LBRACE); + setState(923); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,108,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(920); + switchBlockStatementGroup(); + } + } + } + setState(925); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,108,_ctx); + } + setState(929); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==CASE || _la==DEFAULT) { + { + { + setState(926); + switchLabel(); + } + } + setState(931); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(932); + match(RBRACE); + } + break; + case 10: + enterOuterAlt(_localctx, 10); + { + setState(934); + match(SYNCHRONIZED); + setState(935); + parExpression(); + setState(936); + block(); + } + break; + case 11: + enterOuterAlt(_localctx, 11); + { + setState(938); + match(RETURN); + setState(940); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(939); + expression(0); + } + } + + setState(942); + match(SEMI); + } + break; + case 12: + enterOuterAlt(_localctx, 12); + { + setState(943); + match(THROW); + setState(944); + expression(0); + setState(945); + match(SEMI); + } + break; + case 13: + enterOuterAlt(_localctx, 13); + { + setState(947); + match(BREAK); + setState(949); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==IDENTIFIER) { + { + setState(948); + match(IDENTIFIER); + } + } + + setState(951); + match(SEMI); + } + break; + case 14: + enterOuterAlt(_localctx, 14); + { + setState(952); + match(CONTINUE); + setState(954); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==IDENTIFIER) { + { + setState(953); + match(IDENTIFIER); + } + } + + setState(956); + match(SEMI); + } + break; + case 15: + enterOuterAlt(_localctx, 15); + { + setState(957); + match(SEMI); + } + break; + case 16: + enterOuterAlt(_localctx, 16); + { + setState(958); + ((StatementContext)_localctx).statementExpression = expression(0); + setState(959); + match(SEMI); + } + break; + case 17: + enterOuterAlt(_localctx, 17); + { + setState(961); + ((StatementContext)_localctx).identifierLabel = match(IDENTIFIER); + setState(962); + match(COLON); + setState(963); + statement(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class CatchClauseContext extends ParserRuleContext { + public TerminalNode CATCH() { return getToken(JavaParser.CATCH, 0); } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public CatchTypeContext catchType() { + return getRuleContext(CatchTypeContext.class,0); + } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public CatchClauseContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_catchClause; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterCatchClause(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitCatchClause(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitCatchClause(this); + else return visitor.visitChildren(this); + } + } + + public final CatchClauseContext catchClause() throws RecognitionException { + CatchClauseContext _localctx = new CatchClauseContext(_ctx, getState()); + enterRule(_localctx, 138, RULE_catchClause); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(966); + match(CATCH); + setState(967); + match(LPAREN); + setState(971); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,114,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(968); + variableModifier(); + } + } + } + setState(973); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,114,_ctx); + } + setState(974); + catchType(); + setState(975); + match(IDENTIFIER); + setState(976); + match(RPAREN); + setState(977); + block(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class CatchTypeContext extends ParserRuleContext { + public List qualifiedName() { + return getRuleContexts(QualifiedNameContext.class); + } + public QualifiedNameContext qualifiedName(int i) { + return getRuleContext(QualifiedNameContext.class,i); + } + public List BITOR() { return getTokens(JavaParser.BITOR); } + public TerminalNode BITOR(int i) { + return getToken(JavaParser.BITOR, i); + } + public CatchTypeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_catchType; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterCatchType(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitCatchType(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitCatchType(this); + else return visitor.visitChildren(this); + } + } + + public final CatchTypeContext catchType() throws RecognitionException { + CatchTypeContext _localctx = new CatchTypeContext(_ctx, getState()); + enterRule(_localctx, 140, RULE_catchType); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(979); + qualifiedName(); + setState(984); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==BITOR) { + { + { + setState(980); + match(BITOR); + setState(981); + qualifiedName(); + } + } + setState(986); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FinallyBlockContext extends ParserRuleContext { + public TerminalNode FINALLY() { return getToken(JavaParser.FINALLY, 0); } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public FinallyBlockContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_finallyBlock; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterFinallyBlock(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitFinallyBlock(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitFinallyBlock(this); + else return visitor.visitChildren(this); + } + } + + public final FinallyBlockContext finallyBlock() throws RecognitionException { + FinallyBlockContext _localctx = new FinallyBlockContext(_ctx, getState()); + enterRule(_localctx, 142, RULE_finallyBlock); + try { + enterOuterAlt(_localctx, 1); + { + setState(987); + match(FINALLY); + setState(988); + block(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ResourceSpecificationContext extends ParserRuleContext { + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public ResourcesContext resources() { + return getRuleContext(ResourcesContext.class,0); + } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public TerminalNode SEMI() { return getToken(JavaParser.SEMI, 0); } + public ResourceSpecificationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_resourceSpecification; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterResourceSpecification(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitResourceSpecification(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitResourceSpecification(this); + else return visitor.visitChildren(this); + } + } + + public final ResourceSpecificationContext resourceSpecification() throws RecognitionException { + ResourceSpecificationContext _localctx = new ResourceSpecificationContext(_ctx, getState()); + enterRule(_localctx, 144, RULE_resourceSpecification); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(990); + match(LPAREN); + setState(991); + resources(); + setState(993); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==SEMI) { + { + setState(992); + match(SEMI); + } + } + + setState(995); + match(RPAREN); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ResourcesContext extends ParserRuleContext { + public List resource() { + return getRuleContexts(ResourceContext.class); + } + public ResourceContext resource(int i) { + return getRuleContext(ResourceContext.class,i); + } + public List SEMI() { return getTokens(JavaParser.SEMI); } + public TerminalNode SEMI(int i) { + return getToken(JavaParser.SEMI, i); + } + public ResourcesContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_resources; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterResources(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitResources(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitResources(this); + else return visitor.visitChildren(this); + } + } + + public final ResourcesContext resources() throws RecognitionException { + ResourcesContext _localctx = new ResourcesContext(_ctx, getState()); + enterRule(_localctx, 146, RULE_resources); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(997); + resource(); + setState(1002); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,117,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(998); + match(SEMI); + setState(999); + resource(); + } + } + } + setState(1004); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,117,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ResourceContext extends ParserRuleContext { + public ClassOrInterfaceTypeContext classOrInterfaceType() { + return getRuleContext(ClassOrInterfaceTypeContext.class,0); + } + public VariableDeclaratorIdContext variableDeclaratorId() { + return getRuleContext(VariableDeclaratorIdContext.class,0); + } + public TerminalNode ASSIGN() { return getToken(JavaParser.ASSIGN, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public ResourceContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_resource; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterResource(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitResource(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitResource(this); + else return visitor.visitChildren(this); + } + } + + public final ResourceContext resource() throws RecognitionException { + ResourceContext _localctx = new ResourceContext(_ctx, getState()); + enterRule(_localctx, 148, RULE_resource); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1008); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,118,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1005); + variableModifier(); + } + } + } + setState(1010); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,118,_ctx); + } + setState(1011); + classOrInterfaceType(); + setState(1012); + variableDeclaratorId(); + setState(1013); + match(ASSIGN); + setState(1014); + expression(0); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class SwitchBlockStatementGroupContext extends ParserRuleContext { + public List switchLabel() { + return getRuleContexts(SwitchLabelContext.class); + } + public SwitchLabelContext switchLabel(int i) { + return getRuleContext(SwitchLabelContext.class,i); + } + public List blockStatement() { + return getRuleContexts(BlockStatementContext.class); + } + public BlockStatementContext blockStatement(int i) { + return getRuleContext(BlockStatementContext.class,i); + } + public SwitchBlockStatementGroupContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_switchBlockStatementGroup; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterSwitchBlockStatementGroup(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitSwitchBlockStatementGroup(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitSwitchBlockStatementGroup(this); + else return visitor.visitChildren(this); + } + } + + public final SwitchBlockStatementGroupContext switchBlockStatementGroup() throws RecognitionException { + SwitchBlockStatementGroupContext _localctx = new SwitchBlockStatementGroupContext(_ctx, getState()); + enterRule(_localctx, 150, RULE_switchBlockStatementGroup); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1017); + _errHandler.sync(this); + _la = _input.LA(1); + do { + { + { + setState(1016); + switchLabel(); + } + } + setState(1019); + _errHandler.sync(this); + _la = _input.LA(1); + } while ( _la==CASE || _la==DEFAULT ); + setState(1022); + _errHandler.sync(this); + _la = _input.LA(1); + do { + { + { + setState(1021); + blockStatement(); + } + } + setState(1024); + _errHandler.sync(this); + _la = _input.LA(1); + } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ABSTRACT) | (1L << ASSERT) | (1L << BOOLEAN) | (1L << BREAK) | (1L << BYTE) | (1L << CHAR) | (1L << CLASS) | (1L << CONTINUE) | (1L << DO) | (1L << DOUBLE) | (1L << FINAL) | (1L << FLOAT) | (1L << FOR) | (1L << IF) | (1L << INT) | (1L << INTERFACE) | (1L << LONG) | (1L << NEW) | (1L << PRIVATE) | (1L << PROTECTED) | (1L << PUBLIC) | (1L << RETURN) | (1L << SHORT) | (1L << STATIC) | (1L << STRICTFP) | (1L << SUPER) | (1L << SWITCH) | (1L << SYNCHRONIZED) | (1L << THIS) | (1L << THROW) | (1L << TRY) | (1L << VOID) | (1L << WHILE) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN) | (1L << LBRACE))) != 0) || ((((_la - 67)) & ~0x3f) == 0 && ((1L << (_la - 67)) & ((1L << (SEMI - 67)) | (1L << (LT - 67)) | (1L << (BANG - 67)) | (1L << (TILDE - 67)) | (1L << (INC - 67)) | (1L << (DEC - 67)) | (1L << (ADD - 67)) | (1L << (SUB - 67)) | (1L << (AT - 67)) | (1L << (IDENTIFIER - 67)))) != 0) ); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class SwitchLabelContext extends ParserRuleContext { + public ExpressionContext constantExpression; + public Token enumConstantName; + public TerminalNode CASE() { return getToken(JavaParser.CASE, 0); } + public TerminalNode COLON() { return getToken(JavaParser.COLON, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode DEFAULT() { return getToken(JavaParser.DEFAULT, 0); } + public SwitchLabelContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_switchLabel; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterSwitchLabel(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitSwitchLabel(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitSwitchLabel(this); + else return visitor.visitChildren(this); + } + } + + public final SwitchLabelContext switchLabel() throws RecognitionException { + SwitchLabelContext _localctx = new SwitchLabelContext(_ctx, getState()); + enterRule(_localctx, 152, RULE_switchLabel); + try { + setState(1034); + _errHandler.sync(this); + switch (_input.LA(1)) { + case CASE: + enterOuterAlt(_localctx, 1); + { + setState(1026); + match(CASE); + setState(1029); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,121,_ctx) ) { + case 1: + { + setState(1027); + ((SwitchLabelContext)_localctx).constantExpression = expression(0); + } + break; + case 2: + { + setState(1028); + ((SwitchLabelContext)_localctx).enumConstantName = match(IDENTIFIER); + } + break; + } + setState(1031); + match(COLON); + } + break; + case DEFAULT: + enterOuterAlt(_localctx, 2); + { + setState(1032); + match(DEFAULT); + setState(1033); + match(COLON); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ForControlContext extends ParserRuleContext { + public ExpressionListContext forUpdate; + public EnhancedForControlContext enhancedForControl() { + return getRuleContext(EnhancedForControlContext.class,0); + } + public List SEMI() { return getTokens(JavaParser.SEMI); } + public TerminalNode SEMI(int i) { + return getToken(JavaParser.SEMI, i); + } + public ForInitContext forInit() { + return getRuleContext(ForInitContext.class,0); + } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public ExpressionListContext expressionList() { + return getRuleContext(ExpressionListContext.class,0); + } + public ForControlContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_forControl; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterForControl(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitForControl(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitForControl(this); + else return visitor.visitChildren(this); + } + } + + public final ForControlContext forControl() throws RecognitionException { + ForControlContext _localctx = new ForControlContext(_ctx, getState()); + enterRule(_localctx, 154, RULE_forControl); + int _la; + try { + setState(1048); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,126,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1036); + enhancedForControl(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1038); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1037); + forInit(); + } + } + + setState(1040); + match(SEMI); + setState(1042); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1041); + expression(0); + } + } + + setState(1044); + match(SEMI); + setState(1046); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1045); + ((ForControlContext)_localctx).forUpdate = expressionList(); + } + } + + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ForInitContext extends ParserRuleContext { + public LocalVariableDeclarationContext localVariableDeclaration() { + return getRuleContext(LocalVariableDeclarationContext.class,0); + } + public ExpressionListContext expressionList() { + return getRuleContext(ExpressionListContext.class,0); + } + public ForInitContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_forInit; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterForInit(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitForInit(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitForInit(this); + else return visitor.visitChildren(this); + } + } + + public final ForInitContext forInit() throws RecognitionException { + ForInitContext _localctx = new ForInitContext(_ctx, getState()); + enterRule(_localctx, 156, RULE_forInit); + try { + setState(1052); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,127,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1050); + localVariableDeclaration(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1051); + expressionList(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EnhancedForControlContext extends ParserRuleContext { + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public VariableDeclaratorIdContext variableDeclaratorId() { + return getRuleContext(VariableDeclaratorIdContext.class,0); + } + public TerminalNode COLON() { return getToken(JavaParser.COLON, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public List variableModifier() { + return getRuleContexts(VariableModifierContext.class); + } + public VariableModifierContext variableModifier(int i) { + return getRuleContext(VariableModifierContext.class,i); + } + public EnhancedForControlContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_enhancedForControl; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterEnhancedForControl(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitEnhancedForControl(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitEnhancedForControl(this); + else return visitor.visitChildren(this); + } + } + + public final EnhancedForControlContext enhancedForControl() throws RecognitionException { + EnhancedForControlContext _localctx = new EnhancedForControlContext(_ctx, getState()); + enterRule(_localctx, 158, RULE_enhancedForControl); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1057); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,128,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1054); + variableModifier(); + } + } + } + setState(1059); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,128,_ctx); + } + setState(1060); + typeType(); + setState(1061); + variableDeclaratorId(); + setState(1062); + match(COLON); + setState(1063); + expression(0); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ParExpressionContext extends ParserRuleContext { + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public ParExpressionContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_parExpression; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterParExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitParExpression(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitParExpression(this); + else return visitor.visitChildren(this); + } + } + + public final ParExpressionContext parExpression() throws RecognitionException { + ParExpressionContext _localctx = new ParExpressionContext(_ctx, getState()); + enterRule(_localctx, 160, RULE_parExpression); + try { + enterOuterAlt(_localctx, 1); + { + setState(1065); + match(LPAREN); + setState(1066); + expression(0); + setState(1067); + match(RPAREN); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExpressionListContext extends ParserRuleContext { + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public ExpressionListContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_expressionList; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterExpressionList(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitExpressionList(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitExpressionList(this); + else return visitor.visitChildren(this); + } + } + + public final ExpressionListContext expressionList() throws RecognitionException { + ExpressionListContext _localctx = new ExpressionListContext(_ctx, getState()); + enterRule(_localctx, 162, RULE_expressionList); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1069); + expression(0); + setState(1074); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(1070); + match(COMMA); + setState(1071); + expression(0); + } + } + setState(1076); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class MethodCallContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public ExpressionListContext expressionList() { + return getRuleContext(ExpressionListContext.class,0); + } + public TerminalNode THIS() { return getToken(JavaParser.THIS, 0); } + public TerminalNode SUPER() { return getToken(JavaParser.SUPER, 0); } + public MethodCallContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_methodCall; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterMethodCall(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitMethodCall(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitMethodCall(this); + else return visitor.visitChildren(this); + } + } + + public final MethodCallContext methodCall() throws RecognitionException { + MethodCallContext _localctx = new MethodCallContext(_ctx, getState()); + enterRule(_localctx, 164, RULE_methodCall); + int _la; + try { + setState(1095); + _errHandler.sync(this); + switch (_input.LA(1)) { + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(1077); + match(IDENTIFIER); + setState(1078); + match(LPAREN); + setState(1080); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1079); + expressionList(); + } + } + + setState(1082); + match(RPAREN); + } + break; + case THIS: + enterOuterAlt(_localctx, 2); + { + setState(1083); + match(THIS); + setState(1084); + match(LPAREN); + setState(1086); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1085); + expressionList(); + } + } + + setState(1088); + match(RPAREN); + } + break; + case SUPER: + enterOuterAlt(_localctx, 3); + { + setState(1089); + match(SUPER); + setState(1090); + match(LPAREN); + setState(1092); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1091); + expressionList(); + } + } + + setState(1094); + match(RPAREN); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExpressionContext extends ParserRuleContext { + public Token prefix; + public Token bop; + public Token postfix; + public PrimaryContext primary() { + return getRuleContext(PrimaryContext.class,0); + } + public MethodCallContext methodCall() { + return getRuleContext(MethodCallContext.class,0); + } + public TerminalNode NEW() { return getToken(JavaParser.NEW, 0); } + public CreatorContext creator() { + return getRuleContext(CreatorContext.class,0); + } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TypeTypeContext typeType() { + return getRuleContext(TypeTypeContext.class,0); + } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public TerminalNode ADD() { return getToken(JavaParser.ADD, 0); } + public TerminalNode SUB() { return getToken(JavaParser.SUB, 0); } + public TerminalNode INC() { return getToken(JavaParser.INC, 0); } + public TerminalNode DEC() { return getToken(JavaParser.DEC, 0); } + public TerminalNode TILDE() { return getToken(JavaParser.TILDE, 0); } + public TerminalNode BANG() { return getToken(JavaParser.BANG, 0); } + public LambdaExpressionContext lambdaExpression() { + return getRuleContext(LambdaExpressionContext.class,0); + } + public TerminalNode COLONCOLON() { return getToken(JavaParser.COLONCOLON, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TypeArgumentsContext typeArguments() { + return getRuleContext(TypeArgumentsContext.class,0); + } + public ClassTypeContext classType() { + return getRuleContext(ClassTypeContext.class,0); + } + public TerminalNode MUL() { return getToken(JavaParser.MUL, 0); } + public TerminalNode DIV() { return getToken(JavaParser.DIV, 0); } + public TerminalNode MOD() { return getToken(JavaParser.MOD, 0); } + public List LT() { return getTokens(JavaParser.LT); } + public TerminalNode LT(int i) { + return getToken(JavaParser.LT, i); + } + public List GT() { return getTokens(JavaParser.GT); } + public TerminalNode GT(int i) { + return getToken(JavaParser.GT, i); + } + public TerminalNode LE() { return getToken(JavaParser.LE, 0); } + public TerminalNode GE() { return getToken(JavaParser.GE, 0); } + public TerminalNode EQUAL() { return getToken(JavaParser.EQUAL, 0); } + public TerminalNode NOTEQUAL() { return getToken(JavaParser.NOTEQUAL, 0); } + public TerminalNode BITAND() { return getToken(JavaParser.BITAND, 0); } + public TerminalNode CARET() { return getToken(JavaParser.CARET, 0); } + public TerminalNode BITOR() { return getToken(JavaParser.BITOR, 0); } + public TerminalNode AND() { return getToken(JavaParser.AND, 0); } + public TerminalNode OR() { return getToken(JavaParser.OR, 0); } + public TerminalNode COLON() { return getToken(JavaParser.COLON, 0); } + public TerminalNode QUESTION() { return getToken(JavaParser.QUESTION, 0); } + public TerminalNode ASSIGN() { return getToken(JavaParser.ASSIGN, 0); } + public TerminalNode ADD_ASSIGN() { return getToken(JavaParser.ADD_ASSIGN, 0); } + public TerminalNode SUB_ASSIGN() { return getToken(JavaParser.SUB_ASSIGN, 0); } + public TerminalNode MUL_ASSIGN() { return getToken(JavaParser.MUL_ASSIGN, 0); } + public TerminalNode DIV_ASSIGN() { return getToken(JavaParser.DIV_ASSIGN, 0); } + public TerminalNode AND_ASSIGN() { return getToken(JavaParser.AND_ASSIGN, 0); } + public TerminalNode OR_ASSIGN() { return getToken(JavaParser.OR_ASSIGN, 0); } + public TerminalNode XOR_ASSIGN() { return getToken(JavaParser.XOR_ASSIGN, 0); } + public TerminalNode RSHIFT_ASSIGN() { return getToken(JavaParser.RSHIFT_ASSIGN, 0); } + public TerminalNode URSHIFT_ASSIGN() { return getToken(JavaParser.URSHIFT_ASSIGN, 0); } + public TerminalNode LSHIFT_ASSIGN() { return getToken(JavaParser.LSHIFT_ASSIGN, 0); } + public TerminalNode MOD_ASSIGN() { return getToken(JavaParser.MOD_ASSIGN, 0); } + public TerminalNode DOT() { return getToken(JavaParser.DOT, 0); } + public TerminalNode THIS() { return getToken(JavaParser.THIS, 0); } + public InnerCreatorContext innerCreator() { + return getRuleContext(InnerCreatorContext.class,0); + } + public TerminalNode SUPER() { return getToken(JavaParser.SUPER, 0); } + public SuperSuffixContext superSuffix() { + return getRuleContext(SuperSuffixContext.class,0); + } + public ExplicitGenericInvocationContext explicitGenericInvocation() { + return getRuleContext(ExplicitGenericInvocationContext.class,0); + } + public NonWildcardTypeArgumentsContext nonWildcardTypeArguments() { + return getRuleContext(NonWildcardTypeArgumentsContext.class,0); + } + public TerminalNode LBRACK() { return getToken(JavaParser.LBRACK, 0); } + public TerminalNode RBRACK() { return getToken(JavaParser.RBRACK, 0); } + public TerminalNode INSTANCEOF() { return getToken(JavaParser.INSTANCEOF, 0); } + public ExpressionContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_expression; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitExpression(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitExpression(this); + else return visitor.visitChildren(this); + } + } + + public final ExpressionContext expression() throws RecognitionException { + return expression(0); + } + + private ExpressionContext expression(int _p) throws RecognitionException { + ParserRuleContext _parentctx = _ctx; + int _parentState = getState(); + ExpressionContext _localctx = new ExpressionContext(_ctx, _parentState); + ExpressionContext _prevctx = _localctx; + int _startState = 166; + enterRecursionRule(_localctx, 166, RULE_expression, _p); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1134); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,138,_ctx) ) { + case 1: + { + setState(1098); + primary(); + } + break; + case 2: + { + setState(1099); + methodCall(); + } + break; + case 3: + { + setState(1100); + match(NEW); + setState(1101); + creator(); + } + break; + case 4: + { + setState(1102); + match(LPAREN); + setState(1106); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,134,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1103); + annotation(); + } + } + } + setState(1108); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,134,_ctx); + } + setState(1109); + typeType(); + setState(1110); + match(RPAREN); + setState(1111); + expression(21); + } + break; + case 5: + { + setState(1113); + ((ExpressionContext)_localctx).prefix = _input.LT(1); + _la = _input.LA(1); + if ( !(((((_la - 83)) & ~0x3f) == 0 && ((1L << (_la - 83)) & ((1L << (INC - 83)) | (1L << (DEC - 83)) | (1L << (ADD - 83)) | (1L << (SUB - 83)))) != 0)) ) { + ((ExpressionContext)_localctx).prefix = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1114); + expression(19); + } + break; + case 6: + { + setState(1115); + ((ExpressionContext)_localctx).prefix = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==BANG || _la==TILDE) ) { + ((ExpressionContext)_localctx).prefix = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1116); + expression(18); + } + break; + case 7: + { + setState(1117); + lambdaExpression(); + } + break; + case 8: + { + setState(1118); + typeType(); + setState(1119); + match(COLONCOLON); + setState(1125); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LT: + case IDENTIFIER: + { + setState(1121); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1120); + typeArguments(); + } + } + + setState(1123); + match(IDENTIFIER); + } + break; + case NEW: + { + setState(1124); + match(NEW); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + case 9: + { + setState(1127); + classType(); + setState(1128); + match(COLONCOLON); + setState(1130); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1129); + typeArguments(); + } + } + + setState(1132); + match(NEW); + } + break; + } + _ctx.stop = _input.LT(-1); + setState(1216); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,144,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + if ( _parseListeners!=null ) triggerExitRuleEvent(); + _prevctx = _localctx; + { + setState(1214); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,143,_ctx) ) { + case 1: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1136); + if (!(precpred(_ctx, 17))) throw new FailedPredicateException(this, "precpred(_ctx, 17)"); + setState(1137); + ((ExpressionContext)_localctx).bop = _input.LT(1); + _la = _input.LA(1); + if ( !(((((_la - 87)) & ~0x3f) == 0 && ((1L << (_la - 87)) & ((1L << (MUL - 87)) | (1L << (DIV - 87)) | (1L << (MOD - 87)))) != 0)) ) { + ((ExpressionContext)_localctx).bop = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1138); + expression(18); + } + break; + case 2: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1139); + if (!(precpred(_ctx, 16))) throw new FailedPredicateException(this, "precpred(_ctx, 16)"); + setState(1140); + ((ExpressionContext)_localctx).bop = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==ADD || _la==SUB) ) { + ((ExpressionContext)_localctx).bop = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1141); + expression(17); + } + break; + case 3: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1142); + if (!(precpred(_ctx, 15))) throw new FailedPredicateException(this, "precpred(_ctx, 15)"); + setState(1150); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,139,_ctx) ) { + case 1: + { + setState(1143); + match(LT); + setState(1144); + match(LT); + } + break; + case 2: + { + setState(1145); + match(GT); + setState(1146); + match(GT); + setState(1147); + match(GT); + } + break; + case 3: + { + setState(1148); + match(GT); + setState(1149); + match(GT); + } + break; + } + setState(1152); + expression(16); + } + break; + case 4: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1153); + if (!(precpred(_ctx, 14))) throw new FailedPredicateException(this, "precpred(_ctx, 14)"); + setState(1154); + ((ExpressionContext)_localctx).bop = _input.LT(1); + _la = _input.LA(1); + if ( !(((((_la - 71)) & ~0x3f) == 0 && ((1L << (_la - 71)) & ((1L << (GT - 71)) | (1L << (LT - 71)) | (1L << (LE - 71)) | (1L << (GE - 71)))) != 0)) ) { + ((ExpressionContext)_localctx).bop = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1155); + expression(15); + } + break; + case 5: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1156); + if (!(precpred(_ctx, 12))) throw new FailedPredicateException(this, "precpred(_ctx, 12)"); + setState(1157); + ((ExpressionContext)_localctx).bop = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==EQUAL || _la==NOTEQUAL) ) { + ((ExpressionContext)_localctx).bop = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1158); + expression(13); + } + break; + case 6: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1159); + if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)"); + setState(1160); + ((ExpressionContext)_localctx).bop = match(BITAND); + setState(1161); + expression(12); + } + break; + case 7: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1162); + if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)"); + setState(1163); + ((ExpressionContext)_localctx).bop = match(CARET); + setState(1164); + expression(11); + } + break; + case 8: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1165); + if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); + setState(1166); + ((ExpressionContext)_localctx).bop = match(BITOR); + setState(1167); + expression(10); + } + break; + case 9: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1168); + if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); + setState(1169); + ((ExpressionContext)_localctx).bop = match(AND); + setState(1170); + expression(9); + } + break; + case 10: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1171); + if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)"); + setState(1172); + ((ExpressionContext)_localctx).bop = match(OR); + setState(1173); + expression(8); + } + break; + case 11: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1174); + if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); + setState(1175); + ((ExpressionContext)_localctx).bop = match(QUESTION); + setState(1176); + expression(0); + setState(1177); + match(COLON); + setState(1178); + expression(6); + } + break; + case 12: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1180); + if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); + setState(1181); + ((ExpressionContext)_localctx).bop = _input.LT(1); + _la = _input.LA(1); + if ( !(((((_la - 70)) & ~0x3f) == 0 && ((1L << (_la - 70)) & ((1L << (ASSIGN - 70)) | (1L << (ADD_ASSIGN - 70)) | (1L << (SUB_ASSIGN - 70)) | (1L << (MUL_ASSIGN - 70)) | (1L << (DIV_ASSIGN - 70)) | (1L << (AND_ASSIGN - 70)) | (1L << (OR_ASSIGN - 70)) | (1L << (XOR_ASSIGN - 70)) | (1L << (MOD_ASSIGN - 70)) | (1L << (LSHIFT_ASSIGN - 70)) | (1L << (RSHIFT_ASSIGN - 70)) | (1L << (URSHIFT_ASSIGN - 70)))) != 0)) ) { + ((ExpressionContext)_localctx).bop = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(1182); + expression(5); + } + break; + case 13: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1183); + if (!(precpred(_ctx, 25))) throw new FailedPredicateException(this, "precpred(_ctx, 25)"); + setState(1184); + ((ExpressionContext)_localctx).bop = match(DOT); + setState(1196); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,141,_ctx) ) { + case 1: + { + setState(1185); + match(IDENTIFIER); + } + break; + case 2: + { + setState(1186); + methodCall(); + } + break; + case 3: + { + setState(1187); + match(THIS); + } + break; + case 4: + { + setState(1188); + match(NEW); + setState(1190); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1189); + nonWildcardTypeArguments(); + } + } + + setState(1192); + innerCreator(); + } + break; + case 5: + { + setState(1193); + match(SUPER); + setState(1194); + superSuffix(); + } + break; + case 6: + { + setState(1195); + explicitGenericInvocation(); + } + break; + } + } + break; + case 14: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1198); + if (!(precpred(_ctx, 24))) throw new FailedPredicateException(this, "precpred(_ctx, 24)"); + setState(1199); + match(LBRACK); + setState(1200); + expression(0); + setState(1201); + match(RBRACK); + } + break; + case 15: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1203); + if (!(precpred(_ctx, 20))) throw new FailedPredicateException(this, "precpred(_ctx, 20)"); + setState(1204); + ((ExpressionContext)_localctx).postfix = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==INC || _la==DEC) ) { + ((ExpressionContext)_localctx).postfix = (Token)_errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + break; + case 16: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1205); + if (!(precpred(_ctx, 13))) throw new FailedPredicateException(this, "precpred(_ctx, 13)"); + setState(1206); + ((ExpressionContext)_localctx).bop = match(INSTANCEOF); + setState(1207); + typeType(); + } + break; + case 17: + { + _localctx = new ExpressionContext(_parentctx, _parentState); + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(1208); + if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(1209); + match(COLONCOLON); + setState(1211); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1210); + typeArguments(); + } + } + + setState(1213); + match(IDENTIFIER); + } + break; + } + } + } + setState(1218); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,144,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + unrollRecursionContexts(_parentctx); + } + return _localctx; + } + + public static class LambdaExpressionContext extends ParserRuleContext { + public LambdaParametersContext lambdaParameters() { + return getRuleContext(LambdaParametersContext.class,0); + } + public TerminalNode ARROW() { return getToken(JavaParser.ARROW, 0); } + public LambdaBodyContext lambdaBody() { + return getRuleContext(LambdaBodyContext.class,0); + } + public LambdaExpressionContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_lambdaExpression; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLambdaExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLambdaExpression(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLambdaExpression(this); + else return visitor.visitChildren(this); + } + } + + public final LambdaExpressionContext lambdaExpression() throws RecognitionException { + LambdaExpressionContext _localctx = new LambdaExpressionContext(_ctx, getState()); + enterRule(_localctx, 168, RULE_lambdaExpression); + try { + enterOuterAlt(_localctx, 1); + { + setState(1219); + lambdaParameters(); + setState(1220); + match(ARROW); + setState(1221); + lambdaBody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LambdaParametersContext extends ParserRuleContext { + public List IDENTIFIER() { return getTokens(JavaParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(JavaParser.IDENTIFIER, i); + } + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public FormalParameterListContext formalParameterList() { + return getRuleContext(FormalParameterListContext.class,0); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public LambdaParametersContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_lambdaParameters; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLambdaParameters(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLambdaParameters(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLambdaParameters(this); + else return visitor.visitChildren(this); + } + } + + public final LambdaParametersContext lambdaParameters() throws RecognitionException { + LambdaParametersContext _localctx = new LambdaParametersContext(_ctx, getState()); + enterRule(_localctx, 170, RULE_lambdaParameters); + int _la; + try { + setState(1239); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,147,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1223); + match(IDENTIFIER); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1224); + match(LPAREN); + setState(1226); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FINAL) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << SHORT))) != 0) || _la==AT || _la==IDENTIFIER) { + { + setState(1225); + formalParameterList(); + } + } + + setState(1228); + match(RPAREN); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(1229); + match(LPAREN); + setState(1230); + match(IDENTIFIER); + setState(1235); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(1231); + match(COMMA); + setState(1232); + match(IDENTIFIER); + } + } + setState(1237); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(1238); + match(RPAREN); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class LambdaBodyContext extends ParserRuleContext { + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public LambdaBodyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_lambdaBody; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterLambdaBody(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitLambdaBody(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitLambdaBody(this); + else return visitor.visitChildren(this); + } + } + + public final LambdaBodyContext lambdaBody() throws RecognitionException { + LambdaBodyContext _localctx = new LambdaBodyContext(_ctx, getState()); + enterRule(_localctx, 172, RULE_lambdaBody); + try { + setState(1243); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case NEW: + case SHORT: + case SUPER: + case THIS: + case VOID: + case DECIMAL_LITERAL: + case HEX_LITERAL: + case OCT_LITERAL: + case BINARY_LITERAL: + case FLOAT_LITERAL: + case HEX_FLOAT_LITERAL: + case BOOL_LITERAL: + case CHAR_LITERAL: + case STRING_LITERAL: + case NULL_LITERAL: + case LPAREN: + case LT: + case BANG: + case TILDE: + case INC: + case DEC: + case ADD: + case SUB: + case AT: + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(1241); + expression(0); + } + break; + case LBRACE: + enterOuterAlt(_localctx, 2); + { + setState(1242); + block(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class PrimaryContext extends ParserRuleContext { + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public TerminalNode THIS() { return getToken(JavaParser.THIS, 0); } + public TerminalNode SUPER() { return getToken(JavaParser.SUPER, 0); } + public LiteralContext literal() { + return getRuleContext(LiteralContext.class,0); + } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public TypeTypeOrVoidContext typeTypeOrVoid() { + return getRuleContext(TypeTypeOrVoidContext.class,0); + } + public TerminalNode DOT() { return getToken(JavaParser.DOT, 0); } + public TerminalNode CLASS() { return getToken(JavaParser.CLASS, 0); } + public NonWildcardTypeArgumentsContext nonWildcardTypeArguments() { + return getRuleContext(NonWildcardTypeArgumentsContext.class,0); + } + public ExplicitGenericInvocationSuffixContext explicitGenericInvocationSuffix() { + return getRuleContext(ExplicitGenericInvocationSuffixContext.class,0); + } + public ArgumentsContext arguments() { + return getRuleContext(ArgumentsContext.class,0); + } + public PrimaryContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_primary; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterPrimary(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitPrimary(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitPrimary(this); + else return visitor.visitChildren(this); + } + } + + public final PrimaryContext primary() throws RecognitionException { + PrimaryContext _localctx = new PrimaryContext(_ctx, getState()); + enterRule(_localctx, 174, RULE_primary); + try { + setState(1263); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,150,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1245); + match(LPAREN); + setState(1246); + expression(0); + setState(1247); + match(RPAREN); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1249); + match(THIS); + } + break; + case 3: + enterOuterAlt(_localctx, 3); + { + setState(1250); + match(SUPER); + } + break; + case 4: + enterOuterAlt(_localctx, 4); + { + setState(1251); + literal(); + } + break; + case 5: + enterOuterAlt(_localctx, 5); + { + setState(1252); + match(IDENTIFIER); + } + break; + case 6: + enterOuterAlt(_localctx, 6); + { + setState(1253); + typeTypeOrVoid(); + setState(1254); + match(DOT); + setState(1255); + match(CLASS); + } + break; + case 7: + enterOuterAlt(_localctx, 7); + { + setState(1257); + nonWildcardTypeArguments(); + setState(1261); + _errHandler.sync(this); + switch (_input.LA(1)) { + case SUPER: + case IDENTIFIER: + { + setState(1258); + explicitGenericInvocationSuffix(); + } + break; + case THIS: + { + setState(1259); + match(THIS); + setState(1260); + arguments(); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassTypeContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public ClassOrInterfaceTypeContext classOrInterfaceType() { + return getRuleContext(ClassOrInterfaceTypeContext.class,0); + } + public TerminalNode DOT() { return getToken(JavaParser.DOT, 0); } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public TypeArgumentsContext typeArguments() { + return getRuleContext(TypeArgumentsContext.class,0); + } + public ClassTypeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classType; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassType(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassType(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassType(this); + else return visitor.visitChildren(this); + } + } + + public final ClassTypeContext classType() throws RecognitionException { + ClassTypeContext _localctx = new ClassTypeContext(_ctx, getState()); + enterRule(_localctx, 176, RULE_classType); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1268); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,151,_ctx) ) { + case 1: + { + setState(1265); + classOrInterfaceType(); + setState(1266); + match(DOT); + } + break; + } + setState(1273); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,152,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1270); + annotation(); + } + } + } + setState(1275); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,152,_ctx); + } + setState(1276); + match(IDENTIFIER); + setState(1278); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1277); + typeArguments(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class CreatorContext extends ParserRuleContext { + public NonWildcardTypeArgumentsContext nonWildcardTypeArguments() { + return getRuleContext(NonWildcardTypeArgumentsContext.class,0); + } + public CreatedNameContext createdName() { + return getRuleContext(CreatedNameContext.class,0); + } + public ClassCreatorRestContext classCreatorRest() { + return getRuleContext(ClassCreatorRestContext.class,0); + } + public ArrayCreatorRestContext arrayCreatorRest() { + return getRuleContext(ArrayCreatorRestContext.class,0); + } + public CreatorContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_creator; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterCreator(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitCreator(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitCreator(this); + else return visitor.visitChildren(this); + } + } + + public final CreatorContext creator() throws RecognitionException { + CreatorContext _localctx = new CreatorContext(_ctx, getState()); + enterRule(_localctx, 178, RULE_creator); + try { + setState(1289); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LT: + enterOuterAlt(_localctx, 1); + { + setState(1280); + nonWildcardTypeArguments(); + setState(1281); + createdName(); + setState(1282); + classCreatorRest(); + } + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case IDENTIFIER: + enterOuterAlt(_localctx, 2); + { + setState(1284); + createdName(); + setState(1287); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LBRACK: + { + setState(1285); + arrayCreatorRest(); + } + break; + case LPAREN: + { + setState(1286); + classCreatorRest(); + } + break; + default: + throw new NoViableAltException(this); + } + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class CreatedNameContext extends ParserRuleContext { + public List IDENTIFIER() { return getTokens(JavaParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(JavaParser.IDENTIFIER, i); + } + public List typeArgumentsOrDiamond() { + return getRuleContexts(TypeArgumentsOrDiamondContext.class); + } + public TypeArgumentsOrDiamondContext typeArgumentsOrDiamond(int i) { + return getRuleContext(TypeArgumentsOrDiamondContext.class,i); + } + public List DOT() { return getTokens(JavaParser.DOT); } + public TerminalNode DOT(int i) { + return getToken(JavaParser.DOT, i); + } + public PrimitiveTypeContext primitiveType() { + return getRuleContext(PrimitiveTypeContext.class,0); + } + public CreatedNameContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_createdName; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterCreatedName(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitCreatedName(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitCreatedName(this); + else return visitor.visitChildren(this); + } + } + + public final CreatedNameContext createdName() throws RecognitionException { + CreatedNameContext _localctx = new CreatedNameContext(_ctx, getState()); + enterRule(_localctx, 180, RULE_createdName); + int _la; + try { + setState(1306); + _errHandler.sync(this); + switch (_input.LA(1)) { + case IDENTIFIER: + enterOuterAlt(_localctx, 1); + { + setState(1291); + match(IDENTIFIER); + setState(1293); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1292); + typeArgumentsOrDiamond(); + } + } + + setState(1302); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==DOT) { + { + { + setState(1295); + match(DOT); + setState(1296); + match(IDENTIFIER); + setState(1298); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1297); + typeArgumentsOrDiamond(); + } + } + + } + } + setState(1304); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + enterOuterAlt(_localctx, 2); + { + setState(1305); + primitiveType(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class InnerCreatorContext extends ParserRuleContext { + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public ClassCreatorRestContext classCreatorRest() { + return getRuleContext(ClassCreatorRestContext.class,0); + } + public NonWildcardTypeArgumentsOrDiamondContext nonWildcardTypeArgumentsOrDiamond() { + return getRuleContext(NonWildcardTypeArgumentsOrDiamondContext.class,0); + } + public InnerCreatorContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_innerCreator; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterInnerCreator(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitInnerCreator(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitInnerCreator(this); + else return visitor.visitChildren(this); + } + } + + public final InnerCreatorContext innerCreator() throws RecognitionException { + InnerCreatorContext _localctx = new InnerCreatorContext(_ctx, getState()); + enterRule(_localctx, 182, RULE_innerCreator); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1308); + match(IDENTIFIER); + setState(1310); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==LT) { + { + setState(1309); + nonWildcardTypeArgumentsOrDiamond(); + } + } + + setState(1312); + classCreatorRest(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ArrayCreatorRestContext extends ParserRuleContext { + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public ArrayInitializerContext arrayInitializer() { + return getRuleContext(ArrayInitializerContext.class,0); + } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public ArrayCreatorRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arrayCreatorRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterArrayCreatorRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitArrayCreatorRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitArrayCreatorRest(this); + else return visitor.visitChildren(this); + } + } + + public final ArrayCreatorRestContext arrayCreatorRest() throws RecognitionException { + ArrayCreatorRestContext _localctx = new ArrayCreatorRestContext(_ctx, getState()); + enterRule(_localctx, 184, RULE_arrayCreatorRest); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1314); + match(LBRACK); + setState(1342); + _errHandler.sync(this); + switch (_input.LA(1)) { + case RBRACK: + { + setState(1315); + match(RBRACK); + setState(1320); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LBRACK) { + { + { + setState(1316); + match(LBRACK); + setState(1317); + match(RBRACK); + } + } + setState(1322); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(1323); + arrayInitializer(); + } + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case NEW: + case SHORT: + case SUPER: + case THIS: + case VOID: + case DECIMAL_LITERAL: + case HEX_LITERAL: + case OCT_LITERAL: + case BINARY_LITERAL: + case FLOAT_LITERAL: + case HEX_FLOAT_LITERAL: + case BOOL_LITERAL: + case CHAR_LITERAL: + case STRING_LITERAL: + case NULL_LITERAL: + case LPAREN: + case LT: + case BANG: + case TILDE: + case INC: + case DEC: + case ADD: + case SUB: + case AT: + case IDENTIFIER: + { + setState(1324); + expression(0); + setState(1325); + match(RBRACK); + setState(1332); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,162,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1326); + match(LBRACK); + setState(1327); + expression(0); + setState(1328); + match(RBRACK); + } + } + } + setState(1334); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,162,_ctx); + } + setState(1339); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,163,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1335); + match(LBRACK); + setState(1336); + match(RBRACK); + } + } + } + setState(1341); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,163,_ctx); + } + } + break; + default: + throw new NoViableAltException(this); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ClassCreatorRestContext extends ParserRuleContext { + public ArgumentsContext arguments() { + return getRuleContext(ArgumentsContext.class,0); + } + public ClassBodyContext classBody() { + return getRuleContext(ClassBodyContext.class,0); + } + public ClassCreatorRestContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_classCreatorRest; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterClassCreatorRest(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitClassCreatorRest(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitClassCreatorRest(this); + else return visitor.visitChildren(this); + } + } + + public final ClassCreatorRestContext classCreatorRest() throws RecognitionException { + ClassCreatorRestContext _localctx = new ClassCreatorRestContext(_ctx, getState()); + enterRule(_localctx, 186, RULE_classCreatorRest); + try { + enterOuterAlt(_localctx, 1); + { + setState(1344); + arguments(); + setState(1346); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,165,_ctx) ) { + case 1: + { + setState(1345); + classBody(); + } + break; + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExplicitGenericInvocationContext extends ParserRuleContext { + public NonWildcardTypeArgumentsContext nonWildcardTypeArguments() { + return getRuleContext(NonWildcardTypeArgumentsContext.class,0); + } + public ExplicitGenericInvocationSuffixContext explicitGenericInvocationSuffix() { + return getRuleContext(ExplicitGenericInvocationSuffixContext.class,0); + } + public ExplicitGenericInvocationContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_explicitGenericInvocation; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterExplicitGenericInvocation(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitExplicitGenericInvocation(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitExplicitGenericInvocation(this); + else return visitor.visitChildren(this); + } + } + + public final ExplicitGenericInvocationContext explicitGenericInvocation() throws RecognitionException { + ExplicitGenericInvocationContext _localctx = new ExplicitGenericInvocationContext(_ctx, getState()); + enterRule(_localctx, 188, RULE_explicitGenericInvocation); + try { + enterOuterAlt(_localctx, 1); + { + setState(1348); + nonWildcardTypeArguments(); + setState(1349); + explicitGenericInvocationSuffix(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeArgumentsOrDiamondContext extends ParserRuleContext { + public TerminalNode LT() { return getToken(JavaParser.LT, 0); } + public TerminalNode GT() { return getToken(JavaParser.GT, 0); } + public TypeArgumentsContext typeArguments() { + return getRuleContext(TypeArgumentsContext.class,0); + } + public TypeArgumentsOrDiamondContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeArgumentsOrDiamond; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeArgumentsOrDiamond(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeArgumentsOrDiamond(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeArgumentsOrDiamond(this); + else return visitor.visitChildren(this); + } + } + + public final TypeArgumentsOrDiamondContext typeArgumentsOrDiamond() throws RecognitionException { + TypeArgumentsOrDiamondContext _localctx = new TypeArgumentsOrDiamondContext(_ctx, getState()); + enterRule(_localctx, 190, RULE_typeArgumentsOrDiamond); + try { + setState(1354); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,166,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1351); + match(LT); + setState(1352); + match(GT); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1353); + typeArguments(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class NonWildcardTypeArgumentsOrDiamondContext extends ParserRuleContext { + public TerminalNode LT() { return getToken(JavaParser.LT, 0); } + public TerminalNode GT() { return getToken(JavaParser.GT, 0); } + public NonWildcardTypeArgumentsContext nonWildcardTypeArguments() { + return getRuleContext(NonWildcardTypeArgumentsContext.class,0); + } + public NonWildcardTypeArgumentsOrDiamondContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_nonWildcardTypeArgumentsOrDiamond; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterNonWildcardTypeArgumentsOrDiamond(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitNonWildcardTypeArgumentsOrDiamond(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitNonWildcardTypeArgumentsOrDiamond(this); + else return visitor.visitChildren(this); + } + } + + public final NonWildcardTypeArgumentsOrDiamondContext nonWildcardTypeArgumentsOrDiamond() throws RecognitionException { + NonWildcardTypeArgumentsOrDiamondContext _localctx = new NonWildcardTypeArgumentsOrDiamondContext(_ctx, getState()); + enterRule(_localctx, 192, RULE_nonWildcardTypeArgumentsOrDiamond); + try { + setState(1359); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,167,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(1356); + match(LT); + setState(1357); + match(GT); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(1358); + nonWildcardTypeArguments(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class NonWildcardTypeArgumentsContext extends ParserRuleContext { + public TerminalNode LT() { return getToken(JavaParser.LT, 0); } + public TypeListContext typeList() { + return getRuleContext(TypeListContext.class,0); + } + public TerminalNode GT() { return getToken(JavaParser.GT, 0); } + public NonWildcardTypeArgumentsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_nonWildcardTypeArguments; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterNonWildcardTypeArguments(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitNonWildcardTypeArguments(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitNonWildcardTypeArguments(this); + else return visitor.visitChildren(this); + } + } + + public final NonWildcardTypeArgumentsContext nonWildcardTypeArguments() throws RecognitionException { + NonWildcardTypeArgumentsContext _localctx = new NonWildcardTypeArgumentsContext(_ctx, getState()); + enterRule(_localctx, 194, RULE_nonWildcardTypeArguments); + try { + enterOuterAlt(_localctx, 1); + { + setState(1361); + match(LT); + setState(1362); + typeList(); + setState(1363); + match(GT); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeListContext extends ParserRuleContext { + public List typeType() { + return getRuleContexts(TypeTypeContext.class); + } + public TypeTypeContext typeType(int i) { + return getRuleContext(TypeTypeContext.class,i); + } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public TypeListContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeList; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeList(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeList(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeList(this); + else return visitor.visitChildren(this); + } + } + + public final TypeListContext typeList() throws RecognitionException { + TypeListContext _localctx = new TypeListContext(_ctx, getState()); + enterRule(_localctx, 196, RULE_typeList); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1365); + typeType(); + setState(1370); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(1366); + match(COMMA); + setState(1367); + typeType(); + } + } + setState(1372); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeTypeContext extends ParserRuleContext { + public ClassOrInterfaceTypeContext classOrInterfaceType() { + return getRuleContext(ClassOrInterfaceTypeContext.class,0); + } + public PrimitiveTypeContext primitiveType() { + return getRuleContext(PrimitiveTypeContext.class,0); + } + public List annotation() { + return getRuleContexts(AnnotationContext.class); + } + public AnnotationContext annotation(int i) { + return getRuleContext(AnnotationContext.class,i); + } + public List LBRACK() { return getTokens(JavaParser.LBRACK); } + public TerminalNode LBRACK(int i) { + return getToken(JavaParser.LBRACK, i); + } + public List RBRACK() { return getTokens(JavaParser.RBRACK); } + public TerminalNode RBRACK(int i) { + return getToken(JavaParser.RBRACK, i); + } + public TypeTypeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeType; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeType(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeType(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeType(this); + else return visitor.visitChildren(this); + } + } + + public final TypeTypeContext typeType() throws RecognitionException { + TypeTypeContext _localctx = new TypeTypeContext(_ctx, getState()); + enterRule(_localctx, 198, RULE_typeType); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(1376); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,169,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1373); + annotation(); + } + } + } + setState(1378); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,169,_ctx); + } + setState(1381); + _errHandler.sync(this); + switch (_input.LA(1)) { + case IDENTIFIER: + { + setState(1379); + classOrInterfaceType(); + } + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + { + setState(1380); + primitiveType(); + } + break; + default: + throw new NoViableAltException(this); + } + setState(1393); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,172,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(1386); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==AT || _la==IDENTIFIER) { + { + { + setState(1383); + annotation(); + } + } + setState(1388); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(1389); + match(LBRACK); + setState(1390); + match(RBRACK); + } + } + } + setState(1395); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,172,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class PrimitiveTypeContext extends ParserRuleContext { + public TerminalNode BOOLEAN() { return getToken(JavaParser.BOOLEAN, 0); } + public TerminalNode CHAR() { return getToken(JavaParser.CHAR, 0); } + public TerminalNode BYTE() { return getToken(JavaParser.BYTE, 0); } + public TerminalNode SHORT() { return getToken(JavaParser.SHORT, 0); } + public TerminalNode INT() { return getToken(JavaParser.INT, 0); } + public TerminalNode LONG() { return getToken(JavaParser.LONG, 0); } + public TerminalNode FLOAT() { return getToken(JavaParser.FLOAT, 0); } + public TerminalNode DOUBLE() { return getToken(JavaParser.DOUBLE, 0); } + public PrimitiveTypeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_primitiveType; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterPrimitiveType(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitPrimitiveType(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitPrimitiveType(this); + else return visitor.visitChildren(this); + } + } + + public final PrimitiveTypeContext primitiveType() throws RecognitionException { + PrimitiveTypeContext _localctx = new PrimitiveTypeContext(_ctx, getState()); + enterRule(_localctx, 200, RULE_primitiveType); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1396); + _la = _input.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << SHORT))) != 0)) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class TypeArgumentsContext extends ParserRuleContext { + public TerminalNode LT() { return getToken(JavaParser.LT, 0); } + public List typeArgument() { + return getRuleContexts(TypeArgumentContext.class); + } + public TypeArgumentContext typeArgument(int i) { + return getRuleContext(TypeArgumentContext.class,i); + } + public TerminalNode GT() { return getToken(JavaParser.GT, 0); } + public List COMMA() { return getTokens(JavaParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(JavaParser.COMMA, i); + } + public TypeArgumentsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_typeArguments; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterTypeArguments(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitTypeArguments(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitTypeArguments(this); + else return visitor.visitChildren(this); + } + } + + public final TypeArgumentsContext typeArguments() throws RecognitionException { + TypeArgumentsContext _localctx = new TypeArgumentsContext(_ctx, getState()); + enterRule(_localctx, 202, RULE_typeArguments); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1398); + match(LT); + setState(1399); + typeArgument(); + setState(1404); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(1400); + match(COMMA); + setState(1401); + typeArgument(); + } + } + setState(1406); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(1407); + match(GT); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class SuperSuffixContext extends ParserRuleContext { + public ArgumentsContext arguments() { + return getRuleContext(ArgumentsContext.class,0); + } + public TerminalNode DOT() { return getToken(JavaParser.DOT, 0); } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public SuperSuffixContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_superSuffix; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterSuperSuffix(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitSuperSuffix(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitSuperSuffix(this); + else return visitor.visitChildren(this); + } + } + + public final SuperSuffixContext superSuffix() throws RecognitionException { + SuperSuffixContext _localctx = new SuperSuffixContext(_ctx, getState()); + enterRule(_localctx, 204, RULE_superSuffix); + try { + setState(1415); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LPAREN: + enterOuterAlt(_localctx, 1); + { + setState(1409); + arguments(); + } + break; + case DOT: + enterOuterAlt(_localctx, 2); + { + setState(1410); + match(DOT); + setState(1411); + match(IDENTIFIER); + setState(1413); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,174,_ctx) ) { + case 1: + { + setState(1412); + arguments(); + } + break; + } + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExplicitGenericInvocationSuffixContext extends ParserRuleContext { + public TerminalNode SUPER() { return getToken(JavaParser.SUPER, 0); } + public SuperSuffixContext superSuffix() { + return getRuleContext(SuperSuffixContext.class,0); + } + public TerminalNode IDENTIFIER() { return getToken(JavaParser.IDENTIFIER, 0); } + public ArgumentsContext arguments() { + return getRuleContext(ArgumentsContext.class,0); + } + public ExplicitGenericInvocationSuffixContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_explicitGenericInvocationSuffix; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterExplicitGenericInvocationSuffix(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitExplicitGenericInvocationSuffix(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitExplicitGenericInvocationSuffix(this); + else return visitor.visitChildren(this); + } + } + + public final ExplicitGenericInvocationSuffixContext explicitGenericInvocationSuffix() throws RecognitionException { + ExplicitGenericInvocationSuffixContext _localctx = new ExplicitGenericInvocationSuffixContext(_ctx, getState()); + enterRule(_localctx, 206, RULE_explicitGenericInvocationSuffix); + try { + setState(1421); + _errHandler.sync(this); + switch (_input.LA(1)) { + case SUPER: + enterOuterAlt(_localctx, 1); + { + setState(1417); + match(SUPER); + setState(1418); + superSuffix(); + } + break; + case IDENTIFIER: + enterOuterAlt(_localctx, 2); + { + setState(1419); + match(IDENTIFIER); + setState(1420); + arguments(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ArgumentsContext extends ParserRuleContext { + public TerminalNode LPAREN() { return getToken(JavaParser.LPAREN, 0); } + public TerminalNode RPAREN() { return getToken(JavaParser.RPAREN, 0); } + public ExpressionListContext expressionList() { + return getRuleContext(ExpressionListContext.class,0); + } + public ArgumentsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arguments; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).enterArguments(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof JavaParserListener ) ((JavaParserListener)listener).exitArguments(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof JavaParserVisitor ) return ((JavaParserVisitor)visitor).visitArguments(this); + else return visitor.visitChildren(this); + } + } + + public final ArgumentsContext arguments() throws RecognitionException { + ArgumentsContext _localctx = new ArgumentsContext(_ctx, getState()); + enterRule(_localctx, 208, RULE_arguments); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(1423); + match(LPAREN); + setState(1425); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLEAN) | (1L << BYTE) | (1L << CHAR) | (1L << DOUBLE) | (1L << FLOAT) | (1L << INT) | (1L << LONG) | (1L << NEW) | (1L << SHORT) | (1L << SUPER) | (1L << THIS) | (1L << VOID) | (1L << DECIMAL_LITERAL) | (1L << HEX_LITERAL) | (1L << OCT_LITERAL) | (1L << BINARY_LITERAL) | (1L << FLOAT_LITERAL) | (1L << HEX_FLOAT_LITERAL) | (1L << BOOL_LITERAL) | (1L << CHAR_LITERAL) | (1L << STRING_LITERAL) | (1L << NULL_LITERAL) | (1L << LPAREN))) != 0) || ((((_la - 72)) & ~0x3f) == 0 && ((1L << (_la - 72)) & ((1L << (LT - 72)) | (1L << (BANG - 72)) | (1L << (TILDE - 72)) | (1L << (INC - 72)) | (1L << (DEC - 72)) | (1L << (ADD - 72)) | (1L << (SUB - 72)) | (1L << (AT - 72)) | (1L << (IDENTIFIER - 72)))) != 0)) { + { + setState(1424); + expressionList(); + } + } + + setState(1427); + match(RPAREN); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + switch (ruleIndex) { + case 83: + return expression_sempred((ExpressionContext)_localctx, predIndex); + } + return true; + } + private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { + switch (predIndex) { + case 0: + return precpred(_ctx, 17); + case 1: + return precpred(_ctx, 16); + case 2: + return precpred(_ctx, 15); + case 3: + return precpred(_ctx, 14); + case 4: + return precpred(_ctx, 12); + case 5: + return precpred(_ctx, 11); + case 6: + return precpred(_ctx, 10); + case 7: + return precpred(_ctx, 9); + case 8: + return precpred(_ctx, 8); + case 9: + return precpred(_ctx, 7); + case 10: + return precpred(_ctx, 6); + case 11: + return precpred(_ctx, 5); + case 12: + return precpred(_ctx, 25); + case 13: + return precpred(_ctx, 24); + case 14: + return precpred(_ctx, 20); + case 15: + return precpred(_ctx, 13); + case 16: + return precpred(_ctx, 3); + } + return true; + } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3q\u0598\4\2\t\2\4"+ + "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ + "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ + "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+ + "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+ + ",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+ + "\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+ + "\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+ + "\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+ + "\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+ + "`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\3\2\5"+ + "\2\u00d6\n\2\3\2\7\2\u00d9\n\2\f\2\16\2\u00dc\13\2\3\2\7\2\u00df\n\2\f"+ + "\2\16\2\u00e2\13\2\3\2\3\2\3\3\7\3\u00e7\n\3\f\3\16\3\u00ea\13\3\3\3\3"+ + "\3\3\3\3\3\3\4\3\4\5\4\u00f2\n\4\3\4\3\4\3\4\5\4\u00f7\n\4\3\4\3\4\3\5"+ + "\7\5\u00fc\n\5\f\5\16\5\u00ff\13\5\3\5\3\5\3\5\3\5\5\5\u0105\n\5\3\5\5"+ + "\5\u0108\n\5\3\6\3\6\3\6\3\6\3\6\5\6\u010f\n\6\3\7\3\7\3\7\3\7\3\7\3\7"+ + "\3\7\3\7\5\7\u0119\n\7\3\b\3\b\5\b\u011d\n\b\3\t\3\t\3\t\5\t\u0122\n\t"+ + "\3\t\3\t\5\t\u0126\n\t\3\t\3\t\5\t\u012a\n\t\3\t\3\t\3\n\3\n\3\n\3\n\7"+ + "\n\u0132\n\n\f\n\16\n\u0135\13\n\3\n\3\n\3\13\7\13\u013a\n\13\f\13\16"+ + "\13\u013d\13\13\3\13\3\13\3\13\7\13\u0142\n\13\f\13\16\13\u0145\13\13"+ + "\3\13\5\13\u0148\n\13\3\f\3\f\3\f\7\f\u014d\n\f\f\f\16\f\u0150\13\f\3"+ + "\r\3\r\3\r\3\r\5\r\u0156\n\r\3\r\3\r\5\r\u015a\n\r\3\r\5\r\u015d\n\r\3"+ + "\r\5\r\u0160\n\r\3\r\3\r\3\16\3\16\3\16\7\16\u0167\n\16\f\16\16\16\u016a"+ + "\13\16\3\17\7\17\u016d\n\17\f\17\16\17\u0170\13\17\3\17\3\17\5\17\u0174"+ + "\n\17\3\17\5\17\u0177\n\17\3\20\3\20\7\20\u017b\n\20\f\20\16\20\u017e"+ + "\13\20\3\21\3\21\3\21\5\21\u0183\n\21\3\21\3\21\5\21\u0187\n\21\3\21\3"+ + "\21\3\22\3\22\7\22\u018d\n\22\f\22\16\22\u0190\13\22\3\22\3\22\3\23\3"+ + "\23\7\23\u0196\n\23\f\23\16\23\u0199\13\23\3\23\3\23\3\24\3\24\5\24\u019f"+ + "\n\24\3\24\3\24\7\24\u01a3\n\24\f\24\16\24\u01a6\13\24\3\24\5\24\u01a9"+ + "\n\24\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\5\25\u01b4\n\25\3\26"+ + "\3\26\3\26\3\26\3\26\7\26\u01bb\n\26\f\26\16\26\u01be\13\26\3\26\3\26"+ + "\5\26\u01c2\n\26\3\26\3\26\3\27\3\27\5\27\u01c8\n\27\3\30\3\30\5\30\u01cc"+ + "\n\30\3\31\3\31\3\31\3\32\3\32\3\32\3\33\3\33\3\33\3\33\5\33\u01d8\n\33"+ + "\3\33\3\33\3\34\3\34\3\34\3\34\3\35\7\35\u01e1\n\35\f\35\16\35\u01e4\13"+ + "\35\3\35\3\35\5\35\u01e8\n\35\3\36\3\36\3\36\3\36\3\36\3\36\3\36\5\36"+ + "\u01f1\n\36\3\37\3\37\3\37\3\37\7\37\u01f7\n\37\f\37\16\37\u01fa\13\37"+ + "\3\37\3\37\3 \3 \3 \7 \u0201\n \f \16 \u0204\13 \3 \3 \3 \3!\7!\u020a"+ + "\n!\f!\16!\u020d\13!\3!\3!\3!\7!\u0212\n!\f!\16!\u0215\13!\3!\3!\5!\u0219"+ + "\n!\3!\3!\3!\3!\7!\u021f\n!\f!\16!\u0222\13!\3!\3!\5!\u0226\n!\3!\3!\3"+ + "\"\3\"\3\"\3\"\3\"\3\"\5\"\u0230\n\"\3#\3#\3#\3$\3$\3$\7$\u0238\n$\f$"+ + "\16$\u023b\13$\3%\3%\3%\5%\u0240\n%\3&\3&\3&\7&\u0245\n&\f&\16&\u0248"+ + "\13&\3\'\3\'\5\'\u024c\n\'\3(\3(\3(\3(\7(\u0252\n(\f(\16(\u0255\13(\3"+ + "(\5(\u0258\n(\5(\u025a\n(\3(\3(\3)\3)\5)\u0260\n)\3)\3)\3)\5)\u0265\n"+ + ")\7)\u0267\n)\f)\16)\u026a\13)\3*\3*\7*\u026e\n*\f*\16*\u0271\13*\3*\3"+ + "*\3*\5*\u0276\n*\5*\u0278\n*\3+\3+\3+\7+\u027d\n+\f+\16+\u0280\13+\3,"+ + "\3,\5,\u0284\n,\3,\3,\3-\3-\3-\7-\u028b\n-\f-\16-\u028e\13-\3-\3-\5-\u0292"+ + "\n-\3-\5-\u0295\n-\3.\7.\u0298\n.\f.\16.\u029b\13.\3.\3.\3.\3/\7/\u02a1"+ + "\n/\f/\16/\u02a4\13/\3/\3/\7/\u02a8\n/\f/\16/\u02ab\13/\3/\3/\3/\3\60"+ + "\3\60\3\60\7\60\u02b3\n\60\f\60\16\60\u02b6\13\60\3\61\3\61\3\61\3\61"+ + "\3\61\3\61\5\61\u02be\n\61\3\62\3\62\3\63\3\63\3\64\3\64\7\64\u02c6\n"+ + "\64\f\64\16\64\u02c9\13\64\3\64\3\64\3\64\3\65\3\65\3\65\5\65\u02d1\n"+ + "\65\3\65\3\65\3\65\5\65\u02d6\n\65\3\65\5\65\u02d9\n\65\3\66\3\66\3\66"+ + "\7\66\u02de\n\66\f\66\16\66\u02e1\13\66\3\67\3\67\3\67\3\67\38\38\38\5"+ + "8\u02ea\n8\39\39\39\39\79\u02f0\n9\f9\169\u02f3\139\59\u02f5\n9\39\59"+ + "\u02f8\n9\39\39\3:\3:\3:\3:\3:\3;\3;\7;\u0303\n;\f;\16;\u0306\13;\3;\3"+ + ";\3<\7<\u030b\n<\f<\16<\u030e\13<\3<\3<\5<\u0312\n<\3=\3=\3=\3=\3=\3="+ + "\5=\u031a\n=\3=\3=\5=\u031e\n=\3=\3=\5=\u0322\n=\3=\3=\5=\u0326\n=\5="+ + "\u0328\n=\3>\3>\5>\u032c\n>\3?\3?\3?\3?\5?\u0332\n?\3@\3@\3A\3A\3A\3B"+ + "\3B\7B\u033b\nB\fB\16B\u033e\13B\3B\3B\3C\3C\3C\3C\3C\5C\u0347\nC\3D\7"+ + "D\u034a\nD\fD\16D\u034d\13D\3D\3D\3D\3E\7E\u0353\nE\fE\16E\u0356\13E\3"+ + "E\3E\5E\u035a\nE\3E\5E\u035d\nE\3F\3F\3F\3F\3F\5F\u0364\nF\3F\3F\3F\3"+ + "F\3F\3F\3F\5F\u036d\nF\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3"+ + "F\3F\3F\3F\6F\u0382\nF\rF\16F\u0383\3F\5F\u0387\nF\3F\5F\u038a\nF\3F\3"+ + "F\3F\3F\7F\u0390\nF\fF\16F\u0393\13F\3F\5F\u0396\nF\3F\3F\3F\3F\7F\u039c"+ + "\nF\fF\16F\u039f\13F\3F\7F\u03a2\nF\fF\16F\u03a5\13F\3F\3F\3F\3F\3F\3"+ + "F\3F\3F\5F\u03af\nF\3F\3F\3F\3F\3F\3F\3F\5F\u03b8\nF\3F\3F\3F\5F\u03bd"+ + "\nF\3F\3F\3F\3F\3F\3F\3F\3F\5F\u03c7\nF\3G\3G\3G\7G\u03cc\nG\fG\16G\u03cf"+ + "\13G\3G\3G\3G\3G\3G\3H\3H\3H\7H\u03d9\nH\fH\16H\u03dc\13H\3I\3I\3I\3J"+ + "\3J\3J\5J\u03e4\nJ\3J\3J\3K\3K\3K\7K\u03eb\nK\fK\16K\u03ee\13K\3L\7L\u03f1"+ + "\nL\fL\16L\u03f4\13L\3L\3L\3L\3L\3L\3M\6M\u03fc\nM\rM\16M\u03fd\3M\6M"+ + "\u0401\nM\rM\16M\u0402\3N\3N\3N\5N\u0408\nN\3N\3N\3N\5N\u040d\nN\3O\3"+ + "O\5O\u0411\nO\3O\3O\5O\u0415\nO\3O\3O\5O\u0419\nO\5O\u041b\nO\3P\3P\5"+ + "P\u041f\nP\3Q\7Q\u0422\nQ\fQ\16Q\u0425\13Q\3Q\3Q\3Q\3Q\3Q\3R\3R\3R\3R"+ + "\3S\3S\3S\7S\u0433\nS\fS\16S\u0436\13S\3T\3T\3T\5T\u043b\nT\3T\3T\3T\3"+ + "T\5T\u0441\nT\3T\3T\3T\3T\5T\u0447\nT\3T\5T\u044a\nT\3U\3U\3U\3U\3U\3"+ + "U\3U\7U\u0453\nU\fU\16U\u0456\13U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U"+ + "\5U\u0464\nU\3U\3U\5U\u0468\nU\3U\3U\3U\5U\u046d\nU\3U\3U\5U\u0471\nU"+ + "\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\5U\u0481\nU\3U\3U\3U\3U\3U"+ + "\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U"+ + "\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\5U\u04a9\nU\3U\3U\3U\3U\5U\u04af\nU\3U"+ + "\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\3U\5U\u04be\nU\3U\7U\u04c1\nU\fU\16"+ + "U\u04c4\13U\3V\3V\3V\3V\3W\3W\3W\5W\u04cd\nW\3W\3W\3W\3W\3W\7W\u04d4\n"+ + "W\fW\16W\u04d7\13W\3W\5W\u04da\nW\3X\3X\5X\u04de\nX\3Y\3Y\3Y\3Y\3Y\3Y"+ + "\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\5Y\u04f0\nY\5Y\u04f2\nY\3Z\3Z\3Z\5Z\u04f7"+ + "\nZ\3Z\7Z\u04fa\nZ\fZ\16Z\u04fd\13Z\3Z\3Z\5Z\u0501\nZ\3[\3[\3[\3[\3[\3"+ + "[\3[\5[\u050a\n[\5[\u050c\n[\3\\\3\\\5\\\u0510\n\\\3\\\3\\\3\\\5\\\u0515"+ + "\n\\\7\\\u0517\n\\\f\\\16\\\u051a\13\\\3\\\5\\\u051d\n\\\3]\3]\5]\u0521"+ + "\n]\3]\3]\3^\3^\3^\3^\7^\u0529\n^\f^\16^\u052c\13^\3^\3^\3^\3^\3^\3^\3"+ + "^\7^\u0535\n^\f^\16^\u0538\13^\3^\3^\7^\u053c\n^\f^\16^\u053f\13^\5^\u0541"+ + "\n^\3_\3_\5_\u0545\n_\3`\3`\3`\3a\3a\3a\5a\u054d\na\3b\3b\3b\5b\u0552"+ + "\nb\3c\3c\3c\3c\3d\3d\3d\7d\u055b\nd\fd\16d\u055e\13d\3e\7e\u0561\ne\f"+ + "e\16e\u0564\13e\3e\3e\5e\u0568\ne\3e\7e\u056b\ne\fe\16e\u056e\13e\3e\3"+ + "e\7e\u0572\ne\fe\16e\u0575\13e\3f\3f\3g\3g\3g\3g\7g\u057d\ng\fg\16g\u0580"+ + "\13g\3g\3g\3h\3h\3h\3h\5h\u0588\nh\5h\u058a\nh\3i\3i\3i\3i\5i\u0590\n"+ + "i\3j\3j\5j\u0594\nj\3j\3j\3j\2\3\u00a8k\2\4\6\b\n\f\16\20\22\24\26\30"+ + "\32\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\u0080"+ + "\u0082\u0084\u0086\u0088\u008a\u008c\u008e\u0090\u0092\u0094\u0096\u0098"+ + "\u009a\u009c\u009e\u00a0\u00a2\u00a4\u00a6\u00a8\u00aa\u00ac\u00ae\u00b0"+ + "\u00b2\u00b4\u00b6\u00b8\u00ba\u00bc\u00be\u00c0\u00c2\u00c4\u00c6\u00c8"+ + "\u00ca\u00cc\u00ce\u00d0\u00d2\2\16\4\2\23\23**\3\2\658\3\29:\3\2UX\3"+ + "\2KL\4\2YZ^^\3\2WX\4\2IJPQ\4\2OORR\4\2HH_i\3\2UV\n\2\5\5\7\7\n\n\20\20"+ + "\26\26\35\35\37\37\'\'\2\u0637\2\u00d5\3\2\2\2\4\u00e8\3\2\2\2\6\u00ef"+ + "\3\2\2\2\b\u0107\3\2\2\2\n\u010e\3\2\2\2\f\u0118\3\2\2\2\16\u011c\3\2"+ + "\2\2\20\u011e\3\2\2\2\22\u012d\3\2\2\2\24\u013b\3\2\2\2\26\u0149\3\2\2"+ + "\2\30\u0151\3\2\2\2\32\u0163\3\2\2\2\34\u016e\3\2\2\2\36\u0178\3\2\2\2"+ + " \u017f\3\2\2\2\"\u018a\3\2\2\2$\u0193\3\2\2\2&\u01a8\3\2\2\2(\u01b3\3"+ + "\2\2\2*\u01b5\3\2\2\2,\u01c7\3\2\2\2.\u01cb\3\2\2\2\60\u01cd\3\2\2\2\62"+ + "\u01d0\3\2\2\2\64\u01d3\3\2\2\2\66\u01db\3\2\2\28\u01e7\3\2\2\2:\u01f0"+ + "\3\2\2\2<\u01f2\3\2\2\2>\u01fd\3\2\2\2@\u020b\3\2\2\2B\u022f\3\2\2\2D"+ + "\u0231\3\2\2\2F\u0234\3\2\2\2H\u023c\3\2\2\2J\u0241\3\2\2\2L\u024b\3\2"+ + "\2\2N\u024d\3\2\2\2P\u025d\3\2\2\2R\u0277\3\2\2\2T\u0279\3\2\2\2V\u0281"+ + "\3\2\2\2X\u0294\3\2\2\2Z\u0299\3\2\2\2\\\u02a2\3\2\2\2^\u02af\3\2\2\2"+ + "`\u02bd\3\2\2\2b\u02bf\3\2\2\2d\u02c1\3\2\2\2f\u02c7\3\2\2\2h\u02d0\3"+ + "\2\2\2j\u02da\3\2\2\2l\u02e2\3\2\2\2n\u02e9\3\2\2\2p\u02eb\3\2\2\2r\u02fb"+ + "\3\2\2\2t\u0300\3\2\2\2v\u0311\3\2\2\2x\u0327\3\2\2\2z\u032b\3\2\2\2|"+ + "\u032d\3\2\2\2~\u0333\3\2\2\2\u0080\u0335\3\2\2\2\u0082\u0338\3\2\2\2"+ + "\u0084\u0346\3\2\2\2\u0086\u034b\3\2\2\2\u0088\u035c\3\2\2\2\u008a\u03c6"+ + "\3\2\2\2\u008c\u03c8\3\2\2\2\u008e\u03d5\3\2\2\2\u0090\u03dd\3\2\2\2\u0092"+ + "\u03e0\3\2\2\2\u0094\u03e7\3\2\2\2\u0096\u03f2\3\2\2\2\u0098\u03fb\3\2"+ + "\2\2\u009a\u040c\3\2\2\2\u009c\u041a\3\2\2\2\u009e\u041e\3\2\2\2\u00a0"+ + "\u0423\3\2\2\2\u00a2\u042b\3\2\2\2\u00a4\u042f\3\2\2\2\u00a6\u0449\3\2"+ + "\2\2\u00a8\u0470\3\2\2\2\u00aa\u04c5\3\2\2\2\u00ac\u04d9\3\2\2\2\u00ae"+ + "\u04dd\3\2\2\2\u00b0\u04f1\3\2\2\2\u00b2\u04f6\3\2\2\2\u00b4\u050b\3\2"+ + "\2\2\u00b6\u051c\3\2\2\2\u00b8\u051e\3\2\2\2\u00ba\u0524\3\2\2\2\u00bc"+ + "\u0542\3\2\2\2\u00be\u0546\3\2\2\2\u00c0\u054c\3\2\2\2\u00c2\u0551\3\2"+ + "\2\2\u00c4\u0553\3\2\2\2\u00c6\u0557\3\2\2\2\u00c8\u0562\3\2\2\2\u00ca"+ + "\u0576\3\2\2\2\u00cc\u0578\3\2\2\2\u00ce\u0589\3\2\2\2\u00d0\u058f\3\2"+ + "\2\2\u00d2\u0591\3\2\2\2\u00d4\u00d6\5\4\3\2\u00d5\u00d4\3\2\2\2\u00d5"+ + "\u00d6\3\2\2\2\u00d6\u00da\3\2\2\2\u00d7\u00d9\5\6\4\2\u00d8\u00d7\3\2"+ + "\2\2\u00d9\u00dc\3\2\2\2\u00da\u00d8\3\2\2\2\u00da\u00db\3\2\2\2\u00db"+ + "\u00e0\3\2\2\2\u00dc\u00da\3\2\2\2\u00dd\u00df\5\b\5\2\u00de\u00dd\3\2"+ + "\2\2\u00df\u00e2\3\2\2\2\u00e0\u00de\3\2\2\2\u00e0\u00e1\3\2\2\2\u00e1"+ + "\u00e3\3\2\2\2\u00e2\u00e0\3\2\2\2\u00e3\u00e4\7\2\2\3\u00e4\3\3\2\2\2"+ + "\u00e5\u00e7\5h\65\2\u00e6\u00e5\3\2\2\2\u00e7\u00ea\3\2\2\2\u00e8\u00e6"+ + "\3\2\2\2\u00e8\u00e9\3\2\2\2\u00e9\u00eb\3\2\2\2\u00ea\u00e8\3\2\2\2\u00eb"+ + "\u00ec\7\"\2\2\u00ec\u00ed\5^\60\2\u00ed\u00ee\7E\2\2\u00ee\5\3\2\2\2"+ + "\u00ef\u00f1\7\33\2\2\u00f0\u00f2\7(\2\2\u00f1\u00f0\3\2\2\2\u00f1\u00f2"+ + "\3\2\2\2\u00f2\u00f3\3\2\2\2\u00f3\u00f6\5^\60\2\u00f4\u00f5\7G\2\2\u00f5"+ + "\u00f7\7Y\2\2\u00f6\u00f4\3\2\2\2\u00f6\u00f7\3\2\2\2\u00f7\u00f8\3\2"+ + "\2\2\u00f8\u00f9\7E\2\2\u00f9\7\3\2\2\2\u00fa\u00fc\5\f\7\2\u00fb\u00fa"+ + "\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe"+ + "\u0104\3\2\2\2\u00ff\u00fd\3\2\2\2\u0100\u0105\5\20\t\2\u0101\u0105\5"+ + "\30\r\2\u0102\u0105\5 \21\2\u0103\u0105\5r:\2\u0104\u0100\3\2\2\2\u0104"+ + "\u0101\3\2\2\2\u0104\u0102\3\2\2\2\u0104\u0103\3\2\2\2\u0105\u0108\3\2"+ + "\2\2\u0106\u0108\7E\2\2\u0107\u00fd\3\2\2\2\u0107\u0106\3\2\2\2\u0108"+ + "\t\3\2\2\2\u0109\u010f\5\f\7\2\u010a\u010f\7 \2\2\u010b\u010f\7,\2\2\u010c"+ + "\u010f\7\60\2\2\u010d\u010f\7\63\2\2\u010e\u0109\3\2\2\2\u010e\u010a\3"+ + "\2\2\2\u010e\u010b\3\2\2\2\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f"+ + "\13\3\2\2\2\u0110\u0119\5h\65\2\u0111\u0119\7%\2\2\u0112\u0119\7$\2\2"+ + "\u0113\u0119\7#\2\2\u0114\u0119\7(\2\2\u0115\u0119\7\3\2\2\u0116\u0119"+ + "\7\24\2\2\u0117\u0119\7)\2\2\u0118\u0110\3\2\2\2\u0118\u0111\3\2\2\2\u0118"+ + "\u0112\3\2\2\2\u0118\u0113\3\2\2\2\u0118\u0114\3\2\2\2\u0118\u0115\3\2"+ + "\2\2\u0118\u0116\3\2\2\2\u0118\u0117\3\2\2\2\u0119\r\3\2\2\2\u011a\u011d"+ + "\7\24\2\2\u011b\u011d\5h\65\2\u011c\u011a\3\2\2\2\u011c\u011b\3\2\2\2"+ + "\u011d\17\3\2\2\2\u011e\u011f\7\13\2\2\u011f\u0121\7q\2\2\u0120\u0122"+ + "\5\22\n\2\u0121\u0120\3\2\2\2\u0121\u0122\3\2\2\2\u0122\u0125\3\2\2\2"+ + "\u0123\u0124\7\23\2\2\u0124\u0126\5\u00c8e\2\u0125\u0123\3\2\2\2\u0125"+ + "\u0126\3\2\2\2\u0126\u0129\3\2\2\2\u0127\u0128\7\32\2\2\u0128\u012a\5"+ + "\u00c6d\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u012b\3\2\2\2"+ + "\u012b\u012c\5\"\22\2\u012c\21\3\2\2\2\u012d\u012e\7J\2\2\u012e\u0133"+ + "\5\24\13\2\u012f\u0130\7F\2\2\u0130\u0132\5\24\13\2\u0131\u012f\3\2\2"+ + "\2\u0132\u0135\3\2\2\2\u0133\u0131\3\2\2\2\u0133\u0134\3\2\2\2\u0134\u0136"+ + "\3\2\2\2\u0135\u0133\3\2\2\2\u0136\u0137\7I\2\2\u0137\23\3\2\2\2\u0138"+ + "\u013a\5h\65\2\u0139\u0138\3\2\2\2\u013a\u013d\3\2\2\2\u013b\u0139\3\2"+ + "\2\2\u013b\u013c\3\2\2\2\u013c\u013e\3\2\2\2\u013d\u013b\3\2\2\2\u013e"+ + "\u0147\7q\2\2\u013f\u0143\7\23\2\2\u0140\u0142\5h\65\2\u0141\u0140\3\2"+ + "\2\2\u0142\u0145\3\2\2\2\u0143\u0141\3\2\2\2\u0143\u0144\3\2\2\2\u0144"+ + "\u0146\3\2\2\2\u0145\u0143\3\2\2\2\u0146\u0148\5\26\f\2\u0147\u013f\3"+ + "\2\2\2\u0147\u0148\3\2\2\2\u0148\25\3\2\2\2\u0149\u014e\5\u00c8e\2\u014a"+ + "\u014b\7[\2\2\u014b\u014d\5\u00c8e\2\u014c\u014a\3\2\2\2\u014d\u0150\3"+ + "\2\2\2\u014e\u014c\3\2\2\2\u014e\u014f\3\2\2\2\u014f\27\3\2\2\2\u0150"+ + "\u014e\3\2\2\2\u0151\u0152\7\22\2\2\u0152\u0155\7q\2\2\u0153\u0154\7\32"+ + "\2\2\u0154\u0156\5\u00c6d\2\u0155\u0153\3\2\2\2\u0155\u0156\3\2\2\2\u0156"+ + "\u0157\3\2\2\2\u0157\u0159\7A\2\2\u0158\u015a\5\32\16\2\u0159\u0158\3"+ + "\2\2\2\u0159\u015a\3\2\2\2\u015a\u015c\3\2\2\2\u015b\u015d\7F\2\2\u015c"+ + "\u015b\3\2\2\2\u015c\u015d\3\2\2\2\u015d\u015f\3\2\2\2\u015e\u0160\5\36"+ + "\20\2\u015f\u015e\3\2\2\2\u015f\u0160\3\2\2\2\u0160\u0161\3\2\2\2\u0161"+ + "\u0162\7B\2\2\u0162\31\3\2\2\2\u0163\u0168\5\34\17\2\u0164\u0165\7F\2"+ + "\2\u0165\u0167\5\34\17\2\u0166\u0164\3\2\2\2\u0167\u016a\3\2\2\2\u0168"+ + "\u0166\3\2\2\2\u0168\u0169\3\2\2\2\u0169\33\3\2\2\2\u016a\u0168\3\2\2"+ + "\2\u016b\u016d\5h\65\2\u016c\u016b\3\2\2\2\u016d\u0170\3\2\2\2\u016e\u016c"+ + "\3\2\2\2\u016e\u016f\3\2\2\2\u016f\u0171\3\2\2\2\u0170\u016e\3\2\2\2\u0171"+ + "\u0173\7q\2\2\u0172\u0174\5\u00d2j\2\u0173\u0172\3\2\2\2\u0173\u0174\3"+ + "\2\2\2\u0174\u0176\3\2\2\2\u0175\u0177\5\"\22\2\u0176\u0175\3\2\2\2\u0176"+ + "\u0177\3\2\2\2\u0177\35\3\2\2\2\u0178\u017c\7E\2\2\u0179\u017b\5&\24\2"+ + "\u017a\u0179\3\2\2\2\u017b\u017e\3\2\2\2\u017c\u017a\3\2\2\2\u017c\u017d"+ + "\3\2\2\2\u017d\37\3\2\2\2\u017e\u017c\3\2\2\2\u017f\u0180\7\36\2\2\u0180"+ + "\u0182\7q\2\2\u0181\u0183\5\22\n\2\u0182\u0181\3\2\2\2\u0182\u0183\3\2"+ + "\2\2\u0183\u0186\3\2\2\2\u0184\u0185\7\23\2\2\u0185\u0187\5\u00c6d\2\u0186"+ + "\u0184\3\2\2\2\u0186\u0187\3\2\2\2\u0187\u0188\3\2\2\2\u0188\u0189\5$"+ + "\23\2\u0189!\3\2\2\2\u018a\u018e\7A\2\2\u018b\u018d\5&\24\2\u018c\u018b"+ + "\3\2\2\2\u018d\u0190\3\2\2\2\u018e\u018c\3\2\2\2\u018e\u018f\3\2\2\2\u018f"+ + "\u0191\3\2\2\2\u0190\u018e\3\2\2\2\u0191\u0192\7B\2\2\u0192#\3\2\2\2\u0193"+ + "\u0197\7A\2\2\u0194\u0196\58\35\2\u0195\u0194\3\2\2\2\u0196\u0199\3\2"+ + "\2\2\u0197\u0195\3\2\2\2\u0197\u0198\3\2\2\2\u0198\u019a\3\2\2\2\u0199"+ + "\u0197\3\2\2\2\u019a\u019b\7B\2\2\u019b%\3\2\2\2\u019c\u01a9\7E\2\2\u019d"+ + "\u019f\7(\2\2\u019e\u019d\3\2\2\2\u019e\u019f\3\2\2\2\u019f\u01a0\3\2"+ + "\2\2\u01a0\u01a9\5\u0082B\2\u01a1\u01a3\5\n\6\2\u01a2\u01a1\3\2\2\2\u01a3"+ + "\u01a6\3\2\2\2\u01a4\u01a2\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5\u01a7\3\2"+ + "\2\2\u01a6\u01a4\3\2\2\2\u01a7\u01a9\5(\25\2\u01a8\u019c\3\2\2\2\u01a8"+ + "\u019e\3\2\2\2\u01a8\u01a4\3\2\2\2\u01a9\'\3\2\2\2\u01aa\u01b4\5*\26\2"+ + "\u01ab\u01b4\5\60\31\2\u01ac\u01b4\5\66\34\2\u01ad\u01b4\5\64\33\2\u01ae"+ + "\u01b4\5\62\32\2\u01af\u01b4\5 \21\2\u01b0\u01b4\5r:\2\u01b1\u01b4\5\20"+ + "\t\2\u01b2\u01b4\5\30\r\2\u01b3\u01aa\3\2\2\2\u01b3\u01ab\3\2\2\2\u01b3"+ + "\u01ac\3\2\2\2\u01b3\u01ad\3\2\2\2\u01b3\u01ae\3\2\2\2\u01b3\u01af\3\2"+ + "\2\2\u01b3\u01b0\3\2\2\2\u01b3\u01b1\3\2\2\2\u01b3\u01b2\3\2\2\2\u01b4"+ + ")\3\2\2\2\u01b5\u01b6\5.\30\2\u01b6\u01b7\7q\2\2\u01b7\u01bc\5V,\2\u01b8"+ + "\u01b9\7C\2\2\u01b9\u01bb\7D\2\2\u01ba\u01b8\3\2\2\2\u01bb\u01be\3\2\2"+ + "\2\u01bc\u01ba\3\2\2\2\u01bc\u01bd\3\2\2\2\u01bd\u01c1\3\2\2\2\u01be\u01bc"+ + "\3\2\2\2\u01bf\u01c0\7/\2\2\u01c0\u01c2\5T+\2\u01c1\u01bf\3\2\2\2\u01c1"+ + "\u01c2\3\2\2\2\u01c2\u01c3\3\2\2\2\u01c3\u01c4\5,\27\2\u01c4+\3\2\2\2"+ + "\u01c5\u01c8\5\u0082B\2\u01c6\u01c8\7E\2\2\u01c7\u01c5\3\2\2\2\u01c7\u01c6"+ + "\3\2\2\2\u01c8-\3\2\2\2\u01c9\u01cc\5\u00c8e\2\u01ca\u01cc\7\62\2\2\u01cb"+ + "\u01c9\3\2\2\2\u01cb\u01ca\3\2\2\2\u01cc/\3\2\2\2\u01cd\u01ce\5\22\n\2"+ + "\u01ce\u01cf\5*\26\2\u01cf\61\3\2\2\2\u01d0\u01d1\5\22\n\2\u01d1\u01d2"+ + "\5\64\33\2\u01d2\63\3\2\2\2\u01d3\u01d4\7q\2\2\u01d4\u01d7\5V,\2\u01d5"+ + "\u01d6\7/\2\2\u01d6\u01d8\5T+\2\u01d7\u01d5\3\2\2\2\u01d7\u01d8\3\2\2"+ + "\2\u01d8\u01d9\3\2\2\2\u01d9\u01da\5\u0082B\2\u01da\65\3\2\2\2\u01db\u01dc"+ + "\5\u00c8e\2\u01dc\u01dd\5F$\2\u01dd\u01de\7E\2\2\u01de\67\3\2\2\2\u01df"+ + "\u01e1\5\n\6\2\u01e0\u01df\3\2\2\2\u01e1\u01e4\3\2\2\2\u01e2\u01e0\3\2"+ + "\2\2\u01e2\u01e3\3\2\2\2\u01e3\u01e5\3\2\2\2\u01e4\u01e2\3\2\2\2\u01e5"+ + "\u01e8\5:\36\2\u01e6\u01e8\7E\2\2\u01e7\u01e2\3\2\2\2\u01e7\u01e6\3\2"+ + "\2\2\u01e89\3\2\2\2\u01e9\u01f1\5<\37\2\u01ea\u01f1\5@!\2\u01eb\u01f1"+ + "\5D#\2\u01ec\u01f1\5 \21\2\u01ed\u01f1\5r:\2\u01ee\u01f1\5\20\t\2\u01ef"+ + "\u01f1\5\30\r\2\u01f0\u01e9\3\2\2\2\u01f0\u01ea\3\2\2\2\u01f0\u01eb\3"+ + "\2\2\2\u01f0\u01ec\3\2\2\2\u01f0\u01ed\3\2\2\2\u01f0\u01ee\3\2\2\2\u01f0"+ + "\u01ef\3\2\2\2\u01f1;\3\2\2\2\u01f2\u01f3\5\u00c8e\2\u01f3\u01f8\5> \2"+ + "\u01f4\u01f5\7F\2\2\u01f5\u01f7\5> \2\u01f6\u01f4\3\2\2\2\u01f7\u01fa"+ + "\3\2\2\2\u01f8\u01f6\3\2\2\2\u01f8\u01f9\3\2\2\2\u01f9\u01fb\3\2\2\2\u01fa"+ + "\u01f8\3\2\2\2\u01fb\u01fc\7E\2\2\u01fc=\3\2\2\2\u01fd\u0202\7q\2\2\u01fe"+ + "\u01ff\7C\2\2\u01ff\u0201\7D\2\2\u0200\u01fe\3\2\2\2\u0201\u0204\3\2\2"+ + "\2\u0202\u0200\3\2\2\2\u0202\u0203\3\2\2\2\u0203\u0205\3\2\2\2\u0204\u0202"+ + "\3\2\2\2\u0205\u0206\7H\2\2\u0206\u0207\5L\'\2\u0207?\3\2\2\2\u0208\u020a"+ + "\5B\"\2\u0209\u0208\3\2\2\2\u020a\u020d\3\2\2\2\u020b\u0209\3\2\2\2\u020b"+ + "\u020c\3\2\2\2\u020c\u0218\3\2\2\2\u020d\u020b\3\2\2\2\u020e\u0219\5."+ + "\30\2\u020f\u0213\5\22\n\2\u0210\u0212\5h\65\2\u0211\u0210\3\2\2\2\u0212"+ + "\u0215\3\2\2\2\u0213\u0211\3\2\2\2\u0213\u0214\3\2\2\2\u0214\u0216\3\2"+ + "\2\2\u0215\u0213\3\2\2\2\u0216\u0217\5.\30\2\u0217\u0219\3\2\2\2\u0218"+ + "\u020e\3\2\2\2\u0218\u020f\3\2\2\2\u0219\u021a\3\2\2\2\u021a\u021b\7q"+ + "\2\2\u021b\u0220\5V,\2\u021c\u021d\7C\2\2\u021d\u021f\7D\2\2\u021e\u021c"+ + "\3\2\2\2\u021f\u0222\3\2\2\2\u0220\u021e\3\2\2\2\u0220\u0221\3\2\2\2\u0221"+ + "\u0225\3\2\2\2\u0222\u0220\3\2\2\2\u0223\u0224\7/\2\2\u0224\u0226\5T+"+ + "\2\u0225\u0223\3\2\2\2\u0225\u0226\3\2\2\2\u0226\u0227\3\2\2\2\u0227\u0228"+ + "\5,\27\2\u0228A\3\2\2\2\u0229\u0230\5h\65\2\u022a\u0230\7%\2\2\u022b\u0230"+ + "\7\3\2\2\u022c\u0230\7\16\2\2\u022d\u0230\7(\2\2\u022e\u0230\7)\2\2\u022f"+ + "\u0229\3\2\2\2\u022f\u022a\3\2\2\2\u022f\u022b\3\2\2\2\u022f\u022c\3\2"+ + "\2\2\u022f\u022d\3\2\2\2\u022f\u022e\3\2\2\2\u0230C\3\2\2\2\u0231\u0232"+ + "\5\22\n\2\u0232\u0233\5@!\2\u0233E\3\2\2\2\u0234\u0239\5H%\2\u0235\u0236"+ + "\7F\2\2\u0236\u0238\5H%\2\u0237\u0235\3\2\2\2\u0238\u023b\3\2\2\2\u0239"+ + "\u0237\3\2\2\2\u0239\u023a\3\2\2\2\u023aG\3\2\2\2\u023b\u0239\3\2\2\2"+ + "\u023c\u023f\5J&\2\u023d\u023e\7H\2\2\u023e\u0240\5L\'\2\u023f\u023d\3"+ + "\2\2\2\u023f\u0240\3\2\2\2\u0240I\3\2\2\2\u0241\u0246\7q\2\2\u0242\u0243"+ + "\7C\2\2\u0243\u0245\7D\2\2\u0244\u0242\3\2\2\2\u0245\u0248\3\2\2\2\u0246"+ + "\u0244\3\2\2\2\u0246\u0247\3\2\2\2\u0247K\3\2\2\2\u0248\u0246\3\2\2\2"+ + "\u0249\u024c\5N(\2\u024a\u024c\5\u00a8U\2\u024b\u0249\3\2\2\2\u024b\u024a"+ + "\3\2\2\2\u024cM\3\2\2\2\u024d\u0259\7A\2\2\u024e\u0253\5L\'\2\u024f\u0250"+ + "\7F\2\2\u0250\u0252\5L\'\2\u0251\u024f\3\2\2\2\u0252\u0255\3\2\2\2\u0253"+ + "\u0251\3\2\2\2\u0253\u0254\3\2\2\2\u0254\u0257\3\2\2\2\u0255\u0253\3\2"+ + "\2\2\u0256\u0258\7F\2\2\u0257\u0256\3\2\2\2\u0257\u0258\3\2\2\2\u0258"+ + "\u025a\3\2\2\2\u0259\u024e\3\2\2\2\u0259\u025a\3\2\2\2\u025a\u025b\3\2"+ + "\2\2\u025b\u025c\7B\2\2\u025cO\3\2\2\2\u025d\u025f\7q\2\2\u025e\u0260"+ + "\5\u00ccg\2\u025f\u025e\3\2\2\2\u025f\u0260\3\2\2\2\u0260\u0268\3\2\2"+ + "\2\u0261\u0262\7G\2\2\u0262\u0264\7q\2\2\u0263\u0265\5\u00ccg\2\u0264"+ + "\u0263\3\2\2\2\u0264\u0265\3\2\2\2\u0265\u0267\3\2\2\2\u0266\u0261\3\2"+ + "\2\2\u0267\u026a\3\2\2\2\u0268\u0266\3\2\2\2\u0268\u0269\3\2\2\2\u0269"+ + "Q\3\2\2\2\u026a\u0268\3\2\2\2\u026b\u0278\5\u00c8e\2\u026c\u026e\5h\65"+ + "\2\u026d\u026c\3\2\2\2\u026e\u0271\3\2\2\2\u026f\u026d\3\2\2\2\u026f\u0270"+ + "\3\2\2\2\u0270\u0272\3\2\2\2\u0271\u026f\3\2\2\2\u0272\u0275\7M\2\2\u0273"+ + "\u0274\t\2\2\2\u0274\u0276\5\u00c8e\2\u0275\u0273\3\2\2\2\u0275\u0276"+ + "\3\2\2\2\u0276\u0278\3\2\2\2\u0277\u026b\3\2\2\2\u0277\u026f\3\2\2\2\u0278"+ + "S\3\2\2\2\u0279\u027e\5^\60\2\u027a\u027b\7F\2\2\u027b\u027d\5^\60\2\u027c"+ + "\u027a\3\2\2\2\u027d\u0280\3\2\2\2\u027e\u027c\3\2\2\2\u027e\u027f\3\2"+ + "\2\2\u027fU\3\2\2\2\u0280\u027e\3\2\2\2\u0281\u0283\7?\2\2\u0282\u0284"+ + "\5X-\2\u0283\u0282\3\2\2\2\u0283\u0284\3\2\2\2\u0284\u0285\3\2\2\2\u0285"+ + "\u0286\7@\2\2\u0286W\3\2\2\2\u0287\u028c\5Z.\2\u0288\u0289\7F\2\2\u0289"+ + "\u028b\5Z.\2\u028a\u0288\3\2\2\2\u028b\u028e\3\2\2\2\u028c\u028a\3\2\2"+ + "\2\u028c\u028d\3\2\2\2\u028d\u0291\3\2\2\2\u028e\u028c\3\2\2\2\u028f\u0290"+ + "\7F\2\2\u0290\u0292\5\\/\2\u0291\u028f\3\2\2\2\u0291\u0292\3\2\2\2\u0292"+ + "\u0295\3\2\2\2\u0293\u0295\5\\/\2\u0294\u0287\3\2\2\2\u0294\u0293\3\2"+ + "\2\2\u0295Y\3\2\2\2\u0296\u0298\5\16\b\2\u0297\u0296\3\2\2\2\u0298\u029b"+ + "\3\2\2\2\u0299\u0297\3\2\2\2\u0299\u029a\3\2\2\2\u029a\u029c\3\2\2\2\u029b"+ + "\u0299\3\2\2\2\u029c\u029d\5\u00c8e\2\u029d\u029e\5J&\2\u029e[\3\2\2\2"+ + "\u029f\u02a1\5\16\b\2\u02a0\u029f\3\2\2\2\u02a1\u02a4\3\2\2\2\u02a2\u02a0"+ + "\3\2\2\2\u02a2\u02a3\3\2\2\2\u02a3\u02a5\3\2\2\2\u02a4\u02a2\3\2\2\2\u02a5"+ + "\u02a9\5\u00c8e\2\u02a6\u02a8\5h\65\2\u02a7\u02a6\3\2\2\2\u02a8\u02ab"+ + "\3\2\2\2\u02a9\u02a7\3\2\2\2\u02a9\u02aa\3\2\2\2\u02aa\u02ac\3\2\2\2\u02ab"+ + "\u02a9\3\2\2\2\u02ac\u02ad\7m\2\2\u02ad\u02ae\5J&\2\u02ae]\3\2\2\2\u02af"+ + "\u02b4\7q\2\2\u02b0\u02b1\7G\2\2\u02b1\u02b3\7q\2\2\u02b2\u02b0\3\2\2"+ + "\2\u02b3\u02b6\3\2\2\2\u02b4\u02b2\3\2\2\2\u02b4\u02b5\3\2\2\2\u02b5_"+ + "\3\2\2\2\u02b6\u02b4\3\2\2\2\u02b7\u02be\5b\62\2\u02b8\u02be\5d\63\2\u02b9"+ + "\u02be\7<\2\2\u02ba\u02be\7=\2\2\u02bb\u02be\7;\2\2\u02bc\u02be\7>\2\2"+ + "\u02bd\u02b7\3\2\2\2\u02bd\u02b8\3\2\2\2\u02bd\u02b9\3\2\2\2\u02bd\u02ba"+ + "\3\2\2\2\u02bd\u02bb\3\2\2\2\u02bd\u02bc\3\2\2\2\u02bea\3\2\2\2\u02bf"+ + "\u02c0\t\3\2\2\u02c0c\3\2\2\2\u02c1\u02c2\t\4\2\2\u02c2e\3\2\2\2\u02c3"+ + "\u02c4\7q\2\2\u02c4\u02c6\7G\2\2\u02c5\u02c3\3\2\2\2\u02c6\u02c9\3\2\2"+ + "\2\u02c7\u02c5\3\2\2\2\u02c7\u02c8\3\2\2\2\u02c8\u02ca\3\2\2\2\u02c9\u02c7"+ + "\3\2\2\2\u02ca\u02cb\7l\2\2\u02cb\u02cc\7q\2\2\u02ccg\3\2\2\2\u02cd\u02ce"+ + "\7l\2\2\u02ce\u02d1\5^\60\2\u02cf\u02d1\5f\64\2\u02d0\u02cd\3\2\2\2\u02d0"+ + "\u02cf\3\2\2\2\u02d1\u02d8\3\2\2\2\u02d2\u02d5\7?\2\2\u02d3\u02d6\5j\66"+ + "\2\u02d4\u02d6\5n8\2\u02d5\u02d3\3\2\2\2\u02d5\u02d4\3\2\2\2\u02d5\u02d6"+ + "\3\2\2\2\u02d6\u02d7\3\2\2\2\u02d7\u02d9\7@\2\2\u02d8\u02d2\3\2\2\2\u02d8"+ + "\u02d9\3\2\2\2\u02d9i\3\2\2\2\u02da\u02df\5l\67\2\u02db\u02dc\7F\2\2\u02dc"+ + "\u02de\5l\67\2\u02dd\u02db\3\2\2\2\u02de\u02e1\3\2\2\2\u02df\u02dd\3\2"+ + "\2\2\u02df\u02e0\3\2\2\2\u02e0k\3\2\2\2\u02e1\u02df\3\2\2\2\u02e2\u02e3"+ + "\7q\2\2\u02e3\u02e4\7H\2\2\u02e4\u02e5\5n8\2\u02e5m\3\2\2\2\u02e6\u02ea"+ + "\5\u00a8U\2\u02e7\u02ea\5h\65\2\u02e8\u02ea\5p9\2\u02e9\u02e6\3\2\2\2"+ + "\u02e9\u02e7\3\2\2\2\u02e9\u02e8\3\2\2\2\u02eao\3\2\2\2\u02eb\u02f4\7"+ + "A\2\2\u02ec\u02f1\5n8\2\u02ed\u02ee\7F\2\2\u02ee\u02f0\5n8\2\u02ef\u02ed"+ + "\3\2\2\2\u02f0\u02f3\3\2\2\2\u02f1\u02ef\3\2\2\2\u02f1\u02f2\3\2\2\2\u02f2"+ + "\u02f5\3\2\2\2\u02f3\u02f1\3\2\2\2\u02f4\u02ec\3\2\2\2\u02f4\u02f5\3\2"+ + "\2\2\u02f5\u02f7\3\2\2\2\u02f6\u02f8\7F\2\2\u02f7\u02f6\3\2\2\2\u02f7"+ + "\u02f8\3\2\2\2\u02f8\u02f9\3\2\2\2\u02f9\u02fa\7B\2\2\u02faq\3\2\2\2\u02fb"+ + "\u02fc\7l\2\2\u02fc\u02fd\7\36\2\2\u02fd\u02fe\7q\2\2\u02fe\u02ff\5t;"+ + "\2\u02ffs\3\2\2\2\u0300\u0304\7A\2\2\u0301\u0303\5v<\2\u0302\u0301\3\2"+ + "\2\2\u0303\u0306\3\2\2\2\u0304\u0302\3\2\2\2\u0304\u0305\3\2\2\2\u0305"+ + "\u0307\3\2\2\2\u0306\u0304\3\2\2\2\u0307\u0308\7B\2\2\u0308u\3\2\2\2\u0309"+ + "\u030b\5\n\6\2\u030a\u0309\3\2\2\2\u030b\u030e\3\2\2\2\u030c\u030a\3\2"+ + "\2\2\u030c\u030d\3\2\2\2\u030d\u030f\3\2\2\2\u030e\u030c\3\2\2\2\u030f"+ + "\u0312\5x=\2\u0310\u0312\7E\2\2\u0311\u030c\3\2\2\2\u0311\u0310\3\2\2"+ + "\2\u0312w\3\2\2\2\u0313\u0314\5\u00c8e\2\u0314\u0315\5z>\2\u0315\u0316"+ + "\7E\2\2\u0316\u0328\3\2\2\2\u0317\u0319\5\20\t\2\u0318\u031a\7E\2\2\u0319"+ + "\u0318\3\2\2\2\u0319\u031a\3\2\2\2\u031a\u0328\3\2\2\2\u031b\u031d\5 "+ + "\21\2\u031c\u031e\7E\2\2\u031d\u031c\3\2\2\2\u031d\u031e\3\2\2\2\u031e"+ + "\u0328\3\2\2\2\u031f\u0321\5\30\r\2\u0320\u0322\7E\2\2\u0321\u0320\3\2"+ + "\2\2\u0321\u0322\3\2\2\2\u0322\u0328\3\2\2\2\u0323\u0325\5r:\2\u0324\u0326"+ + "\7E\2\2\u0325\u0324\3\2\2\2\u0325\u0326\3\2\2\2\u0326\u0328\3\2\2\2\u0327"+ + "\u0313\3\2\2\2\u0327\u0317\3\2\2\2\u0327\u031b\3\2\2\2\u0327\u031f\3\2"+ + "\2\2\u0327\u0323\3\2\2\2\u0328y\3\2\2\2\u0329\u032c\5|?\2\u032a\u032c"+ + "\5~@\2\u032b\u0329\3\2\2\2\u032b\u032a\3\2\2\2\u032c{\3\2\2\2\u032d\u032e"+ + "\7q\2\2\u032e\u032f\7?\2\2\u032f\u0331\7@\2\2\u0330\u0332\5\u0080A\2\u0331"+ + "\u0330\3\2\2\2\u0331\u0332\3\2\2\2\u0332}\3\2\2\2\u0333\u0334\5F$\2\u0334"+ + "\177\3\2\2\2\u0335\u0336\7\16\2\2\u0336\u0337\5n8\2\u0337\u0081\3\2\2"+ + "\2\u0338\u033c\7A\2\2\u0339\u033b\5\u0084C\2\u033a\u0339\3\2\2\2\u033b"+ + "\u033e\3\2\2\2\u033c\u033a\3\2\2\2\u033c\u033d\3\2\2\2\u033d\u033f\3\2"+ + "\2\2\u033e\u033c\3\2\2\2\u033f\u0340\7B\2\2\u0340\u0083\3\2\2\2\u0341"+ + "\u0342\5\u0086D\2\u0342\u0343\7E\2\2\u0343\u0347\3\2\2\2\u0344\u0347\5"+ + "\u008aF\2\u0345\u0347\5\u0088E\2\u0346\u0341\3\2\2\2\u0346\u0344\3\2\2"+ + "\2\u0346\u0345\3\2\2\2\u0347\u0085\3\2\2\2\u0348\u034a\5\16\b\2\u0349"+ + "\u0348\3\2\2\2\u034a\u034d\3\2\2\2\u034b\u0349\3\2\2\2\u034b\u034c\3\2"+ + "\2\2\u034c\u034e\3\2\2\2\u034d\u034b\3\2\2\2\u034e\u034f\5\u00c8e\2\u034f"+ + "\u0350\5F$\2\u0350\u0087\3\2\2\2\u0351\u0353\5\f\7\2\u0352\u0351\3\2\2"+ + "\2\u0353\u0356\3\2\2\2\u0354\u0352\3\2\2\2\u0354\u0355\3\2\2\2\u0355\u0359"+ + "\3\2\2\2\u0356\u0354\3\2\2\2\u0357\u035a\5\20\t\2\u0358\u035a\5 \21\2"+ + "\u0359\u0357\3\2\2\2\u0359\u0358\3\2\2\2\u035a\u035d\3\2\2\2\u035b\u035d"+ + "\7E\2\2\u035c\u0354\3\2\2\2\u035c\u035b\3\2\2\2\u035d\u0089\3\2\2\2\u035e"+ + "\u03c7\5\u0082B\2\u035f\u0360\7\4\2\2\u0360\u0363\5\u00a8U\2\u0361\u0362"+ + "\7N\2\2\u0362\u0364\5\u00a8U\2\u0363\u0361\3\2\2\2\u0363\u0364\3\2\2\2"+ + "\u0364\u0365\3\2\2\2\u0365\u0366\7E\2\2\u0366\u03c7\3\2\2\2\u0367\u0368"+ + "\7\30\2\2\u0368\u0369\5\u00a2R\2\u0369\u036c\5\u008aF\2\u036a\u036b\7"+ + "\21\2\2\u036b\u036d\5\u008aF\2\u036c\u036a\3\2\2\2\u036c\u036d\3\2\2\2"+ + "\u036d\u03c7\3\2\2\2\u036e\u036f\7\27\2\2\u036f\u0370\7?\2\2\u0370\u0371"+ + "\5\u009cO\2\u0371\u0372\7@\2\2\u0372\u0373\5\u008aF\2\u0373\u03c7\3\2"+ + "\2\2\u0374\u0375\7\64\2\2\u0375\u0376\5\u00a2R\2\u0376\u0377\5\u008aF"+ + "\2\u0377\u03c7\3\2\2\2\u0378\u0379\7\17\2\2\u0379\u037a\5\u008aF\2\u037a"+ + "\u037b\7\64\2\2\u037b\u037c\5\u00a2R\2\u037c\u037d\7E\2\2\u037d\u03c7"+ + "\3\2\2\2\u037e\u037f\7\61\2\2\u037f\u0389\5\u0082B\2\u0380\u0382\5\u008c"+ + "G\2\u0381\u0380\3\2\2\2\u0382\u0383\3\2\2\2\u0383\u0381\3\2\2\2\u0383"+ + "\u0384\3\2\2\2\u0384\u0386\3\2\2\2\u0385\u0387\5\u0090I\2\u0386\u0385"+ + "\3\2\2\2\u0386\u0387\3\2\2\2\u0387\u038a\3\2\2\2\u0388\u038a\5\u0090I"+ + "\2\u0389\u0381\3\2\2\2\u0389\u0388\3\2\2\2\u038a\u03c7\3\2\2\2\u038b\u038c"+ + "\7\61\2\2\u038c\u038d\5\u0092J\2\u038d\u0391\5\u0082B\2\u038e\u0390\5"+ + "\u008cG\2\u038f\u038e\3\2\2\2\u0390\u0393\3\2\2\2\u0391\u038f\3\2\2\2"+ + "\u0391\u0392\3\2\2\2\u0392\u0395\3\2\2\2\u0393\u0391\3\2\2\2\u0394\u0396"+ + "\5\u0090I\2\u0395\u0394\3\2\2\2\u0395\u0396\3\2\2\2\u0396\u03c7\3\2\2"+ + "\2\u0397\u0398\7+\2\2\u0398\u0399\5\u00a2R\2\u0399\u039d\7A\2\2\u039a"+ + "\u039c\5\u0098M\2\u039b\u039a\3\2\2\2\u039c\u039f\3\2\2\2\u039d\u039b"+ + "\3\2\2\2\u039d\u039e\3\2\2\2\u039e\u03a3\3\2\2\2\u039f\u039d\3\2\2\2\u03a0"+ + "\u03a2\5\u009aN\2\u03a1\u03a0\3\2\2\2\u03a2\u03a5\3\2\2\2\u03a3\u03a1"+ + "\3\2\2\2\u03a3\u03a4\3\2\2\2\u03a4\u03a6\3\2\2\2\u03a5\u03a3\3\2\2\2\u03a6"+ + "\u03a7\7B\2\2\u03a7\u03c7\3\2\2\2\u03a8\u03a9\7,\2\2\u03a9\u03aa\5\u00a2"+ + "R\2\u03aa\u03ab\5\u0082B\2\u03ab\u03c7\3\2\2\2\u03ac\u03ae\7&\2\2\u03ad"+ + "\u03af\5\u00a8U\2\u03ae\u03ad\3\2\2\2\u03ae\u03af\3\2\2\2\u03af\u03b0"+ + "\3\2\2\2\u03b0\u03c7\7E\2\2\u03b1\u03b2\7.\2\2\u03b2\u03b3\5\u00a8U\2"+ + "\u03b3\u03b4\7E\2\2\u03b4\u03c7\3\2\2\2\u03b5\u03b7\7\6\2\2\u03b6\u03b8"+ + "\7q\2\2\u03b7\u03b6\3\2\2\2\u03b7\u03b8\3\2\2\2\u03b8\u03b9\3\2\2\2\u03b9"+ + "\u03c7\7E\2\2\u03ba\u03bc\7\r\2\2\u03bb\u03bd\7q\2\2\u03bc\u03bb\3\2\2"+ + "\2\u03bc\u03bd\3\2\2\2\u03bd\u03be\3\2\2\2\u03be\u03c7\7E\2\2\u03bf\u03c7"+ + "\7E\2\2\u03c0\u03c1\5\u00a8U\2\u03c1\u03c2\7E\2\2\u03c2\u03c7\3\2\2\2"+ + "\u03c3\u03c4\7q\2\2\u03c4\u03c5\7N\2\2\u03c5\u03c7\5\u008aF\2\u03c6\u035e"+ + "\3\2\2\2\u03c6\u035f\3\2\2\2\u03c6\u0367\3\2\2\2\u03c6\u036e\3\2\2\2\u03c6"+ + "\u0374\3\2\2\2\u03c6\u0378\3\2\2\2\u03c6\u037e\3\2\2\2\u03c6\u038b\3\2"+ + "\2\2\u03c6\u0397\3\2\2\2\u03c6\u03a8\3\2\2\2\u03c6\u03ac\3\2\2\2\u03c6"+ + "\u03b1\3\2\2\2\u03c6\u03b5\3\2\2\2\u03c6\u03ba\3\2\2\2\u03c6\u03bf\3\2"+ + "\2\2\u03c6\u03c0\3\2\2\2\u03c6\u03c3\3\2\2\2\u03c7\u008b\3\2\2\2\u03c8"+ + "\u03c9\7\t\2\2\u03c9\u03cd\7?\2\2\u03ca\u03cc\5\16\b\2\u03cb\u03ca\3\2"+ + "\2\2\u03cc\u03cf\3\2\2\2\u03cd\u03cb\3\2\2\2\u03cd\u03ce\3\2\2\2\u03ce"+ + "\u03d0\3\2\2\2\u03cf\u03cd\3\2\2\2\u03d0\u03d1\5\u008eH\2\u03d1\u03d2"+ + "\7q\2\2\u03d2\u03d3\7@\2\2\u03d3\u03d4\5\u0082B\2\u03d4\u008d\3\2\2\2"+ + "\u03d5\u03da\5^\60\2\u03d6\u03d7\7\\\2\2\u03d7\u03d9\5^\60\2\u03d8\u03d6"+ + "\3\2\2\2\u03d9\u03dc\3\2\2\2\u03da\u03d8\3\2\2\2\u03da\u03db\3\2\2\2\u03db"+ + "\u008f\3\2\2\2\u03dc\u03da\3\2\2\2\u03dd\u03de\7\25\2\2\u03de\u03df\5"+ + "\u0082B\2\u03df\u0091\3\2\2\2\u03e0\u03e1\7?\2\2\u03e1\u03e3\5\u0094K"+ + "\2\u03e2\u03e4\7E\2\2\u03e3\u03e2\3\2\2\2\u03e3\u03e4\3\2\2\2\u03e4\u03e5"+ + "\3\2\2\2\u03e5\u03e6\7@\2\2\u03e6\u0093\3\2\2\2\u03e7\u03ec\5\u0096L\2"+ + "\u03e8\u03e9\7E\2\2\u03e9\u03eb\5\u0096L\2\u03ea\u03e8\3\2\2\2\u03eb\u03ee"+ + "\3\2\2\2\u03ec\u03ea\3\2\2\2\u03ec\u03ed\3\2\2\2\u03ed\u0095\3\2\2\2\u03ee"+ + "\u03ec\3\2\2\2\u03ef\u03f1\5\16\b\2\u03f0\u03ef\3\2\2\2\u03f1\u03f4\3"+ + "\2\2\2\u03f2\u03f0\3\2\2\2\u03f2\u03f3\3\2\2\2\u03f3\u03f5\3\2\2\2\u03f4"+ + "\u03f2\3\2\2\2\u03f5\u03f6\5P)\2\u03f6\u03f7\5J&\2\u03f7\u03f8\7H\2\2"+ + "\u03f8\u03f9\5\u00a8U\2\u03f9\u0097\3\2\2\2\u03fa\u03fc\5\u009aN\2\u03fb"+ + "\u03fa\3\2\2\2\u03fc\u03fd\3\2\2\2\u03fd\u03fb\3\2\2\2\u03fd\u03fe\3\2"+ + "\2\2\u03fe\u0400\3\2\2\2\u03ff\u0401\5\u0084C\2\u0400\u03ff\3\2\2\2\u0401"+ + "\u0402\3\2\2\2\u0402\u0400\3\2\2\2\u0402\u0403\3\2\2\2\u0403\u0099\3\2"+ + "\2\2\u0404\u0407\7\b\2\2\u0405\u0408\5\u00a8U\2\u0406\u0408\7q\2\2\u0407"+ + "\u0405\3\2\2\2\u0407\u0406\3\2\2\2\u0408\u0409\3\2\2\2\u0409\u040d\7N"+ + "\2\2\u040a\u040b\7\16\2\2\u040b\u040d\7N\2\2\u040c\u0404\3\2\2\2\u040c"+ + "\u040a\3\2\2\2\u040d\u009b\3\2\2\2\u040e\u041b\5\u00a0Q\2\u040f\u0411"+ + "\5\u009eP\2\u0410\u040f\3\2\2\2\u0410\u0411\3\2\2\2\u0411\u0412\3\2\2"+ + "\2\u0412\u0414\7E\2\2\u0413\u0415\5\u00a8U\2\u0414\u0413\3\2\2\2\u0414"+ + "\u0415\3\2\2\2\u0415\u0416\3\2\2\2\u0416\u0418\7E\2\2\u0417\u0419\5\u00a4"+ + "S\2\u0418\u0417\3\2\2\2\u0418\u0419\3\2\2\2\u0419\u041b\3\2\2\2\u041a"+ + "\u040e\3\2\2\2\u041a\u0410\3\2\2\2\u041b\u009d\3\2\2\2\u041c\u041f\5\u0086"+ + "D\2\u041d\u041f\5\u00a4S\2\u041e\u041c\3\2\2\2\u041e\u041d\3\2\2\2\u041f"+ + "\u009f\3\2\2\2\u0420\u0422\5\16\b\2\u0421\u0420\3\2\2\2\u0422\u0425\3"+ + "\2\2\2\u0423\u0421\3\2\2\2\u0423\u0424\3\2\2\2\u0424\u0426\3\2\2\2\u0425"+ + "\u0423\3\2\2\2\u0426\u0427\5\u00c8e\2\u0427\u0428\5J&\2\u0428\u0429\7"+ + "N\2\2\u0429\u042a\5\u00a8U\2\u042a\u00a1\3\2\2\2\u042b\u042c\7?\2\2\u042c"+ + "\u042d\5\u00a8U\2\u042d\u042e\7@\2\2\u042e\u00a3\3\2\2\2\u042f\u0434\5"+ + "\u00a8U\2\u0430\u0431\7F\2\2\u0431\u0433\5\u00a8U\2\u0432\u0430\3\2\2"+ + "\2\u0433\u0436\3\2\2\2\u0434\u0432\3\2\2\2\u0434\u0435\3\2\2\2\u0435\u00a5"+ + "\3\2\2\2\u0436\u0434\3\2\2\2\u0437\u0438\7q\2\2\u0438\u043a\7?\2\2\u0439"+ + "\u043b\5\u00a4S\2\u043a\u0439\3\2\2\2\u043a\u043b\3\2\2\2\u043b\u043c"+ + "\3\2\2\2\u043c\u044a\7@\2\2\u043d\u043e\7-\2\2\u043e\u0440\7?\2\2\u043f"+ + "\u0441\5\u00a4S\2\u0440\u043f\3\2\2\2\u0440\u0441\3\2\2\2\u0441\u0442"+ + "\3\2\2\2\u0442\u044a\7@\2\2\u0443\u0444\7*\2\2\u0444\u0446\7?\2\2\u0445"+ + "\u0447\5\u00a4S\2\u0446\u0445\3\2\2\2\u0446\u0447\3\2\2\2\u0447\u0448"+ + "\3\2\2\2\u0448\u044a\7@\2\2\u0449\u0437\3\2\2\2\u0449\u043d\3\2\2\2\u0449"+ + "\u0443\3\2\2\2\u044a\u00a7\3\2\2\2\u044b\u044c\bU\1\2\u044c\u0471\5\u00b0"+ + "Y\2\u044d\u0471\5\u00a6T\2\u044e\u044f\7!\2\2\u044f\u0471\5\u00b4[\2\u0450"+ + "\u0454\7?\2\2\u0451\u0453\5h\65\2\u0452\u0451\3\2\2\2\u0453\u0456\3\2"+ + "\2\2\u0454\u0452\3\2\2\2\u0454\u0455\3\2\2\2\u0455\u0457\3\2\2\2\u0456"+ + "\u0454\3\2\2\2\u0457\u0458\5\u00c8e\2\u0458\u0459\7@\2\2\u0459\u045a\5"+ + "\u00a8U\27\u045a\u0471\3\2\2\2\u045b\u045c\t\5\2\2\u045c\u0471\5\u00a8"+ + "U\25\u045d\u045e\t\6\2\2\u045e\u0471\5\u00a8U\24\u045f\u0471\5\u00aaV"+ + "\2\u0460\u0461\5\u00c8e\2\u0461\u0467\7k\2\2\u0462\u0464\5\u00ccg\2\u0463"+ + "\u0462\3\2\2\2\u0463\u0464\3\2\2\2\u0464\u0465\3\2\2\2\u0465\u0468\7q"+ + "\2\2\u0466\u0468\7!\2\2\u0467\u0463\3\2\2\2\u0467\u0466\3\2\2\2\u0468"+ + "\u0471\3\2\2\2\u0469\u046a\5\u00b2Z\2\u046a\u046c\7k\2\2\u046b\u046d\5"+ + "\u00ccg\2\u046c\u046b\3\2\2\2\u046c\u046d\3\2\2\2\u046d\u046e\3\2\2\2"+ + "\u046e\u046f\7!\2\2\u046f\u0471\3\2\2\2\u0470\u044b\3\2\2\2\u0470\u044d"+ + "\3\2\2\2\u0470\u044e\3\2\2\2\u0470\u0450\3\2\2\2\u0470\u045b\3\2\2\2\u0470"+ + "\u045d\3\2\2\2\u0470\u045f\3\2\2\2\u0470\u0460\3\2\2\2\u0470\u0469\3\2"+ + "\2\2\u0471\u04c2\3\2\2\2\u0472\u0473\f\23\2\2\u0473\u0474\t\7\2\2\u0474"+ + "\u04c1\5\u00a8U\24\u0475\u0476\f\22\2\2\u0476\u0477\t\b\2\2\u0477\u04c1"+ + "\5\u00a8U\23\u0478\u0480\f\21\2\2\u0479\u047a\7J\2\2\u047a\u0481\7J\2"+ + "\2\u047b\u047c\7I\2\2\u047c\u047d\7I\2\2\u047d\u0481\7I\2\2\u047e\u047f"+ + "\7I\2\2\u047f\u0481\7I\2\2\u0480\u0479\3\2\2\2\u0480\u047b\3\2\2\2\u0480"+ + "\u047e\3\2\2\2\u0481\u0482\3\2\2\2\u0482\u04c1\5\u00a8U\22\u0483\u0484"+ + "\f\20\2\2\u0484\u0485\t\t\2\2\u0485\u04c1\5\u00a8U\21\u0486\u0487\f\16"+ + "\2\2\u0487\u0488\t\n\2\2\u0488\u04c1\5\u00a8U\17\u0489\u048a\f\r\2\2\u048a"+ + "\u048b\7[\2\2\u048b\u04c1\5\u00a8U\16\u048c\u048d\f\f\2\2\u048d\u048e"+ + "\7]\2\2\u048e\u04c1\5\u00a8U\r\u048f\u0490\f\13\2\2\u0490\u0491\7\\\2"+ + "\2\u0491\u04c1\5\u00a8U\f\u0492\u0493\f\n\2\2\u0493\u0494\7S\2\2\u0494"+ + "\u04c1\5\u00a8U\13\u0495\u0496\f\t\2\2\u0496\u0497\7T\2\2\u0497\u04c1"+ + "\5\u00a8U\n\u0498\u0499\f\b\2\2\u0499\u049a\7M\2\2\u049a\u049b\5\u00a8"+ + "U\2\u049b\u049c\7N\2\2\u049c\u049d\5\u00a8U\b\u049d\u04c1\3\2\2\2\u049e"+ + "\u049f\f\7\2\2\u049f\u04a0\t\13\2\2\u04a0\u04c1\5\u00a8U\7\u04a1\u04a2"+ + "\f\33\2\2\u04a2\u04ae\7G\2\2\u04a3\u04af\7q\2\2\u04a4\u04af\5\u00a6T\2"+ + "\u04a5\u04af\7-\2\2\u04a6\u04a8\7!\2\2\u04a7\u04a9\5\u00c4c\2\u04a8\u04a7"+ + "\3\2\2\2\u04a8\u04a9\3\2\2\2\u04a9\u04aa\3\2\2\2\u04aa\u04af\5\u00b8]"+ + "\2\u04ab\u04ac\7*\2\2\u04ac\u04af\5\u00ceh\2\u04ad\u04af\5\u00be`\2\u04ae"+ + "\u04a3\3\2\2\2\u04ae\u04a4\3\2\2\2\u04ae\u04a5\3\2\2\2\u04ae\u04a6\3\2"+ + "\2\2\u04ae\u04ab\3\2\2\2\u04ae\u04ad\3\2\2\2\u04af\u04c1\3\2\2\2\u04b0"+ + "\u04b1\f\32\2\2\u04b1\u04b2\7C\2\2\u04b2\u04b3\5\u00a8U\2\u04b3\u04b4"+ + "\7D\2\2\u04b4\u04c1\3\2\2\2\u04b5\u04b6\f\26\2\2\u04b6\u04c1\t\f\2\2\u04b7"+ + "\u04b8\f\17\2\2\u04b8\u04b9\7\34\2\2\u04b9\u04c1\5\u00c8e\2\u04ba\u04bb"+ + "\f\5\2\2\u04bb\u04bd\7k\2\2\u04bc\u04be\5\u00ccg\2\u04bd\u04bc\3\2\2\2"+ + "\u04bd\u04be\3\2\2\2\u04be\u04bf\3\2\2\2\u04bf\u04c1\7q\2\2\u04c0\u0472"+ + "\3\2\2\2\u04c0\u0475\3\2\2\2\u04c0\u0478\3\2\2\2\u04c0\u0483\3\2\2\2\u04c0"+ + "\u0486\3\2\2\2\u04c0\u0489\3\2\2\2\u04c0\u048c\3\2\2\2\u04c0\u048f\3\2"+ + "\2\2\u04c0\u0492\3\2\2\2\u04c0\u0495\3\2\2\2\u04c0\u0498\3\2\2\2\u04c0"+ + "\u049e\3\2\2\2\u04c0\u04a1\3\2\2\2\u04c0\u04b0\3\2\2\2\u04c0\u04b5\3\2"+ + "\2\2\u04c0\u04b7\3\2\2\2\u04c0\u04ba\3\2\2\2\u04c1\u04c4\3\2\2\2\u04c2"+ + "\u04c0\3\2\2\2\u04c2\u04c3\3\2\2\2\u04c3\u00a9\3\2\2\2\u04c4\u04c2\3\2"+ + "\2\2\u04c5\u04c6\5\u00acW\2\u04c6\u04c7\7j\2\2\u04c7\u04c8\5\u00aeX\2"+ + "\u04c8\u00ab\3\2\2\2\u04c9\u04da\7q\2\2\u04ca\u04cc\7?\2\2\u04cb\u04cd"+ + "\5X-\2\u04cc\u04cb\3\2\2\2\u04cc\u04cd\3\2\2\2\u04cd\u04ce\3\2\2\2\u04ce"+ + "\u04da\7@\2\2\u04cf\u04d0\7?\2\2\u04d0\u04d5\7q\2\2\u04d1\u04d2\7F\2\2"+ + "\u04d2\u04d4\7q\2\2\u04d3\u04d1\3\2\2\2\u04d4\u04d7\3\2\2\2\u04d5\u04d3"+ + "\3\2\2\2\u04d5\u04d6\3\2\2\2\u04d6\u04d8\3\2\2\2\u04d7\u04d5\3\2\2\2\u04d8"+ + "\u04da\7@\2\2\u04d9\u04c9\3\2\2\2\u04d9\u04ca\3\2\2\2\u04d9\u04cf\3\2"+ + "\2\2\u04da\u00ad\3\2\2\2\u04db\u04de\5\u00a8U\2\u04dc\u04de\5\u0082B\2"+ + "\u04dd\u04db\3\2\2\2\u04dd\u04dc\3\2\2\2\u04de\u00af\3\2\2\2\u04df\u04e0"+ + "\7?\2\2\u04e0\u04e1\5\u00a8U\2\u04e1\u04e2\7@\2\2\u04e2\u04f2\3\2\2\2"+ + "\u04e3\u04f2\7-\2\2\u04e4\u04f2\7*\2\2\u04e5\u04f2\5`\61\2\u04e6\u04f2"+ + "\7q\2\2\u04e7\u04e8\5.\30\2\u04e8\u04e9\7G\2\2\u04e9\u04ea\7\13\2\2\u04ea"+ + "\u04f2\3\2\2\2\u04eb\u04ef\5\u00c4c\2\u04ec\u04f0\5\u00d0i\2\u04ed\u04ee"+ + "\7-\2\2\u04ee\u04f0\5\u00d2j\2\u04ef\u04ec\3\2\2\2\u04ef\u04ed\3\2\2\2"+ + "\u04f0\u04f2\3\2\2\2\u04f1\u04df\3\2\2\2\u04f1\u04e3\3\2\2\2\u04f1\u04e4"+ + "\3\2\2\2\u04f1\u04e5\3\2\2\2\u04f1\u04e6\3\2\2\2\u04f1\u04e7\3\2\2\2\u04f1"+ + "\u04eb\3\2\2\2\u04f2\u00b1\3\2\2\2\u04f3\u04f4\5P)\2\u04f4\u04f5\7G\2"+ + "\2\u04f5\u04f7\3\2\2\2\u04f6\u04f3\3\2\2\2\u04f6\u04f7\3\2\2\2\u04f7\u04fb"+ + "\3\2\2\2\u04f8\u04fa\5h\65\2\u04f9\u04f8\3\2\2\2\u04fa\u04fd\3\2\2\2\u04fb"+ + "\u04f9\3\2\2\2\u04fb\u04fc\3\2\2\2\u04fc\u04fe\3\2\2\2\u04fd\u04fb\3\2"+ + "\2\2\u04fe\u0500\7q\2\2\u04ff\u0501\5\u00ccg\2\u0500\u04ff\3\2\2\2\u0500"+ + "\u0501\3\2\2\2\u0501\u00b3\3\2\2\2\u0502\u0503\5\u00c4c\2\u0503\u0504"+ + "\5\u00b6\\\2\u0504\u0505\5\u00bc_\2\u0505\u050c\3\2\2\2\u0506\u0509\5"+ + "\u00b6\\\2\u0507\u050a\5\u00ba^\2\u0508\u050a\5\u00bc_\2\u0509\u0507\3"+ + "\2\2\2\u0509\u0508\3\2\2\2\u050a\u050c\3\2\2\2\u050b\u0502\3\2\2\2\u050b"+ + "\u0506\3\2\2\2\u050c\u00b5\3\2\2\2\u050d\u050f\7q\2\2\u050e\u0510\5\u00c0"+ + "a\2\u050f\u050e\3\2\2\2\u050f\u0510\3\2\2\2\u0510\u0518\3\2\2\2\u0511"+ + "\u0512\7G\2\2\u0512\u0514\7q\2\2\u0513\u0515\5\u00c0a\2\u0514\u0513\3"+ + "\2\2\2\u0514\u0515\3\2\2\2\u0515\u0517\3\2\2\2\u0516\u0511\3\2\2\2\u0517"+ + "\u051a\3\2\2\2\u0518\u0516\3\2\2\2\u0518\u0519\3\2\2\2\u0519\u051d\3\2"+ + "\2\2\u051a\u0518\3\2\2\2\u051b\u051d\5\u00caf\2\u051c\u050d\3\2\2\2\u051c"+ + "\u051b\3\2\2\2\u051d\u00b7\3\2\2\2\u051e\u0520\7q\2\2\u051f\u0521\5\u00c2"+ + "b\2\u0520\u051f\3\2\2\2\u0520\u0521\3\2\2\2\u0521\u0522\3\2\2\2\u0522"+ + "\u0523\5\u00bc_\2\u0523\u00b9\3\2\2\2\u0524\u0540\7C\2\2\u0525\u052a\7"+ + "D\2\2\u0526\u0527\7C\2\2\u0527\u0529\7D\2\2\u0528\u0526\3\2\2\2\u0529"+ + "\u052c\3\2\2\2\u052a\u0528\3\2\2\2\u052a\u052b\3\2\2\2\u052b\u052d\3\2"+ + "\2\2\u052c\u052a\3\2\2\2\u052d\u0541\5N(\2\u052e\u052f\5\u00a8U\2\u052f"+ + "\u0536\7D\2\2\u0530\u0531\7C\2\2\u0531\u0532\5\u00a8U\2\u0532\u0533\7"+ + "D\2\2\u0533\u0535\3\2\2\2\u0534\u0530\3\2\2\2\u0535\u0538\3\2\2\2\u0536"+ + "\u0534\3\2\2\2\u0536\u0537\3\2\2\2\u0537\u053d\3\2\2\2\u0538\u0536\3\2"+ + "\2\2\u0539\u053a\7C\2\2\u053a\u053c\7D\2\2\u053b\u0539\3\2\2\2\u053c\u053f"+ + "\3\2\2\2\u053d\u053b\3\2\2\2\u053d\u053e\3\2\2\2\u053e\u0541\3\2\2\2\u053f"+ + "\u053d\3\2\2\2\u0540\u0525\3\2\2\2\u0540\u052e\3\2\2\2\u0541\u00bb\3\2"+ + "\2\2\u0542\u0544\5\u00d2j\2\u0543\u0545\5\"\22\2\u0544\u0543\3\2\2\2\u0544"+ + "\u0545\3\2\2\2\u0545\u00bd\3\2\2\2\u0546\u0547\5\u00c4c\2\u0547\u0548"+ + "\5\u00d0i\2\u0548\u00bf\3\2\2\2\u0549\u054a\7J\2\2\u054a\u054d\7I\2\2"+ + "\u054b\u054d\5\u00ccg\2\u054c\u0549\3\2\2\2\u054c\u054b\3\2\2\2\u054d"+ + "\u00c1\3\2\2\2\u054e\u054f\7J\2\2\u054f\u0552\7I\2\2\u0550\u0552\5\u00c4"+ + "c\2\u0551\u054e\3\2\2\2\u0551\u0550\3\2\2\2\u0552\u00c3\3\2\2\2\u0553"+ + "\u0554\7J\2\2\u0554\u0555\5\u00c6d\2\u0555\u0556\7I\2\2\u0556\u00c5\3"+ + "\2\2\2\u0557\u055c\5\u00c8e\2\u0558\u0559\7F\2\2\u0559\u055b\5\u00c8e"+ + "\2\u055a\u0558\3\2\2\2\u055b\u055e\3\2\2\2\u055c\u055a\3\2\2\2\u055c\u055d"+ + "\3\2\2\2\u055d\u00c7\3\2\2\2\u055e\u055c\3\2\2\2\u055f\u0561\5h\65\2\u0560"+ + "\u055f\3\2\2\2\u0561\u0564\3\2\2\2\u0562\u0560\3\2\2\2\u0562\u0563\3\2"+ + "\2\2\u0563\u0567\3\2\2\2\u0564\u0562\3\2\2\2\u0565\u0568\5P)\2\u0566\u0568"+ + "\5\u00caf\2\u0567\u0565\3\2\2\2\u0567\u0566\3\2\2\2\u0568\u0573\3\2\2"+ + "\2\u0569\u056b\5h\65\2\u056a\u0569\3\2\2\2\u056b\u056e\3\2\2\2\u056c\u056a"+ + "\3\2\2\2\u056c\u056d\3\2\2\2\u056d\u056f\3\2\2\2\u056e\u056c\3\2\2\2\u056f"+ + "\u0570\7C\2\2\u0570\u0572\7D\2\2\u0571\u056c\3\2\2\2\u0572\u0575\3\2\2"+ + "\2\u0573\u0571\3\2\2\2\u0573\u0574\3\2\2\2\u0574\u00c9\3\2\2\2\u0575\u0573"+ + "\3\2\2\2\u0576\u0577\t\r\2\2\u0577\u00cb\3\2\2\2\u0578\u0579\7J\2\2\u0579"+ + "\u057e\5R*\2\u057a\u057b\7F\2\2\u057b\u057d\5R*\2\u057c\u057a\3\2\2\2"+ + "\u057d\u0580\3\2\2\2\u057e\u057c\3\2\2\2\u057e\u057f\3\2\2\2\u057f\u0581"+ + "\3\2\2\2\u0580\u057e\3\2\2\2\u0581\u0582\7I\2\2\u0582\u00cd\3\2\2\2\u0583"+ + "\u058a\5\u00d2j\2\u0584\u0585\7G\2\2\u0585\u0587\7q\2\2\u0586\u0588\5"+ + "\u00d2j\2\u0587\u0586\3\2\2\2\u0587\u0588\3\2\2\2\u0588\u058a\3\2\2\2"+ + "\u0589\u0583\3\2\2\2\u0589\u0584\3\2\2\2\u058a\u00cf\3\2\2\2\u058b\u058c"+ + "\7*\2\2\u058c\u0590\5\u00ceh\2\u058d\u058e\7q\2\2\u058e\u0590\5\u00d2"+ + "j\2\u058f\u058b\3\2\2\2\u058f\u058d\3\2\2\2\u0590\u00d1\3\2\2\2\u0591"+ + "\u0593\7?\2\2\u0592\u0594\5\u00a4S\2\u0593\u0592\3\2\2\2\u0593\u0594\3"+ + "\2\2\2\u0594\u0595\3\2\2\2\u0595\u0596\7@\2\2\u0596\u00d3\3\2\2\2\u00b4"+ + "\u00d5\u00da\u00e0\u00e8\u00f1\u00f6\u00fd\u0104\u0107\u010e\u0118\u011c"+ + "\u0121\u0125\u0129\u0133\u013b\u0143\u0147\u014e\u0155\u0159\u015c\u015f"+ + "\u0168\u016e\u0173\u0176\u017c\u0182\u0186\u018e\u0197\u019e\u01a4\u01a8"+ + "\u01b3\u01bc\u01c1\u01c7\u01cb\u01d7\u01e2\u01e7\u01f0\u01f8\u0202\u020b"+ + "\u0213\u0218\u0220\u0225\u022f\u0239\u023f\u0246\u024b\u0253\u0257\u0259"+ + "\u025f\u0264\u0268\u026f\u0275\u0277\u027e\u0283\u028c\u0291\u0294\u0299"+ + "\u02a2\u02a9\u02b4\u02bd\u02c7\u02d0\u02d5\u02d8\u02df\u02e9\u02f1\u02f4"+ + "\u02f7\u0304\u030c\u0311\u0319\u031d\u0321\u0325\u0327\u032b\u0331\u033c"+ + "\u0346\u034b\u0354\u0359\u035c\u0363\u036c\u0383\u0386\u0389\u0391\u0395"+ + "\u039d\u03a3\u03ae\u03b7\u03bc\u03c6\u03cd\u03da\u03e3\u03ec\u03f2\u03fd"+ + "\u0402\u0407\u040c\u0410\u0414\u0418\u041a\u041e\u0423\u0434\u043a\u0440"+ + "\u0446\u0449\u0454\u0463\u0467\u046c\u0470\u0480\u04a8\u04ae\u04bd\u04c0"+ + "\u04c2\u04cc\u04d5\u04d9\u04dd\u04ef\u04f1\u04f6\u04fb\u0500\u0509\u050b"+ + "\u050f\u0514\u0518\u051c\u0520\u052a\u0536\u053d\u0540\u0544\u054c\u0551"+ + "\u055c\u0562\u0567\u056c\u0573\u057e\u0587\u0589\u058f\u0593"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseListener.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseListener.java new file mode 100644 index 000000000..1caf7a8bd --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseListener.java @@ -0,0 +1,1299 @@ +// Generated from JavaParser.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** + * This class provides an empty implementation of {@link JavaParserListener}, + * which can be extended to create a listener which only needs to handle a subset + * of the available methods. + */ +public class JavaParserBaseListener implements JavaParserListener { + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCompilationUnit(JavaParser.CompilationUnitContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCompilationUnit(JavaParser.CompilationUnitContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitPackageDeclaration(JavaParser.PackageDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitImportDeclaration(JavaParser.ImportDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeDeclaration(JavaParser.TypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeDeclaration(JavaParser.TypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterModifier(JavaParser.ModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitModifier(JavaParser.ModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterVariableModifier(JavaParser.VariableModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitVariableModifier(JavaParser.VariableModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeParameters(JavaParser.TypeParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeParameters(JavaParser.TypeParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeParameter(JavaParser.TypeParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeParameter(JavaParser.TypeParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeBound(JavaParser.TypeBoundContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeBound(JavaParser.TypeBoundContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEnumConstants(JavaParser.EnumConstantsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEnumConstants(JavaParser.EnumConstantsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEnumConstant(JavaParser.EnumConstantContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEnumConstant(JavaParser.EnumConstantContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassBody(JavaParser.ClassBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassBody(JavaParser.ClassBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceBody(JavaParser.InterfaceBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceBody(JavaParser.InterfaceBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterMemberDeclaration(JavaParser.MemberDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitMemberDeclaration(JavaParser.MemberDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitMethodDeclaration(JavaParser.MethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterMethodBody(JavaParser.MethodBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitMethodBody(JavaParser.MethodBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFieldDeclaration(JavaParser.FieldDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConstDeclaration(JavaParser.ConstDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterVariableDeclarator(JavaParser.VariableDeclaratorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitVariableDeclarator(JavaParser.VariableDeclaratorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterVariableInitializer(JavaParser.VariableInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitVariableInitializer(JavaParser.VariableInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArrayInitializer(JavaParser.ArrayInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArrayInitializer(JavaParser.ArrayInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeArgument(JavaParser.TypeArgumentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeArgument(JavaParser.TypeArgumentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterQualifiedNameList(JavaParser.QualifiedNameListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitQualifiedNameList(JavaParser.QualifiedNameListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFormalParameters(JavaParser.FormalParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFormalParameters(JavaParser.FormalParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFormalParameterList(JavaParser.FormalParameterListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFormalParameterList(JavaParser.FormalParameterListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFormalParameter(JavaParser.FormalParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFormalParameter(JavaParser.FormalParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLastFormalParameter(JavaParser.LastFormalParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLastFormalParameter(JavaParser.LastFormalParameterContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterQualifiedName(JavaParser.QualifiedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitQualifiedName(JavaParser.QualifiedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLiteral(JavaParser.LiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLiteral(JavaParser.LiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterIntegerLiteral(JavaParser.IntegerLiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitIntegerLiteral(JavaParser.IntegerLiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFloatLiteral(JavaParser.FloatLiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFloatLiteral(JavaParser.FloatLiteralContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotation(JavaParser.AnnotationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotation(JavaParser.AnnotationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterElementValuePairs(JavaParser.ElementValuePairsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitElementValuePairs(JavaParser.ElementValuePairsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterElementValuePair(JavaParser.ElementValuePairContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitElementValuePair(JavaParser.ElementValuePairContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterElementValue(JavaParser.ElementValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitElementValue(JavaParser.ElementValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterDefaultValue(JavaParser.DefaultValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitDefaultValue(JavaParser.DefaultValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterBlock(JavaParser.BlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitBlock(JavaParser.BlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterBlockStatement(JavaParser.BlockStatementContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitBlockStatement(JavaParser.BlockStatementContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStatement(JavaParser.StatementContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStatement(JavaParser.StatementContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCatchClause(JavaParser.CatchClauseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCatchClause(JavaParser.CatchClauseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCatchType(JavaParser.CatchTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCatchType(JavaParser.CatchTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFinallyBlock(JavaParser.FinallyBlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFinallyBlock(JavaParser.FinallyBlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterResourceSpecification(JavaParser.ResourceSpecificationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitResourceSpecification(JavaParser.ResourceSpecificationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterResources(JavaParser.ResourcesContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitResources(JavaParser.ResourcesContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterResource(JavaParser.ResourceContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitResource(JavaParser.ResourceContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterSwitchLabel(JavaParser.SwitchLabelContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitSwitchLabel(JavaParser.SwitchLabelContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterForControl(JavaParser.ForControlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitForControl(JavaParser.ForControlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterForInit(JavaParser.ForInitContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitForInit(JavaParser.ForInitContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEnhancedForControl(JavaParser.EnhancedForControlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEnhancedForControl(JavaParser.EnhancedForControlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterParExpression(JavaParser.ParExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitParExpression(JavaParser.ParExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExpressionList(JavaParser.ExpressionListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExpressionList(JavaParser.ExpressionListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterMethodCall(JavaParser.MethodCallContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitMethodCall(JavaParser.MethodCallContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExpression(JavaParser.ExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExpression(JavaParser.ExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLambdaExpression(JavaParser.LambdaExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLambdaExpression(JavaParser.LambdaExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLambdaParameters(JavaParser.LambdaParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLambdaParameters(JavaParser.LambdaParametersContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLambdaBody(JavaParser.LambdaBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLambdaBody(JavaParser.LambdaBodyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterPrimary(JavaParser.PrimaryContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitPrimary(JavaParser.PrimaryContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassType(JavaParser.ClassTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassType(JavaParser.ClassTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCreator(JavaParser.CreatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCreator(JavaParser.CreatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCreatedName(JavaParser.CreatedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCreatedName(JavaParser.CreatedNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInnerCreator(JavaParser.InnerCreatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInnerCreator(JavaParser.InnerCreatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterClassCreatorRest(JavaParser.ClassCreatorRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitClassCreatorRest(JavaParser.ClassCreatorRestContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeList(JavaParser.TypeListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeList(JavaParser.TypeListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeType(JavaParser.TypeTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeType(JavaParser.TypeTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterPrimitiveType(JavaParser.PrimitiveTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitPrimitiveType(JavaParser.PrimitiveTypeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTypeArguments(JavaParser.TypeArgumentsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTypeArguments(JavaParser.TypeArgumentsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterSuperSuffix(JavaParser.SuperSuffixContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitSuperSuffix(JavaParser.SuperSuffixContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArguments(JavaParser.ArgumentsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArguments(JavaParser.ArgumentsContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitTerminal(TerminalNode node) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitErrorNode(ErrorNode node) { } +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseVisitor.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseVisitor.java new file mode 100644 index 000000000..87937222a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserBaseVisitor.java @@ -0,0 +1,749 @@ +// Generated from JavaParser.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; +import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@link JavaParserVisitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public class JavaParserBaseVisitor extends AbstractParseTreeVisitor implements JavaParserVisitor { + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCompilationUnit(JavaParser.CompilationUnitContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitPackageDeclaration(JavaParser.PackageDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitImportDeclaration(JavaParser.ImportDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeDeclaration(JavaParser.TypeDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitModifier(JavaParser.ModifierContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitVariableModifier(JavaParser.VariableModifierContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeParameters(JavaParser.TypeParametersContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeParameter(JavaParser.TypeParameterContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeBound(JavaParser.TypeBoundContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEnumConstants(JavaParser.EnumConstantsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEnumConstant(JavaParser.EnumConstantContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassBody(JavaParser.ClassBodyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceBody(JavaParser.InterfaceBodyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitMemberDeclaration(JavaParser.MemberDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitMethodDeclaration(JavaParser.MethodDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitMethodBody(JavaParser.MethodBodyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFieldDeclaration(JavaParser.FieldDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitConstDeclaration(JavaParser.ConstDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitVariableDeclarator(JavaParser.VariableDeclaratorContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitVariableInitializer(JavaParser.VariableInitializerContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArrayInitializer(JavaParser.ArrayInitializerContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeArgument(JavaParser.TypeArgumentContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitQualifiedNameList(JavaParser.QualifiedNameListContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFormalParameters(JavaParser.FormalParametersContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFormalParameterList(JavaParser.FormalParameterListContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFormalParameter(JavaParser.FormalParameterContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLastFormalParameter(JavaParser.LastFormalParameterContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitQualifiedName(JavaParser.QualifiedNameContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLiteral(JavaParser.LiteralContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitIntegerLiteral(JavaParser.IntegerLiteralContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFloatLiteral(JavaParser.FloatLiteralContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotation(JavaParser.AnnotationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitElementValuePairs(JavaParser.ElementValuePairsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitElementValuePair(JavaParser.ElementValuePairContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitElementValue(JavaParser.ElementValueContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitDefaultValue(JavaParser.DefaultValueContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitBlock(JavaParser.BlockContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitBlockStatement(JavaParser.BlockStatementContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitStatement(JavaParser.StatementContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCatchClause(JavaParser.CatchClauseContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCatchType(JavaParser.CatchTypeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFinallyBlock(JavaParser.FinallyBlockContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitResourceSpecification(JavaParser.ResourceSpecificationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitResources(JavaParser.ResourcesContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitResource(JavaParser.ResourceContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitSwitchLabel(JavaParser.SwitchLabelContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitForControl(JavaParser.ForControlContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitForInit(JavaParser.ForInitContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEnhancedForControl(JavaParser.EnhancedForControlContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitParExpression(JavaParser.ParExpressionContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExpressionList(JavaParser.ExpressionListContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitMethodCall(JavaParser.MethodCallContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExpression(JavaParser.ExpressionContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLambdaExpression(JavaParser.LambdaExpressionContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLambdaParameters(JavaParser.LambdaParametersContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLambdaBody(JavaParser.LambdaBodyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitPrimary(JavaParser.PrimaryContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassType(JavaParser.ClassTypeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCreator(JavaParser.CreatorContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCreatedName(JavaParser.CreatedNameContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInnerCreator(JavaParser.InnerCreatorContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitClassCreatorRest(JavaParser.ClassCreatorRestContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeList(JavaParser.TypeListContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeType(JavaParser.TypeTypeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitPrimitiveType(JavaParser.PrimitiveTypeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTypeArguments(JavaParser.TypeArgumentsContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitSuperSuffix(JavaParser.SuperSuffixContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArguments(JavaParser.ArgumentsContext ctx) { return visitChildren(ctx); } +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserListener.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserListener.java new file mode 100644 index 000000000..4c4cf2a2f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserListener.java @@ -0,0 +1,1060 @@ +// Generated from JavaParser.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; +import org.antlr.v4.runtime.tree.ParseTreeListener; + +/** + * This interface defines a complete listener for a parse tree produced by + * {@link JavaParser}. + */ +public interface JavaParserListener extends ParseTreeListener { + /** + * Enter a parse tree produced by {@link JavaParser#compilationUnit}. + * @param ctx the parse tree + */ + void enterCompilationUnit(JavaParser.CompilationUnitContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#compilationUnit}. + * @param ctx the parse tree + */ + void exitCompilationUnit(JavaParser.CompilationUnitContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#packageDeclaration}. + * @param ctx the parse tree + */ + void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#packageDeclaration}. + * @param ctx the parse tree + */ + void exitPackageDeclaration(JavaParser.PackageDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#importDeclaration}. + * @param ctx the parse tree + */ + void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#importDeclaration}. + * @param ctx the parse tree + */ + void exitImportDeclaration(JavaParser.ImportDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeDeclaration}. + * @param ctx the parse tree + */ + void enterTypeDeclaration(JavaParser.TypeDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeDeclaration}. + * @param ctx the parse tree + */ + void exitTypeDeclaration(JavaParser.TypeDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#modifier}. + * @param ctx the parse tree + */ + void enterModifier(JavaParser.ModifierContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#modifier}. + * @param ctx the parse tree + */ + void exitModifier(JavaParser.ModifierContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classOrInterfaceModifier}. + * @param ctx the parse tree + */ + void enterClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classOrInterfaceModifier}. + * @param ctx the parse tree + */ + void exitClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#variableModifier}. + * @param ctx the parse tree + */ + void enterVariableModifier(JavaParser.VariableModifierContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#variableModifier}. + * @param ctx the parse tree + */ + void exitVariableModifier(JavaParser.VariableModifierContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classDeclaration}. + * @param ctx the parse tree + */ + void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classDeclaration}. + * @param ctx the parse tree + */ + void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeParameters}. + * @param ctx the parse tree + */ + void enterTypeParameters(JavaParser.TypeParametersContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeParameters}. + * @param ctx the parse tree + */ + void exitTypeParameters(JavaParser.TypeParametersContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeParameter}. + * @param ctx the parse tree + */ + void enterTypeParameter(JavaParser.TypeParameterContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeParameter}. + * @param ctx the parse tree + */ + void exitTypeParameter(JavaParser.TypeParameterContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeBound}. + * @param ctx the parse tree + */ + void enterTypeBound(JavaParser.TypeBoundContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeBound}. + * @param ctx the parse tree + */ + void exitTypeBound(JavaParser.TypeBoundContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#enumDeclaration}. + * @param ctx the parse tree + */ + void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#enumDeclaration}. + * @param ctx the parse tree + */ + void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#enumConstants}. + * @param ctx the parse tree + */ + void enterEnumConstants(JavaParser.EnumConstantsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#enumConstants}. + * @param ctx the parse tree + */ + void exitEnumConstants(JavaParser.EnumConstantsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#enumConstant}. + * @param ctx the parse tree + */ + void enterEnumConstant(JavaParser.EnumConstantContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#enumConstant}. + * @param ctx the parse tree + */ + void exitEnumConstant(JavaParser.EnumConstantContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#enumBodyDeclarations}. + * @param ctx the parse tree + */ + void enterEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#enumBodyDeclarations}. + * @param ctx the parse tree + */ + void exitEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceDeclaration}. + * @param ctx the parse tree + */ + void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceDeclaration}. + * @param ctx the parse tree + */ + void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classBody}. + * @param ctx the parse tree + */ + void enterClassBody(JavaParser.ClassBodyContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classBody}. + * @param ctx the parse tree + */ + void exitClassBody(JavaParser.ClassBodyContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceBody}. + * @param ctx the parse tree + */ + void enterInterfaceBody(JavaParser.InterfaceBodyContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceBody}. + * @param ctx the parse tree + */ + void exitInterfaceBody(JavaParser.InterfaceBodyContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classBodyDeclaration}. + * @param ctx the parse tree + */ + void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classBodyDeclaration}. + * @param ctx the parse tree + */ + void exitClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#memberDeclaration}. + * @param ctx the parse tree + */ + void enterMemberDeclaration(JavaParser.MemberDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#memberDeclaration}. + * @param ctx the parse tree + */ + void exitMemberDeclaration(JavaParser.MemberDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#methodDeclaration}. + * @param ctx the parse tree + */ + void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#methodDeclaration}. + * @param ctx the parse tree + */ + void exitMethodDeclaration(JavaParser.MethodDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#methodBody}. + * @param ctx the parse tree + */ + void enterMethodBody(JavaParser.MethodBodyContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#methodBody}. + * @param ctx the parse tree + */ + void exitMethodBody(JavaParser.MethodBodyContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeTypeOrVoid}. + * @param ctx the parse tree + */ + void enterTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeTypeOrVoid}. + * @param ctx the parse tree + */ + void exitTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#genericMethodDeclaration}. + * @param ctx the parse tree + */ + void enterGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#genericMethodDeclaration}. + * @param ctx the parse tree + */ + void exitGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#genericConstructorDeclaration}. + * @param ctx the parse tree + */ + void enterGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#genericConstructorDeclaration}. + * @param ctx the parse tree + */ + void exitGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#constructorDeclaration}. + * @param ctx the parse tree + */ + void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#constructorDeclaration}. + * @param ctx the parse tree + */ + void exitConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#fieldDeclaration}. + * @param ctx the parse tree + */ + void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#fieldDeclaration}. + * @param ctx the parse tree + */ + void exitFieldDeclaration(JavaParser.FieldDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceBodyDeclaration}. + * @param ctx the parse tree + */ + void enterInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceBodyDeclaration}. + * @param ctx the parse tree + */ + void exitInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceMemberDeclaration}. + * @param ctx the parse tree + */ + void enterInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceMemberDeclaration}. + * @param ctx the parse tree + */ + void exitInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#constDeclaration}. + * @param ctx the parse tree + */ + void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#constDeclaration}. + * @param ctx the parse tree + */ + void exitConstDeclaration(JavaParser.ConstDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#constantDeclarator}. + * @param ctx the parse tree + */ + void enterConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#constantDeclarator}. + * @param ctx the parse tree + */ + void exitConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceMethodDeclaration}. + * @param ctx the parse tree + */ + void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceMethodDeclaration}. + * @param ctx the parse tree + */ + void exitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#interfaceMethodModifier}. + * @param ctx the parse tree + */ + void enterInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#interfaceMethodModifier}. + * @param ctx the parse tree + */ + void exitInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#genericInterfaceMethodDeclaration}. + * @param ctx the parse tree + */ + void enterGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#genericInterfaceMethodDeclaration}. + * @param ctx the parse tree + */ + void exitGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#variableDeclarators}. + * @param ctx the parse tree + */ + void enterVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#variableDeclarators}. + * @param ctx the parse tree + */ + void exitVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#variableDeclarator}. + * @param ctx the parse tree + */ + void enterVariableDeclarator(JavaParser.VariableDeclaratorContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#variableDeclarator}. + * @param ctx the parse tree + */ + void exitVariableDeclarator(JavaParser.VariableDeclaratorContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#variableDeclaratorId}. + * @param ctx the parse tree + */ + void enterVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#variableDeclaratorId}. + * @param ctx the parse tree + */ + void exitVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#variableInitializer}. + * @param ctx the parse tree + */ + void enterVariableInitializer(JavaParser.VariableInitializerContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#variableInitializer}. + * @param ctx the parse tree + */ + void exitVariableInitializer(JavaParser.VariableInitializerContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#arrayInitializer}. + * @param ctx the parse tree + */ + void enterArrayInitializer(JavaParser.ArrayInitializerContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#arrayInitializer}. + * @param ctx the parse tree + */ + void exitArrayInitializer(JavaParser.ArrayInitializerContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classOrInterfaceType}. + * @param ctx the parse tree + */ + void enterClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classOrInterfaceType}. + * @param ctx the parse tree + */ + void exitClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeArgument}. + * @param ctx the parse tree + */ + void enterTypeArgument(JavaParser.TypeArgumentContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeArgument}. + * @param ctx the parse tree + */ + void exitTypeArgument(JavaParser.TypeArgumentContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#qualifiedNameList}. + * @param ctx the parse tree + */ + void enterQualifiedNameList(JavaParser.QualifiedNameListContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#qualifiedNameList}. + * @param ctx the parse tree + */ + void exitQualifiedNameList(JavaParser.QualifiedNameListContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#formalParameters}. + * @param ctx the parse tree + */ + void enterFormalParameters(JavaParser.FormalParametersContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#formalParameters}. + * @param ctx the parse tree + */ + void exitFormalParameters(JavaParser.FormalParametersContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#formalParameterList}. + * @param ctx the parse tree + */ + void enterFormalParameterList(JavaParser.FormalParameterListContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#formalParameterList}. + * @param ctx the parse tree + */ + void exitFormalParameterList(JavaParser.FormalParameterListContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#formalParameter}. + * @param ctx the parse tree + */ + void enterFormalParameter(JavaParser.FormalParameterContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#formalParameter}. + * @param ctx the parse tree + */ + void exitFormalParameter(JavaParser.FormalParameterContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#lastFormalParameter}. + * @param ctx the parse tree + */ + void enterLastFormalParameter(JavaParser.LastFormalParameterContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#lastFormalParameter}. + * @param ctx the parse tree + */ + void exitLastFormalParameter(JavaParser.LastFormalParameterContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#qualifiedName}. + * @param ctx the parse tree + */ + void enterQualifiedName(JavaParser.QualifiedNameContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#qualifiedName}. + * @param ctx the parse tree + */ + void exitQualifiedName(JavaParser.QualifiedNameContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#literal}. + * @param ctx the parse tree + */ + void enterLiteral(JavaParser.LiteralContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#literal}. + * @param ctx the parse tree + */ + void exitLiteral(JavaParser.LiteralContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#integerLiteral}. + * @param ctx the parse tree + */ + void enterIntegerLiteral(JavaParser.IntegerLiteralContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#integerLiteral}. + * @param ctx the parse tree + */ + void exitIntegerLiteral(JavaParser.IntegerLiteralContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#floatLiteral}. + * @param ctx the parse tree + */ + void enterFloatLiteral(JavaParser.FloatLiteralContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#floatLiteral}. + * @param ctx the parse tree + */ + void exitFloatLiteral(JavaParser.FloatLiteralContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#altAnnotationQualifiedName}. + * @param ctx the parse tree + */ + void enterAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#altAnnotationQualifiedName}. + * @param ctx the parse tree + */ + void exitAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotation}. + * @param ctx the parse tree + */ + void enterAnnotation(JavaParser.AnnotationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotation}. + * @param ctx the parse tree + */ + void exitAnnotation(JavaParser.AnnotationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#elementValuePairs}. + * @param ctx the parse tree + */ + void enterElementValuePairs(JavaParser.ElementValuePairsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#elementValuePairs}. + * @param ctx the parse tree + */ + void exitElementValuePairs(JavaParser.ElementValuePairsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#elementValuePair}. + * @param ctx the parse tree + */ + void enterElementValuePair(JavaParser.ElementValuePairContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#elementValuePair}. + * @param ctx the parse tree + */ + void exitElementValuePair(JavaParser.ElementValuePairContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#elementValue}. + * @param ctx the parse tree + */ + void enterElementValue(JavaParser.ElementValueContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#elementValue}. + * @param ctx the parse tree + */ + void exitElementValue(JavaParser.ElementValueContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#elementValueArrayInitializer}. + * @param ctx the parse tree + */ + void enterElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#elementValueArrayInitializer}. + * @param ctx the parse tree + */ + void exitElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationTypeDeclaration}. + * @param ctx the parse tree + */ + void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationTypeDeclaration}. + * @param ctx the parse tree + */ + void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationTypeBody}. + * @param ctx the parse tree + */ + void enterAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationTypeBody}. + * @param ctx the parse tree + */ + void exitAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationTypeElementDeclaration}. + * @param ctx the parse tree + */ + void enterAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationTypeElementDeclaration}. + * @param ctx the parse tree + */ + void exitAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationTypeElementRest}. + * @param ctx the parse tree + */ + void enterAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationTypeElementRest}. + * @param ctx the parse tree + */ + void exitAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationMethodOrConstantRest}. + * @param ctx the parse tree + */ + void enterAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationMethodOrConstantRest}. + * @param ctx the parse tree + */ + void exitAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationMethodRest}. + * @param ctx the parse tree + */ + void enterAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationMethodRest}. + * @param ctx the parse tree + */ + void exitAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#annotationConstantRest}. + * @param ctx the parse tree + */ + void enterAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#annotationConstantRest}. + * @param ctx the parse tree + */ + void exitAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#defaultValue}. + * @param ctx the parse tree + */ + void enterDefaultValue(JavaParser.DefaultValueContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#defaultValue}. + * @param ctx the parse tree + */ + void exitDefaultValue(JavaParser.DefaultValueContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#block}. + * @param ctx the parse tree + */ + void enterBlock(JavaParser.BlockContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#block}. + * @param ctx the parse tree + */ + void exitBlock(JavaParser.BlockContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#blockStatement}. + * @param ctx the parse tree + */ + void enterBlockStatement(JavaParser.BlockStatementContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#blockStatement}. + * @param ctx the parse tree + */ + void exitBlockStatement(JavaParser.BlockStatementContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#localVariableDeclaration}. + * @param ctx the parse tree + */ + void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#localVariableDeclaration}. + * @param ctx the parse tree + */ + void exitLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#localTypeDeclaration}. + * @param ctx the parse tree + */ + void enterLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#localTypeDeclaration}. + * @param ctx the parse tree + */ + void exitLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#statement}. + * @param ctx the parse tree + */ + void enterStatement(JavaParser.StatementContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#statement}. + * @param ctx the parse tree + */ + void exitStatement(JavaParser.StatementContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#catchClause}. + * @param ctx the parse tree + */ + void enterCatchClause(JavaParser.CatchClauseContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#catchClause}. + * @param ctx the parse tree + */ + void exitCatchClause(JavaParser.CatchClauseContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#catchType}. + * @param ctx the parse tree + */ + void enterCatchType(JavaParser.CatchTypeContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#catchType}. + * @param ctx the parse tree + */ + void exitCatchType(JavaParser.CatchTypeContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#finallyBlock}. + * @param ctx the parse tree + */ + void enterFinallyBlock(JavaParser.FinallyBlockContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#finallyBlock}. + * @param ctx the parse tree + */ + void exitFinallyBlock(JavaParser.FinallyBlockContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#resourceSpecification}. + * @param ctx the parse tree + */ + void enterResourceSpecification(JavaParser.ResourceSpecificationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#resourceSpecification}. + * @param ctx the parse tree + */ + void exitResourceSpecification(JavaParser.ResourceSpecificationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#resources}. + * @param ctx the parse tree + */ + void enterResources(JavaParser.ResourcesContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#resources}. + * @param ctx the parse tree + */ + void exitResources(JavaParser.ResourcesContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#resource}. + * @param ctx the parse tree + */ + void enterResource(JavaParser.ResourceContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#resource}. + * @param ctx the parse tree + */ + void exitResource(JavaParser.ResourceContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#switchBlockStatementGroup}. + * @param ctx the parse tree + */ + void enterSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#switchBlockStatementGroup}. + * @param ctx the parse tree + */ + void exitSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#switchLabel}. + * @param ctx the parse tree + */ + void enterSwitchLabel(JavaParser.SwitchLabelContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#switchLabel}. + * @param ctx the parse tree + */ + void exitSwitchLabel(JavaParser.SwitchLabelContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#forControl}. + * @param ctx the parse tree + */ + void enterForControl(JavaParser.ForControlContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#forControl}. + * @param ctx the parse tree + */ + void exitForControl(JavaParser.ForControlContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#forInit}. + * @param ctx the parse tree + */ + void enterForInit(JavaParser.ForInitContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#forInit}. + * @param ctx the parse tree + */ + void exitForInit(JavaParser.ForInitContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#enhancedForControl}. + * @param ctx the parse tree + */ + void enterEnhancedForControl(JavaParser.EnhancedForControlContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#enhancedForControl}. + * @param ctx the parse tree + */ + void exitEnhancedForControl(JavaParser.EnhancedForControlContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#parExpression}. + * @param ctx the parse tree + */ + void enterParExpression(JavaParser.ParExpressionContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#parExpression}. + * @param ctx the parse tree + */ + void exitParExpression(JavaParser.ParExpressionContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#expressionList}. + * @param ctx the parse tree + */ + void enterExpressionList(JavaParser.ExpressionListContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#expressionList}. + * @param ctx the parse tree + */ + void exitExpressionList(JavaParser.ExpressionListContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#methodCall}. + * @param ctx the parse tree + */ + void enterMethodCall(JavaParser.MethodCallContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#methodCall}. + * @param ctx the parse tree + */ + void exitMethodCall(JavaParser.MethodCallContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#expression}. + * @param ctx the parse tree + */ + void enterExpression(JavaParser.ExpressionContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#expression}. + * @param ctx the parse tree + */ + void exitExpression(JavaParser.ExpressionContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#lambdaExpression}. + * @param ctx the parse tree + */ + void enterLambdaExpression(JavaParser.LambdaExpressionContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#lambdaExpression}. + * @param ctx the parse tree + */ + void exitLambdaExpression(JavaParser.LambdaExpressionContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#lambdaParameters}. + * @param ctx the parse tree + */ + void enterLambdaParameters(JavaParser.LambdaParametersContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#lambdaParameters}. + * @param ctx the parse tree + */ + void exitLambdaParameters(JavaParser.LambdaParametersContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#lambdaBody}. + * @param ctx the parse tree + */ + void enterLambdaBody(JavaParser.LambdaBodyContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#lambdaBody}. + * @param ctx the parse tree + */ + void exitLambdaBody(JavaParser.LambdaBodyContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#primary}. + * @param ctx the parse tree + */ + void enterPrimary(JavaParser.PrimaryContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#primary}. + * @param ctx the parse tree + */ + void exitPrimary(JavaParser.PrimaryContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classType}. + * @param ctx the parse tree + */ + void enterClassType(JavaParser.ClassTypeContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classType}. + * @param ctx the parse tree + */ + void exitClassType(JavaParser.ClassTypeContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#creator}. + * @param ctx the parse tree + */ + void enterCreator(JavaParser.CreatorContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#creator}. + * @param ctx the parse tree + */ + void exitCreator(JavaParser.CreatorContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#createdName}. + * @param ctx the parse tree + */ + void enterCreatedName(JavaParser.CreatedNameContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#createdName}. + * @param ctx the parse tree + */ + void exitCreatedName(JavaParser.CreatedNameContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#innerCreator}. + * @param ctx the parse tree + */ + void enterInnerCreator(JavaParser.InnerCreatorContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#innerCreator}. + * @param ctx the parse tree + */ + void exitInnerCreator(JavaParser.InnerCreatorContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#arrayCreatorRest}. + * @param ctx the parse tree + */ + void enterArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#arrayCreatorRest}. + * @param ctx the parse tree + */ + void exitArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#classCreatorRest}. + * @param ctx the parse tree + */ + void enterClassCreatorRest(JavaParser.ClassCreatorRestContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#classCreatorRest}. + * @param ctx the parse tree + */ + void exitClassCreatorRest(JavaParser.ClassCreatorRestContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#explicitGenericInvocation}. + * @param ctx the parse tree + */ + void enterExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#explicitGenericInvocation}. + * @param ctx the parse tree + */ + void exitExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeArgumentsOrDiamond}. + * @param ctx the parse tree + */ + void enterTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeArgumentsOrDiamond}. + * @param ctx the parse tree + */ + void exitTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#nonWildcardTypeArgumentsOrDiamond}. + * @param ctx the parse tree + */ + void enterNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#nonWildcardTypeArgumentsOrDiamond}. + * @param ctx the parse tree + */ + void exitNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#nonWildcardTypeArguments}. + * @param ctx the parse tree + */ + void enterNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#nonWildcardTypeArguments}. + * @param ctx the parse tree + */ + void exitNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeList}. + * @param ctx the parse tree + */ + void enterTypeList(JavaParser.TypeListContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeList}. + * @param ctx the parse tree + */ + void exitTypeList(JavaParser.TypeListContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeType}. + * @param ctx the parse tree + */ + void enterTypeType(JavaParser.TypeTypeContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeType}. + * @param ctx the parse tree + */ + void exitTypeType(JavaParser.TypeTypeContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#primitiveType}. + * @param ctx the parse tree + */ + void enterPrimitiveType(JavaParser.PrimitiveTypeContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#primitiveType}. + * @param ctx the parse tree + */ + void exitPrimitiveType(JavaParser.PrimitiveTypeContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#typeArguments}. + * @param ctx the parse tree + */ + void enterTypeArguments(JavaParser.TypeArgumentsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#typeArguments}. + * @param ctx the parse tree + */ + void exitTypeArguments(JavaParser.TypeArgumentsContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#superSuffix}. + * @param ctx the parse tree + */ + void enterSuperSuffix(JavaParser.SuperSuffixContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#superSuffix}. + * @param ctx the parse tree + */ + void exitSuperSuffix(JavaParser.SuperSuffixContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#explicitGenericInvocationSuffix}. + * @param ctx the parse tree + */ + void enterExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#explicitGenericInvocationSuffix}. + * @param ctx the parse tree + */ + void exitExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx); + /** + * Enter a parse tree produced by {@link JavaParser#arguments}. + * @param ctx the parse tree + */ + void enterArguments(JavaParser.ArgumentsContext ctx); + /** + * Exit a parse tree produced by {@link JavaParser#arguments}. + * @param ctx the parse tree + */ + void exitArguments(JavaParser.ArgumentsContext ctx); +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserVisitor.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserVisitor.java new file mode 100644 index 000000000..55625147d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavaParserVisitor.java @@ -0,0 +1,643 @@ +// Generated from JavaParser.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.java.parser; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by {@link JavaParser}. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public interface JavaParserVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link JavaParser#compilationUnit}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCompilationUnit(JavaParser.CompilationUnitContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#packageDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitPackageDeclaration(JavaParser.PackageDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#importDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitImportDeclaration(JavaParser.ImportDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeDeclaration(JavaParser.TypeDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#modifier}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitModifier(JavaParser.ModifierContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classOrInterfaceModifier}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassOrInterfaceModifier(JavaParser.ClassOrInterfaceModifierContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#variableModifier}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitVariableModifier(JavaParser.VariableModifierContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassDeclaration(JavaParser.ClassDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeParameters}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeParameters(JavaParser.TypeParametersContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeParameter}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeParameter(JavaParser.TypeParameterContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeBound}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeBound(JavaParser.TypeBoundContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#enumDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEnumDeclaration(JavaParser.EnumDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#enumConstants}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEnumConstants(JavaParser.EnumConstantsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#enumConstant}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEnumConstant(JavaParser.EnumConstantContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#enumBodyDeclarations}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEnumBodyDeclarations(JavaParser.EnumBodyDeclarationsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classBody}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassBody(JavaParser.ClassBodyContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceBody}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceBody(JavaParser.InterfaceBodyContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classBodyDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#memberDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitMemberDeclaration(JavaParser.MemberDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#methodDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitMethodDeclaration(JavaParser.MethodDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#methodBody}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitMethodBody(JavaParser.MethodBodyContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeTypeOrVoid}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeTypeOrVoid(JavaParser.TypeTypeOrVoidContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#genericMethodDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitGenericMethodDeclaration(JavaParser.GenericMethodDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#genericConstructorDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitGenericConstructorDeclaration(JavaParser.GenericConstructorDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#constructorDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#fieldDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFieldDeclaration(JavaParser.FieldDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceBodyDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceBodyDeclaration(JavaParser.InterfaceBodyDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceMemberDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceMemberDeclaration(JavaParser.InterfaceMemberDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#constDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitConstDeclaration(JavaParser.ConstDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#constantDeclarator}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitConstantDeclarator(JavaParser.ConstantDeclaratorContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceMethodDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#interfaceMethodModifier}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInterfaceMethodModifier(JavaParser.InterfaceMethodModifierContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#genericInterfaceMethodDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitGenericInterfaceMethodDeclaration(JavaParser.GenericInterfaceMethodDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#variableDeclarators}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitVariableDeclarators(JavaParser.VariableDeclaratorsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#variableDeclarator}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitVariableDeclarator(JavaParser.VariableDeclaratorContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#variableDeclaratorId}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitVariableDeclaratorId(JavaParser.VariableDeclaratorIdContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#variableInitializer}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitVariableInitializer(JavaParser.VariableInitializerContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#arrayInitializer}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArrayInitializer(JavaParser.ArrayInitializerContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classOrInterfaceType}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassOrInterfaceType(JavaParser.ClassOrInterfaceTypeContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeArgument}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeArgument(JavaParser.TypeArgumentContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#qualifiedNameList}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitQualifiedNameList(JavaParser.QualifiedNameListContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#formalParameters}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFormalParameters(JavaParser.FormalParametersContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#formalParameterList}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFormalParameterList(JavaParser.FormalParameterListContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#formalParameter}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFormalParameter(JavaParser.FormalParameterContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#lastFormalParameter}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLastFormalParameter(JavaParser.LastFormalParameterContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#qualifiedName}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitQualifiedName(JavaParser.QualifiedNameContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#literal}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLiteral(JavaParser.LiteralContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#integerLiteral}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitIntegerLiteral(JavaParser.IntegerLiteralContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#floatLiteral}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFloatLiteral(JavaParser.FloatLiteralContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#altAnnotationQualifiedName}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAltAnnotationQualifiedName(JavaParser.AltAnnotationQualifiedNameContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotation}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotation(JavaParser.AnnotationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#elementValuePairs}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitElementValuePairs(JavaParser.ElementValuePairsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#elementValuePair}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitElementValuePair(JavaParser.ElementValuePairContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#elementValue}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitElementValue(JavaParser.ElementValueContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#elementValueArrayInitializer}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitElementValueArrayInitializer(JavaParser.ElementValueArrayInitializerContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationTypeDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationTypeBody}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationTypeBody(JavaParser.AnnotationTypeBodyContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationTypeElementDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationTypeElementDeclaration(JavaParser.AnnotationTypeElementDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationTypeElementRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationTypeElementRest(JavaParser.AnnotationTypeElementRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationMethodOrConstantRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationMethodOrConstantRest(JavaParser.AnnotationMethodOrConstantRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationMethodRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationMethodRest(JavaParser.AnnotationMethodRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#annotationConstantRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitAnnotationConstantRest(JavaParser.AnnotationConstantRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#defaultValue}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitDefaultValue(JavaParser.DefaultValueContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#block}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitBlock(JavaParser.BlockContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#blockStatement}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitBlockStatement(JavaParser.BlockStatementContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#localVariableDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#localTypeDeclaration}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLocalTypeDeclaration(JavaParser.LocalTypeDeclarationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#statement}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStatement(JavaParser.StatementContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#catchClause}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCatchClause(JavaParser.CatchClauseContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#catchType}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCatchType(JavaParser.CatchTypeContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#finallyBlock}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFinallyBlock(JavaParser.FinallyBlockContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#resourceSpecification}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitResourceSpecification(JavaParser.ResourceSpecificationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#resources}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitResources(JavaParser.ResourcesContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#resource}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitResource(JavaParser.ResourceContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#switchBlockStatementGroup}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitSwitchBlockStatementGroup(JavaParser.SwitchBlockStatementGroupContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#switchLabel}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitSwitchLabel(JavaParser.SwitchLabelContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#forControl}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitForControl(JavaParser.ForControlContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#forInit}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitForInit(JavaParser.ForInitContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#enhancedForControl}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEnhancedForControl(JavaParser.EnhancedForControlContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#parExpression}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitParExpression(JavaParser.ParExpressionContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#expressionList}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExpressionList(JavaParser.ExpressionListContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#methodCall}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitMethodCall(JavaParser.MethodCallContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#expression}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExpression(JavaParser.ExpressionContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#lambdaExpression}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLambdaExpression(JavaParser.LambdaExpressionContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#lambdaParameters}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLambdaParameters(JavaParser.LambdaParametersContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#lambdaBody}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLambdaBody(JavaParser.LambdaBodyContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#primary}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitPrimary(JavaParser.PrimaryContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classType}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassType(JavaParser.ClassTypeContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#creator}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCreator(JavaParser.CreatorContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#createdName}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCreatedName(JavaParser.CreatedNameContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#innerCreator}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInnerCreator(JavaParser.InnerCreatorContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#arrayCreatorRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArrayCreatorRest(JavaParser.ArrayCreatorRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#classCreatorRest}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitClassCreatorRest(JavaParser.ClassCreatorRestContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#explicitGenericInvocation}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExplicitGenericInvocation(JavaParser.ExplicitGenericInvocationContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeArgumentsOrDiamond}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeArgumentsOrDiamond(JavaParser.TypeArgumentsOrDiamondContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#nonWildcardTypeArgumentsOrDiamond}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitNonWildcardTypeArgumentsOrDiamond(JavaParser.NonWildcardTypeArgumentsOrDiamondContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#nonWildcardTypeArguments}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitNonWildcardTypeArguments(JavaParser.NonWildcardTypeArgumentsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeList}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeList(JavaParser.TypeListContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeType}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeType(JavaParser.TypeTypeContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#primitiveType}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitPrimitiveType(JavaParser.PrimitiveTypeContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#typeArguments}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTypeArguments(JavaParser.TypeArgumentsContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#superSuffix}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitSuperSuffix(JavaParser.SuperSuffixContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#explicitGenericInvocationSuffix}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExplicitGenericInvocationSuffix(JavaParser.ExplicitGenericInvocationSuffixContext ctx); + /** + * Visit a parse tree produced by {@link JavaParser#arguments}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArguments(JavaParser.ArgumentsContext ctx); +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/JavacParser.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavacParser.java new file mode 100644 index 000000000..562fdd43f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/JavacParser.java @@ -0,0 +1,283 @@ +package com.itsaky.androidide.language.java.parser; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.itsaky.androidide.javadoc.JavaDoc; +import com.itsaky.androidide.javadoc.JavaDocParser; +import com.itsaky.androidide.javadoc.JavaDocParserBuilder; +import com.itsaky.androidide.javadoc.OutputType; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.model.ClassDescription; +import com.itsaky.androidide.language.java.parser.model.ConstructorDescription; +import com.itsaky.androidide.language.java.parser.model.FieldDescription; +import com.itsaky.androidide.language.java.parser.model.MethodDescription; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.parser.Parser; +import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.Tokens; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Options; +import io.github.rosemoe.editor.text.Content; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.lang.model.element.Modifier; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardLocation; + +import static com.sun.tools.javac.tree.JCTree.*; + +public class JavacParser { + + private Context context; + private ParserFactory parserFactory; + private JavaDocParser javadocParser; + private DiagnosticCollector diagnostics; + private boolean canParse = true; + + private static final String DOT = "."; + private static final String CONSTRUCTOR_NAME = ""; + + public JavacParser() { + context = new Context(); + diagnostics = new DiagnosticCollector(); + context.put(DiagnosticListener.class, diagnostics); + Options.instance(context).put("allowStringFolding", "false"); + JavacFileManager fileManager = new JavacFileManager(context, true, Charsets.UTF_8); + try { + fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, ImmutableList.of()); + } catch (IOException e) { + canParse = false; + } + parserFactory = ParserFactory.instance(context); + } + + @Nullable + public JCCompilationUnit parse(Content src) { + return parse(src.toString()); + } + + @Nullable + public JCCompilationUnit parse(final String src) { + if (!canParse) return null; + SimpleJavaFileObject source = new SimpleJavaFileObject(URI.create("source"), JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return src; + } + }; + Log.instance(context).useSource(source); + diagnostics.clearDiagnostics(); + Parser parser = + parserFactory.newParser(src, + /*keepDocComments=*/ true, // Necessary, because we show doc comments in AndroidIDE + /*keepEndPos=*/ true, + /*keepLineMap=*/ true); + JCCompilationUnit unit; + unit = parser.parseCompilationUnit(); + unit.sourcefile = source; + return unit; + } + + @Nullable + public List> getDiagnostics() { + if (!canParse) return null; + return diagnostics.getDiagnostics(); + } + + public List parseClasses(JCCompilationUnit unit) { + List classes = new ArrayList<>(); + List typeDecls = unit.getTypeDecls(); + for (JCTree typeDecl : typeDecls) { + if (typeDecl instanceof JCClassDecl) { + classes.add(parseClass(unit, (JCClassDecl) typeDecl)); + } + } + return classes; + } + + private IClass parseClass(JCCompilationUnit unit, JCClassDecl classDecl) { + final String className = unit.getPackageName() + DOT + classDecl.getSimpleName(); + final int modifiers = JavaUtil.toJavaModifiers(classDecl.getModifiers().getFlags()); + + ClassDescription clazz = new ClassDescription( + className, + modifiers, + false, + classDecl.getKind() == Tree.Kind.ANNOTATION_TYPE, + classDecl.getKind() == Tree.Kind.ENUM, + false); + + IClass extendsClass = JavaUtil.jcTypeToClass(unit, classDecl.getExtendsClause()); + if (extendsClass != null) { + clazz.setSuperclass(extendsClass); + } else { + clazz.setSuperclass(JavaClassManager.getInstance().getParsedClass(Object.class.getName())); + } + + List members = classDecl.getMembers(); + for (JCTree member : members) { + if (member instanceof JCTree.JCMethodDecl) { + addMethod(unit, clazz, (JCTree.JCMethodDecl) member); + } else if (member instanceof JCTree.JCVariableDecl) { + addVariable(unit, clazz, classDecl, (JCTree.JCVariableDecl) member); + } else if(member instanceof JCTree.JCClassDecl) { + addNestedClass(unit, classDecl, (JCTree.JCClassDecl) member); + } + } + if(clazz != null && unit.docComments != null && unit.docComments.hasComment(classDecl)) { + Tokens.Comment comment = unit.docComments.getComment(classDecl); + if(comment.getStyle() == Tokens.Comment.CommentStyle.JAVADOC) { + processJavaDoc(comment, clazz); + } + } + //now add constructor + //add methods + return clazz; + } + + private void addNestedClass(@NonNull JCCompilationUnit ast, JCClassDecl parent, JCClassDecl classDecl) { + final String className = ast.getPackageName() + DOT + parent.getSimpleName() + "$" + classDecl.getSimpleName(); + final int modifiers = JavaUtil.toJavaModifiers(classDecl.getModifiers().getFlags()); + ClassDescription clazz = new ClassDescription( + className, + modifiers, + false, + classDecl.getKind() == Tree.Kind.ANNOTATION_TYPE, + classDecl.getKind() == Tree.Kind.ENUM, + false); + IClass extendsClass = JavaUtil.jcTypeToClass(ast, classDecl.getExtendsClause()); + if (extendsClass != null) { + clazz.setSuperclass(extendsClass); + } else { + clazz.setSuperclass(JavaClassManager.getInstance().getParsedClass(Object.class.getName())); + } + + + List members = classDecl.getMembers(); + for (JCTree member : members) { + if (member instanceof JCTree.JCMethodDecl) { + addMethod(ast, clazz, (JCTree.JCMethodDecl) member); + } else if (member instanceof JCTree.JCVariableDecl) { + addVariable(ast, clazz, classDecl, (JCTree.JCVariableDecl) member); + } else if(member instanceof JCTree.JCClassDecl) { + addNestedClass(ast, classDecl, (JCTree.JCClassDecl) member); + } + } + + if(clazz != null && ast.docComments != null && ast.docComments.hasComment(classDecl)) { + Tokens.Comment comment = ast.docComments.getComment(classDecl); + if(comment.getStyle() == Tokens.Comment.CommentStyle.JAVADOC) { + processJavaDoc(comment, clazz); + } + } + } + + private void addVariable(@NonNull JCCompilationUnit unit, + ClassDescription clazz, @NonNull JCClassDecl classDecl, + @NonNull JCTree.JCVariableDecl member) { + String name = member.getName().toString(); + int modifiers = JavaUtil.toJavaModifiers(member.getModifiers().getFlags()); + IClass type = JavaUtil.jcTypeToClass(unit, member.getType()); + JCTree.JCExpression initializer = member.getInitializer(); + FieldDescription fieldDescription = new FieldDescription( + modifiers, + type, + name, + initializer != null ? initializer.toString() : null); + clazz.addField(fieldDescription); + if(fieldDescription != null && unit.docComments != null && unit.docComments.hasComment(member)) { + Tokens.Comment comment = unit.docComments.getComment(member); + if(comment.getStyle() == Tokens.Comment.CommentStyle.JAVADOC) { + processJavaDoc(comment, fieldDescription); + } + } + } + + private void addMethod(@NonNull JCCompilationUnit unit, + @NonNull ClassDescription clazz, + @NonNull JCTree.JCMethodDecl member) { + + + final String methodName = member.getName().toString(); + final int modifiers = JavaUtil.toJavaModifiers(member.getModifiers().getFlags()); + final List methodParameters = new ArrayList<>(); + List parameters = member.getParameters(); + for (JCTree.JCVariableDecl parameter : parameters) { + JCTree type = parameter.getType(); + IClass paramType = JavaUtil.jcTypeToClass(unit, type); + methodParameters.add(paramType); + } + + IClass returnType = JavaUtil.jcTypeToClass(unit, member.getReturnType()); + IJavaDocCommentable commetable = null; + if (member.getName().toString().equals(CONSTRUCTOR_NAME)) { + ConstructorDescription constructor = new ConstructorDescription( + clazz.getFullClassName(), + methodParameters); + clazz.addConstructor(constructor); + commetable = constructor; + } else { + MethodDescription methodDescription = new MethodDescription( + methodName, + modifiers, + methodParameters, + returnType); + clazz.addMethod(methodDescription); + commetable = methodDescription; + } + + if(commetable != null && unit.docComments != null && unit.docComments.hasComment(member)) { + Tokens.Comment comment = unit.docComments.getComment(member); + if(comment.getStyle() == Tokens.Comment.CommentStyle.JAVADOC) { + processJavaDoc(comment, commetable); + } + } + } + + private void processJavaDoc(Tokens.Comment comment, IJavaDocCommentable commetable) { + if(javadocParser == null) { + javadocParser = JavaDocParserBuilder.withBasicTags() + .withOutputType(OutputType.HTML) + .build(); + } + final JavaDoc doc = javadocParser.parse(comment.getText()); + final String html = doc.getSummary() + "\n" + doc.getDescription(); + commetable.setHtmlJavaDoc(html); + } + + + private void addConstructor(ClassDescription clazz, JCTree.JCMethodDecl member) { + ConstructorDescription constructorDescription; + } + + private JCClassDecl resolveClassSimpleName(List typeDecls) { + for (JCTree typeDecl : typeDecls) { + if (typeDecl instanceof JCClassDecl) { + JCModifiers modifiers = ((JCClassDecl) typeDecl).getModifiers(); + Set flags = modifiers.getFlags(); + for (Modifier flag : flags) { + if (flag.equals(Modifier.PUBLIC)) { + return (JCClassDecl) typeDecl; + } + } + } + } + return null; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteExpression.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteExpression.java new file mode 100644 index 000000000..45e4b31ba --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteExpression.java @@ -0,0 +1,151 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IField; +import com.itsaky.androidide.language.java.parser.internal.IMethod; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.sun.tools.javac.tree.EndPosTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import static com.sun.tools.javac.tree.JCTree.JCErroneous; +import static com.sun.tools.javac.tree.JCTree.JCExpression; + +/** + * This class very complex, implement after + */ +public class CompleteExpression extends JavaCompleteMatcherImpl { + private static final String TAG = "CompleteExpression"; + private final JavaDexClassLoader mClassLoader; + private EndPosTable mEndPositions; + + private JCCompilationUnit mAst; + private IClass mCurrentType; + + private int mCursor; + private CodeEditor mEditor; + + public CompleteExpression(@NonNull JavaDexClassLoader classLoader) { + mClassLoader = classLoader; + } + + public void prepare(CodeEditor editor, JCCompilationUnit ast) { + mEditor = editor; + mCursor = editor.getCursor().getLeft(); + mAst = ast; + mEndPositions = ast.endPositions; + + List typeDecls = mAst.getTypeDecls(); + for (JCTree typeDecl : typeDecls) { + if (typeDecl instanceof JCTree.JCClassDecl) { + int startPosition = typeDecl.getStartPosition(); + int endPosition = typeDecl.getEndPosition(mEndPositions); + if (startPosition <= mCursor && mCursor <= endPosition) { + String simpleName = ((JCTree.JCClassDecl) typeDecl).getSimpleName().toString(); + JCExpression packageName = ast.getPackageName(); + mCurrentType = JavaClassManager.getInstance() + .getParsedClass(packageName + "." + simpleName); + } + } + } + } + + @Override + public void getSuggestion(CodeEditor editor, String incomplete, List suggestItems) { + + } + + @Override + public boolean process(JCCompilationUnit ast, CodeEditor editor, Expression expression, + String unused, ArrayList result) { + try { + prepare(editor, ast); + return expression != null && performComplete(expression.getExpression(), result); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + private boolean performComplete(JCExpression jcExpression, ArrayList result) { + if (jcExpression instanceof JCErroneous) { + List errorTrees = ((JCErroneous) jcExpression).getErrorTrees(); + JCTree errExpr = errorTrees.get(0); + if (errExpr instanceof JCExpression) { + return performComplete((JCExpression) errExpr, result); + } + + } else if (jcExpression instanceof JCFieldAccess) { + return performCompleteFieldAccess((JCFieldAccess) jcExpression, result); + + } else if (jcExpression instanceof JCTree.JCIdent) { + return performCompleteIdent((JCTree.JCIdent) jcExpression, result); + + } + return false; + } + + /** + * Suggestion method, variable + */ + private boolean performCompleteIdent(JCTree.JCIdent jcIdent, ArrayList result) { + return false; + } + + private boolean performCompleteFieldAccess(@NonNull JCFieldAccess jcFieldAccess, + @NonNull ArrayList result) { + int startPosition = jcFieldAccess.getStartPosition(); + int cursorOffset = mCursor - startPosition; + int incompleteLength = jcFieldAccess.getIdentifier().length(); + String incomplete = jcFieldAccess.getIdentifier().toString(); + //simple hack, improve later + if (incomplete.equalsIgnoreCase("")) { + incomplete = ""; + } + + JCExpression expression = jcFieldAccess.getExpression(); + TypeResolver resolver = new TypeResolver(mClassLoader, mAst, mCurrentType); + IClass type = resolver.resolveType(expression, mCursor); + if (type != null) { + + List methods = type.getMethods(); + for (IMethod method : methods) { + if(Modifier.isPublic(method.getModifiers())) { + if(resolver.isStatic() && !Modifier.isStatic(method.getModifiers())) + continue; + if (method.getMethodName().toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + setInfo(method, mEditor, incomplete); + result.add(method); + } + } + } + + ArrayList fields = type.getFields(); + for (IField field : fields) { + if(Modifier.isPublic(field.getFieldModifiers())) { + if(resolver.isStatic() && !Modifier.isStatic(field.getFieldModifiers())) + continue; + if (field.getFieldName().toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + setInfo(field, mEditor, incomplete); + result.add(field); + } + } + } + + return true; + } + return false; + } + + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteNewKeyword.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteNewKeyword.java new file mode 100644 index 000000000..88db7a3d0 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteNewKeyword.java @@ -0,0 +1,81 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.language.java.parser.model.ConstructorDescription; +import com.itsaky.androidide.language.java.parser.model.PrimitiveArrayConstructorDescription; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Locale; + +/** + * Suggest constructor + */ +public class CompleteNewKeyword extends JavaCompleteMatcherImpl { + private static final Pattern NEW_CLASS = Pattern.compile( + "(\\s*new\\s+)(" + CONSTRUCTOR.pattern() + ")$", Pattern.MULTILINE); + private static final String[] PRIMITIVE_ARRAY_TYPE = + {"boolean", "byte", "double", "char", "float", "int", "long", "short"}; + + private final JavaDexClassLoader mClassLoader; + + public CompleteNewKeyword(JavaDexClassLoader classLoader) { + mClassLoader = classLoader; + } + + @Override + public boolean process(JCTree.JCCompilationUnit ast, + CodeEditor editor, Expression expression, + String statement, ArrayList result) { + Matcher matcher = NEW_CLASS.matcher(statement); + if (matcher.find()) { + String incompleteCts = matcher.group(2); + return getSuggestionInternal(editor, incompleteCts, result); + } + return false; + } + + @Override + public void getSuggestion(@NonNull CodeEditor editor, + @NonNull String incomplete, + @NonNull List suggestItems) { + getSuggestionInternal(editor, incomplete, suggestItems); + } + + private boolean getSuggestionInternal(@NonNull CodeEditor editor, @NonNull String incomplete, + @NonNull List suggestItems) { + if (incomplete.isEmpty()) { + return false; + } + + boolean handled = false; + //try to find constructor + List classes = mClassLoader.findAllWithPrefix(incomplete); + for (IClass clazz : classes) { + List constructors = clazz.getConstructors(); + setInfo(constructors, editor, incomplete); + suggestItems.addAll(constructors); + handled = true; + } + for (String type : PRIMITIVE_ARRAY_TYPE) { + if (type.toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + PrimitiveArrayConstructorDescription c + = new PrimitiveArrayConstructorDescription(type); + setInfo(c, editor, incomplete); + suggestItems.add(c); + handled = true; + } + } + + return handled; + } + + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompletePackage.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompletePackage.java new file mode 100644 index 000000000..db79f1a8c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompletePackage.java @@ -0,0 +1,93 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.PackageManager; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.language.java.parser.model.PackageDescription; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Locale; + +/** + * Complete package + * e.g. + *

+ * java.i| + * java.util.| + * java.util.Hash| + */ +public class CompletePackage extends JavaCompleteMatcherImpl { + private static final String TAG = "CompletePackage"; + + private static final Pattern PACKAGE + = Pattern.compile("^\\s*(package)\\s+([_A-Za-z0-9.]+)"); + private static final Pattern IMPORT_OR_IMPORT_STATIC + = Pattern.compile("^\\s*import(\\s+static)?\\s+([_A-Za-z0-9.]+)"); + + @NonNull + private final PackageManager mPackageManager; + + public CompletePackage(@NonNull PackageManager packageManager) { + mPackageManager = packageManager; + } + + @Override + public boolean process(JCTree.JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList result) { + Matcher matcher = PACKAGE.matcher(statement); + if (matcher.find()) { + String incompletePkg = matcher.group(2); + getSuggestion(editor, incompletePkg, result); + return true; + } + + matcher = IMPORT_OR_IMPORT_STATIC.matcher(statement); + if (matcher.find()) { + boolean isStatic = matcher.group(1) != null; + String incompletePkg = matcher.group(2); + getSuggestion(editor, incompletePkg, result); + } + + return false; + } + + @Override + public void getSuggestion(CodeEditor editor, String expr, List suggestItems) { + getSuggestionInternal(editor, expr, suggestItems, false); + } + + private void getSuggestionInternal(CodeEditor editor, String expr, List suggestItems, + boolean addSemicolon) { + + //package must be contains dot (.) + if (!expr.contains(".")) { + return; + } + + //completed package java.lang + int lastDotIndex = expr.lastIndexOf("."); + String completedPart = expr.substring(0, lastDotIndex /*not contains dot*/); + String incompletePart = expr.substring(lastDotIndex + 1); + + PackageDescription packages = mPackageManager.trace(completedPart); + if (packages != null) { + //members of current package + //such as java has more member (util, io, lang) + HashMap members = packages.getChild(); + for (Map.Entry entry : members.entrySet()) { + PackageDescription packageDescription = entry.getValue(); + if (packageDescription.getName().toLowerCase(Locale.US).startsWith(incompletePart.toLowerCase(Locale.US))) { + setInfo(packageDescription, editor, incompletePart); + suggestItems.add(packageDescription); + } + + } + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteString.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteString.java new file mode 100644 index 000000000..c367ead39 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteString.java @@ -0,0 +1,65 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IMethod; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Locale; +import java.lang.reflect.Modifier; + +public class CompleteString extends JavaCompleteMatcherImpl { + public static final Pattern STRING_DOT = + Pattern.compile("\"\\s*\\.\\s*$", Pattern.MULTILINE); + public static final Pattern STRING_DOT_EXPR + = Pattern.compile("\"\\s*\\.\\s*(" + METHOD_NAME.pattern() + ")$"); + private static final String TAG = "CompleteString"; + private final JavaDexClassLoader mClassLoader; + + public CompleteString(JavaDexClassLoader classLoader) { + mClassLoader = classLoader; + } + + @Override + public boolean process(JCTree.JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList suggestItems) { + Matcher matcher = STRING_DOT.matcher(statement); + if (matcher.find()) { + getSuggestion(editor, "", suggestItems); + return true; + } + matcher = STRING_DOT_EXPR.matcher(statement); + if (matcher.find()) { + String incompleteMethod = matcher.group(1); + getSuggestion(editor, incompleteMethod, suggestItems); + return true; + } + return false; + } + + /** + * Complete string only filter method, not filter field or constructor + */ + @Override + public void getSuggestion(CodeEditor editor, String incomplete, List suggestItems) { + JavaClassManager reader = mClassLoader.getClassReader(); + IClass stringClass = reader.getParsedClass(String.class.getName()); + assert stringClass != null; + ArrayList methods = new ArrayList<>(); + for (IMethod method : stringClass.getMethods()) { + if(!Modifier.isPublic(method.getModifiers())) + continue; + if (method.getMethodName().toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + suggestItems.add(method); + } + } + setInfo(methods, editor, incomplete); + suggestItems.addAll(methods); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteThisKeyword.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteThisKeyword.java new file mode 100644 index 000000000..95a760d7d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteThisKeyword.java @@ -0,0 +1,124 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.language.java.parser.model.FieldDescription; +import com.itsaky.androidide.language.java.parser.model.MethodDescription; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.sun.tools.javac.tree.JCTree.JCClassDecl; +import static com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import static com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import static com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import static com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +public class CompleteThisKeyword extends JavaCompleteMatcherImpl { + private static final Pattern THIS_DOT = Pattern.compile("(\\W)this\\s*\\.\\s*$"); + private static final Pattern THIS_DOT_EXPR = Pattern.compile("\\Wthis\\s*\\.\\s*(" + Patterns.IDENTIFIER.pattern() + ")$"); + private static final String TAG = "CompleteThisKeyword"; + private static JavaDexClassLoader mClassLoader; + + public CompleteThisKeyword(JavaDexClassLoader classLoader) { + this.mClassLoader = classLoader; + } + + protected static void addMethod(JCCompilationUnit unit, JCMethodDecl method, CodeEditor editor, String incomplete, + List result) { + if (method.getName().toString().toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + List typeParameters + = method.getTypeParameters(); + ArrayList paramsStr = new ArrayList<>(); + for (JCTypeParameter typeParameter : typeParameters) { + paramsStr.add(typeParameter.toString()); + } + IClass returnType = null; + String rName = JavaUtil.findImportedClassName(unit, method.getReturnType().toString()); + if(rName != null && rName.trim().length() > 0) { + returnType = mClassLoader.getClassReader().getParsedClass(rName); + } + MethodDescription desc = new MethodDescription( + method.getName().toString(), + returnType, + method.getModifiers().flags, + paramsStr); + setInfo(desc, editor, incomplete); + result.add(desc); + } + } + + protected static void addVariable(JCCompilationUnit unit, JCVariableDecl member, CodeEditor editor, String incomplete, + List result) { + if (member.getName().toString().toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US))) { + IClass returnType = null; + String rName = JavaUtil.findImportedClassName(unit, member.getType().toString()); + if(rName != null && rName.trim().length() > 0) { + returnType = mClassLoader.getClassReader().getParsedClass(rName); + } + int flags = (int) member.getModifiers().flags; + FieldDescription desc = new FieldDescription( + flags, + returnType, + member.getName().toString(), + null); + setInfo(desc, editor, incomplete); + result.add(desc); + } + } + + @Override + public boolean process(JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList result) { + Matcher matcher = THIS_DOT.matcher(statement); + if (matcher.find()) { + getSuggestionInternal(editor, result, ast, ""); + return true; + } + matcher = THIS_DOT_EXPR.matcher(statement); + if (matcher.find()) { + String incomplete = matcher.group(1); + getSuggestionInternal(editor, result, ast, incomplete); + return true; + } + return false; + } + + @Override + public void getSuggestion(CodeEditor editor, String incomplete, List suggestItems) { + + } + + private void getSuggestionInternal(@NonNull CodeEditor editor, @NonNull ArrayList result, + @NonNull JCCompilationUnit unit, + @NonNull String incomplete) { + if (unit == null) { + return; + } + //current file declare + List typeDecls = unit.getTypeDecls(); + if (typeDecls.isEmpty()) { + return; + } + JCTree jcTree = typeDecls.get(0); + if (jcTree instanceof JCClassDecl) { + List members = + ((JCClassDecl) jcTree).getMembers(); + for (JCTree member : members) { + if (member instanceof JCVariableDecl) { + addVariable(unit, (JCVariableDecl) member, editor, incomplete, result); + } else if (member instanceof JCMethodDecl) { + JCMethodDecl method = (JCMethodDecl) member; + addMethod(unit, method, editor, incomplete, result); + } + } + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteTypeDeclared.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteTypeDeclared.java new file mode 100644 index 000000000..fcce075bb --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteTypeDeclared.java @@ -0,0 +1,130 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.interfaces.Filter; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Complete class declaration + *

+ * public? static? final? class Name (extends otherClass)? (implements otherInterfaces)? + * public? enum Name + * public? final? interface Name (extends otherInterfaces)? + */ +public class CompleteTypeDeclared extends JavaCompleteMatcherImpl { + //case: public class A + //case: public class Name extends OtherClass + //case: class Name extends C implements D + public static final Pattern CLASS_DECLARE = Pattern.compile( + //more modifiers, public static final .... + "((public|protected|private|abstract|static|final|strictfp)\\s+)*" + + //type + "((class|inteface|enum)\\s+)" + + //name + "([a-zA-Z_][a-zA-Z0-9_]*)" + + //inherit + "(\\s+extends\\s+([a-zA-Z_][a-zA-Z0-9_]*))?" + + "(\\s+implements\\s+([a-zA-Z_][a-zA-Z0-9_]*))?"); + private static final Pattern END_EXTENDS + = Pattern.compile("\\s+extends\\s+([a-zA-Z_][a-zA-Z0-9_]*)$"); + private static final Pattern END_IMPLEMENTS + = Pattern.compile("\\s+implements\\s+([a-zA-Z_][a-zA-Z0-9_]*)$"); + + private static final String TAG = "CompleteClassDeclared"; + private JavaDexClassLoader mClassLoader; + + public CompleteTypeDeclared(JavaDexClassLoader classLoader) { + + mClassLoader = classLoader; + } + + @Override + public boolean process(JCTree.JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList result) { + Matcher matcher = CLASS_DECLARE.matcher(statement); + if (matcher.find()) { + matcher = END_IMPLEMENTS.matcher(statement); + if (matcher.find()) { + String incompleteInterface = matcher.group(1); + return getSuggestionInternal(editor, incompleteInterface, result, + "interface"); + + } + + matcher = END_EXTENDS.matcher(statement); + if (matcher.find()) { + String incompleteInterface = matcher.group(1); + return getSuggestionInternal(editor, incompleteInterface, result, + "class"); + + } + + } + return false; + } + + /** + * @param declareType - enum, class, annotation, interface + */ + private boolean getSuggestionInternal(@NonNull CodeEditor editor, + @NonNull String incomplete, + @NonNull List result, + @Nullable String declareType) { + + //filter interfaces or classes + Filter filter = null; + switch (declareType) { + case "interface": + filter = new Filter() { + @Override + public boolean accept(IClass clazz) { + if (Modifier.isFinal(clazz.getModifiers())) { + return false; + } + if (!Modifier.isPublic(clazz.getModifiers())) { + return false; + } + return clazz.isInterface(); + } + }; + break; + case "class": + filter = new Filter() { + @Override + public boolean accept(IClass clazz) { + if (Modifier.isFinal(clazz.getModifiers())) { + return false; + } + if (!Modifier.isPublic(clazz.getModifiers())) { + return false; + } + return !clazz.isInterface(); + } + }; + break; + } + + List classes = mClassLoader.findAllWithPrefix(incomplete, filter); + if (classes.size() > 0) { + setInfo(classes, editor, incomplete); + result.addAll(classes); + return true; + } + return false; + } + + @Override + public void getSuggestion(CodeEditor editor, String incomplete, List suggestItems) { + getSuggestionInternal(editor, incomplete, suggestItems, null); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteWord.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteWord.java new file mode 100644 index 000000000..fe3331aa2 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/CompleteWord.java @@ -0,0 +1,157 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.JavacParser; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.language.java.parser.model.KeywordDescription; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static com.itsaky.androidide.language.java.parser.expression.CompleteThisKeyword.*; +import java.util.Locale; + +/** + * Final complete, no context, suggest class name, method name, + * variable or any start with incomplete + */ +public class CompleteWord extends JavaCompleteMatcherImpl { + private static final String TAG = "CompleteWord"; + private final static Set KEYWORDS; + + static { + String[] kws = { + "abstract", "continue", "for", "new", "switch", + "assert", "default", "if", "package", "synchronized", + "boolean", "do", "goto", "private", "this", + "break", "double", "implements", "protected", "throw", + "byte", "else", "import", "public", "throws", + "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", + "char", "final", "interface", "static", "void", + "class", "finally", "long", "strictfp", "volatile", + "const", "float", "native", "super", "while", + "null", "true", "false" + }; + Set s = new HashSet<>(Arrays.asList(kws)); + KEYWORDS = Collections.unmodifiableSet(s); + } + + private JavacParser mJavaParser; + private JavaDexClassLoader mClassLoader; + + public CompleteWord(JavacParser javaParser, JavaDexClassLoader classLoader) { + this.mJavaParser = javaParser; + mClassLoader = classLoader; + } + + @Override + public boolean process(JCTree.JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList result) { + return getSuggestionInternal(editor, statement, result); + } + + @Override + public void getSuggestion(CodeEditor editor, String incomplete, List suggestItems) { + getSuggestionInternal(editor, incomplete, suggestItems); + } + + private boolean getSuggestionInternal(CodeEditor editor, String incomplete, List suggestItems) { + boolean result = getPossibleInCurrentFile(editor, incomplete, suggestItems); + result |= getKeyword(editor, incomplete, suggestItems); + return result; + } + + private boolean getKeyword(CodeEditor editor, String incomplete, List suggestItems) { + if (incomplete.trim().isEmpty()) { + return false; + } + boolean found = false; + for (String keyword : KEYWORDS) { + if (keyword.toLowerCase(Locale.US).startsWith(incomplete.toLowerCase(Locale.US)) && !keyword.equalsIgnoreCase(incomplete)) { + KeywordDescription e = new KeywordDescription(keyword); + setInfo(e, editor, incomplete); + suggestItems.add(e); + found = true; + } + } + return found; + } + + private boolean getPossibleInCurrentFile(@NonNull CodeEditor editor, @NonNull String incomplete, + @NonNull List suggestItems) { + if (incomplete.trim().isEmpty()) { + return false; + } + + JCTree.JCCompilationUnit ast; + try { + ast = mJavaParser.parse(editor.getText()); + } catch (Exception e) { + return false; + } + + getPossibleResult(editor, suggestItems, ast, incomplete); + + List classes = mClassLoader.findAllWithPrefix(incomplete); + + setInfo(classes, editor, incomplete); + suggestItems.addAll(classes); + + return classes.size() > 0; + } + + private void getPossibleResult(CodeEditor editor, List result, + JCTree.JCCompilationUnit ast, String incomplete) { + if (ast == null) { + return; + } + + List typeDecls = ast.getTypeDecls(); + if (typeDecls.isEmpty()) { + return; + } + JCTree jcTree = typeDecls.get(0); + if (jcTree instanceof JCTree.JCClassDecl) { + List members = + ((JCTree.JCClassDecl) jcTree).getMembers(); + for (JCTree member : members) { + if (member instanceof JCTree.JCVariableDecl) { + addVariable(ast, (JCTree.JCVariableDecl) member, editor, incomplete, result); + } else if (member instanceof JCTree.JCMethodDecl) { + JCTree.JCMethodDecl method = (JCTree.JCMethodDecl) member; + addMethod(ast, method, editor, incomplete, result); + if (method.getStartPosition() <= editor.getCursor().getLeft() + && method.getBody().getEndPosition(ast.endPositions) >= editor.getCursor().getLeft()) { + collectFromMethod(ast, editor, incomplete, result, method); + } + } + } + } + } + + private void collectFromMethod(JCTree.JCCompilationUnit unit, CodeEditor editor, String incomplete, List result, + JCTree.JCMethodDecl method) { + List statements + = method.getBody().getStatements(); + for (JCTree.JCStatement statement : statements) { + if (statement instanceof JCTree.JCVariableDecl) { + JCTree.JCVariableDecl field = (JCTree.JCVariableDecl) statement; + addVariable(unit, field, editor, incomplete, result); + } + } + + List parameters = method.getParameters(); + for (JCTree.JCVariableDecl parameter : parameters) { + addVariable(unit, parameter, editor, incomplete, result); + } + + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/IJavaCompleteMatcher.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/IJavaCompleteMatcher.java new file mode 100644 index 000000000..bae266538 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/IJavaCompleteMatcher.java @@ -0,0 +1,18 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.List; + +public interface IJavaCompleteMatcher { + boolean process(JCTree.JCCompilationUnit ast, CodeEditor editor, Expression expression, String statement, ArrayList result) + throws Exception; + + void getSuggestion(@NonNull CodeEditor editor, + @NonNull String incomplete, + @NonNull List suggestItems); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/JavaCompleteMatcherImpl.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/JavaCompleteMatcherImpl.java new file mode 100644 index 000000000..f1e8a8028 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/JavaCompleteMatcherImpl.java @@ -0,0 +1,58 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.language.java.parser.model.JavaSuggestItemImpl; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.List; +import java.util.regex.Pattern; + +public abstract class JavaCompleteMatcherImpl implements IJavaCompleteMatcher { + //statement end with character, number or dot + public static final Pattern END_WITH_CHARACTER_OR_DOT + = Pattern.compile("[.0-9A-Za-z_]\\s*$", Pattern.MULTILINE); + //statement end with dot "str." + public static final Pattern END_WITH_DOT = Pattern.compile("\\.\\s*$", Pattern.MULTILINE); + + /** + * Check statement is valid when end with dot + */ + public static final Pattern VALID_WHEN_END_WITH_DOT + = Pattern.compile( + "[" + + "\"" + //string: "Hello".| + ")" + //expression in parentheses: (new String("")).| + "0-9A-Za-z_" + //name of variable or identifier: variable.| + "\\]" + //array access: array[].| + "]\\s*\\.\\s*$", Pattern.MULTILINE); + public static final Pattern KEYWORD_DOT + = Pattern.compile("(" + Patterns.RE_KEYWORDS.pattern() + ")\\s*\\.\\s*$"); + + + public static final Pattern METHOD_NAME = Patterns.IDENTIFIER; + public static final Pattern VARIABLE_NAME = Patterns.IDENTIFIER; + //String or java.lang.String + public static final Pattern CLASS_NAME = Pattern.compile( + Patterns.IDENTIFIER.pattern() + "(\\s*\\.\\s*" + Patterns.IDENTIFIER.pattern() + ")*"); + //java.util.* + public static final Pattern PACKAGE_NAME = CLASS_NAME; + //java.io.FileInputStream + public static final Pattern CONSTRUCTOR = CLASS_NAME; + + private static final String TAG = "JavaCompleteMatcherImpl"; + + protected static void setInfo(List members, CodeEditor editor, String incomplete) { + for (SuggestItem member : members) { + if (member instanceof JavaSuggestItemImpl) { + setInfo((JavaSuggestItemImpl) member, editor, incomplete); + } else { + } + } + } + + protected static void setInfo(Object member, CodeEditor editor, String incomplete) { + if (member instanceof JavaSuggestItemImpl) { + ((JavaSuggestItemImpl) member).setEditor(editor); + ((JavaSuggestItemImpl) member).setIncomplete(incomplete); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PackageImporter.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PackageImporter.java new file mode 100644 index 000000000..17542a7ad --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PackageImporter.java @@ -0,0 +1,102 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import android.text.Editable; +import android.widget.EditText; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.util.EditorUtil; +import io.github.rosemoe.editor.text.Content; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import io.github.rosemoe.editor.text.CharPosition; +import android.text.TextUtils; +import com.blankj.utilcode.util.ThrowableUtils; +import java.util.Set; +import java.util.HashSet; + +/** + * Created by Duy on 21-Jul-17. + */ + +public class PackageImporter { + private static final String TAG = "ImportUtil"; + + /** + * Add import statement if import does not already exist. + */ + public static void importClass(Content editor, String className) { + String packageName = JavaUtil.getPackageName(className); + if (getImportedClassName(editor, className) == null + && !packageName.isEmpty() + && !packageName.equals("java.lang") + && !packageName.equals(EditorUtil.getCurrentPackage(editor.toString()))) { + organizeImports(editor, "import " + className.replace("$", ".") + ";"); + } + } + + public static String getImportedClassName(EditText editor, @Nullable String className) { + return getImportedClassName(editor, className); + } + + public static String getImportedClassName(CharSequence src, @Nullable String className) { + if (className == null) return null; + + Pattern pattern = PatternFactory.makeImportClass(className); + Matcher matcher = pattern.matcher(src); + if (matcher.find()) { + return matcher.group(2); + } + return PatternFactory.match(src, pattern); + } + + + public static void organizeImports(Content editor, String importStr) { + try { + ArrayList imprts = getImports(editor); + imprts.add(importStr); + Collections.sort(imprts); + final Set imports = new HashSet(); + for(String imprt : imprts) { + imports.add(imprt.trim()); + } + String imprt = TextUtils.join("\n", imports).trim(); + + int s = PatternFactory.firstMatch(editor, PatternFactory.IMPORT); + int e = PatternFactory.lastMatch(editor, PatternFactory.IMPORT); + + if (s >= 0 && e >= 0 && e < editor.length()) { + CharPosition start = editor.getIndexer().getCharPosition(s); + CharPosition end = editor.getIndexer().getCharPosition(e); + if (s < e) { + editor.replace(start.line, start.column, end.line, end.column, imprt); + } else if (s == e) { + editor.insert(start.line, start.column, imprt); + } + } else { + int p = PatternFactory.lastMatch(editor, PatternFactory.PACKAGE); + int c = PatternFactory.firstMatch(editor, CompleteTypeDeclared.CLASS_DECLARE); + + if(p >= 0 && c >= 0 && p < c) { + CharPosition start = editor.getIndexer().getCharPosition(p); + CharPosition end = editor.getIndexer().getCharPosition(c); + imprt = "\n\n" + imprt + "\n"; + if(p < c) { + editor.replace(start.line, start.column, end.line, end.column, imprt); + } else if(p == c) { + editor.insert(start.line, start.column, imprt); + } else { + editor.insert(0, 0, imprt); + } + } + } + } catch (Throwable th) {} + } + + public static ArrayList getImports(Content editor) { + return PatternFactory.allMatch(editor, PatternFactory.IMPORT); + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PatternFactory.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PatternFactory.java new file mode 100644 index 000000000..01d5300db --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/PatternFactory.java @@ -0,0 +1,119 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PatternFactory { + public static final Pattern PACKAGE = Pattern.compile("package\\s+[^;]*;"); + public static final Pattern PACKAGE_NAME = Pattern.compile("[A-Za-z_]+(.[A-Za-z][A-Za-z0-9_]*)*"); + public static final Pattern IMPORT = Pattern.compile("(import\\s+)([^;]*)(\\s?);"); + public static final Pattern WORD = Pattern.compile("[^\\s-]+$"); + + public static final String IDENTIFIER_STR = "[A-Za-z][A-Za-z0-9]*"; + public static final Pattern IDENTIFIER = Pattern.compile(IDENTIFIER_STR); + + public static final Pattern ANNOTATION = Pattern.compile("@[A-Za-z][A-Za-z0-9]*"); + public static final Pattern BRACKET = Pattern.compile("\\[(.*?)\\]"); + public static final Pattern MODIFIERS = Pattern.compile("\\b(public|protected|private|abstract|static|final|strictfp)\\b"); + public static final Pattern SPLIT_NON_WORD = Pattern.compile("\\W+"); + public static final String SPLIT_NON_WORD_STR = "\\W+"; + public static final String[] PRIMITIVE_TYPE = new String[]{"boolean", "byte", "char", "int", + "short", "long", "float", "double"}; + public static final String[] KEYWORD_MODIFIERS = new String[]{"public", "private", "protected", + "static", "final", "synchronized", "volatile", "transient", "native", "strictfp"}; + public static final String[] KEYWORD_TYPE = new String[]{"class", "interface", "enum"}; + public static final String[] KEYWORD; + + public static final String GENERIC_STR = "<[A-Z][a-zA-Z0-9_<>, ]*>"; + + public static final Pattern FILE_NAME = Pattern.compile("[A-Za-z][A-Za-z0-9_\\-.]*"); + + static { + KEYWORD = new String[PRIMITIVE_TYPE.length + KEYWORD_MODIFIERS.length + KEYWORD_TYPE.length]; + System.arraycopy(PRIMITIVE_TYPE, 0, KEYWORD, 0, PRIMITIVE_TYPE.length); + System.arraycopy(KEYWORD_MODIFIERS, 0, KEYWORD, PRIMITIVE_TYPE.length, KEYWORD_MODIFIERS.length); + System.arraycopy(KEYWORD_TYPE, 0, KEYWORD, KEYWORD_MODIFIERS.length, KEYWORD_TYPE.length); + } + + public static Pattern makeImportClass(String className) { + return Pattern.compile("(import\\s+)(.*" + className + ")(\\s?;)"); + } + + @Nullable + public static String lastMatchStr(CharSequence text, Pattern pattern) { + Matcher matcher = pattern.matcher(text); + ArrayList list = new ArrayList<>(); + while (matcher.find()) { + list.add(matcher.group()); + } + if (list.size() == 0) return null; + return list.get(list.size() - 1); + } + + @Nullable + public static String match(CharSequence text, Pattern pattern) { + Matcher matcher = pattern.matcher(text); + if (matcher.find()) return matcher.group(); + else return null; + } + + public static ArrayList allMatch(CharSequence text, Pattern pattern) { + Matcher matcher = pattern.matcher(text); + ArrayList list = new ArrayList<>(); + while (matcher.find()) { + list.add(matcher.group()); + } + return list; + } + + + public static int lastMatch(CharSequence editor, Pattern pattern) { + int last = -1; + Matcher matcher = pattern.matcher(editor); + while (matcher.find()) last = matcher.end(); + return last; + } + + public static int matchEnd(CharSequence editor, Pattern pattern, int start) { + Matcher matcher = pattern.matcher(editor); + if (matcher.find(start)) { + return matcher.end(); + } + return -1; + } + + public static int firstMatch(CharSequence editor, Pattern pattern) { + Matcher matcher = pattern.matcher(editor); + if (matcher.find()) { + return matcher.start(); + } + return -1; + } + + public static Pattern makeInstance(String prefix) { + //ArrayList list = new ArrayList(); + return Pattern.compile("(" + IDENTIFIER_STR + ")" + "(\\s?)" + //type + "((" + GENERIC_STR + ")?(\\s?)|(\\s+))" + //generic or space + "(" + prefix + ")(\\s?)([,;=)])"); //name + } + + public static int lastMatch(String statement, String pattern) { + return lastMatch(statement, Pattern.compile(pattern)); + } + + public static int lastMatch(String statement, Pattern pattern) { + return lastMatch(statement, pattern, 0); + } + + public static int lastMatch(String expr, Pattern pattern, int start) { + Matcher matcher = pattern.matcher(expr.substring(start)); + int index = -1; + while (matcher.find()) { + index = matcher.end(); + } + return index != 0 ? index + start : index; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/Patterns.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/Patterns.java new file mode 100644 index 000000000..039cbf78f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/Patterns.java @@ -0,0 +1,68 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import java.util.regex.Pattern; + +import static java.util.regex.Pattern.compile; + +/** + * Created by Duy on 11-Feb-17. + */ + +@SuppressWarnings("DefaultFileTemplate") +public class Patterns { + + public static final Pattern JAVA_COMMENTS = compile("(//.*)|(/\\*(?:.|[\\n\\r])*?\\*/)"); + /** + * match string java + * include + *

+ * 'string' + *

+ * And can not find close quote + *

+ * 'sadhasdhasdhashdhas ds asda sd + */ + public static final Pattern STRINGS = Pattern.compile( + "((\")(.*?)(\"))" +//'string' + "|((\")(.+))", Pattern.DOTALL); // no end string 'asdasdasd + + + public static final Pattern PRIMITIVE_TYPES = compile("boolean|byte|char|int|short|long|float|double"); + public static final Pattern KEYWORD_TYPES = compile("class|interface|enum"); + public static final Pattern KEYWORDS_MODS = compile("public|private|protected|static|final|" + + "synchronized|volatile|transient|native|strictfp|abstract"); + public static final Pattern KEYWORDS = compile(PRIMITIVE_TYPES.pattern() + + KEYWORDS_MODS.pattern() + "|" + + KEYWORD_TYPES.pattern() + "|" + + "super|this|void|assert|break|case|catch|" + + "const|continue|default|do|else|extends|finally|for|goto|if|implements|import|instanceof|" + + "interface|new|package|return|switch|throw|throws|try|while|true|false|null"); + + public static final Pattern RE_BRACKETS = compile("(\\s*\\[\\s*\\])"); + + public static final Pattern IDENTIFIER = compile("[a-zA-Z_][a-zA-Z0-9_]*"); + //case: JCTree.JCClassDecl + //case: java.util.ArrayList) + public static final Pattern RE_QUALID = compile(IDENTIFIER + "(\\s*\\.\\s*" + IDENTIFIER + ")?"); + public static final Pattern RE_REFERENCE_TYPE = compile(RE_QUALID + RE_BRACKETS.pattern() + "\\*"); + public static final Pattern RE_TYPE = RE_REFERENCE_TYPE; + + public static final Pattern TYPE_DECLARE_MODIFIERS = compile("public|protected|private|abstract|static|final|strictfp"); + public static final Pattern TYPE_DECLARE_HEAD = compile("class|inteface|enum"); + + //case: public class A + //case: public class Lamborghini extends Car + public static final Pattern RE_TYPE_DECL = compile( + "((public|protected|private|abstract|static|final|strictfp)\\s+)*" + + "(class|inteface|enum)\\s+" + + "[a-zA-Z_][a-zA-Z0-9_]*" + + "(\\s+(extends|implements)(\\s+)([a-zA-Z_][a-zA-Z0-9_]*))?"); + + public static final Pattern RE_ARRAY_TYPE = compile("^\\s*(" + RE_QUALID + ")(" + RE_BRACKETS + ")+\\s*"); + public static final Pattern RE_SELECT_OR_ACCESS = compile("^\\s*(" + IDENTIFIER + ")\\s*(\\[.*])?\\s*$"); + public static final Pattern RE_ARRAY_ACCESS = compile("^\\s*(" + IDENTIFIER + ")" + "\\s*(\\[.*])+\\s*$"); + public static final Pattern RE_CASTING = compile("\\s*\\((" + RE_QUALID + "\\s*)\\)\\s*" + IDENTIFIER); + public static final Pattern RE_KEYWORDS = KEYWORDS; + + public static final Pattern PACKAGE_NAME = compile("([A-Za-z0-9_]([.][a-zA-Z0-9_])?)*"); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/StatementParser.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/StatementParser.java new file mode 100644 index 000000000..72dc4aec8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/StatementParser.java @@ -0,0 +1,68 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import com.itsaky.androidide.language.java.parser.util.EditorUtil; +import io.github.rosemoe.editor.widget.CodeEditor; + +public class StatementParser { + /** + * " Search back from the cursor position till meeting '{' or ';'. + * " '{' means statement start, ';' means end of a previous statement. + * + * @return statement before cursor + * " Note: It's the base for parsing. And It's OK for most cases. + */ + public static String resolveStatementFromCursor(CodeEditor editor) { + String lineBeforeCursor = getCurrentLine(editor); + if (lineBeforeCursor.matches("^\\s*(import|package)\\s+")) { + return lineBeforeCursor; + } + int oldCursor = editor.getCursor().getLeft(); + int newCursor = oldCursor - 1; + while (true) { + if (newCursor == 0) break; + char c = editor.getText().charAt(newCursor); + if (c == '{' || c == '}' || c == ';') { + newCursor++; + break; + } + newCursor--; + } + String statement = editor.getText().subSequence(newCursor, oldCursor).toString(); + return mergeLine(statement); + } + + + public static String getCurrentLine(CodeEditor editText) { + return EditorUtil.getLineBeforeCursor(editText, editText.getCursor().getLeft()); + } + + public static String mergeLine(String statement) { + statement = cleanStatement(statement); + return statement; + } + + /** + * set string literal empty, remove comments, trim begining or ending spaces + * case: ' sb. /* block comment"/ append( "stringliteral" ) // comment ' + * return 'sb.append("")' + */ + private static String cleanStatement(String code) { + if (code.matches("\\s*")) { + return ""; + } + code = removeComment(code); //clear all comment + //clear all string content + code = code.replaceAll(Patterns.STRINGS.toString(), "\"\""); + code = EditorUtil.trimLeft(code); + code = code.replaceAll("[\n\t\r]", ""); + return code; + } + + /** + * remove all comment + */ + private static String removeComment(String code) { + return code.replaceAll(Patterns.JAVA_COMMENTS.toString(), ""); + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/TypeResolver.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/TypeResolver.java new file mode 100644 index 000000000..9882995ee --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/expression/TypeResolver.java @@ -0,0 +1,376 @@ +package com.itsaky.androidide.language.java.parser.expression; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IField; +import com.itsaky.androidide.language.java.parser.internal.IMethod; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.sun.tools.javac.tree.JCTree; +import java.util.LinkedList; +import java.util.List; + +import static com.itsaky.androidide.language.java.parser.internal.JavaUtil.*; +import static com.sun.tools.javac.tree.JCTree.JCArrayAccess; +import static com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; +import static com.sun.tools.javac.tree.JCTree.JCBlock; +import static com.sun.tools.javac.tree.JCTree.JCCatch; +import static com.sun.tools.javac.tree.JCTree.JCClassDecl; +import static com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import static com.sun.tools.javac.tree.JCTree.JCExpression; +import static com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import static com.sun.tools.javac.tree.JCTree.JCIdent; +import static com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import static com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import static com.sun.tools.javac.tree.JCTree.JCStatement; +import static com.sun.tools.javac.tree.JCTree.JCTry; +import static com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +public class TypeResolver { + private static final String TAG = "TypeResolver"; + private JavaDexClassLoader mClassLoader; + private JCCompilationUnit mUnit; + private IClass mCurrentType; + + private boolean isStatic= false; + + public boolean isStatic() { + return isStatic; + } + + public TypeResolver(JavaDexClassLoader classLoader, + JCCompilationUnit unit, + IClass currentType) { + mClassLoader = classLoader; + mUnit = unit; + mCurrentType = currentType; + } + + public IClass resolveType(@NonNull JCExpression expression, int cursor) { + return resolveTypeImpl(expression, cursor); + } + + @Nullable + private IClass resolveTypeImpl(@NonNull final JCExpression expression, int cursor) { + List list = extractExpressionAtCursor(expression, cursor); + if (list == null) { + return null; + } + String exceptionMessage = "Can not resolve type of expression "; + IClass currentType = mCurrentType; + for (JCTree tree : list) { + //only once time on this case + if (tree instanceof JCIdent) { + JCIdent jcIdent = (JCIdent) tree; + + //variable declaration, static import or inner class + //case: variableDecl + JCVariableDecl variableDecl = getVariableDeclaration(mUnit, jcIdent); + if (variableDecl != null) { + currentType = JavaUtil.jcTypeToClass(mUnit, variableDecl.getType()); + } else { + //case: System.out -> find imported class, this expression can be static access + String className = findImportedClassName(mUnit, jcIdent.getName().toString()); + currentType = mClassLoader.getClassReader().getParsedClass(className); + isStatic = true; + } + // TODO: 13-Jun-18 case: static import + // TODO: 13-Jun-18 case inner class + } else if (tree instanceof JCMethodInvocation) { + // TODO: 13-Jun-18 find method in current class or import static + JCMethodInvocation jcMethod = (JCMethodInvocation) tree; + JCExpression methodSelect = jcMethod.getMethodSelect(); + if (methodSelect instanceof JCFieldAccess) { + String methodName = ((JCFieldAccess) methodSelect).getIdentifier().toString(); + List arguments = jcMethod.getArguments(); + IClass[] types = new IClass[arguments.size()]; + IMethod method = currentType.getMethod(methodName, types); + if (method == null) { + throw new UnsupportedOperationException(exceptionMessage + tree); + } + currentType = method.getMethodReturnType(); + } else if (methodSelect instanceof JCIdent) { //method in current class + String methodName = ((JCIdent) methodSelect).getName().toString(); + IMethod method = currentType.getMethod(methodName, null); + if (method == null) { + throw new UnsupportedOperationException(exceptionMessage + tree); + } + currentType = method.getMethodReturnType(); + } else { + throw new UnsupportedOperationException(exceptionMessage + tree); + } + } else if (tree instanceof JCFieldAccess) { + if (currentType == null) { + throw new UnsupportedOperationException(exceptionMessage + tree); + } + + String name = ((JCFieldAccess) tree).getIdentifier().toString(); + IField field = currentType.getField(name); + if (field == null) { + throw new UnsupportedOperationException(exceptionMessage + tree); + } + currentType = field.getFieldType(); + } else if (tree instanceof JCArrayAccess) { + JCIdent jcIdent = (JCIdent) ((JCArrayAccess) tree).getExpression(); + + //variable declaration, static import or inner class + //case: variableDecl + JCVariableDecl variableDecl = getVariableDeclaration(mUnit, jcIdent); + if (variableDecl != null) { + if (!(variableDecl.getType() instanceof JCArrayTypeTree)) { + throw new UnsupportedOperationException("can not resolve type of array access " + tree); + } + String className = ((JCArrayTypeTree) variableDecl.getType()) + .getType().toString(); + className = findImportedClassName(mUnit, className); + currentType = mClassLoader.getClassReader().getParsedClass(className); + } + } + } + + return currentType; + } + + + @Nullable + private List extractExpressionAtCursor(JCExpression expression, int cursor) { + JCTree tree = expression; + LinkedList list = new LinkedList<>(); + while (tree != null) { + if (getEndPosition(tree) > cursor) { + break; + } + if (tree instanceof JCMethodInvocation) { + list.addFirst(tree); + + JCExpression methodSelect = ((JCMethodInvocation) tree).getMethodSelect(); + if (methodSelect instanceof JCIdent) { + break; + } else if (methodSelect instanceof JCFieldAccess) { + tree = ((JCFieldAccess) methodSelect).getExpression(); + + } else { //unsupported + return null; + } + } else if (tree instanceof JCFieldAccess) { //var.field + list.addFirst(tree); + //select before + tree = ((JCFieldAccess) tree).getExpression(); + + } else if (tree instanceof JCIdent) { //var, it should be before any expression + list.addFirst(tree); + break; + + } else if (tree instanceof JCArrayAccess) { //variable.array[i].toString + list.addFirst(tree); + //select declare name + tree = ((JCArrayAccess) tree).getExpression(); //select array name + if (tree instanceof JCIdent) { + break; + } else if (tree instanceof JCFieldAccess) { + } else { + throw new UnsupportedOperationException("can not extract expression at array " + tree); + } + } else { //unsupported + //should not happen + return null; + } + } + return list; + } + + @Nullable + private JCVariableDecl getVariableDeclaration(final JCCompilationUnit unit, + final JCIdent jcIdent) { + List typeDecls = unit.getTypeDecls(); + for (JCTree typeDecl : typeDecls) { + JCVariableDecl variableDecl = getVariableDeclaration(typeDecl, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + } + return null; + } + + /** + * Visit all scope and find variable declaration when given jcIdent + * + * @param parent - parent block to find + */ + @Nullable + private JCVariableDecl getVariableDeclaration(final JCTree parent, + final JCIdent jcIdent) { + // TODO: 14-Jun-18 need add parent if jcIdent to resolve exactly scope + if (parent instanceof JCBlock) { + List statements = ((JCBlock) parent).getStatements(); + return getVariableDeclarationFromStatements(parent, statements, jcIdent); + + } else if (parent instanceof JCTree.JCCase) { + JCTree.JCCase jcCase = (JCTree.JCCase) parent; + return getVariableDeclarationFromStatements(parent, jcCase.getStatements(), jcIdent); + + } else if (parent instanceof JCClassDecl) { + List members = ((JCClassDecl) parent).getMembers(); + //all member equals scope + for (JCTree member : members) { + if (member instanceof JCVariableDecl) { //variable + JCVariableDecl variableDecl = (JCVariableDecl) member; + if (canBeSampleVariable(parent, variableDecl, jcIdent)) { + return variableDecl; + } + } else if (member instanceof JCMethodDecl) { //method + JCMethodDecl jcMethodDecl = (JCMethodDecl) member; + JCBlock jcMethodDeclBody = jcMethodDecl.getBody(); + JCVariableDecl variableDecl = getVariableDeclaration(jcMethodDeclBody, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + + variableDecl = getVariableDeclarationFromStatements(member, + ((JCMethodDecl) member).getParameters(), jcIdent); + if (variableDecl != null) { + return variableDecl; + } + } else { + JCVariableDecl variableDecl = getVariableDeclaration(member, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + } + } + } else if (parent instanceof JCTree.JCDoWhileLoop) { + return getVariableDeclaration(((JCTree.JCDoWhileLoop) parent).getStatement(), jcIdent); + + } else if (parent instanceof JCTree.JCEnhancedForLoop) { + JCVariableDecl variable = ((JCTree.JCEnhancedForLoop) parent).getVariable(); + if (canBeSampleVariable(parent, variable, jcIdent)) { + return variable; + } + return getVariableDeclaration(((JCTree.JCEnhancedForLoop) parent).getStatement(), jcIdent); + + } else if (parent instanceof JCTree.JCForLoop) { + List initializer = ((JCTree.JCForLoop) parent).getInitializer(); + JCVariableDecl variableDecl = getVariableDeclarationFromStatements(parent, initializer, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + return getVariableDeclaration(((JCTree.JCForLoop) parent).getStatement(), jcIdent); + + } else if (parent instanceof JCTree.JCIf) { + JCTree.JCIf jcIf = (JCTree.JCIf) parent; + JCStatement thenStatement = jcIf.getThenStatement(); + JCVariableDecl variableDecl = getVariableDeclaration(thenStatement, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + JCStatement elseStatement = jcIf.getElseStatement(); + if (elseStatement != null) { + return getVariableDeclaration(elseStatement, jcIdent); + } + + } else if (parent instanceof JCTree.JCLabeledStatement) { + return getVariableDeclaration(((JCTree.JCLabeledStatement) parent).getStatement(), jcIdent); + + } else if (parent instanceof JCTree.JCSynchronized) { + return getVariableDeclaration(((JCTree.JCSynchronized) parent).getBlock(), jcIdent); + + } else if (parent instanceof JCTry) { + JCTry jcTry = (JCTry) parent; + JCBlock jcTryBlock = jcTry.getBlock(); + JCVariableDecl variableDecl = getVariableDeclaration(jcTryBlock, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + for (JCCatch jcCatch : jcTry.getCatches()) { + JCVariableDecl parameter = jcCatch.getParameter(); + if (canBeSampleVariable(jcCatch, parameter, jcIdent)) { + return parameter; + } + JCBlock jcCatchBlock = jcCatch.getBlock(); + variableDecl = getVariableDeclaration(jcCatchBlock, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + } + + } else if (parent instanceof JCTree.JCWhileLoop) { + return getVariableDeclaration(((JCTree.JCWhileLoop) parent).getStatement(), jcIdent); + + } + return null; + } + + @Nullable + private JCVariableDecl getVariableDeclarationFromStatements(JCTree parent, + List statements, + JCIdent jcIdent) { + for (JCStatement statement : statements) { + if (statement instanceof JCVariableDecl) { + JCVariableDecl variableDecl = (JCVariableDecl) statement; + if (canBeSampleVariable(parent, variableDecl, jcIdent)) { + return variableDecl; + } + } else { + JCVariableDecl variableDecl = getVariableDeclaration(statement, jcIdent); + if (variableDecl != null) { + return variableDecl; + } + } + } + return null; + } + + + /** + * @param parent - scope of variable + */ + private boolean canBeSampleVariable(@NonNull JCTree parent, + @NonNull JCVariableDecl variable, + /*should all parent if identifier*/ + @NonNull JCIdent ident) { + if (!variable.getName().equals(ident.getName())) { + return false; + } + + //identifier inside or equal scope if variable o + //------------------------------------------- + // private ArrayList list = new ArrayList(); + // void method(){ + // list.toString() + //} + //------------------------------------------- + // void method(ArrayList list){ + // list.toString() + //} + //------------------------------------------- + //void method(){ + // ArrayList list; + // list.toString() + //} + if (isChildOfParent(parent, ident)) { + int startPosition = variable.getStartPosition(); + int startPosition1 = ident.getStartPosition(); + + return true; + } + return false; + } + + private boolean isChildOfParent(JCTree parent, JCTree child) { + //scope of child inside parent + return parent.getStartPosition() <= child.getStartPosition() + && getEndPosition(parent) >= getEndPosition(child); + } + + private int getEndPosition(JCTree tree) { + return tree.getEndPosition(mUnit.endPositions); + } + + static class c { + static void cd() { + + } + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/CompiledClassLoader.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/CompiledClassLoader.java new file mode 100644 index 000000000..416fd807a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/CompiledClassLoader.java @@ -0,0 +1,55 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import android.text.TextUtils; +import androidx.annotation.NonNull; +import com.elvishew.xlog.XLog; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.models.ConstantsBridge; +import dalvik.system.DexFile; +import dalvik.system.PathClassLoader; +import java.io.File; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +class CompiledClassLoader { + + @NonNull + public ArrayList getCompiledClassesFromProject(@NonNull AndroidProject project) { + ArrayList classes = new ArrayList<>(); + try { + final List dexes = ConstantsBridge.PROJECT_DEXES; + final PathClassLoader loader = new PathClassLoader(TextUtils.join(File.pathSeparator, dexes), ClassLoader.getSystemClassLoader()); + if (dexes == null || dexes.size() <= 0) return classes; + for (String dex : dexes) { + final DexFile d = new DexFile(new File(dex)); + Enumeration entries = d.entries(); + String name = null; + while (entries.hasMoreElements() && (name = entries.nextElement()) != null) { + while(name.startsWith(File.separator)) + name = name.substring(1); + if(name.contains(File.separator)) + name = name.replace(File.separator, "."); + Class load = tryLoad(loader, name); + if (load != null) + classes.add(load); + } + d.close(); + } + + ConstantsBridge.CLASS_LOAD_SUCCESS = true; + return classes; + } catch (Throwable th) { + ConstantsBridge.CLASS_LOAD_SUCCESS = false; + return classes; + } + } + + private Class tryLoad(ClassLoader loader, String name) { + try { + return loader.loadClass(name); + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClass.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClass.java new file mode 100644 index 000000000..9647ba94e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClass.java @@ -0,0 +1,44 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.model.ConstructorDescription; +import java.util.ArrayList; +import java.util.List; + +public interface IClass extends IJavaDocCommentable { + int getModifiers(); + + @Nullable + String getFullClassName(); + + @Nullable + String getSimpleName(); + + boolean isInterface(); + + boolean isEnum(); + + boolean isPrimitive(); + + boolean isAnnotation(); + + boolean isMemberClass(); + + @Nullable + IMethod getMethod(@NonNull String methodName, @Nullable IClass[] argsType); + + @Nullable + IField getField(@NonNull String name); + + List getMethods(); + + @Nullable + IClass getSuperclass(); + + ArrayList getFields(); + + List getMember(String prefix); + + List getConstructors(); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClassManager.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClassManager.java new file mode 100644 index 000000000..b57936314 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IClassManager.java @@ -0,0 +1,16 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.Nullable; +import androidx.annotation.NonNull; +import com.itsaky.androidide.interfaces.Filter; +import java.util.List; + +public interface IClassManager { + void update(IClass clazz); + + void remove(String fullClassName); + + @NonNull + List find(@NonNull String simpleNamePrefix, + @Nullable Filter filter); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IField.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IField.java new file mode 100644 index 000000000..5c1e569e5 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IField.java @@ -0,0 +1,17 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public interface IField extends IJavaDocCommentable { + @NonNull + String getFieldName(); + + @NonNull + IClass getFieldType(); + + int getFieldModifiers(); + + @Nullable + Object getFieldValue(); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IMethod.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IMethod.java new file mode 100644 index 000000000..70ce30bd3 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/IMethod.java @@ -0,0 +1,16 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.NonNull; + +public interface IMethod extends IJavaDocCommentable { + @NonNull + String getMethodName(); + + @NonNull + IClass getMethodReturnType(); + + @NonNull + IClass[] getMethodParameterTypes(); + + int getModifiers(); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaClassManager.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaClassManager.java new file mode 100644 index 000000000..cc5120073 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaClassManager.java @@ -0,0 +1,253 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.core.util.Pair; +import com.blankj.utilcode.util.FileIOUtils; +import com.blankj.utilcode.util.FileUtils; +import com.itsaky.androidide.interfaces.Filter; +import com.itsaky.androidide.language.java.parser.JavacParser; +import com.itsaky.androidide.language.java.parser.model.ClassDescription; +import com.itsaky.androidide.models.AndroidProject; +import com.sun.tools.javac.tree.JCTree; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +public class JavaClassManager implements IClassManager { + + private static final String TAG = "JavaClassReader"; + private static final String JAVA_DOT_LANG_DOT = "java.lang."; + private static JavaClassManager INSTANCE; + + /** + * All classes sorted by simple class name, fastest find list of classes start with prefix + */ + private final ArrayList> mSimpleNames = new ArrayList<>(); + /** + * All classes sorted by full class name, use for faster find class name by using binary search + */ + private final ArrayList mFullNames = new ArrayList<>(); + /** + * Map contains parsed class, parsed class is java class in jar file or from user + */ + private final HashMap mLoaded = new HashMap<>(); + + private File mBootClasspath; + + private JavaClassManager(File bootClassPath) { + mBootClasspath = bootClassPath; + } + + public static JavaClassManager getInstance(File classpath) { + if (INSTANCE == null) { + INSTANCE = new JavaClassManager(classpath); + } + return INSTANCE; + } + + public static JavaClassManager getInstance() { + if (INSTANCE == null) { + throw new RuntimeException("JavaClassManager not init"); + } + return INSTANCE; + } + + @NonNull + public ArrayList getAllClasses() { + return mFullNames; + } + + public void loadFromProject(AndroidProject project) { + try { + CompiledClassLoader classLoader = new CompiledClassLoader(); + ArrayList classes = classLoader.getCompiledClassesFromProject(project); + for (Class clazz : classes) { + getClassWrapper(clazz); + } + JavacParser parser = new JavacParser(); + List javaSrcDirs = project.getSourcePaths(); + for (String dir : javaSrcDirs) { + final File javaSrcDir = new File(dir); + Collection javaFiles = FileUtils.listFilesInDirWithFilter(javaSrcDir, (f -> f.isFile() && f.getName().endsWith(".java")), true); + for (File javaFile : javaFiles) { + String content = FileIOUtils.readFile2String(javaFile); + JCTree.JCCompilationUnit ast = parser.parse(content); + List parseClasses = parser.parseClasses(ast); + for (IClass aClass : parseClasses) { + update(aClass); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + /** + * @param fullName - full class name + */ + @Nullable + public IClass getParsedClass(String fullName) { + IClass cache = mLoaded.get(fullName); + if (cache != null) { + return cache; + } + return mLoaded.get(JAVA_DOT_LANG_DOT + fullName); + } + + @NonNull + public IClass getClassWrapper(@NonNull Class clazz) { + IClass cache = mLoaded.get(clazz.getName()); + if (cache != null) { + return cache; + } + ClassDescription wrapper = new ClassDescription(clazz); + update(wrapper); + wrapper.initMembers(clazz); + return wrapper; + } + + @Override + public void update(IClass value) { + String fullClassName = value.getFullClassName(); + if (mLoaded.containsKey(fullClassName)) { + mLoaded.put(fullClassName, value); + return; + } + mLoaded.put(fullClassName, value); + + if (mFullNames.size() == 0) { + mFullNames.add(value); + } else { + boolean found = false; + for (int i = 0; i < mFullNames.size(); i++) { + IClass iClass = mFullNames.get(i); + if (fullClassName.compareTo(iClass.getFullClassName()) <= 0) { + mFullNames.add(i, value); + found = true; + break; + } + } + if (!found) { + mFullNames.add(value); + } + } + String simpleName = value.getSimpleName(); + Pair simplePair = new Pair(simpleName, value); + if (mSimpleNames.size() == 0) { + mSimpleNames.add(simplePair); + } else { + boolean found = false; + for (int i = 0; i < mSimpleNames.size(); i++) { + Pair pair = mSimpleNames.get(i); + if (simpleName.compareTo(pair.first) <= 0) { + mSimpleNames.add(i, simplePair); + found = true; + break; + } + } + if (!found) { + mSimpleNames.add(simplePair); + } + } + } + + @Override + public void remove(String fullClassName) { + IClass remove = mLoaded.remove(fullClassName); + int index = Collections.binarySearch(mFullNames, remove, + new Comparator() { + @Override + public int compare(IClass o1, IClass o2) { + return o1.getFullClassName().compareTo(o2.getFullClassName()); + } + }); + if (index >= 0) { + mFullNames.remove(index); + } + Pair key = new Pair(remove.getSimpleName(), remove); + index = Collections.binarySearch(mSimpleNames, key, + new Comparator>() { + @Override + public int compare(Pair o1, + Pair o2) { + return o1.first.compareTo(o2.first); + } + }); + if (index >= 0) { + mSimpleNames.remove(index); + } + } + + /** + * search class with binary search + * + * @param classes - sorted classes by name + * @param prefix - prefix if class name + */ + @Nullable + private List> binarySearch( + @NonNull List> classes, + @NonNull String prefix) { + int start = -1, end = -1; + int left = 0; + int right = classes.size() - 1; + while (left <= right) { + int mid = (left + right) / 2; + String name = classes.get(mid).first; + String midValue = name.substring(0, Math.min(name.length(), prefix.length())); + if (midValue.trim().toLowerCase(Locale.US).compareTo(prefix.toLowerCase(Locale.US)) < 0) { + left = mid + 1; + } else if (midValue.trim().toLowerCase(Locale.US).compareTo(prefix.toLowerCase(Locale.US)) > 0) { + right = mid - 1; + } else { + start = mid; + end = mid; + while (start >= 0 && + classes.get(start) + .first.trim().toLowerCase(Locale.US) + .startsWith(prefix.toLowerCase(Locale.US))) { + start--; + } + while (end < classes.size() && + classes.get(end) + .first.trim().toLowerCase(Locale.US) + .startsWith(prefix.toLowerCase(Locale.US))) { + end++; + } + start++; + end--; + break; + } + } + if (end >= 0 && start >= 0 && end - start + 1 /*length*/ >= 1) { + return classes.subList(start, end + 1); + } + return null; + } + + @Override + @NonNull + public List find(@NonNull String simpleNamePrefix, @Nullable Filter filter) { + ArrayList result = new ArrayList<>(); + List> simple = binarySearch(mSimpleNames, simpleNamePrefix); + if (simple != null) { + for (Pair c : simple) { + if (filter != null) { + if (!filter.accept(c.second)) { + continue; + } + } + result.add(c.second); + } + } + return result; + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaDexClassLoader.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaDexClassLoader.java new file mode 100644 index 000000000..c1a4793f8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaDexClassLoader.java @@ -0,0 +1,95 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.interfaces.Filter; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.models.AndroidProject; +import java.io.File; +import java.util.List; + +/** + * Created by Duy on 20-Jul-17. + */ + +public class JavaDexClassLoader { + private static final Filter mClassFilter = new Filter() { + @Override + public boolean accept(IClass aClass) { + return !(aClass.isAnnotation() || aClass.isInterface() || aClass.isEnum() || aClass.isMemberClass()); + } + }; + private static final Filter mEnumFilter = new Filter() { + @Override + public boolean accept(IClass aClass) { + return aClass.isEnum(); + } + }; + private static final Filter mInterfaceFilter = new Filter() { + @Override + public boolean accept(IClass aClass) { + return aClass.isInterface(); + } + }; + private static final Filter mAnnotationFilter = new Filter() { + @Override + public boolean accept(IClass aClass) { + return aClass.isAnnotation(); + } + }; + + private JavaClassManager mClassReader; + + public JavaDexClassLoader(File classpath) { + mClassReader = JavaClassManager.getInstance(classpath); + } + + public JavaClassManager getClassReader() { + return mClassReader; + } + + @NonNull + public List findAllWithPrefix(String simpleNamePrefix) { + return mClassReader.find(simpleNamePrefix, null); + } + + @NonNull + public List findAllWithPrefix(@NonNull String simpleNamePrefix, + @Nullable Filter filter) { + return mClassReader.find(simpleNamePrefix, filter); + } + + public List findClasses(String simpleNamePrefix) { + return mClassReader.find(simpleNamePrefix, mClassFilter); + } + + public List findInterfaces(String simpleNamePrefix) { + return mClassReader.find(simpleNamePrefix, mInterfaceFilter); + } + + public List findEnums(String simpleNamePrefix) { + return mClassReader.find(simpleNamePrefix, mEnumFilter); + + } + + public List findAnnotations(String simpleNamePrefix) { + return mClassReader.find(simpleNamePrefix, mAnnotationFilter); + } + + + public void loadAllClasses(AndroidProject projectFile) { + mClassReader.loadFromProject(projectFile); + } + + public void updateClasses(List classes) { + for (IClass aClass : classes) { + mClassReader.update(aClass); + } + } + + public void updateClass(IClass... classes) { + for (IClass aClass : classes) { + mClassReader.update(aClass); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaUtil.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaUtil.java new file mode 100644 index 000000000..c170e6149 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/JavaUtil.java @@ -0,0 +1,191 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.blankj.utilcode.util.FileUtils; +import com.sun.tools.javac.tree.JCTree; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import javax.lang.model.element.Modifier; + +/** + * Created by Duy on 20-Jul-17. + */ + +public class JavaUtil { + public static String getSimpleName(String className) { + if (className.contains(".")) { + className = className.substring(className.lastIndexOf(".") + 1); + } + + return getArrayTypeIfNeeded(className); + } + + @NonNull + public static String getPackageName(String classname) { + if (classname.contains(".")) { + return classname.substring(0, classname.lastIndexOf(".")); + } else { + return ""; + } + } + + public static String getInverseName(String className) { + String[] split = className.split("."); + String result = ""; + for (String s : split) { + result = s + result; + } + return result; + } + + + public static boolean isValidClassName(@Nullable String name) { + return name != null && name.matches("[A-Za-z_][A-Za-z0-9_]*"); + } + + @Nullable + public static String getClassName(File javaSrc, String filePath) { + if (filePath.startsWith(javaSrc.getPath())) { + //hello/src/main/java + //hello -> + String filename = filePath.substring(filePath.indexOf(javaSrc.getPath()) + javaSrc.getPath().length() + 1); + filename = filename.replace(File.separator, "."); + if (filename.endsWith(".java")) { + filename = filename.substring(0, filename.lastIndexOf(".java")); + } + return filename; + } else { + return null; + } + } + + public static int toJavaModifiers(Set modifierSet) { + int modifiers = 0; + for (Modifier modifier : modifierSet) { + switch (modifier) { + case FINAL: + modifiers |= java.lang.reflect.Modifier.FINAL; + break; + case PROTECTED: + modifiers |= java.lang.reflect.Modifier.PROTECTED; + + break; + case PRIVATE: + modifiers |= java.lang.reflect.Modifier.PRIVATE; + + break; + case ABSTRACT: + modifiers |= java.lang.reflect.Modifier.ABSTRACT; + + break; + case NATIVE: + modifiers |= java.lang.reflect.Modifier.NATIVE; + + case PUBLIC: + modifiers |= java.lang.reflect.Modifier.PUBLIC; + + case STATIC: + modifiers |= java.lang.reflect.Modifier.STATIC; + + case TRANSIENT: + modifiers |= java.lang.reflect.Modifier.TRANSIENT; + + break; + case VOLATILE: + modifiers |= java.lang.reflect.Modifier.VOLATILE; + + break; + case SYNCHRONIZED: + modifiers |= java.lang.reflect.Modifier.SYNCHRONIZED; + + break; + case STRICTFP: + modifiers |= java.lang.reflect.Modifier.STRICT; + + break; + } + } + return modifiers; + } + + @NonNull + public static String findImportedClassName(@NonNull JCTree.JCCompilationUnit mUnit, + @NonNull String className) { + List imports = mUnit.getImports(); + for (JCTree.JCImport jcImport : imports) { + String fullName = jcImport.getQualifiedIdentifier().toString(); + if (fullName.equals(className) || fullName.endsWith("." + className)) { + return fullName; + } + } + return className; + } + + @Nullable + public static IClass jcTypeToClass(JCTree.JCCompilationUnit unit, JCTree type) { + if (type == null) { + return null; + } + String className; + if (type instanceof JCTree.JCTypeApply) { + return jcTypeToClass(unit, ((JCTree.JCTypeApply) type).getType()); + } else { + className = type.toString(); + } + + className = findImportedClassName(unit, className); + return JavaClassManager.getInstance().getParsedClass(className); + } + public static ArrayList listClassName(File src) { + if (!src.exists()) return new ArrayList(); + + Collection files = FileUtils.listFilesInDirWithFilter(src, (f -> f.isFile() && f.getName().endsWith(".java")), true); + + ArrayList classes = new ArrayList<>(); + String srcPath = src.getPath(); + for (File file : files) { + String javaPath = file.getPath(); + javaPath = javaPath.substring(srcPath.length() + 1, javaPath.length() - 5); //.java + javaPath = javaPath.replace(File.separator, "."); + classes.add(javaPath); + } + return classes; + } + + public static String getArrayTypeIfNeeded(String currentType) { + if(currentType == null) + return ""; + String type = new String(currentType); + if(type.startsWith("[")) { + type = type.substring(1).trim(); + if (type.equals("Z")) { + type = "boolean[]"; + } else if (type.equals("B")) { + type = "byte[]"; + } else if (type.equals("C")) { + type = "char[]"; + } else if (type.equals("S")) { + type = "short[]"; + } else if (type.equals("I")) { + type = "int[]"; + } else if (type.equals("J")) { + type = "long[]"; + } else if (type.equals("F")) { + type = "float[]"; + } else if (type.equals("D")) { + type = "double[]"; + } else { + if(type.endsWith(";")) + type = type.substring(0, type.length()); + type = type + "[]"; + } + } + return type; + } + + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/PackageManager.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/PackageManager.java new file mode 100644 index 000000000..32d0001a5 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/internal/PackageManager.java @@ -0,0 +1,62 @@ +package com.itsaky.androidide.language.java.parser.internal; + +import android.os.FileObserver; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.model.PackageDescription; +import com.itsaky.androidide.models.AndroidProject; +import java.io.File; +import java.util.ArrayList; + +public class PackageManager { + private static final String TAG = "AutoCompletePackage"; + private PackageDescription root; + private FileObserver fileObserver; + + public PackageManager() { + root = PackageDescription.root(); + } + + public void init(AndroidProject projectFile, JavaClassManager classReader) { + ArrayList classes = classReader.getAllClasses(); + for (IClass clazz : classes) { + root.put(clazz.getFullClassName()); + } + + final String parentPath = new File(projectFile.getMainModulePath(), "src/main/java").getPath(); + fileObserver = new FileObserver(parentPath) { + @Override + public void onEvent(int event, String path) { + remove(path, parentPath); + add(path, parentPath); + } + }; + fileObserver.startWatching(); + } + + private void add(String child, String parent) { + if (child.startsWith(parent)) { + child = child.substring(parent.length() + 1); + child = child.replace(File.separator, "."); + root.put(child); + } + } + + @Nullable + private PackageDescription remove(String child, String parent) { + if (child.startsWith(parent)) { + child = child.substring(parent.length() + 1); + child = child.replace(File.separator, "."); + return root.remove(child); + } + return null; + } + + public void destroy() { + if (fileObserver != null) fileObserver.stopWatching(); + } + + @Nullable + public PackageDescription trace(String child) { + return this.root.get(child); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ClassDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ClassDescription.java new file mode 100644 index 000000000..c5fc18eb3 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ClassDescription.java @@ -0,0 +1,313 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.expression.PackageImporter; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IField; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; +import com.itsaky.androidide.language.java.parser.internal.IMethod; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +public class ClassDescription extends JavaSuggestItemImpl implements IClass { + private static final String TAG = "ClassDescription"; + @NonNull + private final String mClassName; + private final ArrayList mConstructors = new ArrayList<>(); + private final ArrayList mFields = new ArrayList<>(); + private final ArrayList mMethods = new ArrayList<>(); + private final ArrayList mImplements = new ArrayList<>(); + private final int mModifiers; + private final boolean mPrimitive, mAnnotation, mEum, isMemberClass; + + //init later + @Nullable + private IClass mSuperClass; + + public ClassDescription(Class c) { + mClassName = c.getName(); + mModifiers = c.getModifiers(); + mPrimitive = c.isPrimitive(); + mAnnotation = c.isAnnotation(); + isMemberClass = c.isMemberClass(); + mEum = c.isEnum(); + } + + public ClassDescription(String className, int modifiers, + boolean isPrimitive, + boolean isAnnotation, + boolean isEnum, + boolean isMember) { + this.mClassName = className; + this.mModifiers = modifiers; + this.mPrimitive = isPrimitive; + this.mAnnotation = isAnnotation; + this.isMemberClass = isMember; + this.mEum = isEnum; + } + + @Override + public boolean isMemberClass() { + return isMemberClass; + } + + private String javadoc; + @Override + public IJavaDocCommentable setHtmlJavaDoc(String javadoc) { + this.javadoc = javadoc; + return this; + } + + @Override + public String getJavaDoc() { + return javadoc; + } + + @Override + public String getName() { + if (getPackageName().isEmpty()) { + return getSimpleName(); + } + return getSimpleName() + " (" + getPackageName() + ")"; + } + + @Override + public final String getDescription() { + return getPackageName().replace("$", "."); + } + + @Override + public String getReturnType() { + return ""; + } + + @Override + public char getTypeHeader() { + return 'c'; + } + + @Override + public int getSuggestionPriority() { + return JavaSuggestItemImpl.CLASS_DESC; + } + + public void onSelectThis(CodeEditor editorView) { + try { + final int length = getIncomplete().length(); + final int start = editorView.getCursor().getLeft() - length; + final int end = editorView.getCursor().getLeft(); + final CharPosition s = editorView.getText().getIndexer().getCharPosition(start); + Content editable = editorView.getText(); + editable.delete(start, end); + editable.insert(s.line, s.column, getSimpleName()); + PackageImporter.importClass(editable, getFullClassName()); + } catch (Exception e) { + } + } + + @Override + public String getSimpleName() { + return JavaUtil.getSimpleName(mClassName).replace("$", "."); + } + + @Override + public String getFullClassName() { + return mClassName; + } + + @Override + @Nullable + public IClass getSuperclass() { + return mSuperClass; + } + + public String getPackageName() { + return JavaUtil.getPackageName(mClassName); + } + + public ArrayList getConstructors() { + return mConstructors; + } + + public ArrayList getFields() { + return mFields; + } + + public void addConstructor(ConstructorDescription constructorDescription) { + this.mConstructors.add(constructorDescription); + } + + public void addField(IField fieldDescription) { + mFields.add(fieldDescription); + } + + public void addMethod(IMethod methodDescription) { + mMethods.add(methodDescription); + } + + public List getMethods() { + return mMethods; + } + + @Override + public String toString() { + return mClassName; + } + + @SuppressWarnings("ConstantConditions") + public ArrayList getMember(String prefix) { + ArrayList result = new ArrayList<>(); + for (ConstructorDescription constructor : mConstructors) { + if (!prefix.isEmpty()) { + if (constructor.getName().startsWith(prefix)) { + result.add(constructor); + } + } + } + for (IField field : mFields) { + if (prefix.isEmpty() || field.getFieldName().startsWith(prefix)) { + result.add(field); + } + } + getMethods(result, prefix); + return result; + } + + public void getMethods(ArrayList result, String prefix) { + for (IMethod method : mMethods) { + if (prefix.isEmpty() || method.getMethodName().startsWith(prefix)) { + result.add(method); + } + } + } + + + @Override + public int getModifiers() { + return mModifiers; + } + + @Override + public boolean isInterface() { + return false; + } + + + public boolean isEnum() { + return mEum; + } + + @Override + public boolean isPrimitive() { + return mPrimitive; + } + + @Override + public boolean isAnnotation() { + return mAnnotation; + } + + @Override + public IMethod getMethod(String methodName, IClass[] argsType) { + for (IMethod method : mMethods) { + if (method.getMethodName().equals(methodName)) { + return method; + } + } + + if (getSuperclass() != null) { + return getSuperclass().getMethod(methodName, argsType); + } + return null; + } + + @Override + public IField getField(String name) { + for (IField field : mFields) { + if (field.getFieldName().equals(name)) { + return field; + } + } + if (getSuperclass() != null) { + return getSuperclass().getField(name); + } + return null; + } + + public void initMembers(Class c) { + mImplements.clear(); + Class[] interfaces = c.getInterfaces(); + for (Class anInterface : interfaces) { + IClass implement = JavaClassManager.getInstance().getClassWrapper(anInterface); + mImplements.add(implement); +// initClassMembers(implement); + } + + if (c.getSuperclass() != null) { + mSuperClass = JavaClassManager.getInstance().getClassWrapper(c.getSuperclass()); + } else { + if (!getFullClassName().equals(Object.class.getName()) + && mSuperClass == null) { + mSuperClass = JavaClassManager.getInstance().getParsedClass(Object.class.getName()); + } + } + +// initClassMembers(mSuperClass); + + for (Constructor constructor : c.getConstructors()) { + if (Modifier.isPublic(constructor.getModifiers())) { + addConstructor(new ConstructorDescription(constructor)); + } + } + + for (Field field : c.getFields()) { + if (Modifier.isPublic(field.getModifiers())) { + if (!field.getName().equals(field.getDeclaringClass().getName())) { + addField(new FieldDescription(field)); + } + } + } + + for (Method method : c.getMethods()) { + if (Modifier.isPublic(method.getModifiers())) { + addMethod(new MethodDescription(method)); + } + } + } + + public void setSuperclass(IClass superclass) { + this.mSuperClass = superclass; +// initClassMembers(mSuperClass); + } + +// private void initClassMembers(IClass clazz) { +// if(clazz.getFields() != null) { +// for(IField f : clazz.getFields()) { +// addField(f); +// } +// } +// +// if(clazz.getMethods() != null) { +// for(IMethod method : clazz.getMethods()) { +// addMethod(method); +// } +// } +// +// if(clazz.getConstructors() != null) { +// for(ConstructorDescription desc : clazz.getConstructors()) { +// addConstructor(desc); +// } +// } +// } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ConstructorDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ConstructorDescription.java new file mode 100644 index 000000000..1deccde11 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/ConstructorDescription.java @@ -0,0 +1,119 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.language.java.parser.expression.PackageImporter; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; + +public class ConstructorDescription extends JavaSuggestItemImpl implements IJavaDocCommentable { + private ArrayList mParameterTypes = new ArrayList<>(); + private String mConstructorName; + + public ConstructorDescription(Constructor constructor) { + mConstructorName = constructor.getName(); + Class[] parameterTypes = constructor.getParameterTypes(); + for (Class parameterType : parameterTypes) { + IClass type = JavaClassManager.getInstance().getClassWrapper(parameterType); + mParameterTypes.add(type); + } + } + + public ConstructorDescription(String name, List paramTypes) { + mConstructorName = name; + mParameterTypes.addAll(paramTypes); + } + + private String javadoc; + @Override + public IJavaDocCommentable setHtmlJavaDoc(String javadoc) { + this.javadoc = javadoc; + return this; + } + + @Override + public String getJavaDoc() { + return javadoc; + } + + @Override + public void onSelectThis(@NonNull CodeEditor editorView) { + try { + final int length = getIncomplete().length(); + final int cursor = editorView.getCursor().getLeft(); + final int start = cursor - length; + Content editable = editorView.getText(); + final CharPosition sPos = editable.getIndexer().getCharPosition(start); + final CharPosition cPos = editable.getIndexer().getCharPosition(cursor); + + if (getParameterTypes().size() > 0) { + editable.replace(sPos.line, sPos.column, cPos.line, cPos.column, getSimpleName() + "()"); + CharPosition select = editable.getIndexer().getCharPosition(start + getSimpleName().length() + 1); + editorView.setSelection(select.line, select.column); + } else { + String text = getSimpleName() + "();"; + editable.replace(sPos.line, sPos.column, cPos.line, cPos.column, text); + CharPosition select = editable.getIndexer().getCharPosition(start + text.length()); + editorView.setSelection(select.line, select.column); + } + + PackageImporter.importClass(editorView.getText(), mConstructorName); + } catch (Exception e) { + } + } + + @Override + public String getName() { + return getSimpleName() + "(" + paramsToString(getParameterTypes()) + ")"; + } + + @Override + public char getTypeHeader() { + return 'c'; + } + + @Override + public String getDescription() { + return "Class constructor"; + } + + @Override + public String getReturnType() { + return ""; + } + + @Override + public String toString() { + return getSimpleName() + "()"; + } + + private String paramsToString(@NonNull ArrayList parameterTypes) { + StringBuilder result = new StringBuilder(); + boolean firstTime = true; + for (IClass parameterType : parameterTypes) { + if (firstTime) { + firstTime = false; + } else { + result.append(","); + } + result.append(parameterType.getSimpleName()); + } + return result.toString(); + } + + public ArrayList getParameterTypes() { + return mParameterTypes; + } + + private String getSimpleName() { + return JavaUtil.getSimpleName(mConstructorName); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/FieldDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/FieldDescription.java new file mode 100644 index 000000000..1c3de6c87 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/FieldDescription.java @@ -0,0 +1,128 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IField; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class FieldDescription extends JavaSuggestItemImpl implements Member, IField { + @NonNull + private String mName; + @NonNull + private IClass mType; + private int mModifiers; + @Nullable + private String mValue; + + public FieldDescription(int modifiers, IClass type, @NonNull String name, String initValue) { + mName = name; + mType = type; + mModifiers = modifiers; + mValue = initValue; + } + + public FieldDescription(Field field) { + mName = field.getName(); + mType = JavaClassManager.getInstance().getClassWrapper(field.getType()); + mModifiers = field.getModifiers(); + + if (Modifier.isStatic(mModifiers)) { + try { + boolean primitive = field.getType().isPrimitive(); + Object o = field.get(null); + if (primitive) { + mValue = o.toString(); + } else { + mValue = o.getClass().getSimpleName(); + } + } catch (Exception ignored) { + } + } + } + + private String javadoc; + @Override + public IJavaDocCommentable setHtmlJavaDoc(String javadoc) { + this.javadoc = javadoc; + return this; + } + + @Override + public String getJavaDoc() { + return javadoc; + } + + @Override + public void onSelectThis(@NonNull CodeEditor editorView) { + insertImpl(editorView, mName); + } + + + @Override + public char getTypeHeader() { + return 'f'; + } + + @Override + public String getName() { + if (mValue == null) { + return mName; + } else { + return mName + "(" + mValue + ")"; + } + } + + @Override + public String getDescription() { + return mValue; + } + + @Override + public String getReturnType() { + if (mType == null) { + return ""; + } + return mType.getSimpleName(); + } + + @Override + public int getSuggestionPriority() { + return JavaSuggestItemImpl.FIELD_DESC; + } + + @Override + public String toString() { + return mName; + } + + + @Override + public int getModifiers() { + return mModifiers; + } + + @Override + public String getFieldName() { + return mName; + } + + @Override + public IClass getFieldType() { + return mType; + } + + @Override + public int getFieldModifiers() { + return mModifiers; + } + + @Override + public Object getFieldValue() { + return mValue; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/JavaSuggestItemImpl.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/JavaSuggestItemImpl.java new file mode 100644 index 000000000..d1b08afc1 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/JavaSuggestItemImpl.java @@ -0,0 +1,60 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; + +public abstract class JavaSuggestItemImpl implements SuggestItem, Cloneable { + public static final int FIELD_DESC = 0; + public static final int METHOD_DESC = 1; + public static final int CLASS_DESC = 2; + public static final int OTHER_DESC = 3; + + private CodeEditor editor; + private String incomplete; + + @Override + public int getSuggestionPriority() { + return OTHER_DESC; + } + + public CodeEditor getEditor() { + return editor; + } + + public void setEditor(CodeEditor editor) { + this.editor = editor; + } + + public String getIncomplete() { + return incomplete; + } + + public void setIncomplete(@NonNull String incomplete) { + this.incomplete = incomplete; + } + + protected void insertImpl(CodeEditor editorView, String text) { + + try { + final int length = getIncomplete().length(); + final int cursor = getEditor().getCursor().getLeft(); + final int start = cursor - length; + Content editable = editorView.getText(); + CharPosition s = editable.getIndexer().getCharPosition(start); + CharPosition c = editable.getIndexer().getCharPosition(cursor); + editable.replace(s.line, s.column, c.line, c.column, text); + CharPosition select = editable.getIndexer().getCharPosition(start + text.length()); + editorView.setSelection(select.line, select.column); + } catch (Exception e) { + } + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/KeywordDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/KeywordDescription.java new file mode 100644 index 000000000..2807a6fdb --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/KeywordDescription.java @@ -0,0 +1,41 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.github.rosemoe.editor.widget.CodeEditor; + +public class KeywordDescription extends JavaSuggestItemImpl { + private final String keyword; + + public KeywordDescription(String keyword) { + this.keyword = keyword; + } + + @Nullable + @Override + public String getName() { + return keyword; + } + + @Nullable + @Override + public String getDescription() { + return null; + } + + @Nullable + @Override + public String getReturnType() { + return null; + } + + @Override + public char getTypeHeader() { + return 'k'; + } + + @Override + public void onSelectThis(@NonNull CodeEditor iEditAreaView) { + insertImpl(iEditAreaView, keyword + " "); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Member.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Member.java new file mode 100644 index 000000000..f44d6ef4e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Member.java @@ -0,0 +1,7 @@ +package com.itsaky.androidide.language.java.parser.model; + +public interface Member { + String getName(); + + int getModifiers(); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/MethodDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/MethodDescription.java new file mode 100644 index 000000000..2080ca446 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/MethodDescription.java @@ -0,0 +1,200 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.IJavaDocCommentable; +import com.itsaky.androidide.language.java.parser.internal.IMethod; +import com.itsaky.androidide.language.java.parser.internal.JavaClassManager; +import com.itsaky.androidide.language.java.parser.internal.JavaUtil; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class MethodDescription extends JavaSuggestItemImpl implements Member, SuggestItem, IMethod { + private String mMethodName; + private int mModifiers; + private ArrayList mParameterTypes = new ArrayList<>(); + private ArrayList mParameters = new ArrayList<>(); + + /** + * Return type of method, null if it is constructor + */ + @Nullable + private IClass mReturnType; + + public MethodDescription(String name, IClass returnType, + long modifiers, ArrayList parameterTypes) { + mMethodName = name; + mReturnType = returnType; + mModifiers = (int) modifiers; + mParameterTypes = parameterTypes; + } + + public MethodDescription(@NonNull String methodName, + int modifiers, + @NonNull List parameters, + @Nullable IClass returnType) { + mMethodName = methodName; + mModifiers = modifiers; + mParameters.addAll(parameters); + mReturnType = returnType; + } + + public MethodDescription(@NonNull Method method) { + mMethodName = method.getName(); + mModifiers = method.getModifiers(); + mReturnType = JavaClassManager.getInstance().getClassWrapper(method.getReturnType()); + Class[] parameterTypes = method.getParameterTypes(); + for (Class parameterType : parameterTypes) { + mParameterTypes.add(parameterType.getName()); + } + } + + private String javadoc; + @Override + public IJavaDocCommentable setHtmlJavaDoc(String javadoc) { + this.javadoc = javadoc; + return this; + } + + @Override + public String getJavaDoc() { + return javadoc; + } + + @Override + public void onSelectThis(@NonNull CodeEditor editorView) { + try { + final int length = getIncomplete().length(); + final int start = editorView.getCursor().getLeft() - length; + Content editable = editorView.getText(); + CharPosition s = editable.getIndexer().getCharPosition(start); + editable.delete(start, editorView.getCursor().getLeft()); + String simpleName = JavaUtil.getSimpleName(mMethodName); + String text = simpleName + "()" + (shouldAddSemicolon(getEditor()) ? ";" : ""); + if (getParameterTypes().size() > 0) { + editable.insert(s.line, s.column, text); + CharPosition select = editable.getIndexer().getCharPosition(start + simpleName.length() + 1); + editorView.setSelection(select.line, select.column); + } else { + editable.insert(s.line, s.column, text); + CharPosition select = editable.getIndexer().getCharPosition(start + text.length()); + editorView.setSelection(select.line, select.column); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private boolean shouldAddSemicolon(CodeEditor editor) { + int cursor = editor.getCursor().getLeft(); + String text = editor.getText().toString(); + while (cursor < text.length()) { + char c = text.charAt(cursor); + if (c == ' ' || c == '\n') { + cursor++; + continue; + } + if (c == ';') { + return false; + } else { + break; + } + } + + if (getMethodReturnType() == null) { + return true; + } + if (void.class.getName().equals(getMethodReturnType().getFullClassName())) { + return true; + } + return false; + } + + public ArrayList getParameterTypes() { + return mParameterTypes; + } + + @Override + public char getTypeHeader() { + return 'm'; + } + + @Override + public String getName() { + return mMethodName + "(" + paramsToString() + ")"; + } + + private String paramsToString() { + StringBuilder result = new StringBuilder(); + boolean firstTime = true; + ArrayList parameterTypes = getParameterTypes(); + for (String parameterType : parameterTypes) { + if (firstTime) { + firstTime = false; + } else { + result.append(","); + + } + result.append(JavaUtil.getSimpleName(parameterType)); + } + return result.toString(); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String getReturnType() { + if (mReturnType == null) { + return ""; + } + return mReturnType.getSimpleName(); + } + + @Override + public int getSuggestionPriority() { + return METHOD_DESC; + } + + @Override + public String toString() { + StringBuilder params = new StringBuilder(); + for (int i = 0; i < mParameterTypes.size(); i++) { + String parameterType = mParameterTypes.get(i); + if (i == mParameterTypes.size() - 1) { + params.append(JavaUtil.getSimpleName(parameterType)); + break; + } + params.append(JavaUtil.getSimpleName(parameterType)).append(","); + } + return mMethodName + "(" + params.toString() + ")"; + } + + @Override + public int getModifiers() { + return mModifiers; + } + + @Override + public String getMethodName() { + return mMethodName; + } + + @Override + public IClass[] getMethodParameterTypes() { + return null; + } + + @Override + public IClass getMethodReturnType() { + return mReturnType; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PackageDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PackageDescription.java new file mode 100644 index 000000000..0cb7c311a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PackageDescription.java @@ -0,0 +1,109 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import android.text.Editable; +import java.util.HashMap; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.text.CharPosition; + +public class PackageDescription extends JavaSuggestItemImpl { + private String mName; + private PackageDescription mParentPkg; + private HashMap mChild = new HashMap<>(); + + private PackageDescription(String childName, PackageDescription parent) { + this.mName = childName; + this.mParentPkg = parent; + } + + public static PackageDescription root() { + return new PackageDescription("", null); + } + + @Override + public void onSelectThis(@NonNull CodeEditor editorView) { + try { + final int cursor = getEditor().getCursor().getLeft(); + final int length = getIncomplete().length(); + final int start = cursor - length; + Content editable = editorView.getText(); + CharPosition s = editable.getIndexer().getCharPosition(start); + CharPosition c = editable.getIndexer().getCharPosition(cursor); + String text; + text = isLeaf() ? mName.replace("$", ".") : mName + "."; + editable.replace(s.line, s.column, c.line, c.column, text); + CharPosition select = editable.getIndexer().getCharPosition(start + text.length()); + editorView.setSelection(select.line, select.column); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public char getTypeHeader() { + return 'p'; + } + + @Override + public String getName() { + return mName; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String getReturnType() { + return null; + } + + + public HashMap getChild() { + return mChild; + } + + private boolean isRoot() { + return mName.isEmpty() || mParentPkg == null; + } + + private boolean isLeaf() { + return mChild.isEmpty(); + } + + public PackageDescription get(String key) { + if (!key.contains(".")) { + return mChild.get(key); + } else { + return get(key.substring(0, key.indexOf("."))) + .get(key.substring(key.indexOf(".") + 1)); + } + } + + public void put(String pkg) { + if (pkg.contains(".")) { + String first = pkg.substring(0, pkg.indexOf(".")); + if (get(first) == null) { + put(first); + } + get(first).put(pkg.substring(pkg.indexOf(".") + 1)); + } else { + this.mChild.put(pkg, new PackageDescription(pkg, this)); + } + } + + public PackageDescription remove(String child) { + if (child.contains(".")) { + return this.mChild.remove(child.substring(0, child.indexOf("."))); + } else { + return this.mChild.remove(child); + } + } + + @Override + public String toString() { + return mName; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PrimitiveArrayConstructorDescription.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PrimitiveArrayConstructorDescription.java new file mode 100644 index 000000000..7e57015fe --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/PrimitiveArrayConstructorDescription.java @@ -0,0 +1,62 @@ +package com.itsaky.androidide.language.java.parser.model; + +import androidx.annotation.NonNull; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; + +/** + * Created by Duy on 20-Jul-17. + */ + +public class PrimitiveArrayConstructorDescription extends JavaSuggestItemImpl { + private String name; + + public PrimitiveArrayConstructorDescription(String name) { + this.name = name; + } + + @Override + public void onSelectThis(@NonNull CodeEditor editorView) { + try { + final int length = getIncomplete().length(); + final int cursor = getEditor().getCursor().getLeft(); + final int start = cursor - length; + Content editable = editorView.getText(); + CharPosition s = editable.getIndexer().getCharPosition(start); + CharPosition c = editable.getIndexer().getCharPosition(cursor); + editable.replace(s.line, s.column, c.line, c.column, name + "[]"); + CharPosition select = editable.getIndexer().getCharPosition(start + name.length() + 1); + editorView.setSelection(select.line, select.column); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public String getName() { + return name + "[]"; + } + + @Override + public char getTypeHeader() { + return 'a'; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String getReturnType() { + return ""; + } + + + @Override + public String toString() { + return name + "[]"; + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Statement.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Statement.java new file mode 100644 index 000000000..514f81adf --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/model/Statement.java @@ -0,0 +1,19 @@ +package com.itsaky.androidide.language.java.parser.model; + +public class Statement { + private final String statement; + private final int offset; + + public Statement(String statement, int offset) { + this.statement = statement; + this.offset = offset; + } + + public String getStatement() { + return statement; + } + + public int getOffset() { + return offset; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/util/EditorUtil.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/EditorUtil.java new file mode 100644 index 000000000..36e971cc0 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/EditorUtil.java @@ -0,0 +1,147 @@ +package com.itsaky.androidide.language.java.parser.util; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import android.util.Log; +import android.widget.EditText; +import com.itsaky.androidide.language.java.parser.expression.PackageImporter; +import com.itsaky.androidide.language.java.parser.expression.PatternFactory; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.regex.Matcher; +import io.github.rosemoe.editor.text.CharPosition; + +/** + * Created by Duy on 20-Jul-17. + */ + +public class EditorUtil { + + private static final String TAG = "EditorUtil"; + + public EditorUtil() { + } + + @Nullable + public static String getCurrentPackage(String editText) { + Matcher matcher = PatternFactory.PACKAGE.matcher(editText); + if (matcher.find()) { + return matcher.group(); + } + return null; + } + + public static String getCurrentClassName(String editor) { + return ""; + } + + @NonNull + public static String getCurrentClassSimpleName(String editor) { + String className = getCurrentClassName(editor); + int i = className.indexOf("."); + if (i == -1) return className; + else { + return className.substring(className.lastIndexOf(".") + 1); + } + } + + + public static ArrayList getPossibleClassName(String source, String simpleName, String prefix) { + Log.d(TAG, "getPossibleClassName() called with: simpleName = [" + simpleName + "], prefix = [" + prefix + "]"); + + ArrayList classList = new ArrayList<>(); + String importedClassName = PackageImporter.getImportedClassName(source, simpleName); + Log.d(TAG, "getPossibleClassName importedClassName = " + importedClassName); + if (importedClassName != null) { + classList.add(importedClassName); + } else { + if (!prefix.contains(".")) { + classList.add(getCurrentClassName(source)); //current member + if (simpleName != null && !simpleName.isEmpty()) { + classList.add("java.lang." + simpleName); //default java.lang package + } else if (!prefix.isEmpty()) { + classList.add("java.lang." + prefix); + } + } else { + classList.add(prefix); + } + } + Log.d(TAG, "getPossibleClassName() returned: " + classList); + return classList; + } + + public static String getLine(EditText editText, int pos) { + if (pos < 0 || pos > editText.length()) return ""; + int line = LineUtils.getLineFromIndex(pos, editText.getLayout().getLineCount(), editText.getLayout()); + + int lineStart = editText.getLayout().getLineStart(line); + int lineEnd = editText.getLayout().getLineEnd(line); + return editText.getText().subSequence(lineStart, lineEnd).toString(); + } + + @Nullable + public static String getWord(EditText editText, int pos, boolean removeParentheses) { + String line = getLine(editText, pos).trim(); + return getLastWord(line, removeParentheses); + } + + @NonNull + public static String getWord(EditText editText, int pos) { + String line = getLine(editText, pos).trim(); + return getLastWord(line, false); + } + + @NonNull + public static String getLastWord(String line, boolean removeParentheses) { + String result = PatternFactory.lastMatchStr(line, PatternFactory.WORD); + if (result != null) { + return removeParentheses ? result.replaceAll(".*\\(", "") : result; + } else { + return ""; + } + } + + @Nullable + public static String getPreWord(EditText editor, int pos) { + String line = getLine(editor, pos); + String[] split = line.split(PatternFactory.SPLIT_NON_WORD_STR); + return split.length >= 2 ? split[split.length - 2] : null; + } + + @NonNull + public static String getLineBeforeCursor(@NonNull CodeEditor editor, final int cursor) { + int start = cursor - 1; + String text = editor.getText().toString(); + while (start > 0 && text.charAt(start) != '\n') { + start = start - 1; + if (start >= 0 && text.charAt(start) == '\n'){ + start++; + break; + } + } + CharPosition s = editor.getText().getIndexer().getCharPosition(start); + CharPosition c = editor.getText().getIndexer().getCharPosition(cursor - 1); + return editor.getText().subContent(s.line, s.column, c.line, c.column).toString(); + } + + public static String trimLeft(String code) { + if (code == null) { + return null; + } + if (code.length() == 0) { + return ""; + } + int index = 0; + while (index < code.length()) { + if (Character.isWhitespace(code.charAt(index))) { + index++; + } else { + break; + } + } + if (index == code.length()) { + return ""; + } + return code.substring(index); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/util/LineUtils.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/LineUtils.java new file mode 100644 index 000000000..9337292ea --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/LineUtils.java @@ -0,0 +1,129 @@ +package com.itsaky.androidide.language.java.parser.util; + +import androidx.annotation.NonNull; +import android.text.Layout; +import android.text.TextUtils; +import android.widget.EditText; +import android.widget.ScrollView; + +public class LineUtils { + private boolean[] toCountLinesArray; + private int[] realLines; + + public static int getYAtLine(ScrollView scrollView, int lineCount, int line) { + if (lineCount == 0) return 0; + return scrollView.getChildAt(0).getHeight() / lineCount * line; + } + + public static int getFirstVisibleLine(@NonNull ScrollView scrollView, int childHeight, + int lineCount) throws ArithmeticException { + if (childHeight == 0) return 0; + int line = (scrollView.getScrollY() * lineCount) / childHeight; + if (line < 0) line = 0; + return line; + } + + public static int getLastVisibleLine(@NonNull ScrollView scrollView, + int childHeight, int lineCount) { + if (childHeight == 0) return 0; + int line = (scrollView.getScrollY() * lineCount) / childHeight; + if (line > lineCount) line = lineCount; + return line; + } + + /** + * Gets the lineInfo from the index of the letter in the text + */ + public static int getLineFromIndex(int index, int lineCount, Layout layout) { + int line; + int currentIndex = 0; + + for (line = 0; line < lineCount; line++) { + currentIndex += layout.getLineEnd(line) - layout.getLineStart(line); + if (currentIndex >= index) { + break; + } + } + return line; + } + + public static int getStartIndexAtLine(EditText editable, int line) { + Layout layout = editable.getLayout(); + if (layout != null) { + return layout.getLineStart(line); + } + return 0; + } + + public boolean[] getGoodLines() { + return toCountLinesArray; + } + + public int[] getRealLines() { + return realLines; + } + + public void updateHasNewLineArray(int lineCount, Layout layout, String text) { + boolean[] hasNewLineArray = new boolean[lineCount]; + toCountLinesArray = new boolean[lineCount]; + realLines = new int[lineCount]; + if (TextUtils.isEmpty(text)) { + toCountLinesArray[0] = false; + realLines[0] = 0; + return; + } + + if (lineCount == 0) return; + + int i; + + // for every lineInfo on the edittext + for (i = 0; i < lineCount; i++) { + // check if this lineInfo contains "\n" + if (layout.getLineEnd(i) == 0) { + hasNewLineArray[i] = false; + } else { + hasNewLineArray[i] = text.charAt(layout.getLineEnd(i) - 1) == '\n'; + } + // if true + if (hasNewLineArray[i]) { + int j = i - 1; + while (j >= 0 && !hasNewLineArray[j]) { + j--; + } + toCountLinesArray[j + 1] = true; + + } + } + + toCountLinesArray[lineCount - 1] = true; + + int realLine = 0; + for (i = 0; i < toCountLinesArray.length; i++) { + realLines[i] = realLine; + if (toCountLinesArray[i]) { + realLine++; + } + } + } + + public int firstReadLine() { + return realLines[0]; + } + + public int lastReadLine() { + return realLines[realLines.length - 1]; + } + + public int fakeLineFromRealLine(int realLine) { + int i; + int fakeLine = 0; + for (i = 0; i < realLines.length; i++) { + if (realLine == realLines[i]) { + fakeLine = i; + break; + } + } + return fakeLine; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/parser/util/SpanUtil.java b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/SpanUtil.java new file mode 100644 index 000000000..53badaf1e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/parser/util/SpanUtil.java @@ -0,0 +1,27 @@ +package com.itsaky.androidide.language.java.parser.util; + +import android.content.Context; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import androidx.core.content.ContextCompat; +import com.itsaky.androidide.language.java.parser.model.ClassDescription; + +/** + * Created by duy on 19/07/2017. + */ + +public class SpanUtil { + + + public static Spannable formatClass(Context context, ClassDescription item) { + SpannableString simpleName = new SpannableString(item.getSimpleName()); + SpannableString packageName = new SpannableString("(" + item.getPackageName() + ")"); + simpleName.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, + android.R.color.primary_text_dark)), 0, simpleName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + packageName.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, + android.R.color.secondary_text_dark)), 0, packageName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return new SpannableStringBuilder().append(simpleName).append(packageName); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/java/provider/JavaCompletionProvider.java b/app/src/main/java/com/itsaky/androidide/language/java/provider/JavaCompletionProvider.java new file mode 100644 index 000000000..330ed5bd8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/java/provider/JavaCompletionProvider.java @@ -0,0 +1,101 @@ +package com.itsaky.androidide.language.java.provider; + +import androidx.core.util.Pair; +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.language.java.parser.Expression; +import com.itsaky.androidide.language.java.parser.ExpressionResolver; +import com.itsaky.androidide.language.java.parser.JavacParser; +import com.itsaky.androidide.language.java.parser.expression.CompleteExpression; +import com.itsaky.androidide.language.java.parser.expression.CompleteNewKeyword; +import com.itsaky.androidide.language.java.parser.expression.CompletePackage; +import com.itsaky.androidide.language.java.parser.expression.CompleteString; +import com.itsaky.androidide.language.java.parser.expression.CompleteThisKeyword; +import com.itsaky.androidide.language.java.parser.expression.CompleteTypeDeclared; +import com.itsaky.androidide.language.java.parser.expression.CompleteWord; +import com.itsaky.androidide.language.java.parser.expression.IJavaCompleteMatcher; +import com.itsaky.androidide.language.java.parser.internal.IClass; +import com.itsaky.androidide.language.java.parser.internal.JavaDexClassLoader; +import com.itsaky.androidide.language.java.parser.internal.PackageManager; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.utils.Environment; +import com.sun.tools.javac.tree.JCTree; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +public class JavaCompletionProvider { + + private final List mCompletors; + private JavaDexClassLoader mClassLoader; + private PackageManager mPackageManager; + private JavacParser mJavaParser; + + private boolean initiated = false; + + public JavaCompletionProvider() { + this.mCompletors = new ArrayList<>(); + this.mClassLoader = new JavaDexClassLoader(Environment.BOOTCLASSPATH); + this.mPackageManager = new PackageManager(); + this.mJavaParser = new JavacParser(); + + addAutoComplete(); + } + + public boolean loadProject(AndroidProject project) { + mClassLoader.loadAllClasses(project); + mPackageManager.init(project, mClassLoader.getClassReader()); + return initiated = true; + } + + public boolean isInitiated() { + return initiated; + } + + private void addAutoComplete() { + mCompletors.add(new CompleteExpression(mClassLoader)); + mCompletors.add(new CompleteNewKeyword(mClassLoader)); + mCompletors.add(new CompletePackage(mPackageManager)); + mCompletors.add(new CompleteString(mClassLoader)); + mCompletors.add(new CompleteTypeDeclared(mClassLoader)); + mCompletors.add(new CompleteThisKeyword(mClassLoader)); + mCompletors.add(new CompleteWord(mJavaParser, mClassLoader)); + } + + public Pair, List>> getSuggestions(CodeEditor editor) { + ArrayList result = new ArrayList<>(); + try { + JCTree.JCCompilationUnit ast = mJavaParser.parse(editor.getText()); + List classes = mJavaParser.parseClasses(ast); + + mClassLoader.updateClasses(classes); + + ExpressionResolver resolver = new ExpressionResolver(ast, editor); + Expression expression = resolver.getExpressionAtCursor(); + + JCTree.JCExpression jcExpression = expression.getExpression(); + int startPosition = jcExpression.getStartPosition(); + CharPosition s = editor.getText().getIndexer().getCharPosition(startPosition); + CharPosition c = new CharPosition(); + c.line = editor.getCursor().getLeftLine(); + c.column = editor.getCursor().getLeftColumn(); + String statement = editor.getText().subContent(s.line, s.column, c.line, c.column).toString(); + for (IJavaCompleteMatcher autoComplete : mCompletors) { + try { + boolean handled = autoComplete.process(ast, editor, expression, statement, result); + if (handled) { + break; + } + } catch (Throwable e) { + } + } + } catch (Throwable e) { + } + return Pair.create(result, mJavaParser.getDiagnostics()); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java b/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java new file mode 100644 index 000000000..cb8268950 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java @@ -0,0 +1,97 @@ +package com.itsaky.androidide.language.logs; + +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import com.itsaky.androidide.models.LogLine; +import com.itsaky.androidide.utils.Either; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.interfaces.EditorLanguage; +import io.github.rosemoe.editor.interfaces.NewlineHandler; +import io.github.rosemoe.editor.struct.CompletionItem; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.text.TextAnalyzer; +import io.github.rosemoe.editor.widget.SymbolPairMatch; +import java.util.ArrayList; +import java.util.List; + +public class LogLanguageImpl implements EditorLanguage { + + private static final LogAnalyzer analyzer = new LogAnalyzer(); + private static final LogCompletor completor = new LogCompletor(); + + public LogAnalyzer addLine(LogLine line) { + return analyzer.addLine(line); + } + + @Override + public CodeAnalyzer getAnalyzer() { + return analyzer; + } + + @Override + public AutoCompleteProvider getAutoCompleteProvider() { + return completor; + } + + @Override + public boolean isAutoCompleteChar(char ch) { + return false; + } + + @Override + public int getIndentAdvance(String content) { + return 0; + } + + @Override + public boolean useTab() { + return false; + } + + @Override + public CharSequence format(CharSequence text) { + return text; + } + + @Override + public SymbolPairMatch getSymbolPairs() { + return new SymbolPairMatch.DefaultSymbolPairs(); + } + + @Override + public NewlineHandler[] getNewlineHandlers() { + return new NewlineHandler[0]; + } + + private static class LogAnalyzer implements CodeAnalyzer { + + private static final List lines = new ArrayList<>(); + + public LogAnalyzer addLine(LogLine line) { + if(line != null) + lines.add(line); + + return this; + } + + @Override + public void analyze(CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { + int lastLine = 0; + for(int i=0;i> getAutoCompleteItems(String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int line) { + return new ArrayList>(); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java new file mode 100644 index 000000000..af89fde4f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java @@ -0,0 +1,107 @@ +package com.itsaky.androidide.language.xml; + +import android.graphics.Color; +import com.itsaky.androidide.language.xml.lexer.XMLLexer; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.struct.HexColor; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.text.TextAnalyzer; +import io.github.rosemoe.editor.widget.EditorColorScheme; +import java.io.StringReader; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CodePointCharStream; +import org.antlr.v4.runtime.Token; + +public class XMLAnalyzer implements CodeAnalyzer { + + @Override + public void analyze(CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { + try { + HashMap lineColors = new HashMap<>(); + CodePointCharStream stream = CharStreams.fromReader(new StringReader(content.toString())); + XMLLexer lexer = new XMLLexer(stream); + Token token = null, previous = null; + int line = 0, column = 0, lastLine = 1; + boolean first = true; + while (delegate.shouldAnalyze()) { + token = lexer.nextToken(); + if (token == null) + break; + if (token.getType() == XMLLexer.EOF) { + lastLine = token.getLine() - 1; + break; + } + line = token.getLine() - 1; + column = token.getCharPositionInLine(); + lastLine = line; + switch (token.getType()) { + case XMLLexer.S : + case XMLLexer.SEA_WS : + if (first) + colors.addNormalIfNull(); + break; + case XMLLexer.COMMENT : + colors.addIfNeeded(line, column, EditorColorScheme.COMMENT); + break; + case XMLLexer.OPEN : + case XMLLexer.OPEN_SLASH : + case XMLLexer.CLOSE : + case XMLLexer.SLASH : + case XMLLexer.SLASH_CLOSE : + case XMLLexer.SPECIAL_CLOSE : + case XMLLexer.EQUALS : + case XMLLexer.XMLDeclOpen : + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + break; + case XMLLexer.STRING : + colors.addIfNeeded(line, column, EditorColorScheme.LITERAL); + addHexColorIfPresent(token, lineColors, line, column); + break; + case XMLLexer.Name : + colors.addIfNeeded(line, column, previous.getType() == XMLLexer.OPEN || previous.getType() == XMLLexer.OPEN_SLASH ? EditorColorScheme.IDENTIFIER_NAME : EditorColorScheme.TEXT_NORMAL); + addHexColorIfPresent(token, lineColors, line, column); + break; + case XMLLexer.TEXT : + colors.addIfNeeded(line, column, EditorColorScheme.TEXT_NORMAL); + addHexColorIfPresent(token, lineColors, line, column); + break; + default : + colors.addIfNeeded(line, column, EditorColorScheme.TEXT_NORMAL); + break; + } + first = false; + if (token.getType() != XMLLexer.SEA_WS && token.getType() != XMLLexer.S) + previous = token; + } + colors.determine(lastLine); + colors.setHexColors(lineColors); + } catch (Throwable th) { + } + } + + private void addHexColorIfPresent(Token token, HashMap lineColors, int line, int column) { + Matcher m = HEX.matcher(token.getText()); + if (m.find()) { + try { + final CharPosition start = new CharPosition(line, column + m.start()); + final CharPosition end = new CharPosition(line, start.column + (m.end() - m.start())); + final HexColor key = new HexColor(start, end); + final Integer value = Color.parseColor(token.getText().substring(m.start(), m.end())); + + // Null checks + start.getClass(); + end.getClass(); + key.getClass(); + value.getClass(); + + lineColors.put(key, value); + } catch (Throwable th) {} + } + } + + private final Pattern HEX = Pattern.compile("#[a-fA-F0-9]{3,8}"); +} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java new file mode 100644 index 000000000..541bda0fa --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java @@ -0,0 +1,54 @@ +package com.itsaky.androidide.language.xml; + +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.language.xml.completion.XMLCompletionService; +import com.itsaky.androidide.models.CompletionListItem; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.struct.CompletionItem; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Collections; +import com.itsaky.androidide.utils.Either; +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import java.util.stream.Collectors; +import com.itsaky.androidide.utils.EitherOfResult; + +public class XMLAutoComplete implements AutoCompleteProvider { + + private CodeEditor editor; + + private Comparator RESULTS_SORTER = new Comparator(){ + + @Override + public int compare(CompletionItem p1, CompletionItem p2) { + return ((CompletionListItem) p1).getSortText().compareTo(((CompletionListItem) p2).getSortText()); + } + }; + + public XMLAutoComplete(CodeEditor editor) { + this.editor = editor; + } + + @Override + public List> getAutoCompleteItems(String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int line) { + // We do not store the completion service here in this class + // This is because, if we modify the instance of the service in app, + // it'll be updated here + // automatically + final XMLCompletionService service = StudioApp.getInstance().getXmlCompletionService(); + List list = new ArrayList(sort(service.complete(editor, prefix.trim()))); + List> result = new ArrayList<>(); + for(CompletionItem item : list) { + result.add(new EitherOfResult(null, item)); + } + return result; + } + + private List sort(List result) { + Collections.sort(result, RESULTS_SORTER); + return result; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java new file mode 100644 index 000000000..ca753a41d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java @@ -0,0 +1,105 @@ +package com.itsaky.androidide.language.xml; + +import com.itsaky.androidide.language.java.manager.JavaCharacter; +import com.itsaky.androidide.language.xml.lexer.XMLLexer; +import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; +import io.github.rosemoe.editor.interfaces.CodeAnalyzer; +import io.github.rosemoe.editor.interfaces.EditorLanguage; +import io.github.rosemoe.editor.interfaces.NewlineHandler; +import io.github.rosemoe.editor.text.TextUtils; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.widget.SymbolPairMatch; +import java.io.StringReader; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; + +public class XMLLanguage implements EditorLanguage { + + private XMLAnalyzer analyzer; + private XMLAutoComplete completer; + private NewlineHandler[] newlineHandlers = new NewlineHandler[] {}; + + public XMLLanguage(CodeEditor editor) { + this.completer = new XMLAutoComplete(editor); + this.analyzer = new XMLAnalyzer(); + this.newlineHandlers = new NewlineHandler[]{new IndentHandler()}; + } + + @Override + public CodeAnalyzer getAnalyzer() { + return analyzer; + } + + @Override + public AutoCompleteProvider getAutoCompleteProvider() { + return completer; + } + + @Override + public boolean isAutoCompleteChar(char ch) { + return JavaCharacter.isJavaIdentifierPart(ch) || ch == '<' || ch == '/'; + } + + @Override + public int getIndentAdvance(String content) { + try { + XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(content))); + Token token = null; + int advance = 0; + while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) { + switch (token.getType()) { + case XMLLexer.OPEN: + case XMLLexer.OPEN_SLASH : + advance++; + break; + case XMLLexer.CLOSE: + case XMLLexer.SLASH_CLOSE : + case XMLLexer.SPECIAL_CLOSE : + advance --; + break; + default : + break; + } + } + advance = Math.max(0, advance); + return advance * 4; + } catch (Throwable e) {} + return 0; + } + + @Override + public SymbolPairMatch getSymbolPairs() { + return new SymbolPairMatch.DefaultSymbolPairs(); + } + + @Override + public boolean useTab() { + return true; + } + + @Override + public CharSequence format(CharSequence content) { + return content; + } + + @Override + public NewlineHandler[] getNewlineHandlers() { + return newlineHandlers; + } + + class IndentHandler implements NewlineHandler { + + @Override + public boolean matchesRequirement(String beforeText, String afterText) { + return true; + } + + @Override + public HandleResult handleNewline(String beforeText, String afterText, int tabSize) { + int count = TextUtils.countLeadingSpaceCount(beforeText, tabSize); + int advanceBefore = getIndentAdvance(beforeText); + StringBuilder sb = new StringBuilder("\n").append(TextUtils.createIndent(count + advanceBefore, tabSize, useTab())); + return new HandleResult(sb, 0); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java b/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java new file mode 100644 index 000000000..072d7eef6 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java @@ -0,0 +1,242 @@ +package com.itsaky.androidide.language.xml.completion; + +import com.itsaky.androidide.language.xml.lexer.XMLLexer; +import com.itsaky.androidide.models.CompletionListItem; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.androidide.utils.FileUtil; +import io.github.rosemoe.editor.widget.CodeEditor; +import java.io.File; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.Token; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +public class XMLCompletionService { + private HashMap attrs; + private List widgets; + private final File ANDROID_ATTRS; + private final File ANDROID_WIDGETS; + + private boolean initiated = false; + + public XMLCompletionService() { + this.ANDROID_ATTRS = new File(Environment.BOOTCLASSPATH.getParentFile(), "data/res/values/attrs.xml"); + this.ANDROID_WIDGETS = new File(Environment.BOOTCLASSPATH.getParentFile(), "data/widgets.txt"); + this.attrs = new HashMap<>(); + this.widgets = new ArrayList<>(); + if(ANDROID_ATTRS.exists() && ANDROID_ATTRS.isFile()) { + addAttributesFrom(ANDROID_ATTRS, true); + } + + if(ANDROID_WIDGETS.exists()) { + processWidgetNames(); + } + initiated = true; + } + + public boolean isInitiated() { + return initiated; + } + + + public List complete(CodeEditor editor, String prefix) { + prefix = prefix.toLowerCase(Locale.US).trim(); + final int line = editor.getCursor().getLeftLine(); + final int column = editor.getCursor().getLeftColumn(); + final List result = new ArrayList<>(); + if(prefix.startsWith("<") || prefix.startsWith(" values = attr.possibleValues; + for(String value : values) + if(value.toLowerCase(Locale.US).contains(prefix)) + result.add(valueAsCompletion(value)); + } + } + } else { + for(Map.Entry entry : attrs.entrySet()) { + Attr attr = entry.getValue(); + if(attr.name.toLowerCase(Locale.US).contains(prefix)) + result.add(attrAsCompletion(attr)); + } + } + } + return handleResults(result); + } + + private CompletionListItem valueAsCompletion(String value) { + CompletionListItem item = new CompletionListItem(); + item.setLabel(value) + .setCommit(value) + .setDesc("Attribute Value") + .setDetail(item.getDesc()) + .setItemType("int") + .setType(CompletionListItem.Type.ATTRIBUTE) + .cursorOffset(item.getCommit().length()); + return item; + } + + private CompletionListItem attrAsCompletion(Attr attr) { + CompletionListItem item = new CompletionListItem(); + item.setLabel(attr.name) + .setCommit(attr.prefix + ":" + attr.name + "=\"" + (attr.prefix.equals("android") && attr.name.equals("id") ? "@+id/\"" : "\"")) + .setDesc("Attribute") + .setDetail(item.getDesc()) + .setItemType("int") + .setType(CompletionListItem.Type.ATTRIBUTE) + .cursorOffset(item.getCommit().length() - 1); + return item; + } + + private CompletionListItem widgetNameAsCompletion(String name, boolean slash) { + CompletionListItem item = new CompletionListItem(); + final String n = simpleName(name); + item.setLabel(n) + .setCommit("<" + (slash ? "/" : "") + n) + .setDesc(name) + .setDetail(item.getDesc()) + .setItemType(" ") + .setType(CompletionListItem.Type.WIDGET); + return item; + } + + private String simpleName(String name) { + return name.substring(name.lastIndexOf(".") + 1); + } + + private List handleResults(List result) { + return result; + } + + private void processWidgetNames() { + String read = FileUtil.readFile(ANDROID_WIDGETS.getAbsolutePath()); + if(read != null && read.length() > 0) { + widgets.clear(); + for(String line : read.split("\\n")) { + String name = line.split("\\s")[0]; + name = name.substring(1); + widgets.add(name); + } + Collections.sort(widgets); + } + } + + private void addAttributesFrom(File f, boolean isAndroid) { + try { + Document doc = Jsoup.parse(f, null); + Elements attrs = doc.getElementsByTag("resources").first().getElementsByTag("attr"); + for(Element attr : attrs) { + Attr a = new Attr(attr.attr("name"), isAndroid); + if(a.name.contains(":")) { + String[] split = a.name.split(":"); + a.prefix = split[0]; + a.name = split[1]; + } + if(attr.hasAttr("format") && attr.attr("format").contains("boolean")) { + a.possibleValues.add("true"); + a.possibleValues.add("false"); + } + Elements enums = attr.getElementsByTag("enum"); + Elements flags = attr.getElementsByTag("flag"); + if(enums != null && enums.size() > 0) { + for(Element e : enums) + a.possibleValues.add(e.attr("name")); + } + if(flags != null && flags.size() > 0) { + for(Element e : flags) + a.possibleValues.add(e.attr("name")); + } + if(this.attrs.containsKey(a.name)) { + Attr b = this.attrs.get(a.name); + if(b != null && b.hasPossibleValues()) + a.possibleValues.addAll(b.possibleValues); + } + this.attrs.put(a.name, a); + } + } catch (Throwable th) {} + } + + private class IsInValueScanner { + + private int cursorIndex; + + public IsInValueScanner(int cursorIndex) { + this.cursorIndex = cursorIndex; + } + + private boolean containsCursor(Token token) { + int start = token.getStartIndex(); + int end = token.getStopIndex(); + return start <= cursorIndex && cursorIndex <= end; + } + + public String scan(String xmlContent) { + try { + XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(xmlContent))); + Token token; + String attrName = null; + while((token = lexer.nextToken()) != null && token.getType() != XMLLexer.EOF) { + if(token.getType() == XMLLexer.STRING && containsCursor(token)) { + String text = token.getText(); + if(text.startsWith("\"")) + return attrName; + } else if(token.getType() == XMLLexer.Name) { + attrName = token.getText(); + } + } + } catch (Throwable e) {} + return null; + } + + } + + private class Attr { + public String prefix; + public String name; + + public Set possibleValues; + + public Attr(String name, boolean isAndroid) { + this.name = name; + this.prefix = isAndroid ? "android" : "app"; + this.possibleValues = new HashSet<>(); + } + + public boolean hasPossibleValues() { + return possibleValues != null && possibleValues.size() > 0; + } + + @Override + public String toString() { + return String.format("[%s=%s]", name, possibleValues.toString()); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/lexer/XMLLexer.java b/app/src/main/java/com/itsaky/androidide/language/xml/lexer/XMLLexer.java new file mode 100644 index 000000000..542864e6f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/xml/lexer/XMLLexer.java @@ -0,0 +1,205 @@ +// Generated from XMLLexer.g4 by ANTLR 4.9.2 +package com.itsaky.androidide.language.xml.lexer; + +// Generated from XMLLexer.g4 by ANTLR 4.9.2 +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class XMLLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + COMMENT=1, CDATA=2, DTD=3, EntityRef=4, CharRef=5, SEA_WS=6, OPEN=7, OPEN_SLASH=8, + XMLDeclOpen=9, TEXT=10, CLOSE=11, SPECIAL_CLOSE=12, SLASH_CLOSE=13, SLASH=14, + EQUALS=15, STRING=16, Name=17, S=18, PI=19; + public static final int + INSIDE=1, PROC_INSTR=2; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE", "INSIDE", "PROC_INSTR" + }; + + private static String[] makeRuleNames() { + return new String[] { + "COMMENT", "CDATA", "DTD", "EntityRef", "CharRef", "SEA_WS", "OPEN", + "CLOSE_OPEN", "XMLDeclOpen", "SPECIAL_OPEN", "TEXT", "CLOSE", "SPECIAL_CLOSE", + "SLASH_CLOSE", "SLASH", "EQUALS", "STRING", "Name", "S", "HEXDIGIT", + "DIGIT", "NameChar", "NameStartChar", "PI", "IGNORE" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, null, null, null, null, null, null, "'<'", "''", null, "'/>'", "'/'", "'='" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "COMMENT", "CDATA", "DTD", "EntityRef", "CharRef", "SEA_WS", "OPEN", + "CLOSE_OPEN", "XMLDeclOpen", "TEXT", "CLOSE", "SPECIAL_CLOSE", "SLASH_CLOSE", + "SLASH", "EQUALS", "STRING", "Name", "S", "PI" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public XMLLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "XMLLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\25\u00f0\b\1\b\1"+ + "\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4"+ + "\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t"+ + "\21\4\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t"+ + "\30\4\31\t\31\4\32\t\32\3\2\3\2\3\2\3\2\3\2\3\2\7\2>\n\2\f\2\16\2A\13"+ + "\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\7\3R\n"+ + "\3\f\3\16\3U\13\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4\3\4\7\4_\n\4\f\4\16\4b\13"+ + "\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6\6\6p\n\6\r\6\16\6q"+ + "\3\6\3\6\3\6\3\6\3\6\3\6\3\6\6\6{\n\6\r\6\16\6|\3\6\3\6\5\6\u0081\n\6"+ + "\3\7\3\7\5\7\u0085\n\7\3\7\6\7\u0088\n\7\r\7\16\7\u0089\3\b\3\b\3\b\3"+ + "\b\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3"+ + "\13\3\13\3\13\3\13\3\13\3\13\3\13\3\f\6\f\u00a8\n\f\r\f\16\f\u00a9\3\r"+ + "\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3"+ + "\20\3\21\3\21\3\22\3\22\7\22\u00c0\n\22\f\22\16\22\u00c3\13\22\3\22\3"+ + "\22\3\22\7\22\u00c8\n\22\f\22\16\22\u00cb\13\22\3\22\5\22\u00ce\n\22\3"+ + "\23\3\23\7\23\u00d2\n\23\f\23\16\23\u00d5\13\23\3\24\3\24\3\24\3\24\3"+ + "\25\3\25\3\26\3\26\3\27\3\27\3\27\3\27\5\27\u00e3\n\27\3\30\5\30\u00e6"+ + "\n\30\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\5?S`\2\33\5\3\7\4\t"+ + "\5\13\6\r\7\17\b\21\t\23\n\25\13\27\2\31\f\33\r\35\16\37\17!\20#\21%\22"+ + "\'\23)\24+\2-\2/\2\61\2\63\25\65\2\5\2\3\4\f\4\2\13\13\"\"\4\2((>>\4\2"+ + "$$>>\4\2))>>\5\2\13\f\17\17\"\"\5\2\62;CHch\3\2\62;\4\2/\60aa\5\2\u00b9"+ + "\u00b9\u0302\u0371\u2041\u2042\n\2<\2\289\7#\2\29"+ + ":\7/\2\2:;\7/\2\2;?\3\2\2\2<>\13\2\2\2=<\3\2\2\2>A\3\2\2\2?@\3\2\2\2?"+ + "=\3\2\2\2@B\3\2\2\2A?\3\2\2\2BC\7/\2\2CD\7/\2\2DE\7@\2\2E\6\3\2\2\2FG"+ + "\7>\2\2GH\7#\2\2HI\7]\2\2IJ\7E\2\2JK\7F\2\2KL\7C\2\2LM\7V\2\2MN\7C\2\2"+ + "NO\7]\2\2OS\3\2\2\2PR\13\2\2\2QP\3\2\2\2RU\3\2\2\2ST\3\2\2\2SQ\3\2\2\2"+ + "TV\3\2\2\2US\3\2\2\2VW\7_\2\2WX\7_\2\2XY\7@\2\2Y\b\3\2\2\2Z[\7>\2\2[\\"+ + "\7#\2\2\\`\3\2\2\2]_\13\2\2\2^]\3\2\2\2_b\3\2\2\2`a\3\2\2\2`^\3\2\2\2"+ + "ac\3\2\2\2b`\3\2\2\2cd\7@\2\2de\3\2\2\2ef\b\4\2\2f\n\3\2\2\2gh\7(\2\2"+ + "hi\5\'\23\2ij\7=\2\2j\f\3\2\2\2kl\7(\2\2lm\7%\2\2mo\3\2\2\2np\5-\26\2"+ + "on\3\2\2\2pq\3\2\2\2qo\3\2\2\2qr\3\2\2\2rs\3\2\2\2st\7=\2\2t\u0081\3\2"+ + "\2\2uv\7(\2\2vw\7%\2\2wx\7z\2\2xz\3\2\2\2y{\5+\25\2zy\3\2\2\2{|\3\2\2"+ + "\2|z\3\2\2\2|}\3\2\2\2}~\3\2\2\2~\177\7=\2\2\177\u0081\3\2\2\2\u0080k"+ + "\3\2\2\2\u0080u\3\2\2\2\u0081\16\3\2\2\2\u0082\u0088\t\2\2\2\u0083\u0085"+ + "\7\17\2\2\u0084\u0083\3\2\2\2\u0084\u0085\3\2\2\2\u0085\u0086\3\2\2\2"+ + "\u0086\u0088\7\f\2\2\u0087\u0082\3\2\2\2\u0087\u0084\3\2\2\2\u0088\u0089"+ + "\3\2\2\2\u0089\u0087\3\2\2\2\u0089\u008a\3\2\2\2\u008a\20\3\2\2\2\u008b"+ + "\u008c\7>\2\2\u008c\u008d\3\2\2\2\u008d\u008e\b\b\3\2\u008e\22\3\2\2\2"+ + "\u008f\u0090\7>\2\2\u0090\u0091\7\61\2\2\u0091\u0092\3\2\2\2\u0092\u0093"+ + "\b\t\3\2\u0093\24\3\2\2\2\u0094\u0095\7>\2\2\u0095\u0096\7A\2\2\u0096"+ + "\u0097\7z\2\2\u0097\u0098\7o\2\2\u0098\u0099\7n\2\2\u0099\u009a\3\2\2"+ + "\2\u009a\u009b\5)\24\2\u009b\u009c\3\2\2\2\u009c\u009d\b\n\3\2\u009d\26"+ + "\3\2\2\2\u009e\u009f\7>\2\2\u009f\u00a0\7A\2\2\u00a0\u00a1\3\2\2\2\u00a1"+ + "\u00a2\5\'\23\2\u00a2\u00a3\3\2\2\2\u00a3\u00a4\b\13\4\2\u00a4\u00a5\b"+ + "\13\5\2\u00a5\30\3\2\2\2\u00a6\u00a8\n\3\2\2\u00a7\u00a6\3\2\2\2\u00a8"+ + "\u00a9\3\2\2\2\u00a9\u00a7\3\2\2\2\u00a9\u00aa\3\2\2\2\u00aa\32\3\2\2"+ + "\2\u00ab\u00ac\7@\2\2\u00ac\u00ad\3\2\2\2\u00ad\u00ae\b\r\6\2\u00ae\34"+ + "\3\2\2\2\u00af\u00b0\7A\2\2\u00b0\u00b1\7@\2\2\u00b1\u00b2\3\2\2\2\u00b2"+ + "\u00b3\b\16\6\2\u00b3\36\3\2\2\2\u00b4\u00b5\7\61\2\2\u00b5\u00b6\7@\2"+ + "\2\u00b6\u00b7\3\2\2\2\u00b7\u00b8\b\17\6\2\u00b8 \3\2\2\2\u00b9\u00ba"+ + "\7\61\2\2\u00ba\"\3\2\2\2\u00bb\u00bc\7?\2\2\u00bc$\3\2\2\2\u00bd\u00c1"+ + "\7$\2\2\u00be\u00c0\n\4\2\2\u00bf\u00be\3\2\2\2\u00c0\u00c3\3\2\2\2\u00c1"+ + "\u00bf\3\2\2\2\u00c1\u00c2\3\2\2\2\u00c2\u00c4\3\2\2\2\u00c3\u00c1\3\2"+ + "\2\2\u00c4\u00ce\7$\2\2\u00c5\u00c9\7)\2\2\u00c6\u00c8\n\5\2\2\u00c7\u00c6"+ + "\3\2\2\2\u00c8\u00cb\3\2\2\2\u00c9\u00c7\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca"+ + "\u00cc\3\2\2\2\u00cb\u00c9\3\2\2\2\u00cc\u00ce\7)\2\2\u00cd\u00bd\3\2"+ + "\2\2\u00cd\u00c5\3\2\2\2\u00ce&\3\2\2\2\u00cf\u00d3\5\61\30\2\u00d0\u00d2"+ + "\5/\27\2\u00d1\u00d0\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3\2\2\2\u00d3"+ + "\u00d4\3\2\2\2\u00d4(\3\2\2\2\u00d5\u00d3\3\2\2\2\u00d6\u00d7\t\6\2\2"+ + "\u00d7\u00d8\3\2\2\2\u00d8\u00d9\b\24\2\2\u00d9*\3\2\2\2\u00da\u00db\t"+ + "\7\2\2\u00db,\3\2\2\2\u00dc\u00dd\t\b\2\2\u00dd.\3\2\2\2\u00de\u00e3\5"+ + "\61\30\2\u00df\u00e3\t\t\2\2\u00e0\u00e3\5-\26\2\u00e1\u00e3\t\n\2\2\u00e2"+ + "\u00de\3\2\2\2\u00e2\u00df\3\2\2\2\u00e2\u00e0\3\2\2\2\u00e2\u00e1\3\2"+ + "\2\2\u00e3\60\3\2\2\2\u00e4\u00e6\t\13\2\2\u00e5\u00e4\3\2\2\2\u00e6\62"+ + "\3\2\2\2\u00e7\u00e8\7A\2\2\u00e8\u00e9\7@\2\2\u00e9\u00ea\3\2\2\2\u00ea"+ + "\u00eb\b\31\6\2\u00eb\64\3\2\2\2\u00ec\u00ed\13\2\2\2\u00ed\u00ee\3\2"+ + "\2\2\u00ee\u00ef\b\32\4\2\u00ef\66\3\2\2\2\25\2\3\4?S`q|\u0080\u0084\u0087"+ + "\u0089\u00a9\u00c1\u00c9\u00cd\u00d3\u00e2\u00e5\7\b\2\2\7\3\2\5\2\2\7"+ + "\4\2\6\2\2"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/AndroidProject.java b/app/src/main/java/com/itsaky/androidide/models/AndroidProject.java new file mode 100644 index 000000000..c6e262e21 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/AndroidProject.java @@ -0,0 +1,195 @@ +package com.itsaky.androidide.models; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.core.util.Pair; +import com.itsaky.androidide.app.StudioApp; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class AndroidProject implements Parcelable { + private String appName; + private String packageName; + private String iconPath; + private String projectPath; + private String mainModule; + private String mainSourcePath; + + private List modulePaths = new ArrayList<>(); + private List sourcePaths = new ArrayList<>(); + private List classPaths = new ArrayList<>(); + + public AndroidProject() { + addSource(StudioApp.getInstance().getLogSenderDir().getAbsolutePath()); + } + + protected AndroidProject(Parcel in) { + appName = in.readString(); + packageName = in.readString(); + iconPath = in.readString(); + projectPath = in.readString(); + mainModule = in.readString(); + mainSourcePath = in.readString(); + in.readList(modulePaths, String.class.getClassLoader()); + in.readList(sourcePaths, String.class.getClassLoader()); + in.readList(classPaths, String.class.getClassLoader()); + } + + public File getBuildDir() { + return new File(getMainModulePath(), "build"); + } + + public AndroidProject setMainModule(String mainModule) { + this.mainModule = mainModule; + return this; + } + + public String getMainModule() { + return mainModule; + } + + public String getMainModulePath() { + return new File(getProjectPath(), getMainModule()).getAbsolutePath(); + } + + public AndroidProject setMainSourcePath(String mainModulePath) { + this.mainSourcePath = mainModulePath; + return this; + } + + public String getMainSourcePath() { + return mainSourcePath; + } + + public AndroidProject setModulePaths(List modulePaths) { + this.modulePaths = modulePaths; + return this; + } + + public List getModulePaths() { + if (modulePaths == null) modulePaths = new ArrayList<>(); + return modulePaths; + } + + public AndroidProject addModule(String path) { + if (!getModulePaths().contains(path)) + getModulePaths().add(path); + return this; + } + + public AndroidProject setSourcePaths(List sourcePaths) { + this.sourcePaths = sourcePaths; + return this; + } + + public List getSourcePaths() { + if (sourcePaths == null) sourcePaths = new ArrayList<>(); + return sourcePaths; + } + + public AndroidProject addSource(String path) { + if (!getSourcePaths().contains(path)) + getSourcePaths().add(path); + return this; + } + + public AndroidProject setClassPaths(List classPaths) { + this.classPaths = classPaths; + return this; + } + + public List getClassPaths() { + if (classPaths == null) classPaths = new ArrayList<>(); + return classPaths; + } + + public AndroidProject addClasspath(String path) { + if (!getClassPaths().contains(path)) + getClassPaths().add(path); + return this; + } + + public AndroidProject setAppName(String appName) { + this.appName = appName; + return this; + } + + public String getAppName() { + return appName; + } + + public AndroidProject setPackageName(String packageName) { + this.packageName = packageName; + return this; + } + + public String getPackageName() { + return packageName; + } + + public AndroidProject setIconPath(String iconPath) { + this.iconPath = iconPath; + return this; + } + + public String getIconPath() { + return iconPath; + } + + public AndroidProject setProjectPath(String projectPath) { + this.projectPath = projectPath; + return this; + } + + public String getProjectPath() { + return projectPath; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel p1, int p2) { + p1.writeString(appName); + p1.writeString(packageName); + p1.writeString(iconPath); + p1.writeString(projectPath); + p1.writeString(mainModule); + p1.writeString(mainSourcePath); + p1.writeList(modulePaths); + p1.writeList(sourcePaths); + p1.writeList(classPaths); + } + + @Override + public String toString() { + return "[" + + "\nappName=" + getAppName() + + "\npackageName=" + getPackageName() + + "\niconPath=" + getIconPath() + + "\nprojectPath=" + getProjectPath() + + "\nmainModule=" + getMainModule() + + "\nmainModulePath=" + getMainModulePath() + + "\nmainModuleSourcePath=" + getMainSourcePath() + + "\nmodules=" + getModulePaths() + + "\nsources=" + getSourcePaths() + + "\nclasspaths=" + getClassPaths() + + "\n]"; + } + + public static final Creator CREATOR = new Creator(){ + + @Override + public AndroidProject createFromParcel(Parcel p1) { + return new AndroidProject(p1); + } + + @Override + public AndroidProject[] newArray(int p1) { + return new AndroidProject[p1]; + } + }; +} diff --git a/app/src/main/java/com/itsaky/androidide/models/ConstantsBridge.java b/app/src/main/java/com/itsaky/androidide/models/ConstantsBridge.java new file mode 100644 index 000000000..e04babeb1 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/ConstantsBridge.java @@ -0,0 +1,13 @@ +package com.itsaky.androidide.models; + +import java.util.List; + +public class ConstantsBridge { + + public static boolean EDITORPREF_SIZE_CHANGED = false; + public static boolean EDITORPREF_FLAGS_CHANGED = false; + public static boolean EDITORPREF_DRAW_HEX_CHANGED = false; + public static boolean CLASS_LOAD_SUCCESS = true; + + public static List PROJECT_DEXES = null; +} diff --git a/app/src/main/java/com/itsaky/androidide/models/DexPair.java b/app/src/main/java/com/itsaky/androidide/models/DexPair.java new file mode 100644 index 000000000..9b5c4e85b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/DexPair.java @@ -0,0 +1,44 @@ +package com.itsaky.androidide.models; + +import android.os.Parcelable; +import android.os.Parcel; + +public class DexPair implements Parcelable { + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel p1, int p2) { + p1.writeString(first); + p1.writeString(second); + } + + public String first; + public String second; + + private DexPair(Parcel in) { + first = in.readString(); + second = in.readString(); + } + + public DexPair(String first, String second) { + this.first = first; + this.second = second; + } + + public static final Creator CREATOR = new Creator(){ + + @Override + public DexPair createFromParcel(Parcel p1) { + return new DexPair(p1); + } + + @Override + public DexPair[] newArray(int p1) { + return new DexPair[p1]; + } + }; +} diff --git a/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java b/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java new file mode 100644 index 000000000..c6b28c184 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java @@ -0,0 +1,59 @@ +package com.itsaky.androidide.models; + +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; + +public class GradleSuggestItem implements SuggestItem { + + private String label; + private String desc; + private String prefix; + private boolean isArtifact; + + public GradleSuggestItem(String label, String desc, String prefix, boolean isArtifact) { + this.label = label; + this.desc = desc; + this.prefix = prefix; + this.isArtifact = isArtifact; + } + + @Override + public String getName() { + return label; + } + + @Override + public String getDescription() { + return desc; + } + + @Override + public String getReturnType() { + return ""; + } + + @Override + public char getTypeHeader() { + return ' '; + } + + @Override + public int getSuggestionPriority() { + return 1; + } + + @Override + public void onSelectThis(CodeEditor editor) { + try { + final int length = prefix.length(); + final int start = editor.getCursor().getLeft() - length; + final int end = editor.getCursor().getLeft(); + final CharPosition s = editor.getText().getIndexer().getCharPosition(start); + Content editable = editor.getText(); + editable.delete(start, end); + editable.insert(s.line, s.column, getName()); + } catch (Throwable ignored) {} + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/LogLine.java b/app/src/main/java/com/itsaky/androidide/models/LogLine.java new file mode 100644 index 000000000..23acd4777 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/LogLine.java @@ -0,0 +1,78 @@ +package com.itsaky.androidide.models; + +import android.content.Context; +import androidx.core.content.ContextCompat; +import com.itsaky.androidide.R; +import java.util.Locale; +import io.github.rosemoe.editor.widget.EditorColorScheme; + +public class LogLine { + + public String date; + public String time; + public String pid; + public String tid; + public String priorityChar; + public String tag; + public String message; + + public int priority; + + // It makes things easier in LogLanguageImpl + public static final int INFO = EditorColorScheme.LOG_INFO; + public static final int DEBUG = EditorColorScheme.LOG_DEBUG; + public static final int ERROR = EditorColorScheme.LOG_ERROR; + public static final int WARNING = EditorColorScheme.LOG_WARNING; + + public LogLine(LogLine src ) { + this(src.date, src.time, src.pid, src.tid, src.priorityChar, src.tag, src.message); + } + + public LogLine(String date, String time, String pid, String tid, String priorityChar, String tag) { + this(date, time, pid, tid, priorityChar, tag, ""); + } + + public LogLine(String date, String time, String pid, String tid, String priorityChar, String tag, String message) { + this.date = date; + this.time = time; + this.pid = pid; + this.tid = tid; + this.priorityChar = priorityChar; + this.tag = tag; + this.message = message; + this.priority = parsePriority(priorityChar); + } + + private int parsePriority(String s) { + if(s == null || s.trim().length() > 1) { + return DEBUG; + } + char c = s.toLowerCase().charAt(0); + if(c == 'w') { + return WARNING; + } else if(c == 'e') { + return ERROR; + } else if(c == 'i') { + return INFO; + } else { + return DEBUG; + } + } + + public int getColor(Context ctx) { + int id = R.color.log_normal; + if(priority == WARNING) { + id = R.color.log_warning; + } else if(priority == ERROR) { + id = R.color.log_error; + } else if(priority == INFO) { + id = R.color.log_info; + } + return ContextCompat.getColor(ctx, id); + } + + @Override + public String toString() { + return String.format("%-6s %-13s %-6s %-6s %-2s %-26s %s", date, time, pid, tid, priorityChar, tag, message); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/NewProjectDetails.java b/app/src/main/java/com/itsaky/androidide/models/NewProjectDetails.java new file mode 100644 index 000000000..e68748f85 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/NewProjectDetails.java @@ -0,0 +1,54 @@ +package com.itsaky.androidide.models; + +public class NewProjectDetails { + + public String name; + public String packageName; + public int minSdk; + public int targetSdk; + + public NewProjectDetails(){} + + public NewProjectDetails(String name, String packageName, int minSdk, int targetSdk) { + this.name = name; + this.packageName = packageName; + this.minSdk = minSdk; + this.targetSdk = targetSdk; + } + + public NewProjectDetails setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public NewProjectDetails setPackageName(String packageName) { + this.packageName = packageName; + return this; + } + + public String getPackageName() { + return packageName; + } + + public NewProjectDetails setMinSdk(int minSdk) { + this.minSdk = minSdk; + return this; + } + + public int getMinSdk() { + return minSdk; + } + + public NewProjectDetails setTargetSdk(int targetSdk) { + this.targetSdk = targetSdk; + return this; + } + + public int getTargetSdk() { + return targetSdk; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/ProjectTemplate.java b/app/src/main/java/com/itsaky/androidide/models/ProjectTemplate.java new file mode 100644 index 000000000..3b9332713 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/ProjectTemplate.java @@ -0,0 +1,69 @@ +package com.itsaky.androidide.models; + +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; +import android.content.Context; + +public class ProjectTemplate { + + private int id; + private String name; + private String description; + + @DrawableRes + private int imageId; + + public ProjectTemplate() { + } + + public ProjectTemplate(int id, String name, String description, int imageId) { + this.id = id; + this.name = name; + this.description = description; + this.imageId = imageId; + } + + public ProjectTemplate setId(int id) { + this.id = id; + return this; + } + + public int getId() { + return id; + } + + public ProjectTemplate setName(Context ctx, @StringRes int name) { + return setName(ctx.getString(name)); + } + + public ProjectTemplate setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; + } + + public ProjectTemplate setDescription(Context ctx, @StringRes int desc) { + return setDescription(ctx.getString(desc)); + } + + public ProjectTemplate setDescription(String description) { + this.description = description; + return this; + } + + public String getDescription() { + return description; + } + + public ProjectTemplate setImageId(@DrawableRes int imageId) { + this.imageId = imageId; + return this; + } + + public int getImageId() { + return imageId; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/SheetOption.java b/app/src/main/java/com/itsaky/androidide/models/SheetOption.java new file mode 100644 index 000000000..cf63029f7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/SheetOption.java @@ -0,0 +1,36 @@ +package com.itsaky.androidide.models; + +public final class SheetOption { + public int id; + public int iconRes; + public int titleRes; + public Object extra; + + public SheetOption(int id, int iconRes, int titleRes) { + this.id = id; + this.iconRes = iconRes; + this.titleRes = titleRes; + } + + public SheetOption(int id, int iconRes, int titleRes, Object extra) { + this.id = id; + this.iconRes = iconRes; + this.titleRes = titleRes; + this.extra = extra; + } + + public SheetOption setExtra(Object extra) { + this.extra = extra; + return this; + } + + @Override + public boolean equals(Object obj) { + if(obj != null && obj instanceof SheetOption) { + SheetOption that = (SheetOption) obj; + return this.iconRes == that.iconRes + && this.titleRes == that.titleRes; + } + return false; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/models/gradle/Artifact.java b/app/src/main/java/com/itsaky/androidide/models/gradle/Artifact.java new file mode 100644 index 000000000..9631b4a94 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/models/gradle/Artifact.java @@ -0,0 +1,88 @@ +package com.itsaky.androidide.models.gradle; + +import com.blankj.utilcode.util.ThrowableUtils; +import com.itsaky.androidide.utils.Environment; +import java.io.File; +import org.json.JSONObject; + +public class Artifact { + + public final String group; + public final String name; + public final String version; + + private Artifact () { + this(null); + } + + private Artifact(String artifact) { + this(group(artifact), name(artifact), version(artifact)); + } + + private Artifact(String group, String name, String version) { + if(group == null + || name == null + || version == null) + throw new IllegalArgumentException(String.format("Artifact%s values cannot be null", toString())); + this.group = group; + this.name = name; + this.version = version; + } + + public boolean isValid() { + return group != null + && name != null + && version != null + && !group.isEmpty() + && !name.isEmpty() + && !version.isEmpty(); + } + + public File folder() { + return Environment.cachedFolderForArtifact(this); + } + + public static Artifact from(JSONObject obj) { + try { + return Artifact.from(obj.getString("requested")); + } catch (Throwable th) { + return null; + } + } + + public static Artifact from(String artifact) { + return new Artifact(artifact); + } + + public static Artifact copy(Artifact src) { + return new Artifact(src.group, src.name, src.version); + } + + private static String group(String artifact) { + return artifact.split(":")[0]; + } + + private static String name(String artifact) { + return artifact.split(":")[1]; + } + + private static String version(String artifact) { + return artifact.split(":")[2]; + } + + @Override + public boolean equals(Object obj) { + if(obj != null && obj instanceof Artifact) { + Artifact that = (Artifact) obj; + return this.group.equals(that.group) + && this.name.equals(that.name) + && this.version.equals(that.version); + } + return false; + } + + @Override + public String toString() { + return String.format("[%s, %s, %s]", group, name, version); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/receivers/LogReceiver.java b/app/src/main/java/com/itsaky/androidide/receivers/LogReceiver.java new file mode 100644 index 000000000..4f8bbe6d9 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/receivers/LogReceiver.java @@ -0,0 +1,104 @@ +package com.itsaky.androidide.receivers; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.itsaky.androidide.models.LogLine; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import com.elvishew.xlog.XLog; + +public class LogReceiver extends BroadcastReceiver { + + private LogListener listener; + + public static final String APPEND_LOG = "com.itsaky.androidide.logs.APPEND_LOG"; + public static final String EXTRA_LINE = "log_line"; + + private LogLine logTag = null; + + public LogReceiver setLogListener(LogListener listener) { + this.listener = listener; + return this; + } + + @Override + public void onReceive(Context context, Intent intent) { + if(intent.getAction().equals(APPEND_LOG) && intent.hasExtra(EXTRA_LINE)) { + String line = intent.getStringExtra(EXTRA_LINE); + if(line == null) return; + try { + sendLogLine(line); + } catch (Throwable th) {} + } + } + + private void sendLogLine(String line) { + Matcher m = LOG_HEAD_PATTERN.matcher(line); + LogLine log = null; + final boolean find = line != null && line.trim().length() > 2 /*if length() == 2 then only [] is available*/ && m.find(); + XLog.i("line -> " + line + "\nlogTag find() -> " + find); + if(find) { + String date = ""; + String time = ""; + String pid = ""; + String tid = ""; + String priority = ""; + String tag = ""; + m = DATE_MATCHER.matcher(line); + if(m.find()) + date = line.substring(m.start(), m.end()); + + m = TIME_MATCHER.matcher(line); + if(m.find()) + time = line.substring(m.start(), m.end()); + + m = PIDTID_MATCHER.matcher(line); + if(m.find()) { + String[] s = line.substring(m.start(), m.end()).split(":"); + if(s.length > 0) + pid = s[0]; + if(s.length > 1) + tid = s[1]; + } + + m = PRIORITYTAG_MATCHER.matcher(line); + if(m.find()) { + String[] s = line.substring(m.start(), m.end()).split("/", 2); + if(s.length > 0) + priority = s[0]; + if(s.length > 1) + tag = s[1]; + if(tag.trim().endsWith("]")) + tag = tag.substring(0, tag.lastIndexOf("]")).trim(); + } + + logTag = new LogLine(date, time, pid, tid, priority, tag); + return; + } + + if(logTag != null) { + log = new LogLine(logTag); + log.message = line; + } else { + log = new LogLine("", "", "", "", "", "", line); + } + + XLog.i("log = " + log + "\nlogListener = " + listener); + if(log != null && listener != null) { + XLog.i("listener.appendLogLine(...) log ->\n" + log); + listener.appendLogLine(log); + logTag = null; + } + } + + public static interface LogListener { + public void appendLogLine(LogLine line); + } + + public static final Pattern DATE_MATCHER = Pattern.compile("\\d{2}-\\d{2}"); + public static final Pattern TIME_MATCHER = Pattern.compile("\\d{2}:\\d{2}:\\d{2}\\.\\d{2,3}"); + public static final Pattern PIDTID_MATCHER = Pattern.compile("\\d{4,5}\\s*:\\s*\\d{4,5}"); + public static final Pattern PRIORITYTAG_MATCHER = Pattern.compile("[A-Z]\\/.*"); + public static final Pattern LOG_HEAD_PATTERN = Pattern.compile("\\[\\s*\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}\\.\\d{2,3}\\s+\\d{4,5}\\s*:\\s*\\d{4,5}\\s+\\w/.*\\]"); +} diff --git a/app/src/main/java/com/itsaky/androidide/services/IDEService.java b/app/src/main/java/com/itsaky/androidide/services/IDEService.java new file mode 100644 index 000000000..2d4fb802a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/IDEService.java @@ -0,0 +1,410 @@ +package com.itsaky.androidide.services; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import com.blankj.utilcode.util.FileUtils; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.models.gradle.Artifact; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.tasks.GradleTask; +import com.itsaky.androidide.tasks.gradle.BaseGradleTasks; +import com.itsaky.androidide.tasks.gradle.build.AssembleDebug; +import com.itsaky.androidide.utils.Environment; +import com.itsaky.androidide.utils.PreferenceManager; +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.json.JSONObject; + +public class IDEService extends Service implements ShellServer.Callback { + + private static IDEService instance; + private ShellServer shell; + private BuildListener listener; + private File module; + private GradleTask currentTask; + + private List dependencies; + + private boolean isBuilding = false; + private boolean outputtingJars = false; + private boolean recreateShellOnDone = false; + + private static boolean isRunning = false; + + private final String RUN_TASK = "> Task"; + private final String STARTING_DAEMON = "Starting a "; + private final String BUILD_SUCCESS = "BUILD SUCCESSFUL"; + private final String BUILD_FAILED = "BUILD FAILED"; + private final String SHOW_DEPENDENCIES_START = ">> DEPENDENCIES START <<"; + private final String SHOW_DEPENDENCIES_END = ">> DEPENDENCIES END <<"; + + public static final String ACTION_CREATED = "BUILD_SERVICE_CREATED"; + + public static final int TASK_SHOW_DEPENDENCIES = 0; + public static final int TASK_ASSEMBLE_DEBUG = 1; + public static final int TASK_ASSEMBLE_RELEASE = 2; + public static final int TASK_BUILD = 3; + public static final int TASK_BUNDLE = 4; + public static final int TASK_CLEAN = 5; + public static final int TASK_CLEAN_BUILD = 6; + public static final int TASK_COMPILE_JAVA = 7; + public static final int TASK_DEX = 8; + public static final int TASK_LINT = 9; + public static final int TASK_LINT_DEBUG = 10; + public static final int TASK_LINT_RELEASE = 11; + + + public IDEService() {} + + public IDEService(String module) { + this(new File(module)); + } + + public IDEService(File module) { + this.module = module; + } + + public void onGradleUpdated() { + if(shell == null) { + createShell(); + return; + } + if(!isBuilding()) { + createShell(); + } else { + recreateShellOnDone = true; + } + } + + public static IDEService getInstance() { + return instance; + } + + public IDEService setListener(BuildListener listener) { + this.listener = listener; + return this; + } + + public IDEService setModule(String path) { + return setModule(new File(path)); + } + + public IDEService setModule(File module) { + this.module = module; + this.shell.append(String.format("cd \"%s\"", module.getAbsolutePath())); + return this; + } + + @Override + public void output(CharSequence charSequence) { + if(listener == null || charSequence == null) return; + final String line = charSequence + .toString() + .replace(":showDependenciesDebug", ":startCompletionServices") + .trim(); + + boolean shouldOutput = true; + if(line.contains(SHOW_DEPENDENCIES_START)) { + shouldOutput = false; + dependencies = new ArrayList<>(); + outputtingJars = true; + if(listener != null) + listener.onRunTask("> Task :app:startCompletionServices", currentTask); + return; + } else if(line.contains(SHOW_DEPENDENCIES_END)) { + shouldOutput = false; + outputtingJars = false; + if(listener != null + && dependencies != null) { + + listener.onGetDependencies(dependencies); + } + StudioApp.getInstance().getPrefManager().putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false); + return; + } + + if(outputtingJars) { + + JSONObject o = asObjectOrNull(line); + try { + if(o.has("type")) { + String type = o.getString("type"); + if(type.equals("ANDROID_JAR")) { + shouldOutput = false; + Environment.setBootClasspath(new File(o.getString("requested"))); + } + } else if(o.has("file")) { + shouldOutput = false; + String jar = o.getString("file"); + + dependencies.add(jar); + } + } catch (Throwable th) {} + } + if(shouldOutput) { + String text = line.replace(StudioApp.getInstance().getRootDir().getAbsolutePath(), "ANDROIDIDE_HOME"); + listener.appendOutput(currentTask, text); + } + if(charSequence.toString().contains(RUN_TASK)) { + listener.onRunTask(charSequence.toString().trim(), currentTask); + } else + if(charSequence.toString().startsWith(STARTING_DAEMON)) { + listener.onStartingGradleDaemon(currentTask); + } else + if(charSequence.toString().contains(BUILD_SUCCESS)) { + isBuilding = false; + outputtingJars = false; + if(recreateShellOnDone) + createShell(); + if(currentTask != null && currentTask.getTaskID() != TASK_SHOW_DEPENDENCIES) + listener.onBuildSuccessful(charSequence.toString().trim(), currentTask); + } else + if(charSequence.toString().contains(BUILD_FAILED)) { + isBuilding = false; + outputtingJars = false; + if(recreateShellOnDone) + createShell(); + if(currentTask != null) { + if(currentTask.getTaskID() == TASK_SHOW_DEPENDENCIES) + listener.onGetDependenciesFailed(); + else listener.onBuildFailed(line.trim(), currentTask); + } + } + } + + private ArrayList dependenciesMapAsList(HashMap dependencies) { + ArrayList result = new ArrayList<>(); + for(Map.Entry entry : dependencies.entrySet()) { + result.add(Artifact.from(String.format("%s:%s", entry.getKey(), entry.getValue()))); + } + return result; + } + + @Override + public void onCreate() { + super.onCreate(); + this.instance = this; + createShell(); + sendBroadcast(new Intent().setAction(ACTION_CREATED)); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + isRunning = true; + return START_NOT_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + FileUtils.delete(Environment.TMP_DIR); + isRunning = false; + } + + @Override + public IBinder onBind(Intent p1) { + return null; + } + + private void createShell() { + if(shell != null) + shell.exit(); + shell = StudioApp.getInstance().newShell(this); + recreateShellOnDone = false; + } + + private JSONObject asObjectOrNull(String line) { + try { + if(line == null) return null; + line = line.trim(); + if(line.length() <= 0) return null; + return new JSONObject(line); + } catch (Throwable th) { + return null; + } + } + + private String currentTime() { + String pattern = "HH:mm:ss"; + DateFormat df = new SimpleDateFormat(pattern, Locale.US); + Date today = Calendar.getInstance().getTime(); + return df.format(today); + } + + private String processCommands(String cmd) { + final PreferenceManager prefs = StudioApp.getInstance().getPrefManager(); + final StringBuilder sb = new StringBuilder(); + sb.append("gradle "); + sb.append(cmd); + if(prefs.isStracktraceEnabled()) { + sb.append(" --stacktrace"); + } + if(prefs.isGradleInfoEnabled()) { + sb.append(" --info"); + } + if(prefs.isGradleDebugEnabled()) { + sb.append(" --debug"); + } + if(prefs.isGradleScanEnabled()) { + sb.append(" --scan"); + } + if(prefs.isGradleWarningEnabled()) { + sb.append(" --warning-mode all"); + } + return sb.toString(); + } + + public void execTask(GradleTask task) { + execTask(task, false); + } + + public void execTask(GradleTask task, boolean stopIfRunning) { + if(stopIfRunning && isBuilding()) { + stopAllDaemons(); + } else if(isBuilding()) { + return; + } + if(listener != null) { + listener.saveFiles(); + currentTask = task; + listener.appendOutput(task, getString(R.string.msg_task_begin, currentTime(), task.getName())); + shell.bgAppend(String.format("cd \"%s\"", module.getAbsolutePath())); + shell.bgAppend(processCommands(task.getCommands())); + isBuilding = true; + listener.showPreparing(); + } + } + + public void showDependencies() { + execTask(BaseGradleTasks.SHOW_DEPENDENCIES); + } + + public void recreateServices() { + execTask(BaseGradleTasks.SHOW_DEPENDENCIES, true); + } + + public void assembleDebug(boolean installApk) { + execTask(((AssembleDebug) BaseGradleTasks.ASSEMBLE_DEBUG).setInstallApk(installApk)); + } + + public void assembleRelease() { + execTask(BaseGradleTasks.ASSEMBLE_RELEASE); + } + + public void build() { + execTask(BaseGradleTasks.BUILD); + } + + public void bundle() { + execTask(BaseGradleTasks.BUNDLE); + } + + public void mergeLibAndProjectDex() { + execTask(BaseGradleTasks.MERGE_LIB_AND_PROJECT_DEX); + } + + public void mergeExtDex() { + execTask(BaseGradleTasks.MERGE_EXT_DEX); + } + + public void mergeDex() { + execTask(BaseGradleTasks.MERGE_DEX); + } + + public void clean() { + execTask(BaseGradleTasks.CLEAN); + } + + public void cleanAndRebuild() { + execTask(BaseGradleTasks.CLEAN_BUILD); + } + + public void stopAllDaemons() { + if(isBuilding()) { + forceStopDaemons(); + } else { + shell.bgAppend("gradle --stop"); + currentTask = null; + if(listener != null) { + listener.appendOutput(null, getString(R.string.msg_daemons_stopped)); + } + } + } + + public void lint() { + execTask(BaseGradleTasks.LINT); + } + + public void lintDebug() { + execTask(BaseGradleTasks.LINT_DEBUG); + } + + public void lintRelease() { + execTask(BaseGradleTasks.LINT_RELEASE); + } + + public void forceStopDaemons() { + if(listener != null) { + final long s = System.currentTimeMillis(); + listener.appendOutput(null, getString(R.string.msg_daemons_force_stopping)); + // Wait for a second! Just to let the user read the message! + while(System.currentTimeMillis() - s <= 1000) {} + } + isBuilding = false; + createShell(); + stopAllDaemons(); + } + + public static boolean isRunning() { + return isRunning; + } + + public boolean isBuilding() { + return isBuilding; + } + + public String typeString(int type) { + switch (type) { + case TASK_SHOW_DEPENDENCIES: + return ""; + case TASK_ASSEMBLE_DEBUG: + return getResources().getString(R.string.build_debug); + case TASK_ASSEMBLE_RELEASE: + return getResources().getString(R.string.build_release); + case TASK_BUILD: + return getResources().getString(R.string.build); + case TASK_CLEAN_BUILD: + return getResources().getString(R.string.clean_amp_build); + case TASK_CLEAN: + return getResources().getString(R.string.clean_project); + case TASK_BUNDLE : + return getResources().getString(R.string.create_aab); + case TASK_DEX: + return getResources().getString(R.string.compiling); + default: return ""; + } + } + + public static interface BuildListener { + public void onStartingGradleDaemon(GradleTask task); + public void onRunTask(String taskName, GradleTask task); + public void onBuildSuccessful(String msg, GradleTask task); + public void onBuildFailed(String msg, GradleTask task); + public void onGetDependencies(List dependencies); + public void onGetDependenciesFailed(); + public void saveFiles(); + + public void appendOutput(GradleTask task, CharSequence text); + public void showPreparing(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/services/Jar2DexService.java b/app/src/main/java/com/itsaky/androidide/services/Jar2DexService.java new file mode 100644 index 000000000..1073cd147 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/Jar2DexService.java @@ -0,0 +1,178 @@ +package com.itsaky.androidide.services; + +import androidx.core.util.Pair; +import com.blankj.utilcode.util.FileUtils; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.interfaces.DexResultListener; +import com.itsaky.androidide.shell.ShellServer; +import com.itsaky.androidide.utils.Environment; +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class Jar2DexService implements ShellServer.Callback { + + private final List mClasspaths; + private final List commands; + private final List dexNames; + private final List dexOuts; + private final ShellServer mServer; + private final File baseBuildDir; + private final DexResultListener listener; + private final StringBuilder outBuilder; + + private int currentDexingIndex = 0; + + private static final String DONE_MESSAGE = "DEXED_SUCCESSFULLY"; + private static final String FAILED_MESSAGE = "Compilation failed"; + private static final String D8_COMMAND = "java -jar %s --debug --lib '%s' --min-api 21 --output '%s' %s && echo 'DEXED_SUCCESSFULLY'"; + + public Jar2DexService(File buildDir, List classpaths, DexResultListener listener) { + this.baseBuildDir = buildDir; + this.mClasspaths = classpaths; + this.listener = listener; + this.mServer = StudioApp.getInstance().newShell(this); + this.outBuilder = new StringBuilder(); + this.commands = new ArrayList<>(); + this.dexNames = new ArrayList<>(); + this.dexOuts = new ArrayList<>(); + this.currentDexingIndex = 0; + } + + public void startDexing() { + commands.clear(); + dexOuts.clear(); + dexNames.clear(); + final File d8 = StudioApp.getInstance().getD8Jar(); + final File androidJar = Environment.BOOTCLASSPATH; + final File androidDexDir = Environment.mkdirIfNotExits(new File(androidJar.getParentFile(), "dex")); + final File baseOut = baseBuildDir; + if(d8 == null || !d8.exists()) { + listener.onDexFailed("d8.jar: File not found!"); + return; + } + + if(androidJar == null || !androidJar.exists()) { + listener.onDexFailed("android.jar: File not found!"); + return; + } + + if(baseOut == null || !baseOut.exists()) { + listener.onDexFailed("Dex out directory: Directory not found!"); + return; + } + + final String d8Path = wrapPathIfNeeded(d8); + final String androidJarPath = wrapPathIfNeeded(androidJar); + for(String classpath : mClasspaths) { + final File cp = new File(classpath); + final String name = !cp.getName().contains(".jar") ? cp.getName() : cp.getName().substring(0, cp.getName().lastIndexOf(".jar")); + if(!cp.exists()) continue; + File out = Environment.mkdirIfNotExits(new File(baseOut, name)); + dexOuts.add(out); + if(out.exists() && containsDexes(out.listFiles())) { + continue; + } + classpath = wrapPathIfNeeded(classpath); + final String outPath = wrapPathIfNeeded(out); + final String FINAL_D8_COMMAND = String.format(D8_COMMAND, d8Path, androidJarPath, outPath, classpath); + commands.add(FINAL_D8_COMMAND); + dexNames.add(name); + } + + if(androidDexDir.exists()) { + if(!containsDexes(androidDexDir.listFiles())) { + addAndroidJarToDex(d8Path, androidJarPath, androidDexDir); + } + } else { + addAndroidJarToDex(d8Path, androidJarPath, androidDexDir); + } + + if(commands.size() <= 0) { + notifyDexed(); + } else dexNext(); + } + + private boolean containsDexes(File[] dir) { + boolean found = false; + for(File f : dir) { + if(f.isFile() && f.getName().endsWith(".dex")) + return true; + else if(f.isDirectory()) { + // can't directly return 'found' + // it will prevent this recuraion from searching other directories + found = containsDexes(f.listFiles()); + if(found) { + return true; + } + } + } + return found; + } + + private void addAndroidJarToDex(String d8Path, String androidJarPath, File androidDexDir) { + dexOuts.add(androidDexDir); + commands.add(0, String.format(D8_COMMAND, d8Path, androidJarPath, !androidDexDir.getAbsolutePath().contains(" ") ? androidDexDir.getAbsolutePath() : "'" + androidDexDir.getAbsolutePath() + "'", androidJarPath)); + dexNames.add(0, "android.jar"); + } + + private String wrapPathIfNeeded(File src) { + return wrapPathIfNeeded(src.getAbsolutePath()); + } + + private String wrapPathIfNeeded(String src) { + return src.contains(" ") ? "'" + src + "'" : src; + } + + private void dexNext() { + mServer.bgAppend(commands.get(currentDexingIndex)); + if(listener != null) { + listener.onDex(dexNames.get(currentDexingIndex)); + } + } + + private boolean canDex() { + return currentDexingIndex < commands.size(); + } + + private void notifyDexed() { + List dexes = new ArrayList<>(); + for(File f : dexOuts) { + List dxs = FileUtils.listFilesInDirWithFilter(f, DEX_FILTER, true); + if(dxs != null && dxs.size() > 0) { + dexes.addAll(dxs.stream().map(d -> d.getAbsolutePath()).collect(Collectors.toList())); + } + } + + if(listener != null) + listener.onDexSuccess(dexes); + } + + @Override + public void output(CharSequence charSequence) { + if(charSequence == null || listener == null) return; + final String line = charSequence.toString().trim(); + final String toAppend = line + "\n"; + outBuilder.append(toAppend); + if(line.contains(DONE_MESSAGE)) { + currentDexingIndex++; + if(canDex()) + dexNext(); + else { + notifyDexed(); + } + } else if(line.contains(FAILED_MESSAGE)) { + listener.onDexFailed(outBuilder.toString()); + } + } + + private final FileFilter DEX_FILTER = new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isFile() && p1.getName().endsWith(".dex"); + } + }; +} diff --git a/app/src/main/java/com/itsaky/androidide/services/MessagingService.java b/app/src/main/java/com/itsaky/androidide/services/MessagingService.java new file mode 100644 index 000000000..78c8b2ad8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/MessagingService.java @@ -0,0 +1,116 @@ +package com.itsaky.androidide.services; + +import android.app.PendingIntent; +import android.content.Intent; +import android.content.pm.PackageManager; +import androidx.core.app.NotificationCompat; +import com.google.firebase.messaging.FirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.BuildConfig; +import com.itsaky.androidide.SplashActivity; +import java.util.Map; +import android.provider.Settings; +import androidx.core.app.NotificationManagerCompat; + +public class MessagingService extends FirebaseMessagingService { + + public static final String TOPIC_UPDATE= "app_update"; + public static final String TOPIC_DEV_MSGS = "developer_notifications"; + + private final String KEY_TITLE = "title"; + private final String KEY_MESSAGE = "message"; + private final String KEY_VERSION = "version"; + private final String KEY_CLICK_ACTION = "click_action"; + + private final String ACTION_OPEN_APP = "open_app"; + private final String ACTION_OPEN_URL = "open_url:"; + + @Override + public void onMessageReceived(RemoteMessage message) { + if(message != null && message.getData() != null) + processNotification(message.getFrom(), message.getData()); + } + + @Override + public void onNewToken(String token) { + super.onNewToken(token); + } + + private void processNotification(String topic, Map data) { + if(topic != null && topic.contains("/")) { + topic = topic.substring(topic.lastIndexOf("/") + 1); + if(topic.equals(TOPIC_UPDATE) && checkHasUpdateData(data)) { + final String title = data.get(KEY_TITLE); + final String msg = data.get(KEY_MESSAGE); + final String version = data.get(KEY_VERSION); + final String action = data.get(KEY_CLICK_ACTION); + final int l = stringAsInt(version); + if(l > BuildConfig.VERSION_CODE) { + showNotificationWithAction(action, title, msg); + } + } else if(topic.equals(TOPIC_DEV_MSGS) && checkHasTitleAndMessage(data)) { + final String title = data.get(KEY_TITLE); + final String msg = data.get(KEY_MESSAGE); + final String action = data.get(KEY_CLICK_ACTION); + showNotificationWithAction(action, title, msg); + } + } + } + + private void showNotificationWithAction(String action, String title, String msg) { + Intent i = null; + int flag = 0; + if (action.equals(ACTION_OPEN_APP)) { + i = StudioApp.getInstance().getPackageManager().getLaunchIntentForPackage(StudioApp.getInstance().getPackageName()); + } else if (action.startsWith(ACTION_OPEN_URL)) { + i = createOpenUrlIntent(action.substring(ACTION_OPEN_URL.length())); + flag = Intent.FLAG_ACTIVITY_NEW_TASK; + } + + if (i != null) { + PendingIntent intent = PendingIntent.getActivity(this, 0, i, flag); + showNotification(title, msg, intent, StudioApp.NOTIFICATION_ID_UPDATE); + } + } + + private void showNotification(String title, String msg, PendingIntent i, String channelId) { + NotificationCompat.Builder b = new NotificationCompat.Builder(this, channelId); + b.setContentTitle(title) + .setContentText(msg) + .setAutoCancel(true) + .setSound(Settings.System.DEFAULT_NOTIFICATION_URI) + .setContentIntent(i); + + NotificationManagerCompat.from(StudioApp.getInstance()).notify(0, b.build()); + } + + private Intent createOpenAppIntent() { + Intent i = new Intent(this, SplashActivity.class); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK); + return i; + } + + private Intent createOpenUrlIntent(String url) { + return new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(url)); + } + + private int stringAsInt(String str) { + try { + return Integer.valueOf(str); + } catch (Throwable th) { + return -1; + } + } + + private boolean checkHasUpdateData(Map data) { + return checkHasTitleAndMessage(data) + && data.containsKey(KEY_VERSION) + && data.containsKey(KEY_CLICK_ACTION); + } + + private boolean checkHasTitleAndMessage(Map data) { + return data.containsKey(KEY_TITLE) + && data.containsKey(KEY_MESSAGE); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/services/compiler/JavaCompilerService.java b/app/src/main/java/com/itsaky/androidide/services/compiler/JavaCompilerService.java new file mode 100644 index 000000000..1a965dbb7 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/compiler/JavaCompilerService.java @@ -0,0 +1,131 @@ +package com.itsaky.androidide.services.compiler; + +import android.text.TextUtils; +import com.blankj.utilcode.util.FileUtils; +import com.itsaky.androidide.interfaces.CompileListener; +import com.itsaky.androidide.models.AndroidProject; +import com.itsaky.androidide.services.compiler.model.CompilerDiagnostic; +import com.itsaky.androidide.services.compiler.model.CompilerDiagnosticImpl; +import com.itsaky.androidide.utils.Environment; +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler; +import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager; +import com.elvishew.xlog.XLog; + +public class JavaCompilerService implements DiagnosticListener { + + private AndroidProject project; + + private CompileListener listener; + private EclipseCompiler compiler; + private EclipseFileManager fileManager; + + private List options; + private final Map> diagnostics = new HashMap<>(); + + private FileFilter JAVA_FILTER = new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isFile() && p1.getName().endsWith(".java"); + } + }; + + public JavaCompilerService(AndroidProject project) { + this.project = project; + + getCompiler(); + } + + public JavaCompilerService setListener(CompileListener listener) { + this.listener = listener; + return this; + } + + private EclipseCompiler getCompiler() { + if(compiler == null) { + this.compiler = new EclipseCompiler(); + this.fileManager = (EclipseFileManager) compiler.getStandardFileManager(this, Locale.US, null); + this.options = new ArrayList<>(); + + options.add("-1.8"); + options.add("-d"); + options.add("none"); + options.add("-proc:none"); + options.add("-warn:all"); + options.add("-g"); + options.add("-bootclasspath"); + options.add(Environment.BOOTCLASSPATH.getAbsolutePath()); + options.add("-cp"); + options.add(TextUtils.join(File.pathSeparator, project.getClassPaths())); + } + + return compiler; + } + + public boolean compileSingle(File file) { + List ops = new ArrayList(options); + ops.add("-sourcepath"); + ops.add(TextUtils.join(File.pathSeparator, project.getSourcePaths())); + + JavaCompiler.CompilationTask task = getCompiler().getTask(null, fileManager, this, ops, null, fileManager.getJavaFileObjects(file)); + diagnostics.clear(); + boolean success = task.call(); + if(this.listener != null) { + this.listener.onCompilationResult(success, diagnostics); + } + return success; + } + + public boolean compileAll() { + List files = new ArrayList(); + for(String path : project.getSourcePaths()) { + if(path == null || path.trim().length() <= 0) continue; + File p = new File(path); + if(!p.exists() || !p.isDirectory()) continue; + files.addAll(FileUtils.listFilesInDirWithFilter(p, JAVA_FILTER, true)); + } + return compile(files); + } + + public boolean compile(List files) { + JavaCompiler.CompilationTask task = getCompiler().getTask(null, fileManager, this, options, null, fileManager.getJavaFileObjectsFromFiles(files)); + diagnostics.clear(); + final long s = System.nanoTime(); + boolean success = task.call(); + XLog.i("[JavaCompiler]" + + "\ncompiled: " + files.size() + " files" + + "\ntimeElapsed: " + (System.nanoTime() - s) + "ns"); + return success; + } + + public Map> getDiagnostics() { + return diagnostics; + } + + @Override + public void report(Diagnostic diagnostic) { + CompilerDiagnostic d = CompilerDiagnosticImpl.fromDiagnostic(diagnostic); + if(diagnostics.containsKey(d.file())) { + List diags = diagnostics.get(d.file()); + if(diags == null) + diags = new ArrayList<>(); + diags.add(d); + diagnostics.put(d.file(), diags); + } else { + List diags = new ArrayList<>(); + diags.add(d); + diagnostics.put(d.file(), diags); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnostic.java b/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnostic.java new file mode 100644 index 000000000..1c7437096 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnostic.java @@ -0,0 +1,14 @@ +package com.itsaky.androidide.services.compiler.model; + +import java.io.File; +import javax.tools.Diagnostic; + +public interface CompilerDiagnostic { + File file(); + long line(); + long column(); + long start(); + long end(); + String message(); + Diagnostic.Kind kind(); +} diff --git a/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnosticImpl.java b/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnosticImpl.java new file mode 100644 index 000000000..e4f18610d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/services/compiler/model/CompilerDiagnosticImpl.java @@ -0,0 +1,88 @@ +package com.itsaky.androidide.services.compiler.model; + +import java.io.File; +import java.util.Locale; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +public class CompilerDiagnosticImpl implements CompilerDiagnostic { + + protected File file; + protected String message; + protected long line = 0; + protected long column = 0; + protected long start = 0; + protected long end = 0; + + protected Diagnostic.Kind kind; + + private CompilerDiagnosticImpl(){} + + private CompilerDiagnosticImpl(Diagnostic diagnostic) { + this.file = new File(diagnostic.getSource().toUri()); + this.message = diagnostic.getMessage(Locale.US); + this.line = diagnostic.getLineNumber(); + this.column = diagnostic.getColumnNumber(); + this.start = diagnostic.getStartPosition(); + this.end = diagnostic.getEndPosition(); + this.kind = diagnostic.getKind(); + } + + private CompilerDiagnosticImpl(CompilerDiagnosticImpl d) { + this.file = d.file(); + this.message = d.message(); + this.line = d.line(); + this.column = d.column(); + this.start = d.start(); + this.end = d.end(); + this.kind = d.kind(); + } + + public static CompilerDiagnosticImpl fromDiagnostic(Diagnostic d) { + return new CompilerDiagnosticImpl(d); + } + + public static CompilerDiagnosticImpl copy(CompilerDiagnosticImpl d) { + return new CompilerDiagnosticImpl(d); + } + + @Override + public Diagnostic.Kind kind() { + return kind; + } + + @Override + public File file() { + return file; + } + + @Override + public long line() { + return line; + } + + @Override + public long column() { + return column; + } + + @Override + public long start() { + return start; + } + + @Override + public long end() { + return end; + } + + @Override + public String message() { + return message; + } + + @Override + public String toString() { + return "CompilerDiagnosticImpl(file=" + file() + ", line=" + line() + ", column=" + column() + ", start=" + start() + ", end=" + end() + ", message=" + message() + ")"; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/shell/ShellServer.java b/app/src/main/java/com/itsaky/androidide/shell/ShellServer.java new file mode 100644 index 000000000..828f99a08 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/shell/ShellServer.java @@ -0,0 +1,156 @@ +package com.itsaky.androidide.shell; + +import com.blankj.utilcode.util.CloseUtils; +import com.blankj.utilcode.util.ThrowableUtils; +import com.elvishew.xlog.XLog; +import com.itsaky.androidide.utils.Environment; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ShellServer extends Thread { + private final List callbacks = Collections.synchronizedList(new ArrayList()); + private BufferedReader output; + private Process process; + + public ShellServer(Callback callback, String command, String dirPath) { + addCallback(callback); + ProcessBuilder processBuilder = new ProcessBuilder(new String[]{command}); + processBuilder.directory(new File(dirPath)); + processBuilder.redirectErrorStream(true); + try { + this.process = processBuilder.start(); + this.output = new BufferedReader(new InputStreamReader(this.process.getInputStream())); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("export HOME=" + Environment.path(Environment.HOME) + " && cd"); + stringBuilder.append("\nexport TMPDIR=" + Environment.path(Environment.mkdirIfNotExits(Environment.TMP_DIR))); + stringBuilder.append("\nexport JAVA_HOME=" + Environment.path(Environment.JAVA_HOME)); + stringBuilder.append("\nexport ANDROID_HOME=" + Environment.path(Environment.ANDROID_HOME)); + stringBuilder.append("\nexport GRADLE_USER_HOME=$HOME/.gradle"); + stringBuilder.append("\nexport PATH=$PATH:$HOME/bin"); + stringBuilder.append("\nexport PATH=$PATH:" + Environment.path(Environment.JAVA_HOME) + "/bin"); + stringBuilder.append("\nexport PATH=$PATH:" + Environment.path(Environment.GRADLE_DIR) + "/bin"); + stringBuilder.append("\nexport PATH=$PATH:" + Environment.path(Environment.ANDROID_HOME) + "/cmdline-tools/latest/bin"); + stringBuilder.append("\nexport PATH=$PATH:" + Environment.path(Environment.ANDROID_HOME) + "/cmake/bin"); + + final String lib = Environment.LIBDIR.getAbsolutePath(); + stringBuilder.append("\nexport LD_LIBRARY_PATH=" + lib); + stringBuilder.append(System.getenv().containsKey("LD_LIBRARY_PATH") ? ":" + System.getenv().get("LD_LIBRARY_PATH") : ""); + + if(android.os.Build.VERSION.SDK_INT >= 30) { + stringBuilder.append("\nexport LD_PRELOAD=" + Environment.LIBHOOKSO.getAbsolutePath()); + } + + stringBuilder.append("\nls -l /system/lib64/libc.so && " + + "ln -sf /apex/com.android.runtime/lib64/bionic/libc.so " + lib + "/librt.so && " + + "ln -sf /apex/com.android.runtime/lib64/bionic/libc.so " + lib + "/libpthread.so"); + + stringBuilder.append("\nchmod -R 777 $HOME"); + stringBuilder.append("\njava -XshowSettings:all > /sdcard/androidide_jdk_settings.txt"); + append(stringBuilder.toString(), false); + } catch (Throwable th) { + if (callback != null) { + String out = ThrowableUtils.getFullStackTrace(th).concat("\n"); + XLog.e("[ShellServer] error setting up server ->\n" + out); + callback.output(out); + } + } + } + + public ShellServer addCallback(Callback callback) { + if (callback != null) { + this.callbacks.add(callback); + } + return this; + } + + public void append(String str) { + append(str, true); + } + + public ShellServer bgAppend(String str) { + append(str, false); + return this; + } + + public ShellServer bgAppend(String... arr) { + for (String s : arr) + bgAppend(s); + return this; + } + + public void append(String str, boolean z) { + if (z) { + try { + if (str.endsWith("\n")) { + output(str); + } else { + output(str.concat("\n")); + } + } catch (Throwable th) { + output(th.toString().concat("\n")); + return; + } + } + try { + this.process.getOutputStream().write(str.concat("\n").getBytes()); + this.process.getOutputStream().flush(); + } catch (IOException e) { + + } + } + + public void append(String... strArr) { + for (String append : strArr) { + append(append); + } + } + + public void exit() { + append("exit"); + } + + public void output(String str) { + int i = 0; + if (this.callbacks != null && this.callbacks.size() != 0) { + Callback[] callbackArr = this.callbacks.toArray(new Callback[0]); + while (i < callbackArr.length) { + callbackArr[i].output(str); + i++; + } + } + } + + public ShellServer removeCallback(Callback callback) { + if (callback != null) { + this.callbacks.remove(callback); + } + return this; + } + + @Override + public void run() { + while (true) { + try { + String readLine = this.output.readLine(); + if (readLine == null) { + break; + } + output(readLine.concat("\n")); + } catch (Throwable th) { + output(th.toString().concat("\n")); + } + } + CloseUtils.closeIOQuietly(new Closeable[]{this.output, this.process.getInputStream(), this.process.getErrorStream(), this.process.getOutputStream()}); + this.process.destroy(); + } + + public interface Callback { + public void output(CharSequence charSequence); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/colorschemes/SchemeWombat.java b/app/src/main/java/com/itsaky/androidide/syntax/colorschemes/SchemeWombat.java new file mode 100644 index 000000000..030254b81 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/colorschemes/SchemeWombat.java @@ -0,0 +1,30 @@ +package com.itsaky.androidide.syntax.colorschemes; + +import io.github.rosemoe.editor.widget.EditorColorScheme; + +public class SchemeWombat extends EditorColorScheme { + + @Override + public void applyDefault() { + super.applyDefault(); + setColor(TEXT_NORMAL, 0xfff6f3e8); + setColor(WHOLE_BACKGROUND, 0xff242424); + setColor(LINE_NUMBER_BACKGROUND, 0xff242424); + setColor(SELECTED_TEXT_BACKGROUND, 0xff898941); + setColor(MATCHED_TEXT_BACKGROUND, 0xff898941); + setColor(TEXT_SELECTED, 0xff000000); + setColor(CURRENT_LINE, 0xff656565); + setColor(LINE_NUMBER, 0xff656565); + setColor(LINE_DIVIDER, 0xff656565); + setColor(COMMENT, 0xff99968b); + setColor(NON_PRINTABLE_CHAR, 0xff99968b); + setColor(IDENTIFIER_NAME, 0xfff08080); + setColor(ANNOTATION, 0xff808080); + setColor(OPERATOR, 0xfff3f6ee); + setColor(FUNCTION_NAME, 0xfff3f6ee); + setColor(LITERAL, 0xff96e454); + setColor(OPERATOR, 0xff8ac6f2); + setColor(IDENTIFIER_VAR, 0xffd4c4a9); + setColor(SELECTION_HANDLE, 0xfff44336); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/DefaultLexer.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/DefaultLexer.java new file mode 100644 index 000000000..373644888 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/DefaultLexer.java @@ -0,0 +1,17 @@ +package com.itsaky.androidide.syntax.lexer; + +import com.itsaky.androidide.syntax.lexer.tokens.Token; +import com.itsaky.androidide.syntax.lexer.tokens.TokenType; + +public abstract class DefaultLexer implements Lexer { + + @Override + public Token token(TokenType type) { + return new Token(type, text(), line(), column()); + } + + @Override + public Token token(TokenType type, int p) { + return new Token(type, text(), line(), column(), p); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/Lexer.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/Lexer.java new file mode 100644 index 000000000..53a44f8a5 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/Lexer.java @@ -0,0 +1,49 @@ +package com.itsaky.androidide.syntax.lexer; + +import com.itsaky.androidide.syntax.lexer.tokens.Token; +import com.itsaky.androidide.syntax.lexer.tokens.TokenType; +import java.io.IOException; + +public interface Lexer { + + /** + * Must be called before anything else. If you're implementing your own lexer, initialize ANTLR or JFlex Lexer's here. + */ + + void init() throws IOException; + + /** + * Line of the current token + */ + int line(); + + /** + * Column number of token in current line + */ + int column(); + + /** + * Text of the current token + */ + String text(); + + /** + * Type of current token + */ + TokenType type(); + + /** + * Direct next token + */ + Token nextToken(); + + /** + * Create new token from the token type. Uses, line(), column(), text() + */ + Token token(TokenType type); + + /** + * Create new token. Will be used for symbol pairs. + */ + Token token(TokenType type, int pairValue); +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/BaseJavaLexer.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/BaseJavaLexer.java new file mode 100644 index 000000000..978f3a98b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/BaseJavaLexer.java @@ -0,0 +1,62 @@ +package com.itsaky.androidide.syntax.lexer.impls; + +import android.graphics.Color; +import com.itsaky.androidide.syntax.lexer.DefaultLexer; +import io.github.rosemoe.editor.struct.BlockLine; +import io.github.rosemoe.editor.struct.HexColor; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.antlr.v4.runtime.Lexer; + +/** + * Java and Groovy lexer is almost same + * Only difference is that groovy has a static field SINGLE_QUOTE_STRING + * + * This class contains common properties included in both lexers + */ +public abstract class BaseJavaLexer extends DefaultLexer { + + protected Lexer lexer; + protected String content; + public int lastLine; + public int maxSwitch; + public int currSwitch; + protected int previous; + protected boolean wasClassName; + protected boolean isFirst; + protected org.antlr.v4.runtime.Token currentToken; + + protected TextAnalyzeResult colors; + public final HashMap lineColors = new HashMap<>(); + public final Stack stack = new Stack(); + protected ArrayList builtinTypes; + + protected void addHexColorIfPresent() { + Matcher m = HEX.matcher(text()); + final int line= line(); + final int column = column(); + if (m.find()) { + try { + final CharPosition start = new CharPosition(line, column + m.start()); + final CharPosition end = new CharPosition(line, start.column + (m.end() - m.start())); + final HexColor key = new HexColor(start, end); + final Integer value = Color.parseColor(text().substring(m.start(), m.end())); + + // Null checks + start.getClass(); + end.getClass(); + key.getClass(); + value.getClass(); + + lineColors.put(key, value); + } catch (Throwable th) {} + } + } + + protected final Pattern HEX = Pattern.compile("#[a-fA-F0-9]{3,8}"); +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/groovy/GroovyLexerImpl.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/groovy/GroovyLexerImpl.java new file mode 100644 index 000000000..c59ee749b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/groovy/GroovyLexerImpl.java @@ -0,0 +1,290 @@ +package com.itsaky.androidide.syntax.lexer.impls.groovy; + +import android.graphics.Color; +import com.itsaky.androidide.language.groovy.lexer.GroovyLexer; +import com.itsaky.androidide.syntax.lexer.Lexer; +import com.itsaky.androidide.syntax.lexer.impls.BaseJavaLexer; +import com.itsaky.androidide.syntax.lexer.tokens.Token; +import com.itsaky.androidide.syntax.lexer.tokens.TokenType; +import io.github.rosemoe.editor.struct.BlockLine; +import io.github.rosemoe.editor.struct.HexColor; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.widget.EditorColorScheme; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.antlr.v4.runtime.CharStreams; + +public class GroovyLexerImpl extends BaseJavaLexer implements Lexer { + + public GroovyLexerImpl(String content, TextAnalyzeResult colors) { + this.content = content; + this.colors = colors; + this.maxSwitch = 0; + this.currSwitch = 0; + this.previous = -1; + this.wasClassName = false; + this.isFirst = true; + + builtinTypes = new ArrayList<>(); + + builtinTypes.add(GroovyLexer.BOOLEAN); + builtinTypes.add(GroovyLexer.BYTE); + builtinTypes.add(GroovyLexer.CHAR); + builtinTypes.add(GroovyLexer.DOUBLE); + builtinTypes.add(GroovyLexer.ENUM); + builtinTypes.add(GroovyLexer.FLOAT); + builtinTypes.add(GroovyLexer.INT); + builtinTypes.add(GroovyLexer.LONG); + builtinTypes.add(GroovyLexer.SHORT); + } + + @Override + public void init() throws IOException { + lexer = new GroovyLexer(CharStreams.fromReader(new StringReader(content))); + } + + @Override + public Token nextToken() { + currentToken = lexer.nextToken(); + if(currentToken.getType() == GroovyLexer.EOF) { + this.lastLine = line(); + return null; + } + return token(type()); + } + + @Override + public int line() { + // currentToken's line index starts from 1 + int line = currentToken.getLine() - 1; + this.lastLine = line; + return line; + } + + @Override + public int column() { + return currentToken.getCharPositionInLine(); + } + + @Override + public String text() { + return currentToken.getText(); + } + + @Override + public TokenType type() { + final int line = line(); + final int column = column(); + final int tokenType = currentToken.getType(); + TokenType type = TokenType.TEXT; + switch(tokenType) { + case GroovyLexer.WS : + type = TokenType.WS; + if(isFirst) + colors.addNormalIfNull(); + break; + case GroovyLexer.ABSTRACT: + case GroovyLexer.ASSERT: + case GroovyLexer.BREAK: + case GroovyLexer.CASE: + case GroovyLexer.CATCH: + case GroovyLexer.CLASS: + case GroovyLexer.CONST: + case GroovyLexer.CONTINUE: + case GroovyLexer.DEFAULT: + case GroovyLexer.DO: + case GroovyLexer.ELSE: + case GroovyLexer.EXTENDS: + case GroovyLexer.FINAL: + case GroovyLexer.FINALLY: + case GroovyLexer.FOR: + case GroovyLexer.IF: + case GroovyLexer.GOTO: + case GroovyLexer.IMPLEMENTS: + case GroovyLexer.IMPORT: + case GroovyLexer.INSTANCEOF: + case GroovyLexer.INTERFACE: + case GroovyLexer.NATIVE: + case GroovyLexer.NEW: + case GroovyLexer.PACKAGE: + case GroovyLexer.PRIVATE: + case GroovyLexer.PROTECTED: + case GroovyLexer.PUBLIC: + case GroovyLexer.RETURN: + case GroovyLexer.STATIC: + case GroovyLexer.STRICTFP: + case GroovyLexer.SUPER: + case GroovyLexer.SWITCH: + case GroovyLexer.SYNCHRONIZED: + case GroovyLexer.THIS: + case GroovyLexer.THROW: + case GroovyLexer.THROWS: + case GroovyLexer.TRANSIENT: + case GroovyLexer.TRY: + case GroovyLexer.VOID: + case GroovyLexer.VOLATILE: + case GroovyLexer.WHILE: + type = TokenType.KEYWORD; + colors.addIfNeeded(line, column, EditorColorScheme.KEYWORD); + wasClassName = false; + break; + case GroovyLexer.DECIMAL_LITERAL: + case GroovyLexer.HEX_LITERAL: + case GroovyLexer.OCT_LITERAL: + case GroovyLexer.BINARY_LITERAL: + case GroovyLexer.FLOAT_LITERAL: + case GroovyLexer.HEX_FLOAT_LITERAL: + case GroovyLexer.BOOL_LITERAL: + case GroovyLexer.CHAR_LITERAL: + case GroovyLexer.NULL_LITERAL: + type = TokenType.NUMBER_LITERAL; + colors.addIfNeeded(line, column, EditorColorScheme.LITERAL); + wasClassName = false; + break; + case GroovyLexer.STRING_LITERAL : + case GroovyLexer.SINGLE_QUOTE_STRING : + type = TokenType.STRING_LITERAL; + colors.addIfNeeded(line, column, EditorColorScheme.LITERAL); + wasClassName = false; + addHexColorIfPresent(); + break; + case GroovyLexer.LPAREN : + case GroovyLexer.RPAREN : + case GroovyLexer.LBRACK : + case GroovyLexer.RBRACK : + case GroovyLexer.SEMI : + case GroovyLexer.COMMA : + case GroovyLexer.ASSIGN : + case GroovyLexer.GT : + case GroovyLexer.LT : + case GroovyLexer.BANG : + case GroovyLexer.TILDE : + case GroovyLexer.QUESTION : + case GroovyLexer.COLON : + case GroovyLexer.EQUAL : + case GroovyLexer.GE : + case GroovyLexer.LE : + case GroovyLexer.NOTEQUAL : + case GroovyLexer.AND : + case GroovyLexer.OR : + case GroovyLexer.INC : + case GroovyLexer.DEC : + case GroovyLexer.ADD : + case GroovyLexer.SUB : + case GroovyLexer.MUL : + case GroovyLexer.DIV : + case GroovyLexer.BITAND : + case GroovyLexer.BITOR : + case GroovyLexer.CARET : + case GroovyLexer.MOD : + case GroovyLexer.ADD_ASSIGN : + case GroovyLexer.SUB_ASSIGN : + case GroovyLexer.MUL_ASSIGN : + case GroovyLexer.DIV_ASSIGN : + case GroovyLexer.AND_ASSIGN : + case GroovyLexer.OR_ASSIGN : + case GroovyLexer.XOR_ASSIGN : + case GroovyLexer.MOD_ASSIGN : + case GroovyLexer.LSHIFT_ASSIGN : + case GroovyLexer.RSHIFT_ASSIGN : + case GroovyLexer.URSHIFT_ASSIGN : + case GroovyLexer.ARROW : + case GroovyLexer.COLONCOLON : + case GroovyLexer.ELLIPSIS : + case GroovyLexer.DOT : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + break; + case GroovyLexer.BOOLEAN: + case GroovyLexer.BYTE : + case GroovyLexer.CHAR: + case GroovyLexer.DOUBLE: + case GroovyLexer.ENUM : + case GroovyLexer.FLOAT: + case GroovyLexer.INT : + case GroovyLexer.LONG: + case GroovyLexer.SHORT: + type = TokenType.TYPE; + colors.addIfNeeded(line, column, EditorColorScheme.IDENTIFIER_NAME); + wasClassName = true; + break; + + case GroovyLexer.COMMENT : + case GroovyLexer.LINE_COMMENT : + type = TokenType.COMMENT; + colors.addIfNeeded(line, column, EditorColorScheme.COMMENT); + wasClassName = false; + break; + case GroovyLexer.AT : + type = TokenType.ANNOTATION; + colors.addIfNeeded(line, column, EditorColorScheme.ANNOTATION); + wasClassName = false; + break; + case GroovyLexer.IDENTIFIER : + type = TokenType.IDENTIFIER; + + if (previous == GroovyLexer.AT) { + colors.addIfNeeded(line, column, EditorColorScheme.ANNOTATION); + wasClassName = false; + break; + } + + if ((previous == GroovyLexer.IDENTIFIER || builtinTypes.contains(previous)) && wasClassName) { + colors.addIfNeeded(line, column, EditorColorScheme.IDENTIFIER_VAR); + wasClassName = false; + break; + } + + colors.addIfNeeded(line, column, EditorColorScheme.TEXT_NORMAL); + break; + case GroovyLexer.LBRACE : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + if (stack.isEmpty()) { + if (currSwitch > maxSwitch) + maxSwitch = currSwitch; + currSwitch = 0; + } + currSwitch++; + BlockLine block = colors.obtainNewBlock(); + block.startLine = line; + block.startColumn = column; + stack.push(block); + break; + case GroovyLexer.RBRACE : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + if (!stack.isEmpty()) { + BlockLine block2 = stack.pop(); + block2.endLine = line; + block2.endColumn = column; + if (block2.startLine != block2.endLine) + colors.addBlockLine(block2); + } + break; + default: + type = TokenType.TEXT; + wasClassName = false; + if (tokenType == GroovyLexer.LBRACK || (tokenType == GroovyLexer.RBRACK && previous == GroovyLexer.LBRACK)) { + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + break; + } + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + break; + } + + isFirst = false; + if(tokenType != GroovyLexer.WS) { + previous = tokenType; + } + + return type; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java new file mode 100644 index 000000000..35198072f --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java @@ -0,0 +1,289 @@ +package com.itsaky.androidide.syntax.lexer.impls.java; + +import android.graphics.Color; +import com.itsaky.androidide.language.java.parser.JavaLexer; +import com.itsaky.androidide.syntax.lexer.Lexer; +import com.itsaky.androidide.syntax.lexer.impls.BaseJavaLexer; +import com.itsaky.androidide.syntax.lexer.tokens.Token; +import com.itsaky.androidide.syntax.lexer.tokens.TokenType; +import io.github.rosemoe.editor.struct.BlockLine; +import io.github.rosemoe.editor.struct.HexColor; +import io.github.rosemoe.editor.text.CharPosition; +import io.github.rosemoe.editor.text.TextAnalyzeResult; +import io.github.rosemoe.editor.widget.EditorColorScheme; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.antlr.v4.runtime.CharStreams; + +public class JavaLexerImpl extends BaseJavaLexer implements Lexer { + + public JavaLexerImpl(String content, TextAnalyzeResult colors) { + this.content = content; + this.colors = colors; + this.maxSwitch = 0; + this.currSwitch = 0; + this.previous = -1; + this.wasClassName = false; + this.isFirst = true; + + builtinTypes = new ArrayList<>(); + + builtinTypes.add(JavaLexer.BOOLEAN); + builtinTypes.add(JavaLexer.BYTE); + builtinTypes.add(JavaLexer.CHAR); + builtinTypes.add(JavaLexer.DOUBLE); + builtinTypes.add(JavaLexer.ENUM); + builtinTypes.add(JavaLexer.FLOAT); + builtinTypes.add(JavaLexer.INT); + builtinTypes.add(JavaLexer.LONG); + builtinTypes.add(JavaLexer.SHORT); + } + + @Override + public void init() throws IOException { + lexer = new JavaLexer(CharStreams.fromReader(new StringReader(content))); + } + + @Override + public Token nextToken() { + currentToken = lexer.nextToken(); + if(currentToken.getType() == JavaLexer.EOF) { + this.lastLine = line(); + return null; + } + return token(type()); + } + + @Override + public int line() { + // currentToken's line index starts from 1 + int line = currentToken.getLine() - 1; + this.lastLine = line; + return line; + } + + @Override + public int column() { + return currentToken.getCharPositionInLine(); + } + + @Override + public String text() { + return currentToken.getText(); + } + + @Override + public TokenType type() { + final int line = line(); + final int column = column(); + final int tokenType = currentToken.getType(); + TokenType type = TokenType.TEXT; + switch(tokenType) { + case JavaLexer.WS : + type = TokenType.WS; + if(isFirst) + colors.addNormalIfNull(); + break; + case JavaLexer.ABSTRACT: + case JavaLexer.ASSERT: + case JavaLexer.BREAK: + case JavaLexer.CASE: + case JavaLexer.CATCH: + case JavaLexer.CLASS: + case JavaLexer.CONST: + case JavaLexer.CONTINUE: + case JavaLexer.DEFAULT: + case JavaLexer.DO: + case JavaLexer.ELSE: + case JavaLexer.EXTENDS: + case JavaLexer.FINAL: + case JavaLexer.FINALLY: + case JavaLexer.FOR: + case JavaLexer.IF: + case JavaLexer.GOTO: + case JavaLexer.IMPLEMENTS: + case JavaLexer.IMPORT: + case JavaLexer.INSTANCEOF: + case JavaLexer.INTERFACE: + case JavaLexer.NATIVE: + case JavaLexer.NEW: + case JavaLexer.PACKAGE: + case JavaLexer.PRIVATE: + case JavaLexer.PROTECTED: + case JavaLexer.PUBLIC: + case JavaLexer.RETURN: + case JavaLexer.STATIC: + case JavaLexer.STRICTFP: + case JavaLexer.SUPER: + case JavaLexer.SWITCH: + case JavaLexer.SYNCHRONIZED: + case JavaLexer.THIS: + case JavaLexer.THROW: + case JavaLexer.THROWS: + case JavaLexer.TRANSIENT: + case JavaLexer.TRY: + case JavaLexer.VOID: + case JavaLexer.VOLATILE: + case JavaLexer.WHILE: + type = TokenType.KEYWORD; + colors.addIfNeeded(line, column, EditorColorScheme.KEYWORD); + wasClassName = false; + break; + case JavaLexer.DECIMAL_LITERAL: + case JavaLexer.HEX_LITERAL: + case JavaLexer.OCT_LITERAL: + case JavaLexer.BINARY_LITERAL: + case JavaLexer.FLOAT_LITERAL: + case JavaLexer.HEX_FLOAT_LITERAL: + case JavaLexer.BOOL_LITERAL: + case JavaLexer.CHAR_LITERAL: + case JavaLexer.NULL_LITERAL: + type = TokenType.NUMBER_LITERAL; + colors.addIfNeeded(line, column, EditorColorScheme.LITERAL); + wasClassName = false; + break; + case JavaLexer.STRING_LITERAL : + type = TokenType.STRING_LITERAL; + colors.addIfNeeded(line, column, EditorColorScheme.LITERAL); + wasClassName = false; + addHexColorIfPresent(); + break; + case JavaLexer.LPAREN : + case JavaLexer.RPAREN : + case JavaLexer.LBRACK : + case JavaLexer.RBRACK : + case JavaLexer.SEMI : + case JavaLexer.COMMA : + case JavaLexer.ASSIGN : + case JavaLexer.GT : + case JavaLexer.LT : + case JavaLexer.BANG : + case JavaLexer.TILDE : + case JavaLexer.QUESTION : + case JavaLexer.COLON : + case JavaLexer.EQUAL : + case JavaLexer.GE : + case JavaLexer.LE : + case JavaLexer.NOTEQUAL : + case JavaLexer.AND : + case JavaLexer.OR : + case JavaLexer.INC : + case JavaLexer.DEC : + case JavaLexer.ADD : + case JavaLexer.SUB : + case JavaLexer.MUL : + case JavaLexer.DIV : + case JavaLexer.BITAND : + case JavaLexer.BITOR : + case JavaLexer.CARET : + case JavaLexer.MOD : + case JavaLexer.ADD_ASSIGN : + case JavaLexer.SUB_ASSIGN : + case JavaLexer.MUL_ASSIGN : + case JavaLexer.DIV_ASSIGN : + case JavaLexer.AND_ASSIGN : + case JavaLexer.OR_ASSIGN : + case JavaLexer.XOR_ASSIGN : + case JavaLexer.MOD_ASSIGN : + case JavaLexer.LSHIFT_ASSIGN : + case JavaLexer.RSHIFT_ASSIGN : + case JavaLexer.URSHIFT_ASSIGN : + case JavaLexer.ARROW : + case JavaLexer.COLONCOLON : + case JavaLexer.ELLIPSIS : + case JavaLexer.DOT : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + break; + case JavaLexer.BOOLEAN: + case JavaLexer.BYTE : + case JavaLexer.CHAR: + case JavaLexer.DOUBLE: + case JavaLexer.ENUM : + case JavaLexer.FLOAT: + case JavaLexer.INT : + case JavaLexer.LONG: + case JavaLexer.SHORT: + type = TokenType.TYPE; + colors.addIfNeeded(line, column, EditorColorScheme.IDENTIFIER_NAME); + wasClassName = true; + break; + + case JavaLexer.COMMENT : + case JavaLexer.LINE_COMMENT : + type = TokenType.COMMENT; + colors.addIfNeeded(line, column, EditorColorScheme.COMMENT); + wasClassName = false; + break; + case JavaLexer.AT : + type = TokenType.ANNOTATION; + colors.addIfNeeded(line, column, EditorColorScheme.ANNOTATION); + wasClassName = false; + break; + case JavaLexer.IDENTIFIER : + type = TokenType.IDENTIFIER; + + if (previous == JavaLexer.AT) { + colors.addIfNeeded(line, column, EditorColorScheme.ANNOTATION); + wasClassName = false; + break; + } + + if ((previous == JavaLexer.IDENTIFIER || builtinTypes.contains(previous)) && wasClassName) { + colors.addIfNeeded(line, column, EditorColorScheme.IDENTIFIER_VAR); + wasClassName = false; + break; + } + + colors.addIfNeeded(line, column, EditorColorScheme.TEXT_NORMAL); + break; + case JavaLexer.LBRACE : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + if (stack.isEmpty()) { + if (currSwitch > maxSwitch) + maxSwitch = currSwitch; + currSwitch = 0; + } + currSwitch++; + BlockLine block = colors.obtainNewBlock(); + block.startLine = line; + block.startColumn = column; + stack.push(block); + break; + case JavaLexer.RBRACE : + type = TokenType.OPERATOR; + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + wasClassName = false; + if (!stack.isEmpty()) { + BlockLine block2 = stack.pop(); + block2.endLine = line; + block2.endColumn = column; + if (block2.startLine != block2.endLine) + colors.addBlockLine(block2); + } + break; + default: + type = TokenType.TEXT; + wasClassName = false; + if (tokenType == JavaLexer.LBRACK || (tokenType == JavaLexer.RBRACK && previous == JavaLexer.LBRACK)) { + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + break; + } + colors.addIfNeeded(line, column, EditorColorScheme.OPERATOR); + break; + } + + isFirst = false; + if(tokenType != JavaLexer.WS) { + previous = tokenType; + } + + return type; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/Token.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/Token.java new file mode 100644 index 000000000..dd8b66c44 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/Token.java @@ -0,0 +1,97 @@ +package com.itsaky.androidide.syntax.lexer.tokens; + +import java.io.Serializable; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.HashMap; + +public class Token implements Serializable { + + public final String text; + public final TokenType type; + public final int line; + public final int column; + public final int length; + + private static HashMap BRACKETS; + + /** + * the pair value to use if this token is one of a pair: + * This is how it is used: + * The opening part will have a positive number X + * The closing part will have a negative number X + * X should be unique for a pair: + * e.g. for ( pairValue = +1 + * for ) pairValue = -1 + */ + public final int pairValue; + + /** + * Constructs a new token + */ + public Token(TokenType type, String text, int line, int column) { + this(type, text, line, column, 0); + } + + /** + * Construct a new part of pair token + */ + public Token(TokenType type, String text, int line, int column, int pairValue) { + this.type = type; + this.text = text; + this.line = line; + this.column = column; + this.length = text.length(); + this.pairValue = pairValue; + this.BRACKETS = brackets(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Token) { + Token token = (Token) obj; + return ((this.line == token.line) && + (this.column == token.column) && + (this.length == token.length) && + (this.type.equals(token.type))); + } else { + return false; + } + } + + public boolean isBracket() { + return BRACKETS.containsKey(text); + } + + public boolean isClosingOperator() { + return pairValue < 0; + } + + @Override + public int hashCode() { + return line + column + length; + } + + @Override + public String toString() { + if (pairValue == 0) { + return String.format("%s (%d, %d) %d", type, line, column, length); + } else { + return String.format("%s (%d, %d) (%d) %d", type, line, column, length, pairValue); + } + } + + private HashMap brackets() { + HashMap brackets = new HashMap<>(); + brackets.put("(", 1); + brackets.put(")", -1); + brackets.put("[", 2); + brackets.put("]", -2); + brackets.put("{", 3); + brackets.put("}", -3); + brackets.put("<", 4); + brackets.put(">", -4); + return brackets; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/TokenType.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/TokenType.java new file mode 100644 index 000000000..bea9f766c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/tokens/TokenType.java @@ -0,0 +1,46 @@ +package com.itsaky.androidide.syntax.lexer.tokens; + +public enum TokenType { + + OPERATOR, + KEYWORD, + IDENTIFIER, + STRING_LITERAL, + NUMBER_LITERAL, + ANNOTATION, + COMMENT, + TYPE, + TEXT, + WS; + public boolean isKeyword() { + return this == TokenType.KEYWORD; + } + + public boolean isOperator() { + return this == TokenType.OPERATOR; + } + + public boolean isIdentifier() { + return this == TokenType.IDENTIFIER; + } + + public boolean isLiteral() { + return this == TokenType.STRING_LITERAL; + } + + public boolean isComment() { + return this == TokenType.COMMENT; + } + + public boolean isType() { + return this == TokenType.TYPE; + } + + public boolean isText() { + return this == TokenType.TEXT; + } + + public boolean isWs() { + return this == TokenType.WS; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java b/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java new file mode 100644 index 000000000..94f3ac2c2 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java @@ -0,0 +1,21 @@ +package com.itsaky.androidide.tasks; + +import com.itsaky.androidide.services.IDEService; + +public abstract class BaseGradleTask implements GradleTask { + + @Override + public boolean shouldSaveFiles() { + return getType() == Type.BUILD + || getType() == Type.LINT + || getTaskID() == IDEService.TASK_DEX; + } + + @Override + public boolean equals(Object obj) { + return obj != null + && obj instanceof GradleTask + && getTaskID() == ((GradleTask) obj).getTaskID() + && getType() == ((GradleTask) obj).getType(); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java b/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java new file mode 100644 index 000000000..7aa75c174 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java @@ -0,0 +1,24 @@ +package com.itsaky.androidide.tasks; + +import java.io.File; + +public interface GradleTask { + + public String getName(); + public String getCommands(); + public int getTaskID(); + public boolean shouldSaveFiles(); + public boolean canOutput(); + public boolean buildsApk(); + public File getApk(String buildFolder, String moduleName); + public Type getType(); + + public static enum Type { + ANDROIDIDE_PLUGIN, + BUILD, + LINT, + HELP, + OTHER + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/TaskExecutor.java b/app/src/main/java/com/itsaky/androidide/tasks/TaskExecutor.java new file mode 100644 index 000000000..fc750533a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/TaskExecutor.java @@ -0,0 +1,29 @@ +package com.itsaky.androidide.tasks; + +import android.os.Handler; +import android.os.Looper; +import com.blankj.utilcode.util.ThrowableUtils; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class TaskExecutor { + private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements + private final Handler handler = new Handler(Looper.getMainLooper()); + + public interface Callback { + void onComplete(R result); + } + + public void executeAsync(Callable callable, Callback callback) { + executor.execute(() -> { + try { + final R result = callable.call(); + handler.post(() -> { + callback.onComplete(result); + }); + } catch (Throwable th) { + } + }); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/ArtifactFinderCallable.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/ArtifactFinderCallable.java new file mode 100644 index 000000000..88ae2b90c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/ArtifactFinderCallable.java @@ -0,0 +1,26 @@ +package com.itsaky.androidide.tasks.callables; + +import com.itsaky.androidide.models.gradle.Artifact; +import com.itsaky.androidide.utils.Environment; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +public final class ArtifactFinderCallable implements Callable> { + + private final List artifacts; + + public ArtifactFinderCallable(List artifacts) { + this.artifacts = artifacts; + } + + @Override + public List call() throws Exception { + final List jars = new ArrayList<>(); + for(Artifact artifact : artifacts) { + jars.addAll(Environment.findJarForArtifact(artifact)); + } + return jars; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/DownloadLinkFetcher.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/DownloadLinkFetcher.java new file mode 100644 index 000000000..5e6c26711 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/DownloadLinkFetcher.java @@ -0,0 +1,34 @@ +package com.itsaky.androidide.tasks.callables; + +import androidx.core.util.Pair; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.utils.Either; +import java.util.List; +import java.util.concurrent.Callable; +import org.json.JSONException; +import org.json.JSONObject; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import java.util.ArrayList; +import org.json.JSONArray; +import android.text.TextUtils; +import com.blankj.utilcode.util.FileUtils; + +public class DownloadLinkFetcher implements Callable>, String>> { + + @Override + public Either>, String> call() throws Exception { + Document doc = Jsoup.connect(StudioApp.getInstance().getDownloadRequestUrl()).get(); + try { + final List> result = new ArrayList<>(); + JSONArray arr = new JSONArray(Jsoup.parse(doc.toString()).body().text()); + for(int i=0;i { + private final Context ctx; + private TreeNode parent; + private File file; + + public FileTreeCallable(Context ctx, TreeNode parent, File file) { + this.ctx = ctx; + this.parent = parent; + this.file = file; + } + + @Override + public Boolean call() throws Exception { + getNodeFromArray(file.listFiles(/*new HiddenFilesFilter()*/), parent); + return true; + } + + private void getNodeFromArray(File[] files, TreeNode parent) { + Arrays.sort(files, new SortFileName()); + Arrays.sort(files, new SortFolder()); + for (File file : files) { + TreeNode node = new TreeNode(file); + node.setViewHolder(new FileTreeViewHolder(ctx)); + parent.addChild(node); + } + } + + public static class HiddenFilesFilter implements FileFilter { + + @Override + public boolean accept(File p1) { + return !p1.getName().startsWith("."); + } + } + + public static class SortFileName implements Comparator { + @Override + public int compare(File f1, File f2) { + return f1.getName().compareTo(f2.getName()); + } + } + + public static class SortFolder implements Comparator { + @Override + public int compare(File f1, File f2) { + if (f1.isDirectory() == f2.isDirectory()) + return 0; + else if (f1.isDirectory() && !f2.isDirectory()) + return -1; + else + return 1; + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/ListDirectoryCallable.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/ListDirectoryCallable.java new file mode 100644 index 000000000..5afdfe21d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/ListDirectoryCallable.java @@ -0,0 +1,28 @@ +package com.itsaky.androidide.tasks.callables; + +import android.text.TextUtils; +import com.blankj.utilcode.util.FileUtils; +import java.io.File; +import java.io.FileFilter; + +public class ListDirectoryCallable implements java.util.concurrent.Callable { + + private File file; + + public ListDirectoryCallable(File file) { + this.file = file; + } + + @Override + public String call() throws Exception { + return TextUtils.join("\n", FileUtils.listFilesInDirWithFilter(file, ARCHIVE_FILTER, false)); + } + + private final FileFilter ARCHIVE_FILTER = new FileFilter(){ + + @Override + public boolean accept(File p1) { + return p1.isFile() && (p1.getName().endsWith(".tar.xz") || p1.getName().endsWith(".zip")); + } + }; +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/ProjectCreatorCallable.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/ProjectCreatorCallable.java new file mode 100644 index 000000000..5d1dc51b3 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/ProjectCreatorCallable.java @@ -0,0 +1,26 @@ +package com.itsaky.androidide.tasks.callables; + +import com.itsaky.androidide.models.NewProjectDetails; +import com.itsaky.androidide.utils.ProjectWriter; +import java.util.concurrent.Callable; +import com.itsaky.androidide.models.ProjectTemplate; +import com.itsaky.androidide.interfaces.ProjectWriterCallback; + +public class ProjectCreatorCallable implements Callable { + + private ProjectTemplate template; + private NewProjectDetails details; + private ProjectWriterCallback callback; + + public ProjectCreatorCallable(ProjectTemplate template, NewProjectDetails details, ProjectWriterCallback callback) { + this.template = template; + this.details = details; + this.callback = callback; + } + + @Override + public Void call() throws Exception { + ProjectWriter.write(template, details, callback); + return null; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/ReadFileTask.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/ReadFileTask.java new file mode 100644 index 000000000..1c2123185 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/ReadFileTask.java @@ -0,0 +1,19 @@ +package com.itsaky.androidide.tasks.callables; + +import com.blankj.utilcode.util.FileIOUtils; +import java.io.File; +import java.util.concurrent.Callable; + +public class ReadFileTask implements Callable { + + private final File file; + + public ReadFileTask(File file) { + this.file = file; + } + + @Override + public String call() throws Exception { + return FileIOUtils.readFile2String(file); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/callables/UnzipCallable.java b/app/src/main/java/com/itsaky/androidide/tasks/callables/UnzipCallable.java new file mode 100644 index 000000000..e198fdf39 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/callables/UnzipCallable.java @@ -0,0 +1,22 @@ +package com.itsaky.androidide.tasks.callables; + +import com.blankj.utilcode.util.ZipUtils; +import java.io.File; +import java.util.List; +import java.util.concurrent.Callable; + +public final class UnzipCallable implements Callable> { + + private File src; + private File dest; + + public UnzipCallable(File src, File dest) { + this.src = src; + this.dest = dest; + } + + @Override + public List call() throws Exception { + return ZipUtils.unzipFile(src, dest); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java new file mode 100644 index 000000000..7c6205022 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java @@ -0,0 +1,37 @@ +package com.itsaky.androidide.tasks.gradle; + +import com.itsaky.androidide.tasks.BaseGradleTask; +import com.itsaky.androidide.tasks.gradle.build.AssembleDebug; +import com.itsaky.androidide.tasks.gradle.build.AssembleRelease; +import com.itsaky.androidide.tasks.gradle.build.Build; +import com.itsaky.androidide.tasks.gradle.build.Bundle; +import com.itsaky.androidide.tasks.gradle.build.Clean; +import com.itsaky.androidide.tasks.gradle.build.CleanBuild; +import com.itsaky.androidide.tasks.gradle.dex.MergeDex; +import com.itsaky.androidide.tasks.gradle.dex.MergeExtDex; +import com.itsaky.androidide.tasks.gradle.dex.MergeLibAndProjectDex; +import com.itsaky.androidide.tasks.gradle.lint.Lint; +import com.itsaky.androidide.tasks.gradle.lint.LintDebug; +import com.itsaky.androidide.tasks.gradle.lint.LintRelease; +import com.itsaky.androidide.tasks.gradle.plugintasks.ShowDependencies; + +public class BaseGradleTasks { + + public static BaseGradleTask + + BUILD = new Build(), + ASSEMBLE_DEBUG = new AssembleDebug(), + ASSEMBLE_RELEASE = new AssembleRelease(), + BUNDLE = new Bundle(), + CLEAN = new Clean(), + CLEAN_BUILD = new CleanBuild(), + LINT = new Lint(), + LINT_DEBUG = new LintDebug(), + LINT_RELEASE = new LintRelease(), + + MERGE_DEX = new MergeDex(), + MERGE_EXT_DEX = new MergeExtDex(), + MERGE_LIB_AND_PROJECT_DEX = new MergeLibAndProjectDex(), + + SHOW_DEPENDENCIES = new ShowDependencies(); +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeDex.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeDex.java new file mode 100644 index 000000000..cf490216b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeDex.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.dex; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class MergeDex extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.task_merge_dex); + } + + @Override + public String getCommands() { + return "mergeDexDebug"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_DEX; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.OTHER; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeExtDex.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeExtDex.java new file mode 100644 index 000000000..1ad34d236 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeExtDex.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.dex; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class MergeExtDex extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.task_merge_dex); + } + + @Override + public String getCommands() { + return "mergeExtDexDebug"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_DEX; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.OTHER; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeLibAndProjectDex.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeLibAndProjectDex.java new file mode 100644 index 000000000..1bbfce59c --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/dex/MergeLibAndProjectDex.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.dex; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class MergeLibAndProjectDex extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.task_merge_dex); + } + + @Override + public String getCommands() { + return "mergeLibDexDebug mergeProjectDexDebug"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_DEX; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.OTHER; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java new file mode 100644 index 000000000..dc70df754 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.lint; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class Lint extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.lint); + } + + @Override + public String getCommands() { + return "lint"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_LINT; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.LINT; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java new file mode 100644 index 000000000..2a720ea46 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java @@ -0,0 +1,46 @@ +package com.itsaky.androidide.tasks.gradle.lint; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class LintDebug extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.lint_debug); + } + + @Override + public String getCommands() { + return "lintDebug"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_LINT_DEBUG; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.LINT; + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java new file mode 100644 index 000000000..a49e01436 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.lint; + +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; + +public class LintRelease extends BaseGradleTask { + + @Override + public String getName() { + return StudioApp.getInstance().getString(R.string.lint_release); + } + + @Override + public String getCommands() { + return "lintRelease"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_LINT; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.LINT; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugintasks/ShowDependencies.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugintasks/ShowDependencies.java new file mode 100644 index 000000000..e321ae2c8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugintasks/ShowDependencies.java @@ -0,0 +1,45 @@ +package com.itsaky.androidide.tasks.gradle.plugintasks; + +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.services.IDEService; +import com.itsaky.androidide.tasks.BaseGradleTask; +import java.io.File; +import com.itsaky.androidide.utils.PreferenceManager; + +public class ShowDependencies extends BaseGradleTask { + + @Override + public String getName() { + return "Start Completion Services"; + } + + @Override + public String getCommands() { + return (StudioApp.getInstance().getPrefManager().getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true) ? "assembleDebug " : "") + "showDependenciesDebug"; + } + + @Override + public int getTaskID() { + return IDEService.TASK_SHOW_DEPENDENCIES; + } + + @Override + public boolean canOutput() { + return true; + } + + @Override + public boolean buildsApk() { + return false; + } + + @Override + public File getApk(String buildFolder, String moduleName) { + return null; + } + + @Override + public Type getType() { + return Type.ANDROIDIDE_PLUGIN; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/EitherOfResult.java b/app/src/main/java/com/itsaky/androidide/utils/EitherOfResult.java new file mode 100644 index 000000000..1ecb65e35 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/EitherOfResult.java @@ -0,0 +1,11 @@ +package com.itsaky.androidide.utils; + +import com.itsaky.androidide.language.java.parser.internal.SuggestItem; +import io.github.rosemoe.editor.struct.CompletionItem; + +public class EitherOfResult extends Either { + + public EitherOfResult(SuggestItem left, CompletionItem right) { + super(left, right); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/Environment.java b/app/src/main/java/com/itsaky/androidide/utils/Environment.java new file mode 100644 index 000000000..24524ee46 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/Environment.java @@ -0,0 +1,152 @@ +package com.itsaky.androidide.utils; + +import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.ThrowableUtils; +import com.blankj.utilcode.util.ZipUtils; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.models.gradle.Artifact; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Collection; + +public final class Environment { + + public static File HOME; + public static File JAVA_HOME; + public static File ANDROID_HOME; + public static File TMP_DIR; + public static File USRDIR; + public static File LIBDIR; + + public static File GRADLE_DIR; + public static File GRADLE_PROPS; + public static File GRADLE_PROPS_DIR; + public static File GRADLE_PLUGIN; + public static File BOOTCLASSPATH; + public static File CACHES_DIR; + public static File AAPT2; + + public static File LIBHOOKSO; + + public static String ANDROID_SDK_FOLDER_NAME = "android-sdk"; + public static String GRADLE_FOLDER_NAME = null; + public static final String JDK_FOLDER_NAME = "jdk"; + public static final String JDK_FOLDER_NAME_OLD = "openjdk-11.0.1"; + public static final String DEFAULT_GRADLE_FOLDER = "gradle-7.1.1"; + public static final String SAMPLE_GRADLE_PROP_CONTENTS = "# Specify global Gradle properties in this file\n# These properties will be applicable for every project you build with Gradle."; + + public static List AARS = new ArrayList<>(); + + private static File getJavaHome() { + File home = new File(HOME, JDK_FOLDER_NAME_OLD); + if(home.exists() && home.isDirectory()) { + FileUtils.rename(home, JDK_FOLDER_NAME); + } + return new File(HOME, JDK_FOLDER_NAME); + } + + static { + final StudioApp app = StudioApp.getInstance(); + final File files21 = new File(HOME, ".gradle/caches/modules-2/files-2.1"); + GRADLE_FOLDER_NAME = app.getPrefManager().getCurrentGradleFolderName(); + final File gradleDir = new File(HOME, "gradle-7.1.1"); + if(gradleDir != null && gradleDir.exists()) { + GRADLE_FOLDER_NAME = !FileUtils.rename(gradleDir, "gradle") ? GRADLE_FOLDER_NAME : "gradle"; + app.getPrefManager().setCurentGradleFolderName(GRADLE_FOLDER_NAME); + } + + HOME = app.getRootDir(); + JAVA_HOME = getJavaHome(); + ANDROID_HOME = new File(HOME, ANDROID_SDK_FOLDER_NAME); + TMP_DIR = mkdirIfNotExits(new File(HOME, "tmp")); + GRADLE_DIR = new File(HOME, GRADLE_FOLDER_NAME); + USRDIR = mkdirIfNotExits(new File(HOME.getParentFile(), "usr")); + LIBDIR = mkdirIfNotExits(new File(USRDIR, "lib")); + + LIBHOOKSO = new File(LIBDIR, "libhook.so"); + CACHES_DIR = new File(HOME, "ide-caches"); + BOOTCLASSPATH = new File(""); + AAPT2 = new File(files21, "com.android.tools.build/aapt2/4.0.1-6197926"); + GRADLE_PLUGIN = new File(files21, "com.itsaky.androidide/gradle"); + GRADLE_PROPS_DIR = new File(HOME, ".gradle"); + GRADLE_PROPS = new File(GRADLE_PROPS_DIR, "gradle.properties"); + } + + public static void updateGradleDir() { + GRADLE_DIR = new File(HOME, GRADLE_FOLDER_NAME); + StudioApp.getInstance().onGradleUpdated(); + } + + public static File getGradleDir() { + String name = DEFAULT_GRADLE_FOLDER; + if(GRADLE_FOLDER_NAME != null) + name = GRADLE_FOLDER_NAME; + return new File(HOME, name); + } + + public static void setBootClasspath(File file) { + BOOTCLASSPATH = new File(file.getAbsolutePath()); + } + + public static String path(File file) { + return file.getAbsolutePath(); + } + + public static File destinationForArtifact(Artifact artifact) { + return mkdirIfNotExits(new File(CACHES_DIR, String.format("%s/%s/%s", artifact.group, artifact.name, artifact.version))); + } + + public static File mkdirIfNotExits(File in) { + if (!in.exists()) + FileUtils.createOrExistsDir(in); + + return in; + } + + public static File cachedFolderForArtifact(Artifact artifact) { + return new File(HOME, String.format(".gradle/caches/modules-2/files-2.1/%s/%s/%s", artifact.group, artifact.name, artifact.version)); + } + + public static List findJarForArtifact(final Artifact artifact) { + List result = new ArrayList<>(); + if(artifact != null && artifact.isValid()) { + File folder = cachedFolderForArtifact(artifact); + for(File f : folder.listFiles(p1 -> p1.isDirectory())) { + File[] jarsOrAars = f.listFiles(p1 -> p1.isFile() && (p1.getName().endsWith(".jar") || p1.getName().endsWith(".aar"))); + if(jarsOrAars != null + && jarsOrAars.length > 0) { + for(File jarOrAar : jarsOrAars) { + if(jarOrAar.getName().endsWith(".jar")) { + result.add(jarOrAar); + } else if(jarOrAar.getName().endsWith(".aar")) { + result.addAll(extractAar(artifact, jarOrAar)); + } + } + } + } + } + return result; + } + + private static List extractAar(final Artifact artifact, File aar) { + try { + final File extractedFolder = destinationForArtifact(artifact); + ZipUtils.unzipFile(aar, mkdirIfNotExits(extractedFolder)); + AARS.add(extractedFolder); + return FileUtils.listFilesInDirWithFilter(extractedFolder, (p1 -> p1.isFile() && p1.getName().endsWith(".jar")), true); + } catch (Throwable e) { + return null; + } + } + + public static class Executables { + public static File GRADLE; + public static File JAVA; + + static { + GRADLE = new File(GRADLE_DIR, "bin/gradle"); + JAVA = new File(JAVA_HOME, "bin/java"); + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/FileUtil.java b/app/src/main/java/com/itsaky/androidide/utils/FileUtil.java new file mode 100644 index 000000000..7442e02f9 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/FileUtil.java @@ -0,0 +1,699 @@ +package com.itsaky.androidide.utils; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LightingColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.net.Uri; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.text.TextUtils; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; + +public class FileUtil +{ + + private static void createNewFile(String path) + { + int lastSep = path.lastIndexOf(File.separator); + if (lastSep > 0) + { + String dirPath = path.substring(0, lastSep); + makeDir(dirPath); + } + + File file = new File(path); + + try + { + if (!file.exists()) + file.createNewFile(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + + public static String readFile(String path) + { + createNewFile(path); + + StringBuilder sb = new StringBuilder(); + FileReader fr = null; + try + { + fr = new FileReader(new File(path)); + + char[] buff = new char[1024]; + int length = 0; + + while ((length = fr.read(buff)) > 0) + { + sb.append(new String(buff, 0, length)); + } + } catch (IOException e) + { + e.printStackTrace(); + } finally + { + if (fr != null) + { + try + { + fr.close(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + } + + return sb.toString(); + } + + public static List readFileAsLineList(String path) + { + createNewFile(path); + List lines = new ArrayList<>(); + FileReader fr = null; + try + { + fr = new FileReader(new File(path)); + char[] buff = new char[1024]; + int length = 0; + while ((length = fr.read(buff)) > 0) + { + lines.add(new String(buff, 0, length)); + } + } catch (IOException e) + { + e.printStackTrace(); + } finally + { + if (fr != null) + { + try + { + fr.close(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + } + + return lines; + } + + public static void writeFile(String path, String str) + { + createNewFile(path); + FileWriter fileWriter = null; + + try + { + fileWriter = new FileWriter(new File(path), false); + fileWriter.write(str); + fileWriter.flush(); + } catch (IOException e) + { + e.printStackTrace(); + } finally + { + try + { + if (fileWriter != null) + fileWriter.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + } + + public static void copyFile(String sourcePath, String destPath) + { + if (!isExistFile(sourcePath)) return; + createNewFile(destPath); + + FileInputStream fis = null; + FileOutputStream fos = null; + + try + { + fis = new FileInputStream(sourcePath); + fos = new FileOutputStream(destPath, false); + + byte[] buff = new byte[1024]; + int length = 0; + + while ((length = fis.read(buff)) > 0) + { + fos.write(buff, 0, length); + } + } catch (IOException e) + { + e.printStackTrace(); + } finally + { + if (fis != null) + { + try + { + fis.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + if (fos != null) + { + try + { + fos.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + + public static void moveFile(String sourcePath, String destPath) + { + copyFile(sourcePath, destPath); + deleteFile(sourcePath); + } + + public static void deleteFile(String path) + { + File file = new File(path); + + if (!file.exists()) return; + + if (file.isFile()) + { + file.delete(); + return; + } + + File[] fileArr = file.listFiles(); + + if (fileArr != null) + { + for (File subFile : fileArr) + { + if (subFile.isDirectory()) + { + deleteFile(subFile.getAbsolutePath()); + } + + if (subFile.isFile()) + { + subFile.delete(); + } + } + } + + file.delete(); + } + + public static boolean isExistFile(String path) + { + File file = new File(path); + return file.exists(); + } + + public static void makeDir(String path) + { + if (!isExistFile(path)) + { + File file = new File(path); + file.mkdirs(); + } + } + + public static void listDir(String path, ArrayList list) + { + File dir = new File(path); + if (!dir.exists() || dir.isFile()) return; + + File[] listFiles = dir.listFiles(); + if (listFiles == null || listFiles.length <= 0) return; + + if (list == null) return; + list.clear(); + for (File file : listFiles) + { + list.add(file.getAbsolutePath()); + } + } + + public static boolean isDirectory(String path) + { + if (!isExistFile(path)) return false; + return new File(path).isDirectory(); + } + + public static boolean isFile(String path) + { + if (!isExistFile(path)) return false; + return new File(path).isFile(); + } + + public static long getFileLength(String path) + { + if (!isExistFile(path)) return 0; + return new File(path).length(); + } + + public static String getExternalStorageDir() + { + return Environment.getExternalStorageDirectory().getAbsolutePath(); + } + + public static String getPackageDataDir(Context context) + { + return context.getExternalFilesDir(null).getAbsolutePath(); + } + + public static String getPublicDir(String type) + { + return Environment.getExternalStoragePublicDirectory(type).getAbsolutePath(); + } + + public static String convertUriToFilePath(final Context context, final Uri uri) + { + String path = null; + if (DocumentsContract.isDocumentUri(context, uri)) + { + if (isExternalStorageDocument(uri)) + { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) + { + path = Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } else if (isDownloadsDocument(uri)) + { + final String id = DocumentsContract.getDocumentId(uri); + + if (!TextUtils.isEmpty(id)) + { + if (id.startsWith("raw:")) + { + return id.replaceFirst("raw:", ""); + } + } + + final Uri contentUri = ContentUris + .withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + + path = getDataColumn(context, contentUri, null, null); + } else if (isMediaDocument(uri)) + { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) + { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) + { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) + { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = MediaStore.Audio.Media._ID + "=?"; + final String[] selectionArgs = new String[]{ + split[1] + }; + + path = getDataColumn(context, contentUri, selection, selectionArgs); + } + } else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uri.getScheme())) + { + path = getDataColumn(context, uri, null, null); + } else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) + { + path = uri.getPath(); + } + + if (path != null) + { + try + { + return URLDecoder.decode(path, "UTF-8"); + } catch (Exception e) + { + return null; + } + } + return null; + } + + private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) + { + Cursor cursor = null; + + final String column = MediaStore.Images.Media.DATA; + final String[] projection = { + column + }; + + try + { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) + { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } catch (Exception e) + { + + } finally + { + if (cursor != null) + { + cursor.close(); + } + } + return null; + } + + + private static boolean isExternalStorageDocument(Uri uri) + { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + private static boolean isDownloadsDocument(Uri uri) + { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + private static boolean isMediaDocument(Uri uri) + { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + private static void saveBitmap(Bitmap bitmap, String destPath) + { + FileOutputStream out = null; + FileUtil.createNewFile(destPath); + try + { + out = new FileOutputStream(new File(destPath)); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + } catch (Exception e) + { + e.printStackTrace(); + } finally + { + try + { + if (out != null) + { + out.close(); + } + } catch (IOException e) + { + e.printStackTrace(); + } + } + } + + public static Bitmap getScaledBitmap(String path, int max) + { + Bitmap src = BitmapFactory.decodeFile(path); + + int width = src.getWidth(); + int height = src.getHeight(); + float rate = 0.0f; + + if (width > height) + { + rate = max / (float) width; + height = (int) (height * rate); + width = max; + } else + { + rate = max / (float) height; + width = (int) (width * rate); + height = max; + } + + return Bitmap.createScaledBitmap(src, width, height, true); + } + + public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) + { + final int width = options.outWidth; + final int height = options.outHeight; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) + { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) + { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + public static Bitmap decodeSampleBitmapFromPath(String path, int reqWidth, int reqHeight) + { + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, options); + + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(path, options); + } + + public static void resizeBitmapFileRetainRatio(String fromPath, String destPath, int max) + { + if (!isExistFile(fromPath)) return; + Bitmap bitmap = getScaledBitmap(fromPath, max); + saveBitmap(bitmap, destPath); + } + + public static void resizeBitmapFileToSquare(String fromPath, String destPath, int max) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Bitmap bitmap = Bitmap.createScaledBitmap(src, max, max, true); + saveBitmap(bitmap, destPath); + } + + public static void resizeBitmapFileToCircle(String fromPath, String destPath) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), + src.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, src.getWidth(), src.getHeight()); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawCircle(src.getWidth() / 2, src.getHeight() / 2, + src.getWidth() / 2, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(src, rect, rect, paint); + + saveBitmap(bitmap, destPath); + } + + public static void resizeBitmapFileWithRoundedBorder(String fromPath, String destPath, int pixels) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src + .getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, src.getWidth(), src.getHeight()); + final RectF rectF = new RectF(rect); + final float roundPx = pixels; + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(src, rect, rect, paint); + + saveBitmap(bitmap, destPath); + } + + public static void cropBitmapFileFromCenter(String fromPath, String destPath, int w, int h) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + + int width = src.getWidth(); + int height = src.getHeight(); + + if (width < w && height < h) + return; + + int x = 0; + int y = 0; + + if (width > w) + x = (width - w) / 2; + + if (height > h) + y = (height - h) / 2; + + int cw = w; + int ch = h; + + if (w > width) + cw = width; + + if (h > height) + ch = height; + + Bitmap bitmap = Bitmap.createBitmap(src, x, y, cw, ch); + saveBitmap(bitmap, destPath); + } + + public static void rotateBitmapFile(String fromPath, String destPath, float angle) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + Bitmap bitmap = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); + saveBitmap(bitmap, destPath); + } + + public static void scaleBitmapFile(String fromPath, String destPath, float x, float y) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Matrix matrix = new Matrix(); + matrix.postScale(x, y); + + int w = src.getWidth(); + int h = src.getHeight(); + + Bitmap bitmap = Bitmap.createBitmap(src, 0, 0, w, h, matrix, true); + saveBitmap(bitmap, destPath); + } + + public static void skewBitmapFile(String fromPath, String destPath, float x, float y) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Matrix matrix = new Matrix(); + matrix.postSkew(x, y); + + int w = src.getWidth(); + int h = src.getHeight(); + + Bitmap bitmap = Bitmap.createBitmap(src, 0, 0, w, h, matrix, true); + saveBitmap(bitmap, destPath); + } + + public static void setBitmapFileColorFilter(String fromPath, String destPath, int color) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + Bitmap bitmap = Bitmap.createBitmap(src, 0, 0, + src.getWidth() - 1, src.getHeight() - 1); + Paint p = new Paint(); + ColorFilter filter = new LightingColorFilter(color, 1); + p.setColorFilter(filter); + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(bitmap, 0, 0, p); + saveBitmap(bitmap, destPath); + } + + public static void setBitmapFileBrightness(String fromPath, String destPath, float brightness) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + ColorMatrix cm = new ColorMatrix(new float[] + { + 1, 0, 0, 0, brightness, + 0, 1, 0, 0, brightness, + 0, 0, 1, 0, brightness, + 0, 0, 0, 1, 0 + }); + + Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig()); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setColorFilter(new ColorMatrixColorFilter(cm)); + canvas.drawBitmap(src, 0, 0, paint); + saveBitmap(bitmap, destPath); + } + + public static void setBitmapFileContrast(String fromPath, String destPath, float contrast) + { + if (!isExistFile(fromPath)) return; + Bitmap src = BitmapFactory.decodeFile(fromPath); + ColorMatrix cm = new ColorMatrix(new float[] + { + contrast, 0, 0, 0, 0, + 0, contrast, 0, 0, 0, + 0, 0, contrast, 0, 0, + 0, 0, 0, 1, 0 + }); + + Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig()); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setColorFilter(new ColorMatrixColorFilter(cm)); + canvas.drawBitmap(src, 0, 0, paint); + + saveBitmap(bitmap, destPath); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/IntProperty.java b/app/src/main/java/com/itsaky/androidide/utils/IntProperty.java new file mode 100644 index 000000000..e95a62530 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/IntProperty.java @@ -0,0 +1,24 @@ +package com.itsaky.androidide.utils; + +import android.util.Property; + +/** + * From AOSP source code. + * + * Copied to support earlier android versions. + */ + +public abstract class IntProperty extends Property { + public IntProperty(String name) { + super(Integer.class, name); + } + /** + * A type-specific variant of {@link #set(Object, Integer)} that is faster when dealing + * with fields of type int. + */ + public abstract void setValue(T object, int value); + @Override + final public void set(T object, Integer value) { + setValue(object, value.intValue()); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/PreferenceManager.java b/app/src/main/java/com/itsaky/androidide/utils/PreferenceManager.java new file mode 100644 index 000000000..fba659edb --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/PreferenceManager.java @@ -0,0 +1,175 @@ +package com.itsaky.androidide.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import java.io.File; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; +import com.itsaky.androidide.app.StudioApp; +import java.io.FileReader; + +public class PreferenceManager { + + private SharedPreferences prefs; + private SharedPreferences.Editor editor; + + public static final int LOGSENDER_LATEST_VERSION = 102; + + public static final String KEY_FRAMEWORK_DOWNLOADED = "framework_downloaded"; + public static final String KEY_FRAMEWORK_INSTALLED = "framework_installed"; + public static final String KEY_IS_FIRST_PROJECT_BUILD = "project_isFirstBuild"; + + public static final String KEY_EDITORFLAG_WS_LEADING = "idepref_editor_wsLeading"; + public static final String KEY_EDITORFLAG_WS_TRAILING = "idepref_editor_wsTrailing"; + public static final String KEY_EDITORFLAG_WS_INNER = "idepref_editor_wsInner"; + public static final String KEY_EDITORFLAG_WS_EMPTY_LINE = "idepref_editor_wsEmptyLine"; + public static final String KEY_EDITORFLAG_LINE_BREAK = "idepref_editor_lineBreak"; + public static final String KEY_EDITOR_DRAW_HEX = "idepref_editor_drawHexColors"; + + public static final String KEY_GRADLE_CURRENT_DIR = "idepref_customGradle_currentFolder"; + public static final String KEY_GRADLE_FILENAMES = "idepref_customGradle_folderNames"; + public static final String KEY_GRADLECMD_STACKTRACRE = "idepref_gradleCmd_stacktrace"; + public static final String KEY_GRADLECMD_DEBUG = "idepref_gradleCmd_debug"; + public static final String KEY_GRADLECMD_SCAN = "idepref_gradleCmd_scan"; + public static final String KEY_GRADLECMD_INFO = "idepref_gradleCmd_info"; + public static final String KEY_GRADLECMD_WARNINGMODE = "idepref_gradleCmd_warningMode"; + + public static final String KEY_LOGSENDER_CURRENT_VERSION = "logsender_currentVersion"; + + @SuppressLint("CommitPrefEdits") + public PreferenceManager(Context ctx) { + this.prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(ctx); + this.editor = prefs.edit(); + } + + public PreferenceManager putInt(String key, int val) { + editor.putInt(key, val).apply(); + return this; + } + + public int getInt(String key) { + return prefs.getInt(key, 0); + } + + public int getInt(String key, int def) { + return prefs.getInt(key, def); + } + + public PreferenceManager putFloat(String key, float val) { + editor.putFloat(key, val).apply(); + return this; + } + + public float getFloat(String key) { + return prefs.getFloat(key, 0f); + } + + public float getFloat(String key, float def) { + return prefs.getFloat(key, def); + } + + public PreferenceManager putBoolean(String key, boolean value) { + editor.putBoolean(key, value).apply(); + return this; + } + + public boolean getBoolean(String key) { + return getBoolean(key, false); + } + + public boolean getBoolean(String key, boolean defaultValue) { + return prefs.getBoolean(key, defaultValue); + } + + public PreferenceManager putString(String key, String value) { + editor.putString(key, value).apply(); + return this; + } + + public String getString(String key) { + return prefs.getString(key, null); + } + + public String getString(String key, String defaultValue) { + return prefs.getString(key, defaultValue); + } + + public boolean isFrameworkDownloaded() { + return getBoolean(KEY_FRAMEWORK_DOWNLOADED); + } + + public boolean isFrameworkInstalled() { + return isFrameworkDownloaded() && getBoolean(KEY_FRAMEWORK_INSTALLED); + } + + public boolean isStracktraceEnabled() { + return getBoolean(KEY_GRADLECMD_STACKTRACRE); + } + + public boolean isGradleInfoEnabled() { + return getBoolean(KEY_GRADLECMD_INFO); + } + + public boolean isGradleDebugEnabled() { + return getBoolean(KEY_GRADLECMD_DEBUG); + } + + public boolean isGradleScanEnabled() { + return getBoolean(KEY_GRADLECMD_SCAN); + } + + public boolean isGradleWarningEnabled() { + return getBoolean(KEY_GRADLECMD_WARNINGMODE); + } + + public PreferenceManager setGradleStacktraceEnabled(boolean enabled) { + return putBoolean(KEY_GRADLECMD_STACKTRACRE, enabled); + } + + public PreferenceManager setGradleInfoEnabled(boolean enabled) { + return putBoolean(KEY_GRADLECMD_INFO, enabled); + } + + public PreferenceManager setGradleDebugEnabled(boolean enabled) { + return putBoolean(KEY_GRADLECMD_DEBUG, enabled); + } + + public PreferenceManager setGradleScanEnabled(boolean enabled) { + return putBoolean(KEY_GRADLECMD_SCAN, enabled); + } + + public PreferenceManager setGradleWarningEnabled(boolean enabled) { + return putBoolean(KEY_GRADLECMD_WARNINGMODE, enabled); + } + + public PreferenceManager addGradleFolder(String name) { + Set folders = prefs.getStringSet(KEY_GRADLE_FILENAMES, new HashSet()); + if(folders == null) { + folders = new HashSet(); + } + if(!folders.contains(name)) { + folders.add(name); + } + editor.putStringSet(KEY_GRADLE_FILENAMES, folders).apply(); + return this; + } + + public Set getGradleFolderNames() { + Set folders = prefs.getStringSet(KEY_GRADLE_FILENAMES, new HashSet()); + if(folders != null && folders.size() > 0) { + return folders; + } else { + return addGradleFolder(Environment.DEFAULT_GRADLE_FOLDER).getGradleFolderNames(); + } + } + + public PreferenceManager setCurentGradleFolderName(String name) { + return addGradleFolder(name).putString(KEY_GRADLE_CURRENT_DIR, name); + } + + public String getCurrentGradleFolderName() { + return getString(KEY_GRADLE_CURRENT_DIR, Environment.DEFAULT_GRADLE_FOLDER); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/ProjectWriter.java b/app/src/main/java/com/itsaky/androidide/utils/ProjectWriter.java new file mode 100644 index 000000000..0ba1a07f9 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/ProjectWriter.java @@ -0,0 +1,239 @@ +package com.itsaky.androidide.utils; + +import com.blankj.utilcode.util.FileIOUtils; +import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.ResourceUtils; +import com.blankj.utilcode.util.ThreadUtils; +import com.blankj.utilcode.util.ZipUtils; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.interfaces.ProjectWriterCallback; +import com.itsaky.androidide.models.NewProjectDetails; +import com.itsaky.androidide.models.ProjectTemplate; +import java.io.File; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +public class ProjectWriter { + + private static ProjectWriterCallback callback; + + private static final String[] FILE_TO_CHANGE = { + "build.gradle", + "app/src/main/AndroidManifest.xml", + "app/src/main/res/values/strings.xml", + "app/src/main/java/$package_name/MainActivity.java" + }; + + private static final String JAVA_PATH_REGEX = "/.*/src/.*/java"; + private static final String ANAME = "$app_name", + PNAME = "$package_name", + MSDK = "$min_sdk", + TSDK = "$target_sdk", + ANDROIDIDE_PLUGIN = "$androidide_gradle_plugin_version"; + + private static final String ANDROIDIDE_PLUGIN_VERSION = "1.0.6"; + + public static String createMenu() { + return "" + + "\n\t" + + "\n"; + } + + public static String createDrawable() { + return "" + + "\n\t\t" + + "\n\t\t" + + "\n"; + } + + public static String createLayout() { + return "" + + "\n " + + "\n " + + "\n" + + "\n " + + "\n" + + "\n " + + "\n " + + "\n " + + "\n " + + "\n " + + "\n " + + "\n"; + } + + public static String getPackageName(File parentPath) { + Matcher pkgMatcher = Pattern.compile(JAVA_PATH_REGEX).matcher(parentPath.getAbsolutePath()); + if(pkgMatcher.find()) { + int end = pkgMatcher.end(); + if(end <= 0) return ""; + String name = parentPath.getAbsolutePath().substring(pkgMatcher.end()); + if(name.startsWith(File.separator)) + name = name.substring(1); + return name.replace(File.separator, "."); + } + return null; + } + + + // TODO: Implement a dynamic source code generator + public static String createJavaClass(String packageName, String className) { + return "package " + packageName + ";\n" + + "\n" + + "public class " + className + " {\n" + + "\t\n" + + "}"; + } + + public static String createJavaInterface(String packageName, String className) { + return "package " + packageName + ";\n" + + "\n" + + "public interface " + className + " {\n" + + "\t\n" + + "}"; + } + + public static String createJavaEnum(String packageName, String className) { + return "package " + packageName + ";\n" + + "\n" + + "public enum " + className + " {\n" + + "\t\n" + + "}"; + } + + public static String createActivity(String packageName, String className) { + return "package " + packageName + ";\n" + + "\n" + + "import androidx.appcompat.app.AppCompatActivity;" + + "\n" + + "public class " + className + " extends AppCompatActivity {\n" + + "\t\n" + + "}"; + } + + public static void write(ProjectTemplate template, NewProjectDetails details, ProjectWriterCallback listener) throws Exception { + write(template.getId(), details, listener); + } + + public static void write(int id, NewProjectDetails details, ProjectWriterCallback listener) throws Exception { + callback = listener; + notifyBegin(); + final StudioApp instance = StudioApp.getInstance(); + final File temp = instance.getTempProjectDir(); + final File projectDir = new File(instance.getProjectsDir(), details.name); + if(projectDir.exists()) { + notifyFailed(instance.getString(R.string.project_exists)); + return; + } + if(temp == null) notifyFailed(instance.getString(R.string.cannot_create_temp)); + if(!FileUtils.delete(temp) || !Environment.mkdirIfNotExits(temp).exists()) notifyFailed(instance.getString(R.string.cannot_create_temp)); + notifyTask(instance.getString(R.string.copying_assets)); + projectDir.mkdirs(); + File destZip = new File(instance.getRootDir(), "templates/" + id + ".zip"); + Environment.mkdirIfNotExits(destZip.getParentFile()); + if(ResourceUtils.copyFileFromAssets("templates/" + destZip.getName(), destZip.getAbsolutePath())) { + ZipUtils.unzipFile(destZip, temp); + notifyTask(instance.getString(R.string.writing_files)); + for(String s : FILE_TO_CHANGE) { + File file = new File(temp, s); + if(file.exists() && s.contains(PNAME)) { + s = s.replace(PNAME, details.packageName.replace(".", "/")); + File f = new File(temp, s); + FileUtils.move(file, f); + + try { + File f2 = file.getParentFile(); + while(!f2.getName().contains(PNAME)) + f2 = f2.getParentFile(); + FileUtils.delete(f2); + } catch (Throwable t) {} + file = f; + } + if(file.exists()) { + String read = FileIOUtils.readFile2String(file); + read = read.replace(ANAME, details.name) + .replace(PNAME, details.packageName) + .replace(MSDK, String.valueOf(details.minSdk)) + .replace(TSDK, String.valueOf(details.targetSdk)) + .replace(ANDROIDIDE_PLUGIN, ANDROIDIDE_PLUGIN_VERSION); + if(FileIOUtils.writeFileFromString(file, read, false)) { + continue; + } else { + notifyFailed(instance.getString(R.string.failed_write_file, file.getName())); + } + } + } + notifyTask(instance.getString(R.string.copying_files)); + if(FileUtils.createOrExistsDir(projectDir)) { + boolean success = true; + for(File f : temp.listFiles()) { + if(success &= FileUtils.copy(f, new File(projectDir, f.getName()))) + continue; + else { + notifyFailed(instance.getString(R.string.failed_write_file, f.getName())); + break; + } + } + if(success) + notifySuccess(); + } else { + notifyFailed(instance.getString(R.string.failed_create_project_dir)); + } + } else { + notifyFailed(instance.getString(R.string.asset_copy_failed)); + } + } + + private static void notifyBegin() { + ThreadUtils.runOnUiThread(() -> { + if(callback != null) + callback.beforeBegin(); + }); + } + + private static void notifyTask(String name) { + ThreadUtils.runOnUiThread(() -> { + if(callback != null) + callback.onProcessTask(name); + }); + } + + private static void notifySuccess() { + ThreadUtils.runOnUiThread(() -> { + if(callback != null) + callback.onSuccess(); + }); + } + + private static void notifyFailed(String reason) { + ThreadUtils.runOnUiThread(() -> { + if(callback != null) + callback.onFailed(reason); + }); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/StudioUtils.java b/app/src/main/java/com/itsaky/androidide/utils/StudioUtils.java new file mode 100644 index 000000000..0457cd756 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/StudioUtils.java @@ -0,0 +1,54 @@ +package com.itsaky.androidide.utils; +import android.content.Context; +import com.itsaky.toaster.Toaster; +import android.util.TypedValue; + +public class StudioUtils { + private Context mContext; + private Toaster mToaster; + + public StudioUtils(Context mContext) { + this.mContext = mContext; + mToaster = getToaster(); + } + + private Toaster getToaster() { + return mToaster == null ? mToaster = new Toaster(mContext) : mToaster; + } + + public void toast(String msg, Toaster.Type type) { + getToaster().setDuration(Toaster.SHORT) + .setText(msg) + .setType(type) + .show(); + } + + public void toast(int msg, Toaster.Type type) { + getToaster().setDuration(Toaster.SHORT) + .setText(msg) + .setType(type) + .show(); + } + + public void toastLong(String msg, Toaster.Type type) { + getToaster().setDuration(Toaster.LONG) + .setText(msg) + .setType(type) + .show(); + } + + public void toastLong(int msg, Toaster.Type type) { + getToaster().setDuration(Toaster.LONG) + .setText(msg) + .setType(type) + .show(); + } + + public float toDp(int px) { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, mContext.getResources().getDisplayMetrics()); + } + + public float toPx(int dp) { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, dp, mContext.getResources().getDisplayMetrics()); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/Symbols.java b/app/src/main/java/com/itsaky/androidide/utils/Symbols.java new file mode 100644 index 000000000..f8cd275b6 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/Symbols.java @@ -0,0 +1,74 @@ +package com.itsaky.androidide.utils; + +import com.itsaky.androidide.fragments.EditorFragment; +import com.itsaky.androidide.views.SymbolInputView.Symbol; +import java.io.File; + +public class Symbols { + + public static Symbol[] forFile(File file) { + if(file.isFile()) { + if(file.getName().endsWith(EditorFragment.EXT_JAVA) + || file.getName().endsWith(EditorFragment.EXT_GRADLE)) + return javaSymbols(); + + if(file.getName().endsWith(EditorFragment.EXT_XML)) + return xmlSymbols(); + } + + return new Symbol[0]; + } + + public static Symbol[] javaSymbols() { + return new Symbol[]{new Symbol("->", "\t"), + new Symbol("{", "{}"), + new Symbol("}"), + new Symbol("(", "()"), + new Symbol(")"), + new Symbol(";"), + new Symbol("="), + new Symbol("\""), + new Symbol("|"), + new Symbol("&"), + new Symbol("!"), + new Symbol("[", "[]"), + new Symbol("]"), + new Symbol("<"), + new Symbol(">"), + new Symbol("+"), + new Symbol("-"), + new Symbol("/"), + new Symbol("*"), + new Symbol("?"), + new Symbol(":"), + new Symbol("_")}; + } + + public static Symbol[] xmlSymbols() { + return new Symbol[]{new Symbol("->", "\t"), + new Symbol("<", "<>"), + new Symbol(">"), + new Symbol("/"), + new Symbol("="), + new Symbol("\""), + new Symbol(":"), + new Symbol("@"), + new Symbol("+"), + new Symbol("(", "()"), + new Symbol(")"), + new Symbol(";"), + new Symbol(","), + new Symbol("."), + new Symbol("?"), + new Symbol("|"), + new Symbol("\\"), + new Symbol("&"), + new Symbol("[", "[]"), + new Symbol("]"), + new Symbol("{", "{}"), + new Symbol("}"), + new Symbol("_"), + new Symbol("-")}; + } + +} diff --git a/app/src/main/java/com/itsaky/androidide/utils/TypefaceUtils.java b/app/src/main/java/com/itsaky/androidide/utils/TypefaceUtils.java new file mode 100644 index 000000000..de593c9f6 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/utils/TypefaceUtils.java @@ -0,0 +1,15 @@ +package com.itsaky.androidide.utils; + +import android.graphics.Typeface; +import com.itsaky.androidide.app.StudioApp; + +public class TypefaceUtils { + + public static Typeface quicksand() { + return Typeface.createFromAsset(StudioApp.getInstance().getAssets(), "fonts/quicksand.ttf"); + } + + public static Typeface jetbrainsMono() { + return Typeface.createFromAsset(StudioApp.getInstance().getAssets(), "fonts/jetbrains-mono.ttf"); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/MaterialBanner.java b/app/src/main/java/com/itsaky/androidide/views/MaterialBanner.java new file mode 100644 index 000000000..f2b3881fd --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/MaterialBanner.java @@ -0,0 +1,172 @@ +package com.itsaky.androidide.views; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.ContextCompat; +import com.itsaky.androidide.databinding.LayoutBannerBinding; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.view.ViewGroup; +import android.animation.AnimatorListenerAdapter; + +public class MaterialBanner extends CoordinatorLayout { + + private LayoutBannerBinding binding; + private OnPositiveClickListener positiveListener; + private OnNegativeClickListener negativeListener; + + private String contentText; + private String leftButtonText; + private String rightButtonText; + private Drawable iconDrawable; + private int backgroundColor; + private int contentTextColor; + private int buttonTextColor; + + public MaterialBanner(Context context) { + this(context, null); + } + + public MaterialBanner(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MaterialBanner(Context context, AttributeSet attrs, int style) { + super(context, attrs, style); + init(); + } + + private void init() { + binding = LayoutBannerBinding.inflate(LayoutInflater.from(getContext()), this, true); + } + + public void show() { + this.binding.contentTextView.setText(contentText); + this.binding.contentIconView.setImageDrawable(iconDrawable); + this.binding.rightButton.setText(rightButtonText); + this.binding.leftButton.setText(leftButtonText); + this.binding.getRoot().setBackgroundColor(backgroundColor); + this.binding.contentTextView.setTextColor(contentTextColor); + this.binding.leftButton.setTextColor(buttonTextColor); + this.binding.rightButton.setTextColor(buttonTextColor); + this.binding.rightButton.setOnClickListener(v -> { if(positiveListener == null) dismiss(); else { positiveListener.onClick(MaterialBanner.this); dismiss(); } }); + this.binding.leftButton.setOnClickListener(v -> { if(negativeListener == null) dismiss(); else { negativeListener.onClick(MaterialBanner.this); dismiss(); } }); + + final ConstraintLayout root = this.binding.getRoot(); + root.measure(-1, -2); + final int height = root.getMeasuredHeight(); + final LayoutParams p = (LayoutParams) root.getLayoutParams(); + p.height = 0; + root.setLayoutParams(p); + root.setVisibility(VISIBLE); + setVisibility(VISIBLE); + + Animation anim = new Animation() { + @Override + public void applyTransformation(float time, Transformation t) { + p.height = time == 1f ? -2 : (int) (height * time); + root.setLayoutParams(p); + root.requestLayout(); + + } + @Override + public boolean willChangeBounds() { + return true; + } + }; + + anim.setDuration(200); + root.startAnimation(anim); + } + + public void dismiss() { + final ConstraintLayout root = this.binding.getRoot(); + final LayoutParams p = (LayoutParams) root.getLayoutParams(); + final int initialHeight = getMeasuredHeight(); + Animation animation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + if (interpolatedTime == 1f) { + root.setVisibility(GONE); + setVisibility(GONE); + } else { + p.height = (int) (initialHeight - (initialHeight * interpolatedTime)); + root.requestLayout(); + } + } + @Override + public boolean willChangeBounds() { + return true; + } + }; + animation.setDuration((long) (initialHeight / getResources().getDisplayMetrics().density)); + root.startAnimation(animation); + } + + public MaterialBanner setIcon(@DrawableRes int icon) { + return setIcon(ContextCompat.getDrawable(getContext(), icon)); + } + + public MaterialBanner setPositive(@StringRes int text, OnPositiveClickListener listener) { + return setPositive(getContext().getString(text), listener); + } + + public MaterialBanner setNegative(@StringRes int text, OnNegativeClickListener listener) { + return setNegative(getContext().getString(text), listener); + } + + public MaterialBanner setContentText(@StringRes int text) { + return setContentText(getContext().getString(text)); + } + + public MaterialBanner setContentText(String contentText) { + this.contentText = contentText; + return this; + } + + public MaterialBanner setIcon(Drawable icon) { + this.iconDrawable = icon; + return this; + } + + public MaterialBanner setPositive(String text, OnPositiveClickListener listener) { + this.rightButtonText = text; + this.positiveListener = listener; + return this; + } + + public MaterialBanner setNegative(String text, OnNegativeClickListener listener) { + this.leftButtonText = text; + this.negativeListener = listener; + return this; + } + + public MaterialBanner setBannerBackgroundColor(int backgroundColor) { + this.backgroundColor = backgroundColor; + return this; + } + + public MaterialBanner setContentTextColor(int contentTextColor) { + this.contentTextColor = contentTextColor; + return this; + } + + public MaterialBanner setButtonTextColor(int buttonTextColor) { + this.buttonTextColor = buttonTextColor; + return this; + } + + public static interface OnPositiveClickListener { + public void onClick(MaterialBanner banner); + } + + public static interface OnNegativeClickListener { + public void onClick(MaterialBanner banner); + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java b/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java new file mode 100644 index 000000000..3b871ae13 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java @@ -0,0 +1,39 @@ +package com.itsaky.androidide.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import androidx.viewpager.widget.ViewPager; + +/** + Copied from StackOverflow + @see https://stackoverflow.com/a/47143096 +*/ + +public class NonSwipableViewPager extends ViewPager +{ + public NonSwipableViewPager(Context ctx) + { + super(ctx); + } + + public NonSwipableViewPager(Context context, AttributeSet attrs) + { + super(context, attrs); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent ev) + { + return false; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) + { + return false; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/SymbolInputView.java b/app/src/main/java/com/itsaky/androidide/views/SymbolInputView.java new file mode 100644 index 000000000..c2611336e --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/SymbolInputView.java @@ -0,0 +1,74 @@ +package com.itsaky.androidide.views; + +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.widget.Button; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import androidx.core.content.ContextCompat; +import androidx.core.widget.TextViewCompat; +import com.itsaky.androidide.R; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.utils.TypefaceUtils; +import io.github.rosemoe.editor.widget.CodeEditor; +import io.github.rosemoe.editor.widget.SymbolChannel; +import android.util.TypedValue; +import androidx.recyclerview.widget.RecyclerView; +import com.itsaky.androidide.adapters.SymbolInputAdapter; +import androidx.recyclerview.widget.LinearLayoutManager; + +public class SymbolInputView extends RecyclerView { + + private SymbolInputAdapter adapter; + + public SymbolInputView(Context context) { + this(context, null); + } + + public SymbolInputView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SymbolInputView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); + } + + public void bindEditor(CodeEditor editor) { + adapter = new SymbolInputAdapter(editor); + setAdapter(adapter); + setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); + } + + public void setSymbols(Symbol... symbols) { + if(adapter != null) { + adapter.setSymbols(true, symbols); + } + } + + public static class Symbol { + public String label; + public String commit; + public int offset; + + public Symbol(String both) { + this(both, 1); + } + + public Symbol(String both, int offset) { + this(both, both, offset); + } + + public Symbol(String label, String commit) { + this(label, commit, 1); + } + + public Symbol(String label, String commit, int offset) { + this.label = label; + this.commit = commit; + this.offset = offset; + } + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/VerticalViewPager.java b/app/src/main/java/com/itsaky/androidide/views/VerticalViewPager.java new file mode 100644 index 000000000..4bb6f1058 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/VerticalViewPager.java @@ -0,0 +1,92 @@ +package com.itsaky.androidide.views; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import androidx.viewpager.widget.ViewPager; + +public class VerticalViewPager extends ViewPager +{ + public static final String TAG = "VerticalViewPager"; + private boolean scrollEnabled = true; + + public VerticalViewPager(Context context) + { + super(context); + init(); + } + + public VerticalViewPager(Context context, AttributeSet attrs) + { + super(context, attrs); + init(); + } + + public void setScrollEnabled(boolean scrollEnabled) + { + this.scrollEnabled = scrollEnabled; + } + + public boolean isScrollEnabled() + { + return scrollEnabled; + } + + private void init() + { + setPageTransformer(true, new VerticalPageTransformer()); + setOverScrollMode(OVER_SCROLL_NEVER); + } + + private class VerticalPageTransformer implements ViewPager.PageTransformer + { + @Override + public void transformPage(View view, float position) + { + if (position < -1) + { + view.setAlpha(0); + } else if (position <= 1) + { + view.setAlpha(1); + view.setTranslationX(view.getWidth() * -position); + float yPosition = position * view.getHeight(); + view.setTranslationY(yPosition); + } else + { + view.setAlpha(0); + } + } + } + + /** + * Swaps the X and Y coordinates of your touch event. + */ + private MotionEvent swapXY(MotionEvent ev) + { + float width = getWidth(); + float height = getHeight(); + float newX = (ev.getY() / height) * width; + float newY = (ev.getX() / width) * height; + ev.setLocation(newX, newY); + return ev; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) + { + boolean intercepted = super.onInterceptTouchEvent(swapXY(ev)); + swapXY(ev); // return touch coordinates to original reference frame for any child views + return intercepted; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent ev) + { + return isScrollEnabled() ? super.onTouchEvent(swapXY(ev)) : true; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/transition/ArcMotionPlus.java b/app/src/main/java/com/itsaky/androidide/views/transition/ArcMotionPlus.java new file mode 100644 index 000000000..2f5e385d8 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/transition/ArcMotionPlus.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 Neil Davies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.itsaky.androidide.views.transition; + +/** + * A PathMotion that generates a curved path along an arc on an imaginary circle containing + * the two points. The two points reside on the circle and a line between them describes + * a chord for the circle that is symmetrical. i.e the angle between the chord and the tangent to + * each point will be the same. + *

+ * A perpendicular line from the midpoint of the line between the two points will intersect + * the center of the circle. Everything about the line from the center of the circle to the midpoint + * of the chord is symmetrical. + *

+ * + *

This may be used in XML as an element inside a transition.

+ *
{@code
+ * 
+ *   
+ * }
+ * 
+ */ +import android.content.Context; +import android.graphics.Path; +import android.util.AttributeSet; +import androidx.transition.PathMotion; + +public class ArcMotionPlus extends PathMotion { + + private static final float DEFAULT_ARC_ANGLE = 90f; + private static final boolean DEFAULT_REFLECT = false; + + private boolean isReflectedArc = DEFAULT_REFLECT; + private float arcAngle = DEFAULT_ARC_ANGLE; + + public ArcMotionPlus() { } + + public ArcMotionPlus(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** + * Returns if we are reflecting the arc + *

The default value is false.

+ * + * @return Is the arc reflected + */ + public boolean isReflectedArc() { + return isReflectedArc; + } + + /** + * Sets whether we should reflect the arc about the line drawn between the start and end points + *

The default value is false.

+ * + * @param isReflectedArc Is the arc reflected about the line between start and end points + */ + public void setReflectedArc(boolean isReflectedArc) { + this.isReflectedArc = isReflectedArc; + } + + + /** + * Returns the arc angle that describes the curve. The larger the angle the more + * pronounce the curve will be. Min value is 1, Max value si 179 + *

The default value is 90.

+ * + * @return The angle of the arc on a circle describing the Path + * between two points. + */ + public float getArcAngle() { + return arcAngle; + } + + + /** + * Sets the arc angle that describes the curve. The larger the angle the more + * pronounce the curve will be. Min value is 1, Max value si 179 + *

The default value is 90.

+ * + * + * @param angle The angle of the arc on a circle describing the Path + * between two points. + */ + public ArcMotionPlus setArcAngle(float angle) { + arcAngle = angle; + return this; + } + + @Override + public Path getPath(float startX, float startY, float endX, float endY) { + float controlP1X, controlP1Y, controlP2X, controlP2Y; + + Path path = new Path(); + path.moveTo(startX, startY); + + CubicBezierArc cubicBezierArc = new CubicBezierArc(arcAngle, startX, startY, endX, endY); + + if(isReflectedArc) { + controlP1X = cubicBezierArc.getReflectedControlPoint1().x; + controlP1Y = cubicBezierArc.getReflectedControlPoint1().y; + controlP2X = cubicBezierArc.getReflectedControlPoint2().x; + controlP2Y = cubicBezierArc.getReflectedControlPoint2().y; + + } else { + controlP1X = cubicBezierArc.getControlPoint1().x; + controlP1Y = cubicBezierArc.getControlPoint1().y; + controlP2X = cubicBezierArc.getControlPoint2().x; + controlP2Y = cubicBezierArc.getControlPoint2().y; + } + + path.cubicTo(controlP1X, controlP1Y, controlP2X, controlP2Y, endX, endY); + return path; + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/transition/CubicBezierArc.java b/app/src/main/java/com/itsaky/androidide/views/transition/CubicBezierArc.java new file mode 100644 index 000000000..d24615e8d --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/transition/CubicBezierArc.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 Neil Davies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.itsaky.androidide.views.transition; + +/** + * A Class that takes an angle, start point and end point that it uses to calculate controls points + * which can be used to describe a curve between the two points that approximates an arc on a circle. + */ +public class CubicBezierArc { + + private Point startPoint; + private Point endPoint; + private Point controlPoint1; + private Point controlPoint2; + private Point reflectedControlPoint1; + private Point reflectedControlPoint2; + + /** + * Create a CubicBezierArc class with arc angle and start and end points + * + * + * @param angle The angle used to describe the arc, the greater the angle the more curved the arc will be + * (min = 1 , max = 179) + * @param startX the x coord of the start point + * @param startY the y coord of the start point + * @param endX the x coord of the end point + * @param endY the y coord of the end point + */ + public CubicBezierArc(float angle, float startX, float startY, float endX, float endY) { + + Point start = new Point(startX, startY); + Point end = new Point(endX,endY); + + if(start.x == end.x && start.y == end.y) { + throw new IllegalArgumentException("Start and end points cannot be the same"); + } + if (angle < 1 || angle > 179) { + throw new IllegalArgumentException("Arc angle must be between 1 and 179 degrees"); + } + startPoint = start; + endPoint = end; + calculateControlPoints(angle,start,end); + } + + /** + * Returns the start point + * @return The start point + */ + public Point getStartPoint() { + return startPoint; + } + + /** + * Returns the end point + * @return The end point + */ + public Point getEndPoint() { + return endPoint; + } + + /** + * Returns the first control point + * @return The first control point + */ + public Point getControlPoint1() { + return controlPoint1; + } + + /** + * Returns the second control point + * @return The second control point + */ + public Point getControlPoint2() { + return controlPoint2; + } + + /** + * Returns the first control point when reflected about line between start and end points + * @return Reflected control point 1 + */ + public Point getReflectedControlPoint1() { + return reflectedControlPoint1; + } + + /** + * Returns the second control point when reflected about line between start and end points + * @return Reflected control point 2 + */ + public Point getReflectedControlPoint2() { + return reflectedControlPoint2; + } + + + public static class Point { + public float x; + public float y; + + public Point() { + } + + public Point(float x, float y) { + this.x = x; + this.y = y; + } + } + + private Point getTrianglePoint(float angle, Point a, Point b) { + double angleRadians = Math.toRadians(angle); + Point thirdPoint = new Point(); + thirdPoint.x = (float) Math.tan(angleRadians) * (b.y - a.y) * -1; + thirdPoint.y = (float) Math.tan(angleRadians) * (b.x - a.x); + thirdPoint.x = thirdPoint.x + a.x; + thirdPoint.y = thirdPoint.y + a.y; + return thirdPoint; + } + + private Point getReflectedPointAboutLine(Point start, Point end, Point reflect) { + Point reflectedPoint = new Point(); + if (start.x != end.x) { + float m = (start.y - end.y) / (start.x - end.x); + float c = end.y - (m * end.x); + float d = (reflect.x + (reflect.y - c) * m) / (1 + (m * m)); + reflectedPoint.x = (2 * d) - reflect.x; + reflectedPoint.y = (2 * d * m) - reflect.y + (2 * c); + } else { + reflectedPoint.y = reflect.y; + reflectedPoint.x = start.x - (reflect.x - start.x); + } + return reflectedPoint; + } + + private void calculateControlPoints(float angle, Point start, Point end) { + double angleRadians = Math.toRadians(angle); + + float deltaX = start.x - end.x; + float deltaY = start.y - end.y; + float halfChordLength = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY)/2; + float radius = halfChordLength / (float) Math.sin(angleRadians/2.0f); + //The length of the line from the start or end point to the control point + float controlLength = (float) ((4f/3f) * Math.tan(angleRadians/4)) * radius; + + float angleToControl = (float) Math.toDegrees(Math.atan(controlLength/radius)); + + //The mid point of the line from start to end + Point midPointChord = new Point((start.x + end.x) / 2, (start.y + end.y) / 2); + + //Angle between line from circle centre to control point, and line between control points + float chordRadiusAngle = 180 - 90 - (angle/2); + + Point center = getTrianglePoint(chordRadiusAngle, midPointChord, end); + controlPoint2 = getTrianglePoint(angleToControl, end, center); + controlPoint1 = getReflectedPointAboutLine(center, midPointChord, controlPoint2); + + //Get reflected control points + reflectedControlPoint1 = getReflectedPointAboutLine(start, end, controlPoint1); + reflectedControlPoint2 = getReflectedPointAboutLine(start, end, controlPoint2); + + } +} diff --git a/app/src/main/java/com/itsaky/androidide/views/transition/ProgressTransition.java b/app/src/main/java/com/itsaky/androidide/views/transition/ProgressTransition.java new file mode 100644 index 000000000..2e6fba943 --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/views/transition/ProgressTransition.java @@ -0,0 +1,58 @@ +package com.itsaky.androidide.views.transition; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.util.Property; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import androidx.transition.Transition; +import androidx.transition.TransitionValues; +import com.itsaky.androidide.utils.IntProperty; + +public class ProgressTransition extends Transition { + + private static final String PROPNAME_PROGRESS = "ProgressTransition:progress"; + private static final Property PROGRESS_PROPERTY = new IntProperty(PROPNAME_PROGRESS) { + + @Override + public void setValue(ProgressBar progressBar, int value) { + progressBar.setProgress(value); + } + + @Override + public Integer get(ProgressBar progressBar) { + return progressBar.getProgress(); + } + }; + + @Override + public void captureStartValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + private void captureValues(TransitionValues transitionValues) { + if (transitionValues.view instanceof ProgressBar) { + ProgressBar progressBar = ((ProgressBar) transitionValues.view); + transitionValues.values.put(PROPNAME_PROGRESS, progressBar.getProgress()); + } + } + + @Override + public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { + if (startValues != null && endValues != null && endValues.view instanceof ProgressBar) { + ProgressBar progressBar = (ProgressBar) endValues.view; + int start = (Integer) startValues.values.get(PROPNAME_PROGRESS); + int end = (Integer) endValues.values.get(PROPNAME_PROGRESS); + if (start != end) { + progressBar.setProgress(start); + return ObjectAnimator.ofInt(progressBar, PROGRESS_PROPERTY, end); + } + } + return null; + } +} diff --git a/app/src/main/java/com/itsaky/toaster/ToastWrapper.java b/app/src/main/java/com/itsaky/toaster/ToastWrapper.java new file mode 100644 index 000000000..79835e03a --- /dev/null +++ b/app/src/main/java/com/itsaky/toaster/ToastWrapper.java @@ -0,0 +1,77 @@ +package com.itsaky.toaster; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; +import android.view.ViewAnimationUtils; +import android.widget.LinearLayout; +import com.google.android.material.animation.ArgbEvaluatorCompat; +import android.os.Build; + +public class ToastWrapper extends LinearLayout +{ + private Toaster mToaster; + + public ToastWrapper(Context context) + { + super(context); + } + + public ToastWrapper(Context context, AttributeSet attrs) + { + super(context, attrs); + } + + public ToastWrapper(Context context, AttributeSet attrs, int style) + { + super(context, attrs, style); + } + + @Override + protected void onAttachedToWindow() + { + super.onAttachedToWindow(); + startRevealAnimation(); + startIconColorChangeAnimation(); + } + + protected void startIconColorChangeAnimation() + { + ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluatorCompat(), Color.WHITE, mToaster.getIconColor()); + anim.setDuration(Toaster.REVEAL_ANIM_DURATION + 300); + anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){ + + @Override + public void onAnimationUpdate(ValueAnimator p1) + { + mToaster.getIcon().setTint((int) p1.getAnimatedValue()); + } + }); + anim.start(); + } + + @Override + protected void onDetachedFromWindow() + { + super.onDetachedFromWindow(); + setBackgroundColor(Color.TRANSPARENT); + } + + public void setToasterInstance(Toaster toaster) + { + this.mToaster = toaster; + } + + protected void startRevealAnimation() + { + setBackgroundDrawable(mToaster.getBackroundDrawable()); + int x = (getLeft());// + getRight()) / 2; + int y = (getTop() + getBottom()) / 2; + int endRadius = Math.max(getHeight(), getWidth()); + Animator anim = ViewAnimationUtils.createCircularReveal(this, x, y, 0, endRadius); + anim.setDuration(Toaster.REVEAL_ANIM_DURATION); + anim.start(); + } +} diff --git a/app/src/main/java/com/itsaky/toaster/Toaster.java b/app/src/main/java/com/itsaky/toaster/Toaster.java new file mode 100644 index 000000000..56f236ae1 --- /dev/null +++ b/app/src/main/java/com/itsaky/toaster/Toaster.java @@ -0,0 +1,183 @@ +package com.itsaky.toaster; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; +import androidx.core.content.ContextCompat; +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; +import com.itsaky.androidide.R; +import com.itsaky.androidide.databinding.LayoutToastBinding; + +public class Toaster +{ + private LayoutToastBinding binding; + + private Toast mToast; + private Context mContext; + private Gravity mGravity; + private Type mType; + private Drawable mDrawable; + private AnimatedVectorDrawableCompat mIcon; + + private int mIconColor = Color.DKGRAY; + private int mDuration = 0; + + public static final int COLOR_SUCCESS = Color.parseColor("#4CAF50"); + public static final int COLOR_ERROR = Color.parseColor("#F44336"); + public static final int REVEAL_ANIM_DURATION = 500; + public static final int SHORT = 2000; + public static final int LONG = 3500; + + public Toaster(Context context) + { + this.mContext = context; + this.mType = Type.INFO; + + this.mDrawable = createBackgroundDrawable(); + + createView(); + } + + protected View createView() + { + binding = LayoutToastBinding.inflate(LayoutInflater.from(mContext)); + binding.toastToastWrapper.setToasterInstance(this); + return binding.getRoot(); + } + + protected Drawable createBackgroundDrawable() + { + GradientDrawable drawable = new GradientDrawable(); + drawable.setShape(GradientDrawable.RECTANGLE); + drawable.setColor(ContextCompat.getColor(mContext, R.color.color_toast_background)); + drawable.setCornerRadius(25); + return drawable; + } + + protected AnimatedVectorDrawableCompat createToastIconAnimation(int tintColor) + { + AnimatedVectorDrawableCompat imageDrawable = AnimatedVectorDrawableCompat.create(mContext, mType == Type.SUCCESS ? R.drawable.ic_ok : R.drawable.ic_error); + imageDrawable.setTint(tintColor); + imageDrawable.setTintMode(PorterDuff.Mode.SRC_ATOP); + binding.toastImage.setImageDrawable(imageDrawable); + return imageDrawable; + } + + public void show() + { + int dp16 = toPx(16); + mIconColor = mType == Type.SUCCESS ? COLOR_SUCCESS : + mType == Type.ERROR ? COLOR_ERROR : + Color.DKGRAY; + int gravity = mGravity == Gravity.TOP_LEFT ? (android.view.Gravity.TOP|android.view.Gravity.START) : + mGravity == Gravity.TOP_RIGHT ? (android.view.Gravity.TOP|android.view.Gravity.END) : + mGravity == Gravity.BOTTOM_RIGHT ? (android.view.Gravity.BOTTOM|android.view.Gravity.END) : + mGravity == Gravity.BOTTOM_LEFT ? (android.view.Gravity.BOTTOM|android.view.Gravity.START) : + android.view.Gravity.TOP|android.view.Gravity.END; + + mIcon = createToastIconAnimation(mIconColor); + + mToast = Toast.makeText(mContext, binding.toastText.getText(), mDuration); + mToast.setGravity(gravity, dp16, dp16); + mToast.setDuration(mDuration); + mToast.setView(binding.getRoot()); + mToast.show(); + + binding.toastImage.setImageDrawable(mIcon); + mIcon.start(); + } + + public Toaster setText(String text) + { + if(binding.toastText == null) + createView(); + + binding.toastText.setText(text); + return this; + } + + public Toaster setText(int textResId) + { + if(binding.toastText == null) + createView(); + + binding.toastText.setText(textResId); + return this; + } + + public Toaster setDuration(int mDuration) + { + this.mDuration = mDuration + REVEAL_ANIM_DURATION; + return this; + } + + public int getDuration() + { + return mDuration; + } + + public Toaster setType(Type type) + { + this.mType = type; + return this; + } + + public Type getType() + { + return mType; + } + + public Toaster setGravity(Gravity mGravity) + { + this.mGravity = mGravity; + return this; + } + + private int toPx(int dp) + { + return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics())); + } + + public Gravity getGravity() + { + return mGravity; + } + + public AnimatedVectorDrawableCompat getIcon() + { + return mIcon; + } + + public Drawable getBackroundDrawable() + { + return mDrawable; + } + + public int getIconColor() + { + return mIconColor; + } + + public enum Type + { + ERROR, + SUCCESS, + INFO + } + + public enum Gravity + { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT + } +} diff --git a/app/src/main/res/animator/dialog_in.xml b/app/src/main/res/animator/dialog_in.xml new file mode 100644 index 000000000..c83bedc4c --- /dev/null +++ b/app/src/main/res/animator/dialog_in.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/animator/dialog_out.xml b/app/src/main/res/animator/dialog_out.xml new file mode 100644 index 000000000..526c9ce9a --- /dev/null +++ b/app/src/main/res/animator/dialog_out.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_launcher_background.png b/app/src/main/res/drawable-hdpi/ic_launcher_background.png new file mode 100644 index 000000000..fdf83c74c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..f3f4bd222 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher_background.png b/app/src/main/res/drawable-mdpi/ic_launcher_background.png new file mode 100644 index 000000000..8aa9f34a1 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..eb364ea0a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..cc14f035a --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher_background.png b/app/src/main/res/drawable-xhdpi/ic_launcher_background.png new file mode 100644 index 000000000..80ab01293 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..885115ceb Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png b/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png new file mode 100644 index 000000000..403f8f04b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..54919779e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_header.png b/app/src/main/res/drawable-xxxhdpi/bg_header.png new file mode 100644 index 000000000..92f6f2883 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_header.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png b/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png new file mode 100644 index 000000000..6e0c3e71c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..a32585a00 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/template_basic.png b/app/src/main/res/drawable-xxxhdpi/template_basic.png new file mode 100644 index 000000000..79e31ae1d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/template_basic.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/template_bottom_navigation.png b/app/src/main/res/drawable-xxxhdpi/template_bottom_navigation.png new file mode 100644 index 000000000..823de810c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/template_bottom_navigation.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/template_empty.png b/app/src/main/res/drawable-xxxhdpi/template_empty.png new file mode 100644 index 000000000..8e307cd59 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/template_empty.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/template_kotlin.png b/app/src/main/res/drawable-xxxhdpi/template_kotlin.png new file mode 100644 index 000000000..54ac39618 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/template_kotlin.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/template_navigation_drawer.jpg b/app/src/main/res/drawable-xxxhdpi/template_navigation_drawer.jpg new file mode 100644 index 000000000..5899faab3 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/template_navigation_drawer.jpg differ diff --git a/app/src/main/res/drawable/bg_bottom_sheet.xml b/app/src/main/res/drawable/bg_bottom_sheet.xml new file mode 100644 index 000000000..c1432cc59 --- /dev/null +++ b/app/src/main/res/drawable/bg_bottom_sheet.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_editor_tab.xml b/app/src/main/res/drawable/bg_editor_tab.xml new file mode 100644 index 000000000..4a1117149 --- /dev/null +++ b/app/src/main/res/drawable/bg_editor_tab.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_ripple.xml b/app/src/main/res/drawable/bg_ripple.xml new file mode 100644 index 000000000..9b1a5df11 --- /dev/null +++ b/app/src/main/res/drawable/bg_ripple.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/bg_ripple_disabled.xml b/app/src/main/res/drawable/bg_ripple_disabled.xml new file mode 100644 index 000000000..34782662b --- /dev/null +++ b/app/src/main/res/drawable/bg_ripple_disabled.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/src/main/res/drawable/bg_ripple_pressed.xml b/app/src/main/res/drawable/bg_ripple_pressed.xml new file mode 100644 index 000000000..b8c1e9872 --- /dev/null +++ b/app/src/main/res/drawable/bg_ripple_pressed.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/src/main/res/drawable/bg_shadow.xml b/app/src/main/res/drawable/bg_shadow.xml new file mode 100644 index 000000000..53576c272 --- /dev/null +++ b/app/src/main/res/drawable/bg_shadow.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 000000000..e25987d43 --- /dev/null +++ b/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_android.xml b/app/src/main/res/drawable/ic_android.xml new file mode 100644 index 000000000..1e8f03b2d --- /dev/null +++ b/app/src/main/res/drawable/ic_android.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/drawable/ic_bash.xml b/app/src/main/res/drawable/ic_bash.xml new file mode 100644 index 000000000..8cb0d4955 --- /dev/null +++ b/app/src/main/res/drawable/ic_bash.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_bash_commands.xml b/app/src/main/res/drawable/ic_bash_commands.xml new file mode 100644 index 000000000..8cb0d4955 --- /dev/null +++ b/app/src/main/res/drawable/ic_bash_commands.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_build_output.xml b/app/src/main/res/drawable/ic_build_output.xml new file mode 100644 index 000000000..a840807ed --- /dev/null +++ b/app/src/main/res/drawable/ic_build_output.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_bundle.xml b/app/src/main/res/drawable/ic_bundle.xml new file mode 100644 index 000000000..984fefa42 --- /dev/null +++ b/app/src/main/res/drawable/ic_bundle.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_chevron_down.xml b/app/src/main/res/drawable/ic_chevron_down.xml new file mode 100644 index 000000000..5d8b5147a --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_down.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_chevron_left.xml b/app/src/main/res/drawable/ic_chevron_left.xml new file mode 100644 index 000000000..e2bac3191 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_left.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_chevron_right.xml b/app/src/main/res/drawable/ic_chevron_right.xml new file mode 100644 index 000000000..dde77d9d9 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_chevron_up.xml b/app/src/main/res/drawable/ic_chevron_up.xml new file mode 100644 index 000000000..fed4a7686 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_up.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_clean.xml b/app/src/main/res/drawable/ic_clean.xml new file mode 100644 index 000000000..c4a322e4a --- /dev/null +++ b/app/src/main/res/drawable/ic_clean.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 000000000..df8b489e5 --- /dev/null +++ b/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_close_all.xml b/app/src/main/res/drawable/ic_close_all.xml new file mode 100644 index 000000000..c7aa4fbe1 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_all.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_close_others.xml b/app/src/main/res/drawable/ic_close_others.xml new file mode 100644 index 000000000..bcfc74c41 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_others.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_close_this.xml b/app/src/main/res/drawable/ic_close_this.xml new file mode 100644 index 000000000..c83a69f66 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_this.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_drawing.xml b/app/src/main/res/drawable/ic_drawing.xml new file mode 100644 index 000000000..7b90fc25a --- /dev/null +++ b/app/src/main/res/drawable/ic_drawing.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_edit_properties.xml b/app/src/main/res/drawable/ic_edit_properties.xml new file mode 100644 index 000000000..a63f0ba02 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_properties.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_error.xml b/app/src/main/res/drawable/ic_error.xml new file mode 100644 index 000000000..09402fa79 --- /dev/null +++ b/app/src/main/res/drawable/ic_error.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_file_copy_path.xml b/app/src/main/res/drawable/ic_file_copy_path.xml new file mode 100644 index 000000000..23ce17bb4 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_copy_path.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_delete.xml b/app/src/main/res/drawable/ic_file_delete.xml new file mode 100644 index 000000000..613cbc3a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_delete.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_info.xml b/app/src/main/res/drawable/ic_file_info.xml new file mode 100644 index 000000000..66773f0fb --- /dev/null +++ b/app/src/main/res/drawable/ic_file_info.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_rename.xml b/app/src/main/res/drawable/ic_file_rename.xml new file mode 100644 index 000000000..5629e285c --- /dev/null +++ b/app/src/main/res/drawable/ic_file_rename.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_unknown.xml b/app/src/main/res/drawable/ic_file_unknown.xml new file mode 100644 index 000000000..bf2460d1b --- /dev/null +++ b/app/src/main/res/drawable/ic_file_unknown.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_filetype_activity.xml b/app/src/main/res/drawable/ic_filetype_activity.xml new file mode 100644 index 000000000..43b1cd9a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_filetype_activity.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_filetype_enum.xml b/app/src/main/res/drawable/ic_filetype_enum.xml new file mode 100644 index 000000000..fbbdcc459 --- /dev/null +++ b/app/src/main/res/drawable/ic_filetype_enum.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_filetype_interface.xml b/app/src/main/res/drawable/ic_filetype_interface.xml new file mode 100644 index 000000000..e60b0df80 --- /dev/null +++ b/app/src/main/res/drawable/ic_filetype_interface.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_folder.xml b/app/src/main/res/drawable/ic_folder.xml new file mode 100644 index 000000000..ac60509e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml new file mode 100644 index 000000000..7b898d20a --- /dev/null +++ b/app/src/main/res/drawable/ic_help.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_hexadecimal.xml b/app/src/main/res/drawable/ic_hexadecimal.xml new file mode 100644 index 000000000..0889d6d78 --- /dev/null +++ b/app/src/main/res/drawable/ic_hexadecimal.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml new file mode 100644 index 000000000..66773f0fb --- /dev/null +++ b/app/src/main/res/drawable/ic_info.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_install.xml b/app/src/main/res/drawable/ic_install.xml new file mode 100644 index 000000000..dff50ed0b --- /dev/null +++ b/app/src/main/res/drawable/ic_install.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_gradle.xml b/app/src/main/res/drawable/ic_language_gradle.xml new file mode 100644 index 000000000..a6c24b57b --- /dev/null +++ b/app/src/main/res/drawable/ic_language_gradle.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_java.xml b/app/src/main/res/drawable/ic_language_java.xml new file mode 100644 index 000000000..3df377479 --- /dev/null +++ b/app/src/main/res/drawable/ic_language_java.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_json.xml b/app/src/main/res/drawable/ic_language_json.xml new file mode 100644 index 000000000..6791c9f87 --- /dev/null +++ b/app/src/main/res/drawable/ic_language_json.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_kotlin.xml b/app/src/main/res/drawable/ic_language_kotlin.xml new file mode 100644 index 000000000..d82087271 --- /dev/null +++ b/app/src/main/res/drawable/ic_language_kotlin.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_language_xml.xml b/app/src/main/res/drawable/ic_language_xml.xml new file mode 100644 index 000000000..adb411f2c --- /dev/null +++ b/app/src/main/res/drawable/ic_language_xml.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_lint.xml b/app/src/main/res/drawable/ic_lint.xml new file mode 100644 index 000000000..2a0a6efc1 --- /dev/null +++ b/app/src/main/res/drawable/ic_lint.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_log.xml b/app/src/main/res/drawable/ic_log.xml new file mode 100644 index 000000000..76ce5b7a2 --- /dev/null +++ b/app/src/main/res/drawable/ic_log.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_min_sdk.xml b/app/src/main/res/drawable/ic_min_sdk.xml new file mode 100644 index 000000000..05058c6c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_min_sdk.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_new_file.xml b/app/src/main/res/drawable/ic_new_file.xml new file mode 100644 index 000000000..4923032da --- /dev/null +++ b/app/src/main/res/drawable/ic_new_file.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_new_folder.xml b/app/src/main/res/drawable/ic_new_folder.xml new file mode 100644 index 000000000..7443727a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_new_folder.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_ok.xml b/app/src/main/res/drawable/ic_ok.xml new file mode 100644 index 000000000..09883f1d5 --- /dev/null +++ b/app/src/main/res/drawable/ic_ok.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_package.xml b/app/src/main/res/drawable/ic_package.xml new file mode 100644 index 000000000..984fefa42 --- /dev/null +++ b/app/src/main/res/drawable/ic_package.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_rebuild.xml b/app/src/main/res/drawable/ic_rebuild.xml new file mode 100644 index 000000000..c87311fbf --- /dev/null +++ b/app/src/main/res/drawable/ic_rebuild.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_recreate.xml b/app/src/main/res/drawable/ic_recreate.xml new file mode 100644 index 000000000..f2d7d61c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_recreate.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_redo.xml b/app/src/main/res/drawable/ic_redo.xml new file mode 100644 index 000000000..381f0fc4a --- /dev/null +++ b/app/src/main/res/drawable/ic_redo.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_run.xml b/app/src/main/res/drawable/ic_run.xml new file mode 100644 index 000000000..eb0a107e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_run.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/drawable/ic_run_debug.xml b/app/src/main/res/drawable/ic_run_debug.xml new file mode 100644 index 000000000..9e7449128 --- /dev/null +++ b/app/src/main/res/drawable/ic_run_debug.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_run_outline.xml b/app/src/main/res/drawable/ic_run_outline.xml new file mode 100644 index 000000000..feb3e3672 --- /dev/null +++ b/app/src/main/res/drawable/ic_run_outline.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_run_release.xml b/app/src/main/res/drawable/ic_run_release.xml new file mode 100644 index 000000000..7754d4d6e --- /dev/null +++ b/app/src/main/res/drawable/ic_run_release.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_save.xml b/app/src/main/res/drawable/ic_save.xml new file mode 100644 index 000000000..166dd6e6b --- /dev/null +++ b/app/src/main/res/drawable/ic_save.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..bc5fd887a --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..4f1446be1 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_stop_daemons.xml b/app/src/main/res/drawable/ic_stop_daemons.xml new file mode 100644 index 000000000..b8cdb470c --- /dev/null +++ b/app/src/main/res/drawable/ic_stop_daemons.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_suggest.xml b/app/src/main/res/drawable/ic_suggest.xml new file mode 100644 index 000000000..358e37fa4 --- /dev/null +++ b/app/src/main/res/drawable/ic_suggest.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_sync.xml b/app/src/main/res/drawable/ic_sync.xml new file mode 100644 index 000000000..707f42f66 --- /dev/null +++ b/app/src/main/res/drawable/ic_sync.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_target_sdk.xml b/app/src/main/res/drawable/ic_target_sdk.xml new file mode 100644 index 000000000..3df5e1f3e --- /dev/null +++ b/app/src/main/res/drawable/ic_target_sdk.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_telegram.xml b/app/src/main/res/drawable/ic_telegram.xml new file mode 100644 index 000000000..8b5b8e770 --- /dev/null +++ b/app/src/main/res/drawable/ic_telegram.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_text_size.xml b/app/src/main/res/drawable/ic_text_size.xml new file mode 100644 index 000000000..a260f895b --- /dev/null +++ b/app/src/main/res/drawable/ic_text_size.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_undo.xml b/app/src/main/res/drawable/ic_undo.xml new file mode 100644 index 000000000..102999c3d --- /dev/null +++ b/app/src/main/res/drawable/ic_undo.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_view.xml b/app/src/main/res/drawable/ic_view.xml new file mode 100644 index 000000000..4feab3b2a --- /dev/null +++ b/app/src/main/res/drawable/ic_view.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_zip.xml b/app/src/main/res/drawable/ic_zip.xml new file mode 100644 index 000000000..5fa7fdbcf --- /dev/null +++ b/app/src/main/res/drawable/ic_zip.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/font/quicksand.ttf b/app/src/main/res/font/quicksand.ttf new file mode 100644 index 000000000..edfa93f21 Binary files /dev/null and b/app/src/main/res/font/quicksand.ttf differ diff --git a/app/src/main/res/layout/activity_download.xml b/app/src/main/res/layout/activity_download.xml new file mode 100644 index 000000000..70b719b63 --- /dev/null +++ b/app/src/main/res/layout/activity_download.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml new file mode 100644 index 000000000..b6198bfaf --- /dev/null +++ b/app/src/main/res/layout/activity_editor.xml @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..1dd4f10fc --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml new file mode 100644 index 000000000..337a54fe1 --- /dev/null +++ b/app/src/main/res/layout/activity_preferences.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 000000000..b5fe32a68 --- /dev/null +++ b/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_editor.xml b/app/src/main/res/layout/fragment_editor.xml new file mode 100644 index 000000000..1a0125be3 --- /dev/null +++ b/app/src/main/res/layout/fragment_editor.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/layout/layout_banner.xml b/app/src/main/res/layout/layout_banner.xml new file mode 100644 index 000000000..4f433b755 --- /dev/null +++ b/app/src/main/res/layout/layout_banner.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_completion_item.xml b/app/src/main/res/layout/layout_completion_item.xml new file mode 100644 index 000000000..46bb0af2d --- /dev/null +++ b/app/src/main/res/layout/layout_completion_item.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_create_file_java.xml b/app/src/main/res/layout/layout_create_file_java.xml new file mode 100644 index 000000000..19b0e0b85 --- /dev/null +++ b/app/src/main/res/layout/layout_create_file_java.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_create_project.xml b/app/src/main/res/layout/layout_create_project.xml new file mode 100644 index 000000000..b76fa5f6f --- /dev/null +++ b/app/src/main/res/layout/layout_create_project.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_create_project_content.xml b/app/src/main/res/layout/layout_create_project_content.xml new file mode 100644 index 000000000..8847274db --- /dev/null +++ b/app/src/main/res/layout/layout_create_project_content.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +