├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── kotlin │ ├── Ani.kt │ ├── Test.kt │ ├── com │ └── liam │ │ ├── ast │ │ ├── psi │ │ │ ├── Converter.kt │ │ │ ├── Node.kt │ │ │ └── Parser.kt │ │ ├── tokenizer │ │ │ ├── KotlinTokenizer.kt │ │ │ ├── Token.kt │ │ │ └── Tokenizer.kt │ │ └── writer │ │ │ ├── Handler.kt │ │ │ ├── LanguageWriter.kt │ │ │ ├── Statement.kt │ │ │ ├── SwiftWriter.kt │ │ │ └── swift │ │ │ ├── FileHandler.kt │ │ │ ├── ModifierWriteHandler.kt │ │ │ ├── decl │ │ │ ├── BlockHandler.kt │ │ │ ├── ClassHandler.kt │ │ │ ├── StructuredHandler.kt │ │ │ └── func │ │ │ │ ├── FuncHandler.kt │ │ │ │ └── FuncParamHandler.kt │ │ │ ├── exp │ │ │ ├── CallHandler.kt │ │ │ ├── ConstHandler.kt │ │ │ ├── NameHandler.kt │ │ │ ├── OperHandler.kt │ │ │ ├── ReturnHandler.kt │ │ │ ├── StringTmplHandler.kt │ │ │ ├── ThisHandler.kt │ │ │ ├── UnaryOpHandler.kt │ │ │ ├── ValueArgHandler.kt │ │ │ ├── binary │ │ │ │ ├── BinaryInfixHandler.kt │ │ │ │ ├── BinaryOpHandler.kt │ │ │ │ └── BinaryTokenHandler.kt │ │ │ └── control │ │ │ │ ├── IFHandler.kt │ │ │ │ └── WhenHandler.kt │ │ │ ├── property │ │ │ ├── PropertyHandler.kt │ │ │ └── PropertyVarHandler.kt │ │ │ └── type │ │ │ ├── NullableHandler.kt │ │ │ ├── PieceHandler.kt │ │ │ ├── TypeHandler.kt │ │ │ ├── TypeOPOper.kt │ │ │ └── TypeParamHandler.kt │ │ ├── gen │ │ ├── SwiftCodeGen.kt │ │ └── swift │ │ │ ├── CodeGen.kt │ │ │ ├── FileCodeGen.kt │ │ │ ├── Logger.kt │ │ │ ├── TypeUtils.kt │ │ │ ├── expr │ │ │ ├── BinaryExpression.kt │ │ │ ├── BinaryWithTypeRHS.kt │ │ │ ├── BlockExpression.kt │ │ │ ├── CallExpression.kt │ │ │ ├── ConstantExpression.kt │ │ │ ├── Expr.kt │ │ │ ├── ForExpression.kt │ │ │ ├── IFExpression.kt │ │ │ ├── INExpression.kt │ │ │ ├── NameRefExpression.kt │ │ │ ├── QualifiedExpression.kt │ │ │ ├── ReturnExpression.kt │ │ │ ├── StringTemplateExpression.kt │ │ │ ├── ThisExpression.kt │ │ │ ├── WhenExpression.kt │ │ │ └── WhileExpression.kt │ │ │ ├── func │ │ │ └── Func.kt │ │ │ ├── oper │ │ │ └── Oper.kt │ │ │ ├── property │ │ │ └── Property.kt │ │ │ ├── scope │ │ │ ├── ClassDiscoverer.kt │ │ │ ├── Discoverer.kt │ │ │ ├── FileDiscoverer.kt │ │ │ └── Scope.kt │ │ │ └── structed │ │ │ └── Class.kt │ │ └── uitls │ │ ├── PackageUtils.kt │ │ └── SourceFileWatch.kt │ ├── main.kt │ └── main2.kt └── test └── kotlin └── com └── liam └── test ├── GenTest.kt ├── basic ├── ControlFlow.kt ├── Functions.kt └── Type.kt └── collections └── In.kt /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /.gradle/ 3 | /build/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin2Swift 2 | Kotlin 转换成 Swift 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.72' 3 | } 4 | plugins { 5 | id 'java' 6 | id 'org.jetbrains.kotlin.jvm' version '1.3.72' 7 | } 8 | 9 | group 'org.example' 10 | version '1.0-SNAPSHOT' 11 | 12 | repositories { 13 | mavenCentral() 14 | maven { url 'https://jitpack.io'} 15 | } 16 | 17 | dependencies { 18 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 19 | // implementation "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin_version" 20 | implementation "org.jetbrains.kotlin:kotlin-compiler:$kotlin_version" 21 | // implementation 'com.github.drieks:antlr-kotlin:9fde270e3a' 22 | // compile 'com.github.cretz.kastree:kastree-ast-jvm:0.4.0' 23 | // compile 'com.github.cretz.kastree:kastree-ast-psi:0.4.0' 24 | // compile 'com.github.cretz.kastree:kastree-ast-common:0.4.0' 25 | compile 'com.alibaba:fastjson:1.2.70' 26 | testCompile group: 'junit', name: 'junit', version: '4.12' 27 | } 28 | 29 | compileKotlin { 30 | kotlinOptions.jvmTarget = "1.8" 31 | } 32 | compileTestKotlin { 33 | kotlinOptions.jvmTarget = "1.8" 34 | } 35 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Kotlin2Swift' 2 | enableFeaturePreview("GRADLE_METADATA") 3 | -------------------------------------------------------------------------------- /src/main/kotlin/Ani.kt: -------------------------------------------------------------------------------- 1 | import java.lang.annotation.ElementType 2 | 3 | /** 4 | * @author liaomin 5 | * @date 6/18/20 11:04 上午 6 | * @version 1.0 7 | */ 8 | 9 | annotation class Ani 10 | -------------------------------------------------------------------------------- /src/main/kotlin/Test.kt: -------------------------------------------------------------------------------- 1 | 2 | import java.util.* 3 | 4 | fun TE(int: Int = 1,string: String):Int{ 5 | val intw = 1 6 | val ww= intw 7 | return ww 8 | } 9 | 10 | 11 | // 12 | //class Te(int: Int){ 13 | // 14 | // constructor(r:String):this(1){ 15 | // 16 | // } 17 | // 18 | // constructor(r:String,int: Int):this(r){ 19 | // fun Te.e(){ 20 | // 21 | // } 22 | // this.e() 23 | // } 24 | //} 25 | // 26 | //fun Te.e(){ 27 | // 28 | //} 29 | // 30 | //fun q(){ 31 | // val e = Te(1) 32 | // e.e() 33 | //} 34 | // 35 | // 36 | //val qwe2:Int = 1 37 | //// set(value) = 38 | //val qwe:Te? = Te(int=2) 39 | 40 | //val q = if (true){1} else 2 41 | //val oneLong = 1L 42 | ////@Ani() 43 | //private var dqwd:Long = 12L 44 | ////TODO bug 45 | //val dq = dqwd-- + ++dqwd + dqwd 46 | //val dq2 = 2 + 2 47 | // 48 | //val oneMillion = 1_000_000 49 | //val creditCardNumber = 1234_5678_9012_3456L 50 | //val socialSecurityNumber = 999_99_9999L 51 | //val hexBytes = 0xFF_EC_DE_5E 52 | // 53 | //fun ft(x:Any) = when(x){ 54 | // is Int ->true 55 | // else -> false 56 | //} 57 | //val bytes = 0b11010010_01101001_10010100_10010010 58 | // 59 | //class A1{} 60 | // 61 | //private class Test { 62 | // var a1:Int = 0 63 | // 64 | // 65 | // private fun test(a:Int):T{ 66 | // this.a1=2 67 | // var q1:Int? = 1 68 | // val q = 1 as? T? 69 | // val q3 = if (true){1} else 2 70 | // return 1 as T 71 | // } 72 | // 73 | // private class Test2 { 74 | // var A2:Int = 0 75 | // 76 | // 77 | // private fun tes22222t(a:Int):T{ 78 | // this.A2=2 79 | // var q1:Int? = 1 80 | // val q = 1 as? T? 81 | // val qwef = fun (){ 82 | // var q221:Int? = 1 83 | // } 84 | // val q3 = if (true){1} else 2 85 | // return q3 as T 86 | // } 87 | // } 88 | //} 89 | 90 | //fun MutableList.swap(index1: Int, index2: Int):T { 91 | // val tmp = this[index1] 92 | // this[index1] = this[index2] 93 | // this[index2] = tmp 94 | // return 1 as T 95 | //} 96 | 97 | //private enum class A1 { 98 | // DW, 99 | // DW2, 100 | //} 101 | 102 | //private enum class A(val int:Int){ 103 | // DW(1), 104 | // DW2(2), 105 | //} 106 | // 107 | // 108 | //class QE(a:String) { 109 | // constructor(a:Int):this(""){ 110 | // A.DW.ordinal 111 | // } 112 | //} 113 | 114 | // 115 | //fun t1(block:(()->Unit)? = null){ 116 | // block?.invoke() 117 | //} 118 | // 119 | //fun t2() = t1{} 120 | // 121 | //open class B{ 122 | // fun t(){} 123 | //} 124 | // 125 | // 126 | //@Ani 127 | //class Test:B { 128 | // var q2:Int = 1 129 | // set(value) { 130 | // var d:B? = B() 131 | //// d!!.t() 132 | // if(value > 0 && field > 0){ 133 | // field = value 134 | // }else{ 135 | // field = 0 136 | // } 137 | // } 138 | // @Ani 139 | // get() { 140 | // return field 141 | // } 142 | // 143 | // constructor():super(){ 144 | // @Ani var dw = 1 145 | // } 146 | // 147 | // constructor(int :Int):super(){ 148 | // 149 | // } 150 | // 151 | // @Ani 152 | // private var int = 1 153 | // 154 | // val string:String = "" 155 | // 156 | //} 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/psi/Converter.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.psi 2 | 3 | import com.intellij.lang.ASTNode 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiWhiteSpace 6 | import org.jetbrains.kotlin.KtNodeTypes 7 | 8 | import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget 9 | import org.jetbrains.kotlin.lexer.KtTokens 10 | import org.jetbrains.kotlin.psi.* 11 | import org.jetbrains.kotlin.psi.psiUtil.* 12 | 13 | 14 | /** 15 | * @author liaomin 16 | * @date 6/19/20 12:21 上午 17 | * @version 1.0 18 | */ 19 | open class Converter { 20 | protected open fun onNode(node: Node, elem: PsiElement) { } 21 | 22 | open fun convertAnnotated(v: KtAnnotatedExpression) = Node.Expr.Annotated( 23 | anns = convertAnnotationSets(v), 24 | expr = convertExpr(v.baseExpression ?: error("No annotated expr for $v")) 25 | ).map(v).let { 26 | // As a special case, instead of annotating a type/binary op, we mean to just annotate its lhs 27 | val expr = it.expr 28 | when (expr) { 29 | is Node.Expr.BinaryOp -> expr.copy( 30 | lhs = it.copy(expr = expr.lhs) 31 | ) 32 | is Node.Expr.TypeOp -> expr.copy( 33 | lhs = it.copy(expr = expr.lhs) 34 | ) 35 | else -> it 36 | } 37 | } 38 | 39 | open fun convertAnnotation(v: KtAnnotationEntry) = Node.Modifier.AnnotationSet.Annotation( 40 | names = v.typeReference?.names ?: error("Missing annotation name"), 41 | typeArgs = v.typeArguments.map { convertType(it) ?: error("No ann typ arg for $v") }, 42 | args = convertValueArgs(v.valueArgumentList) 43 | ).map(v) 44 | 45 | open fun convertAnnotationSet(v: KtAnnotation) = Node.Modifier.AnnotationSet( 46 | target = v.useSiteTarget?.let(::convertAnnotationSetTarget), 47 | anns = v.entries.map(::convertAnnotation) 48 | ).map(v) 49 | 50 | open fun convertAnnotationSets(v: KtElement): List = v.children.flatMap { elem -> 51 | // We go over the node children because we want to preserve order 52 | when (elem) { 53 | is KtAnnotationEntry -> 54 | listOf(Node.Modifier.AnnotationSet( 55 | target = elem.useSiteTarget?.let(::convertAnnotationSetTarget), 56 | anns = listOf(convertAnnotation(elem)) 57 | ).map(elem)) 58 | is KtAnnotation -> 59 | listOf(convertAnnotationSet(elem)) 60 | is KtFileAnnotationList -> 61 | convertAnnotationSets(elem) 62 | else -> 63 | emptyList() 64 | } 65 | } 66 | 67 | open fun convertAnnotationSetTarget(v: KtAnnotationUseSiteTarget) = when (v.getAnnotationUseSiteTarget()) { 68 | AnnotationUseSiteTarget.FIELD -> Node.Modifier.AnnotationSet.Target.FIELD 69 | AnnotationUseSiteTarget.FILE -> Node.Modifier.AnnotationSet.Target.FILE 70 | AnnotationUseSiteTarget.PROPERTY -> Node.Modifier.AnnotationSet.Target.PROPERTY 71 | AnnotationUseSiteTarget.PROPERTY_GETTER -> Node.Modifier.AnnotationSet.Target.GET 72 | AnnotationUseSiteTarget.PROPERTY_SETTER -> Node.Modifier.AnnotationSet.Target.SET 73 | AnnotationUseSiteTarget.RECEIVER -> Node.Modifier.AnnotationSet.Target.RECEIVER 74 | AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> Node.Modifier.AnnotationSet.Target.PARAM 75 | AnnotationUseSiteTarget.SETTER_PARAMETER -> Node.Modifier.AnnotationSet.Target.SETPARAM 76 | AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> Node.Modifier.AnnotationSet.Target.DELEGATE 77 | } 78 | 79 | open fun convertAnonFunc(v: KtNamedFunction) = Node.Expr.AnonFunc(convertFunc(v)) 80 | 81 | open fun convertArrayAccess(v: KtArrayAccessExpression) = Node.Expr.ArrayAccess( 82 | expr = convertExpr(v.arrayExpression ?: error("No array expr for $v")), 83 | indices = v.indexExpressions.map(::convertExpr) 84 | ).map(v) 85 | 86 | open fun convertBinaryOp(v: KtBinaryExpression) = Node.Expr.BinaryOp( 87 | lhs = convertExpr(v.left ?: error("No binary lhs for $v")), 88 | oper = binaryTokensByText[v.operationReference.text].let { 89 | if (it != null) Node.Expr.BinaryOp.Oper.Token(it).map(v.operationReference) 90 | else Node.Expr.BinaryOp.Oper.Infix(v.operationReference.text).map(v.operationReference) 91 | }, 92 | rhs = convertExpr(v.right ?: error("No binary rhs for $v")) 93 | ).map(v) 94 | 95 | open fun convertBinaryOp(v: KtQualifiedExpression) = Node.Expr.BinaryOp( 96 | lhs = convertExpr(v.receiverExpression), 97 | oper = Node.Expr.BinaryOp.Oper.Token( 98 | if (v is KtDotQualifiedExpression) Node.Expr.BinaryOp.Token.DOT else Node.Expr.BinaryOp.Token.DOT_SAFE 99 | ), 100 | rhs = convertExpr(v.selectorExpression ?: error("No qualified rhs for $v")) 101 | ).map(v) 102 | 103 | open fun convertBlock(v: KtBlockExpression) = Node.Block( 104 | stmts = v.statements.map(::convertStmtNo) 105 | ).map(v) 106 | 107 | open fun convertBrace(v: KtBlockExpression) = Node.Expr.Brace( 108 | params = emptyList(), 109 | block = convertBlock(v) 110 | ).map(v) 111 | 112 | open fun convertBrace(v: KtFunctionLiteral) = Node.Expr.Brace( 113 | params = v.valueParameters.map(::convertBraceParam), 114 | block = v.bodyExpression?.let(::convertBlock) 115 | ).map(v) 116 | 117 | open fun convertBrace(v: KtLambdaExpression) = Node.Expr.Brace( 118 | params = v.valueParameters.map(::convertBraceParam), 119 | block = v.bodyExpression?.let(::convertBlock) 120 | ).map(v) 121 | 122 | open fun convertBraceParam(v: KtParameter) = Node.Expr.Brace.Param( 123 | vars = convertPropertyVars(v), 124 | destructType = if (v.destructuringDeclaration != null) v.typeReference?.let(::convertType) else null 125 | ).map(v) 126 | 127 | open fun convertBreak(v: KtBreakExpression) = Node.Expr.Break( 128 | label = v.getLabelName() 129 | ).map(v) 130 | 131 | open fun convertCall(v: KtCallExpression) = Node.Expr.Call( 132 | expr = convertExpr(v.calleeExpression ?: error("No call expr for $v")), 133 | typeArgs = v.typeArguments.map(::convertType), 134 | args = convertValueArgs(v.valueArgumentList), 135 | lambda = v.lambdaArguments.singleOrNull()?.let(::convertCallTrailLambda) 136 | ).map(v) 137 | 138 | open fun convertCallTrailLambda(v: KtLambdaArgument): Node.Expr.Call.TrailLambda { 139 | var label: String? = null 140 | var anns: List = emptyList() 141 | fun KtExpression.extractLambda(allowParens: Boolean = false): KtLambdaExpression? = when (this) { 142 | is KtLambdaExpression -> this 143 | is KtLabeledExpression -> baseExpression?.extractLambda(allowParens).also { 144 | label = getLabelName() 145 | } 146 | is KtAnnotatedExpression -> baseExpression?.extractLambda(allowParens).also { 147 | anns = convertAnnotationSets(this) 148 | } 149 | is KtParenthesizedExpression -> if (allowParens) expression?.extractLambda(allowParens) else null 150 | else -> null 151 | } 152 | val expr = v.getArgumentExpression()?.extractLambda() ?: error("No lambda for $v") 153 | return Node.Expr.Call.TrailLambda( 154 | anns = anns, 155 | label = label, 156 | func = convertBrace(expr) 157 | ).map(v) 158 | } 159 | 160 | open fun convertCollLit(v: KtCollectionLiteralExpression) = Node.Expr.CollLit( 161 | exprs = v.getInnerExpressions().map(::convertExpr) 162 | ).map(v) 163 | 164 | open fun convertConst(v: KtConstantExpression) = Node.Expr.Const( 165 | value = v.text, 166 | form = when (v.node.elementType) { 167 | KtNodeTypes.BOOLEAN_CONSTANT -> Node.Expr.Const.Form.BOOLEAN 168 | KtNodeTypes.CHARACTER_CONSTANT -> Node.Expr.Const.Form.CHAR 169 | KtNodeTypes.INTEGER_CONSTANT -> Node.Expr.Const.Form.INT 170 | KtNodeTypes.FLOAT_CONSTANT -> Node.Expr.Const.Form.FLOAT 171 | KtNodeTypes.NULL -> Node.Expr.Const.Form.NULL 172 | else -> error("Unrecognized const type for $v") 173 | } 174 | ) 175 | 176 | open fun convertConstructor(v: KtSecondaryConstructor) = Node.Decl.Constructor( 177 | mods = convertModifiers(v), 178 | params = v.valueParameters.map(::convertFuncParam), 179 | delegationCall = if (v.hasImplicitDelegationCall()) null else v.getDelegationCall().let { 180 | Node.Decl.Constructor.DelegationCall( 181 | target = 182 | if (it.isCallToThis) Node.Decl.Constructor.DelegationTarget.THIS 183 | else Node.Decl.Constructor.DelegationTarget.SUPER, 184 | args = convertValueArgs(it.valueArgumentList) 185 | ).map(it) 186 | }, 187 | block = v.bodyExpression?.let(::convertBlock) 188 | ).map(v) 189 | 190 | open fun convertContinue(v: KtContinueExpression) = Node.Expr.Continue( 191 | label = v.getLabelName() 192 | ).map(v) 193 | 194 | open fun convertDecl(v: KtDeclaration): Node.Decl = when (v) { 195 | is KtEnumEntry -> convertEnumEntry(v) 196 | is KtClassOrObject -> convertStructured(v) 197 | is KtAnonymousInitializer -> convertInit(v) 198 | is KtNamedFunction -> convertFunc(v) 199 | is KtDestructuringDeclaration -> convertProperty(v) 200 | is KtProperty -> convertProperty(v) 201 | is KtTypeAlias -> convertTypeAlias(v) 202 | is KtSecondaryConstructor -> convertConstructor(v) 203 | else -> error("Unrecognized declaration type for $v") 204 | } 205 | 206 | open fun convertDoubleColonRefCallable(v: KtCallableReferenceExpression) = Node.Expr.DoubleColonRef.Callable( 207 | recv = v.receiverExpression?.let { convertDoubleColonRefRecv(it, v.questionMarks) }, 208 | name = v.callableReference.getReferencedName() 209 | ).map(v) 210 | 211 | open fun convertDoubleColonRefClass(v: KtClassLiteralExpression) = Node.Expr.DoubleColonRef.Class( 212 | recv = v.receiverExpression?.let { convertDoubleColonRefRecv(it, v.questionMarks) } 213 | ).map(v) 214 | 215 | open fun convertDoubleColonRefRecv(v: KtExpression, questionMarks: Int): Node.Expr.DoubleColonRef.Recv = when(v) { 216 | is KtSimpleNameExpression -> Node.Expr.DoubleColonRef.Recv.Type( 217 | type = Node.TypeRef.Simple( 218 | listOf(Node.TypeRef.Simple.Piece(v.getReferencedName(), emptyList()).map(v)) 219 | ).map(v), 220 | questionMarks = questionMarks 221 | ).map(v) 222 | is KtCallExpression -> 223 | if (v.valueArgumentList == null && v.lambdaArguments.isEmpty()) 224 | Node.Expr.DoubleColonRef.Recv.Type( 225 | type = Node.TypeRef.Simple(listOf(Node.TypeRef.Simple.Piece( 226 | name = v.calleeExpression?.text ?: error("Missing text for call ref type of $v"), 227 | typeParams = convertTypeParams(v.typeArgumentList) 228 | ).map(v))).map(v), 229 | questionMarks = questionMarks 230 | ).map(v) 231 | else Node.Expr.DoubleColonRef.Recv.Expr(convertExpr(v)).map(v) 232 | is KtDotQualifiedExpression -> { 233 | val lhs = convertDoubleColonRefRecv(v.receiverExpression, questionMarks) 234 | val rhs = v.selectorExpression?.let { convertDoubleColonRefRecv(it, questionMarks) } 235 | if (lhs is Node.Expr.DoubleColonRef.Recv.Type && rhs is Node.Expr.DoubleColonRef.Recv.Type) 236 | Node.Expr.DoubleColonRef.Recv.Type( 237 | type = Node.TypeRef.Simple(lhs.type.pieces + rhs.type.pieces).map(v), 238 | questionMarks = 0 239 | ).map(v) 240 | else Node.Expr.DoubleColonRef.Recv.Expr(convertExpr(v)).map(v) 241 | } 242 | else -> Node.Expr.DoubleColonRef.Recv.Expr(convertExpr(v)).map(v) 243 | } 244 | 245 | open fun convertEnumEntry(v: KtEnumEntry) = Node.Decl.EnumEntry( 246 | mods = convertModifiers(v), 247 | name = v.name ?: error("Unnamed enum"), 248 | args = convertValueArgs((v.superTypeListEntries.firstOrNull() as? KtSuperTypeCallEntry)?.valueArgumentList), 249 | members = v.declarations.map(::convertDecl) 250 | ).map(v) 251 | 252 | open fun convertExpr(v: KtExpression): Node.Expr = when (v) { 253 | is KtIfExpression -> convertIf(v) 254 | is KtTryExpression -> convertTry(v) 255 | is KtForExpression -> convertFor(v) 256 | is KtWhileExpressionBase -> convertWhile(v) 257 | is KtBinaryExpression -> convertBinaryOp(v) 258 | is KtQualifiedExpression -> convertBinaryOp(v) 259 | is KtUnaryExpression -> convertUnaryOp(v) 260 | is KtBinaryExpressionWithTypeRHS -> convertTypeOp(v) 261 | is KtIsExpression -> convertTypeOp(v) 262 | is KtCallableReferenceExpression -> convertDoubleColonRefCallable(v) 263 | is KtClassLiteralExpression -> convertDoubleColonRefClass(v) 264 | is KtParenthesizedExpression -> convertParen(v) 265 | is KtStringTemplateExpression -> convertStringTmpl(v) 266 | is KtConstantExpression -> convertConst(v) 267 | is KtBlockExpression -> convertBrace(v) 268 | is KtFunctionLiteral -> convertBrace(v) 269 | is KtLambdaExpression -> convertBrace(v) 270 | is KtThisExpression -> convertThis(v) 271 | is KtSuperExpression -> convertSuper(v) 272 | is KtWhenExpression -> convertWhen(v) 273 | is KtObjectLiteralExpression -> convertObject(v) 274 | is KtThrowExpression -> convertThrow(v) 275 | is KtReturnExpression -> convertReturn(v) 276 | is KtContinueExpression -> convertContinue(v) 277 | is KtBreakExpression -> convertBreak(v) 278 | is KtCollectionLiteralExpression -> convertCollLit(v) 279 | is KtSimpleNameExpression -> convertName(v) 280 | is KtLabeledExpression -> convertLabeled(v) 281 | is KtAnnotatedExpression -> convertAnnotated(v) 282 | is KtCallExpression -> convertCall(v) 283 | is KtArrayAccessExpression -> convertArrayAccess(v) 284 | is KtNamedFunction -> convertAnonFunc(v) 285 | is KtProperty -> convertPropertyExpr(v) 286 | is KtDestructuringDeclaration -> convertPropertyExpr(v) 287 | // TODO: this is present in a recovery test where an interface decl is on rhs of a gt expr 288 | is KtClass -> throw Unsupported("Class expressions not supported") 289 | else -> error("Unrecognized expression type from $v") 290 | } 291 | 292 | open fun convertFile(v: KtFile) = Node.File( 293 | anns = convertAnnotationSets(v), 294 | pkg = v.packageDirective?.takeIf { it.packageNames.isNotEmpty() }?.let(::convertPackage), 295 | imports = v.importDirectives.map(::convertImport), 296 | decls = v.declarations.map(::convertDecl) 297 | ).map(v) 298 | 299 | open fun convertFor(v: KtForExpression) = Node.Expr.For( 300 | anns = v.loopParameter?.annotations?.map(::convertAnnotationSet) ?: emptyList(), 301 | vars = convertPropertyVars(v.loopParameter ?: error("No param on for $v")), 302 | inExpr = convertExpr(v.loopRange ?: error("No in range for $v")), 303 | body = convertExpr(v.body ?: error("No body for $v")) 304 | ).map(v) 305 | 306 | open fun convertFunc(v: KtNamedFunction) = Node.Decl.Func( 307 | mods = convertModifiers(v), 308 | typeParams = 309 | if (v.hasTypeParameterListBeforeFunctionName()) v.typeParameters.map(::convertTypeParam) else emptyList(), 310 | receiverType = v.receiverTypeReference?.let(::convertType), 311 | name = v.name, 312 | paramTypeParams = 313 | if (!v.hasTypeParameterListBeforeFunctionName()) v.typeParameters.map(::convertTypeParam) else emptyList(), 314 | params = v.valueParameters.map(::convertFuncParam), 315 | type = v.typeReference?.let(::convertType), 316 | typeConstraints = v.typeConstraints.map(::convertTypeConstraint), 317 | body = v.bodyExpression?.let(::convertFuncBody) 318 | ).map(v) 319 | 320 | open fun convertFuncBody(v: KtExpression) = 321 | if (v is KtBlockExpression) Node.Decl.Func.Body.Block(convertBlock(v)).map(v) 322 | else Node.Decl.Func.Body.Expr(convertExpr(v)).map(v) 323 | 324 | open fun convertFuncParam(v: KtParameter) = Node.Decl.Func.Param( 325 | mods = convertModifiers(v), 326 | readOnly = if (v.hasValOrVar()) !v.isMutable else null, 327 | name = v.name ?: error("No param name"), 328 | type = v.typeReference?.let(::convertType), 329 | default = v.defaultValue?.let(::convertExpr) 330 | ).map(v) 331 | 332 | open fun convertIf(v: KtIfExpression) = Node.Expr.If( 333 | expr = convertExpr(v.condition ?: error("No cond on if for $v")), 334 | body = convertExpr(v.then ?: error("No then on if for $v")), 335 | elseBody = v.`else`?.let(::convertExpr) 336 | ).map(v) 337 | 338 | open fun convertImport(v: KtImportDirective) = Node.Import( 339 | names = v.importedFqName?.pathSegments()?.map { it.asString() } ?: error("Missing import path"), 340 | wildcard = v.isAllUnder, 341 | alias = v.aliasName 342 | ).map(v) 343 | 344 | open fun convertInit(v: KtAnonymousInitializer) = Node.Decl.Init( 345 | block = convertBlock(v.body as? KtBlockExpression ?: error("No init block for $v")) 346 | ).map(v) 347 | 348 | open fun convertLabeled(v: KtLabeledExpression) = Node.Expr.Labeled( 349 | label = v.getLabelName() ?: error("No label name for $v"), 350 | expr = convertExpr(v.baseExpression ?: error("No label expr for $v")) 351 | ).map(v) 352 | 353 | open fun convertModifiers(v: KtModifierListOwner) = convertModifiers(v.modifierList) 354 | 355 | open fun convertModifiers(v: KtModifierList?) = v?.node?.children().orEmpty().mapNotNull { node -> 356 | // We go over the node children because we want to preserve order 357 | node.psi.let { 358 | when (it) { 359 | is KtAnnotationEntry -> Node.Modifier.AnnotationSet( 360 | target = it.useSiteTarget?.let(::convertAnnotationSetTarget), 361 | anns = listOf(convertAnnotation(it)) 362 | ).map(it) 363 | is KtAnnotation -> convertAnnotationSet(it) 364 | is PsiWhiteSpace -> null 365 | else -> when (node.text) { 366 | // We ignore some modifiers because we handle them elsewhere 367 | "enum", "companion" -> null 368 | else -> modifiersByText[node.text]?.let { 369 | Node.Modifier.Lit(it).let { lit -> (node.psi as? KtElement)?.let { lit.map(it) } ?: lit } 370 | } ?: error("Unrecognized modifier: ${node.text}") 371 | } 372 | } 373 | } 374 | }.toList() 375 | 376 | open fun convertName(v: KtSimpleNameExpression) = Node.Expr.Name( 377 | name = v.getReferencedName() 378 | ).map(v) 379 | 380 | open fun convertObject(v: KtObjectLiteralExpression) = Node.Expr.Object( 381 | parents = v.objectDeclaration.superTypeListEntries.map(::convertParent), 382 | members = v.objectDeclaration.declarations.map(::convertDecl) 383 | ).map(v) 384 | 385 | open fun convertPackage(v: KtPackageDirective) = Node.Package( 386 | mods = convertModifiers(v), 387 | names = v.packageNames.map { it.getReferencedName() } 388 | ).map(v) 389 | 390 | open fun convertParen(v: KtParenthesizedExpression) = Node.Expr.Paren( 391 | expr = convertExpr(v.expression ?: error("No paren expr for $v")) 392 | ) 393 | 394 | open fun convertParent(v: KtSuperTypeListEntry) = when (v) { 395 | is KtSuperTypeCallEntry -> Node.Decl.Structured.Parent.CallConstructor( 396 | type = v.typeReference?.let(::convertTypeRef) as? Node.TypeRef.Simple ?: error("Bad type on super call $v"), 397 | typeArgs = v.typeArguments.map(::convertType), 398 | args = convertValueArgs(v.valueArgumentList), 399 | // TODO 400 | lambda = null 401 | ).map(v) 402 | else -> Node.Decl.Structured.Parent.Type( 403 | type = v.typeReference?.let(::convertTypeRef) as? Node.TypeRef.Simple ?: error("Bad type on super call $v"), 404 | by = (v as? KtDelegatedSuperTypeEntry)?.delegateExpression?.let(::convertExpr) 405 | ).map(v) 406 | } 407 | 408 | open fun convertPrimaryConstructor(v: KtPrimaryConstructor) = Node.Decl.Structured.PrimaryConstructor( 409 | mods = convertModifiers(v), 410 | params = v.valueParameters.map(::convertFuncParam) 411 | ).map(v) 412 | 413 | open fun convertProperty(v: KtDestructuringDeclaration) = Node.Decl.Property( 414 | mods = convertModifiers(v), 415 | readOnly = !v.isVar, 416 | typeParams = emptyList(), 417 | receiverType = null, 418 | vars = v.entries.map(::convertPropertyVar), 419 | typeConstraints = emptyList(), 420 | delegated = false, 421 | expr = v.initializer?.let(::convertExpr), 422 | accessors = null 423 | ).map(v) 424 | 425 | open fun convertProperty(v: KtProperty) = Node.Decl.Property( 426 | mods = convertModifiers(v), 427 | readOnly = !v.isVar, 428 | typeParams = v.typeParameters.map(::convertTypeParam), 429 | receiverType = v.receiverTypeReference?.let(::convertType), 430 | vars = listOf(Node.Decl.Property.Var( 431 | name = v.name ?: error("No property name on $v"), 432 | type = v.typeReference?.let(::convertType) 433 | ).map(v)), 434 | typeConstraints = v.typeConstraints.map(::convertTypeConstraint), 435 | delegated = v.hasDelegateExpression(), 436 | expr = v.delegateExpressionOrInitializer?.let(::convertExpr), 437 | accessors = v.accessors.map(::convertPropertyAccessor).let { 438 | if (it.isEmpty()) null else Node.Decl.Property.Accessors( 439 | first = it.first(), 440 | second = it.getOrNull(1) 441 | ) 442 | } 443 | ).map(v) 444 | 445 | open fun convertPropertyAccessor(v: KtPropertyAccessor) = 446 | if (v.isGetter) Node.Decl.Property.Accessor.Get( 447 | mods = convertModifiers(v), 448 | type = v.returnTypeReference?.let(::convertType), 449 | body = v.bodyExpression?.let(::convertFuncBody) 450 | ).map(v) else Node.Decl.Property.Accessor.Set( 451 | mods = convertModifiers(v), 452 | paramMods = v.parameter?.let(::convertModifiers) ?: emptyList(), 453 | paramName = v.parameter?.name, 454 | paramType = v.parameter?.typeReference?.let(::convertType), 455 | body = v.bodyExpression?.let(::convertFuncBody) 456 | ).map(v) 457 | 458 | open fun convertPropertyExpr(v: KtDestructuringDeclaration) = Node.Expr.Property( 459 | decl = convertProperty(v) 460 | ).map(v) 461 | 462 | open fun convertPropertyExpr(v: KtProperty) = Node.Expr.Property( 463 | decl = convertProperty(v) 464 | ).map(v) 465 | 466 | open fun convertPropertyVar(v: KtDestructuringDeclarationEntry) = 467 | if (v.name == "_") null else Node.Decl.Property.Var( 468 | name = v.name ?: error("No property name on $v"), 469 | type = v.typeReference?.let(::convertType) 470 | ).map(v) 471 | 472 | open fun convertPropertyVars(v: KtParameter) = 473 | v.destructuringDeclaration?.entries?.map(::convertPropertyVar) ?: listOf( 474 | if (v.name == "_") null else Node.Decl.Property.Var( 475 | name = v.name ?: error("No property name on $v"), 476 | type = v.typeReference?.let(::convertType) 477 | ).map(v) 478 | ) 479 | 480 | open fun convertReturn(v: KtReturnExpression) = Node.Expr.Return( 481 | label = v.getLabelName(), 482 | expr = v.returnedExpression?.let(::convertExpr) 483 | ).map(v) 484 | 485 | open fun convertStmtNo(v: KtExpression) = 486 | if (v is KtDeclaration) Node.Stmt.Decl(convertDecl(v)).map(v) else Node.Stmt.Expr(convertExpr(v)).map(v) 487 | 488 | open fun convertStringTmpl(v: KtStringTemplateExpression) = Node.Expr.StringTmpl( 489 | elems = v.entries.map(::convertStringTmplElem), 490 | raw = v.text.startsWith("\"\"\"") 491 | ).map(v) 492 | 493 | open fun convertStringTmplElem(v: KtStringTemplateEntry) = when (v) { 494 | is KtLiteralStringTemplateEntry -> 495 | Node.Expr.StringTmpl.Elem.Regular(v.text).map(v) 496 | is KtSimpleNameStringTemplateEntry -> 497 | Node.Expr.StringTmpl.Elem.ShortTmpl(v.expression?.text ?: error("No short tmpl text")).map(v) 498 | is KtBlockStringTemplateEntry -> 499 | Node.Expr.StringTmpl.Elem.LongTmpl(convertExpr(v.expression ?: error("No expr tmpl"))).map(v) 500 | is KtEscapeStringTemplateEntry -> 501 | if (v.text.startsWith("\\u")) 502 | Node.Expr.StringTmpl.Elem.UnicodeEsc(v.text.substring(2)).map(v) 503 | else 504 | Node.Expr.StringTmpl.Elem.RegularEsc(v.unescapedValue.first()).map(v) 505 | else -> 506 | error("Unrecognized string template type for $v") 507 | } 508 | 509 | open fun convertStructured(v: KtClassOrObject) = Node.Decl.Structured( 510 | mods = convertModifiers(v), 511 | form = when (v) { 512 | is KtClass -> when { 513 | v.isEnum() -> Node.Decl.Structured.Form.ENUM_CLASS 514 | v.isInterface() -> Node.Decl.Structured.Form.INTERFACE 515 | else -> Node.Decl.Structured.Form.CLASS 516 | } 517 | is KtObjectDeclaration -> 518 | if (v.isCompanion()) Node.Decl.Structured.Form.COMPANION_OBJECT 519 | else Node.Decl.Structured.Form.OBJECT 520 | else -> error("Unknown type of $v") 521 | }, 522 | name = v.name ?: error("Missing name"), 523 | typeParams = v.typeParameters.map(::convertTypeParam), 524 | primaryConstructor = v.primaryConstructor?.let(::convertPrimaryConstructor), 525 | // TODO: this 526 | parentAnns = emptyList(), 527 | parents = v.superTypeListEntries.map(::convertParent), 528 | typeConstraints = v.typeConstraints.map(::convertTypeConstraint), 529 | members = v.declarations.map(::convertDecl) 530 | ).map(v) 531 | 532 | open fun convertSuper(v: KtSuperExpression) = Node.Expr.Super( 533 | typeArg = v.superTypeQualifier?.let(::convertType), 534 | label = v.getLabelName() 535 | ).map(v) 536 | 537 | open fun convertThis(v: KtThisExpression) = Node.Expr.This( 538 | label = v.getLabelName() 539 | ).map(v) 540 | 541 | open fun convertThrow(v: KtThrowExpression) = Node.Expr.Throw( 542 | expr = convertExpr(v.thrownExpression ?: error("No throw expr for $v")) 543 | ).map(v) 544 | 545 | open fun convertTry(v: KtTryExpression) = Node.Expr.Try( 546 | block = convertBlock(v.tryBlock), 547 | catches = v.catchClauses.map(::convertTryCatch), 548 | finallyBlock = v.finallyBlock?.finalExpression?.let(::convertBlock) 549 | ).map(v) 550 | 551 | open fun convertTryCatch(v: KtCatchClause) = Node.Expr.Try.Catch( 552 | anns = v.catchParameter?.annotations?.map(::convertAnnotationSet) ?: emptyList(), 553 | varName = v.catchParameter?.name ?: error("No catch param name for $v"), 554 | varType = v.catchParameter?.typeReference?. 555 | let(::convertTypeRef) as? Node.TypeRef.Simple ?: error("Invalid catch param type for $v"), 556 | block = convertBlock(v.catchBody as? KtBlockExpression ?: error("No catch block for $v")) 557 | ).map(v) 558 | 559 | open fun convertType(v: KtTypeProjection) = 560 | v.typeReference?.let { convertType(it, v.modifierList) } 561 | 562 | open fun convertType(v: KtTypeReference, modifierList: KtModifierList?): Node.Type = Node.Type( 563 | mods = convertModifiers(modifierList), 564 | ref = convertTypeRef(v) 565 | ).map(v) 566 | 567 | open fun convertType(v: KtTypeReference): Node.Type = Node.Type( 568 | // Paren modifiers are inside the ref... 569 | mods = if (v.hasParentheses()) emptyList() else convertModifiers(v), 570 | ref = convertTypeRef(v) 571 | ).map(v) 572 | 573 | open fun convertTypeAlias(v: KtTypeAlias) = Node.Decl.TypeAlias( 574 | mods = convertModifiers(v), 575 | name = v.name ?: error("No type alias name for $v"), 576 | typeParams = v.typeParameters.map(::convertTypeParam), 577 | type = convertType(v.getTypeReference() ?: error("No type alias ref for $v")) 578 | ).map(v) 579 | 580 | open fun convertTypeConstraint(v: KtTypeConstraint) = Node.TypeConstraint( 581 | anns = v.children.mapNotNull { 582 | when (it) { 583 | is KtAnnotationEntry -> 584 | Node.Modifier.AnnotationSet(target = null, anns = listOf(convertAnnotation(it))).map(it) 585 | is KtAnnotation -> convertAnnotationSet(it) 586 | else -> null 587 | } 588 | }, 589 | name = v.subjectTypeParameterName?.getReferencedName() ?: error("No type constraint name for $v"), 590 | type = convertType(v.boundTypeReference ?: error("No type constraint type for $v")) 591 | ).map(v) 592 | 593 | open fun convertTypeOp(v: KtBinaryExpressionWithTypeRHS) = Node.Expr.TypeOp( 594 | lhs = convertExpr(v.left), 595 | oper = v.operationReference.let { 596 | Node.Expr.TypeOp.Oper(typeTokensByText[it.text] ?: error("Unable to find op ref $it")).map(it) 597 | }, 598 | rhs = convertType(v.right ?: error("No type op rhs for $v")) 599 | ).map(v) 600 | 601 | open fun convertTypeOp(v: KtIsExpression) = Node.Expr.TypeOp( 602 | lhs = convertExpr(v.leftHandSide), 603 | oper = v.operationReference.let { 604 | Node.Expr.TypeOp.Oper(typeTokensByText[it.text] ?: error("Unable to find op ref $it")).map(it) 605 | }, 606 | rhs = convertType(v.typeReference ?: error("No type op rhs for $v")) 607 | ) 608 | 609 | open fun convertTypeParam(v: KtTypeParameter) = Node.TypeParam( 610 | mods = convertModifiers(v), 611 | name = v.name ?: error("No type param name for $v"), 612 | type = v.extendsBound?.let(::convertTypeRef) 613 | ).map(v) 614 | 615 | open fun convertTypeParams(v: KtTypeArgumentList?) = v?.arguments?.map { 616 | if (it.projectionKind == KtProjectionKind.STAR) null 617 | else convertType(it) 618 | } ?: emptyList() 619 | 620 | open fun convertTypeRef(v: KtTypeReference) = 621 | convertTypeRef(v.typeElement ?: error("Missing typ elem")).let { 622 | if (!v.hasParentheses()) it else Node.TypeRef.Paren( 623 | mods = convertModifiers(v), 624 | type = it 625 | ).map(v) 626 | } 627 | 628 | open fun convertTypeRef(v: KtTypeElement): Node.TypeRef = when (v) { 629 | is KtFunctionType -> Node.TypeRef.Func( 630 | receiverType = v.receiverTypeReference?.let(::convertType), 631 | params = v.parameters.map { 632 | Node.TypeRef.Func.Param( 633 | name = it.name, 634 | type = convertType(it.typeReference ?: error("No param type")) 635 | ).map(it) 636 | }, 637 | type = convertType(v.returnTypeReference ?: error("No return type")) 638 | ).map(v) 639 | is KtUserType -> Node.TypeRef.Simple( 640 | pieces = generateSequence(v) { it.qualifier }.toList().reversed().map { 641 | Node.TypeRef.Simple.Piece( 642 | name = it.referencedName ?: error("No type name for $it"), 643 | typeParams = convertTypeParams(it.typeArgumentList) 644 | ).map(it) 645 | } 646 | ).map(v) 647 | is KtNullableType -> Node.TypeRef.Nullable( 648 | // If there are modifiers or the inner type is a function, the type is a paren 649 | type = convertModifiers(v.modifierList).let { mods -> 650 | val innerType = convertTypeRef(v.innerType ?: error("No inner type for nullable")) 651 | if (v.innerType !is KtFunctionType && mods.isEmpty()) innerType 652 | else Node.TypeRef.Paren(mods, convertTypeRef(v.innerType!!)) 653 | } 654 | ).map(v) 655 | is KtDynamicType -> Node.TypeRef.Dynamic().map(v) 656 | else -> error("Unrecognized type of $v") 657 | } 658 | 659 | open fun convertUnaryOp(v: KtUnaryExpression) = Node.Expr.UnaryOp( 660 | expr = convertExpr(v.baseExpression ?: error("No unary expr for $v")), 661 | oper = v.operationReference.let { 662 | Node.Expr.UnaryOp.Oper(unaryTokensByText[it.text] ?: error("Unable to find op ref $it")).map(it) 663 | }, 664 | prefix = v is KtPrefixExpression 665 | ).map(v) 666 | 667 | open fun convertValueArg(v: KtValueArgument) = Node.ValueArg( 668 | name = v.getArgumentName()?.asName?.asString(), 669 | asterisk = v.getSpreadElement() != null, 670 | expr = convertExpr(v.getArgumentExpression() ?: error("No expr for value arg")) 671 | ).map(v) 672 | 673 | open fun convertValueArgs(v: KtValueArgumentList?) = v?.arguments?.map(::convertValueArg) ?: emptyList() 674 | 675 | open fun convertWhen(v: KtWhenExpression) = Node.Expr.When( 676 | expr = v.subjectExpression?.let(::convertExpr), 677 | entries = v.entries.map(::convertWhenEntry) 678 | ).map(v) 679 | 680 | open fun convertWhenCond(v: KtWhenCondition) = when (v) { 681 | is KtWhenConditionWithExpression -> Node.Expr.When.Cond.Expr( 682 | expr = convertExpr(v.expression ?: error("No when cond expr for $v")) 683 | ).map(v) 684 | is KtWhenConditionInRange -> Node.Expr.When.Cond.In( 685 | expr = convertExpr(v.rangeExpression ?: error("No when in expr for $v")), 686 | not = v.isNegated 687 | ).map(v) 688 | is KtWhenConditionIsPattern -> Node.Expr.When.Cond.Is( 689 | type = convertType(v.typeReference ?: error("No when is type for $v")), 690 | not = v.isNegated 691 | ).map(v) 692 | else -> error("Unrecognized when cond of $v") 693 | } 694 | 695 | open fun convertWhenEntry(v: KtWhenEntry) = Node.Expr.When.Entry( 696 | conds = v.conditions.map(::convertWhenCond), 697 | body = convertExpr(v.expression ?: error("No when entry body for $v")) 698 | ).map(v) 699 | 700 | open fun convertWhile(v: KtWhileExpressionBase) = Node.Expr.While( 701 | expr = convertExpr(v.condition ?: error("No while cond for $v")), 702 | body = convertExpr(v.body ?: error("No while body for $v")), 703 | doWhile = v is KtDoWhileExpression 704 | ).map(v) 705 | 706 | protected open fun T.map(v: PsiElement) = also { 707 | it.element = v 708 | onNode(it, v) 709 | } 710 | 711 | class Unsupported(message: String) : UnsupportedOperationException(message) 712 | 713 | companion object : Converter() { 714 | internal val modifiersByText = Node.Modifier.Keyword.values().map { it.name.toLowerCase() to it }.toMap() 715 | internal val binaryTokensByText = Node.Expr.BinaryOp.Token.values().map { it.str to it }.toMap() 716 | internal val unaryTokensByText = Node.Expr.UnaryOp.Token.values().map { it.str to it }.toMap() 717 | internal val typeTokensByText = Node.Expr.TypeOp.Token.values().map { it.str to it }.toMap() 718 | 719 | internal val KtTypeReference.names get() = (typeElement as? KtUserType)?.names ?: emptyList() 720 | internal val KtUserType.names get(): List = 721 | referencedName?.let { (qualifier?.names ?: emptyList()) + it } ?: emptyList() 722 | internal val KtExpression?.block get() = (this as? KtBlockExpression)?.statements ?: emptyList() 723 | internal val KtDoubleColonExpression.questionMarks get() = 724 | generateSequence(node.firstChildNode, ASTNode::getTreeNext). 725 | takeWhile { it.elementType != KtTokens.COLONCOLON }. 726 | count { it.elementType == KtTokens.QUEST } 727 | } 728 | } 729 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/psi/Node.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.psi 2 | 3 | import com.alibaba.fastjson.annotation.JSONField 4 | import com.intellij.psi.PsiElement 5 | 6 | /** 7 | * @author liaomin 8 | * @date 6/19/20 12:23 上午 9 | * @version 1.0 10 | */ 11 | sealed class Node { 12 | var tag: Any? = null 13 | @JSONField(serialize = false) 14 | var element: PsiElement? = null 15 | var parent:Node? = null 16 | 17 | interface WithAnnotations { 18 | val anns: List 19 | } 20 | 21 | interface WithModifiers : WithAnnotations { 22 | val mods: List 23 | override val anns: List get() = mods.mapNotNull { it as? Modifier.AnnotationSet } 24 | } 25 | 26 | 27 | data class File( 28 | override val anns: List, 29 | val pkg: Package?, 30 | val imports: List, 31 | val decls: List 32 | ) : Node(), WithAnnotations 33 | 34 | data class Package( 35 | override val mods: List, 36 | val names: List 37 | ) : Node(), WithModifiers 38 | 39 | data class Import( 40 | val names: List, 41 | val wildcard: Boolean, 42 | val alias: String? 43 | ) : Node() 44 | 45 | sealed class Decl : Node() { 46 | data class Structured( 47 | override val mods: List, 48 | val form: Form, 49 | val name: String, 50 | val typeParams: List, 51 | val primaryConstructor: PrimaryConstructor?, 52 | val parentAnns: List, 53 | val parents: List, 54 | val typeConstraints: List, 55 | // TODO: Can include primary constructor 56 | val members: List 57 | ) : Decl(), WithModifiers { 58 | enum class Form { 59 | CLASS, ENUM_CLASS, INTERFACE, OBJECT, COMPANION_OBJECT 60 | } 61 | sealed class Parent : Node() { 62 | data class CallConstructor( 63 | val type: TypeRef.Simple, 64 | val typeArgs: List, 65 | val args: List, 66 | val lambda: Expr.Call.TrailLambda? 67 | ) : Parent() 68 | data class Type( 69 | val type: TypeRef.Simple, 70 | val by: Expr? 71 | ) : Parent() 72 | } 73 | data class PrimaryConstructor( 74 | override val mods: List, 75 | val params: List 76 | ) : Node(), WithModifiers 77 | } 78 | data class Init(val block: Block) : Decl() 79 | data class Func( 80 | override val mods: List, 81 | val typeParams: List, //泛型 82 | val receiverType: Type?, //扩展方法的类型 83 | // Name not present on anonymous functions 84 | val name: String?, 85 | val paramTypeParams: List, //? 86 | val params: List, 87 | val type: Type?, //返回类型 88 | val typeConstraints: List, 89 | val body: Body? 90 | ) : Decl(), WithModifiers { 91 | data class Param( 92 | override val mods: List, 93 | val readOnly: Boolean?, 94 | val name: String, 95 | // Type can be null for anon functions 96 | val type: Type?, 97 | val default: Expr? 98 | ) : Node(), WithModifiers 99 | sealed class Body : Node() { 100 | data class Block(val block: Node.Block) : Body() 101 | data class Expr(val expr: Node.Expr) : Body() 102 | } 103 | } 104 | data class Property( 105 | override val mods: List, 106 | val readOnly: Boolean, 107 | val typeParams: List, 108 | val receiverType: Type?, 109 | // Always at least one, more than one is destructuring, null is underscore in destructure 110 | val vars: List, 111 | val typeConstraints: List, 112 | val delegated: Boolean, 113 | val expr: Expr?, 114 | val accessors: Accessors? 115 | ) : Decl(), WithModifiers { 116 | data class Var( 117 | val name: String, 118 | val type: Type? 119 | ) : Node() 120 | data class Accessors( 121 | val first: Accessor, 122 | val second: Accessor? 123 | ) : Node() 124 | sealed class Accessor : Node(), WithModifiers { 125 | data class Get( 126 | override val mods: List, 127 | val type: Type?, 128 | val body: Func.Body? 129 | ) : Accessor() 130 | data class Set( 131 | override val mods: List, 132 | val paramMods: List, 133 | val paramName: String?, 134 | val paramType: Type?, 135 | val body: Func.Body? 136 | ) : Accessor() 137 | } 138 | } 139 | data class TypeAlias( 140 | override val mods: List, 141 | val name: String, 142 | val typeParams: List, 143 | val type: Type 144 | ) : Decl(), WithModifiers 145 | data class Constructor( 146 | override val mods: List, 147 | val params: List, 148 | val delegationCall: DelegationCall?, 149 | val block: Block? 150 | ) : Decl(), WithModifiers { 151 | data class DelegationCall( 152 | val target: DelegationTarget, 153 | val args: List 154 | ) : Node() 155 | enum class DelegationTarget { THIS, SUPER } 156 | } 157 | data class EnumEntry( 158 | override val mods: List, 159 | val name: String, 160 | val args: List, 161 | val members: List 162 | ) : Decl(), WithModifiers 163 | } 164 | 165 | data class TypeParam( 166 | override val mods: List, 167 | val name: String, 168 | val type: TypeRef? 169 | ) : Node(), WithModifiers 170 | 171 | data class TypeConstraint( 172 | override val anns: List, 173 | val name: String, 174 | val type: Type 175 | ) : Node(), WithAnnotations 176 | 177 | sealed class TypeRef : Node() { 178 | data class Paren( 179 | override val mods: List, 180 | val type: TypeRef 181 | ) : TypeRef(), WithModifiers 182 | data class Func( 183 | val receiverType: Type?, 184 | val params: List, 185 | val type: Type 186 | ) : TypeRef() { 187 | data class Param( 188 | val name: String?, 189 | val type: Type 190 | ) : Node() 191 | } 192 | data class Simple( 193 | val pieces: List 194 | ) : TypeRef() { 195 | data class Piece( 196 | val name: String, 197 | // Null means any 198 | val typeParams: List 199 | ) : Node() 200 | } 201 | data class Nullable(val type: TypeRef) : TypeRef() 202 | data class Dynamic(val _unused_: Boolean = false) : TypeRef() 203 | } 204 | 205 | data class Type( 206 | override val mods: List, 207 | val ref: TypeRef 208 | ) : Node(), WithModifiers 209 | 210 | data class ValueArg( 211 | val name: String?, 212 | val asterisk: Boolean, 213 | val expr: Expr 214 | ) : Node() 215 | 216 | sealed class Expr : Node() { 217 | data class If( 218 | val expr: Expr, 219 | val body: Expr, 220 | val elseBody: Expr? 221 | ) : Expr() 222 | data class Try( 223 | val block: Block, 224 | val catches: List, 225 | val finallyBlock: Block? 226 | ) : Expr() { 227 | data class Catch( 228 | override val anns: List, 229 | val varName: String, 230 | val varType: TypeRef.Simple, 231 | val block: Block 232 | ) : Node(), WithAnnotations 233 | } 234 | data class For( 235 | override val anns: List, 236 | // More than one means destructure, null means underscore 237 | val vars: List, 238 | val inExpr: Expr, 239 | val body: Expr 240 | ) : Expr(), WithAnnotations 241 | data class While( 242 | val expr: Expr, 243 | val body: Expr, 244 | val doWhile: Boolean 245 | ) : Expr() 246 | data class BinaryOp( 247 | val lhs: Expr, 248 | val oper: Oper, 249 | val rhs: Expr 250 | ) : Expr() { 251 | sealed class Oper : Node() { 252 | data class Infix(val str: String) : Oper() 253 | data class Token(val token: BinaryOp.Token) : Oper() 254 | } 255 | enum class Token(val str: String) { 256 | MUL("*"), DIV("/"), MOD("%"), ADD("+"), SUB("-"), 257 | IN("in"), NOT_IN("!in"), 258 | GT(">"), GTE(">="), LT("<"), LTE("<="), 259 | EQ("=="), NEQ("!="), 260 | ASSN("="), MUL_ASSN("*="), DIV_ASSN("/="), MOD_ASSN("%="), ADD_ASSN("+="), SUB_ASSN("-="), 261 | OR("||"), AND("&&"), ELVIS("?:"), RANGE(".."), 262 | DOT("."), DOT_SAFE("?."), SAFE("?") 263 | } 264 | } 265 | data class UnaryOp( 266 | val expr: Expr, 267 | val oper: Oper, 268 | val prefix: Boolean 269 | ) : Expr() { 270 | data class Oper(val token: Token) : Node() 271 | enum class Token(val str: String) { 272 | NEG("-"), POS("+"), INC("++"), DEC("--"), NOT("!"), NULL_DEREF("!!") 273 | } 274 | } 275 | data class TypeOp( 276 | val lhs: Expr, 277 | val oper: Oper, 278 | val rhs: Type 279 | ) : Expr() { 280 | data class Oper(val token: Token) : Node() 281 | enum class Token(val str: String) { 282 | AS("as"), AS_SAFE("as?"), COL(":"), IS("is"), NOT_IS("!is") 283 | } 284 | } 285 | sealed class DoubleColonRef : Expr() { 286 | abstract val recv: Recv? 287 | data class Callable( 288 | override val recv: Recv?, 289 | val name: String 290 | ) : DoubleColonRef() 291 | data class Class( 292 | override val recv: Recv? 293 | ) : DoubleColonRef() 294 | sealed class Recv : Node() { 295 | data class Expr(val expr: Node.Expr) : Recv() 296 | data class Type( 297 | val type: TypeRef.Simple, 298 | val questionMarks: Int 299 | ) : Recv() 300 | } 301 | } 302 | data class Paren( 303 | val expr: Expr 304 | ) : Expr() 305 | data class StringTmpl( 306 | val elems: List, 307 | val raw: Boolean 308 | ) : Expr() { 309 | sealed class Elem : Node() { 310 | data class Regular(val str: String) : Elem(){ 311 | override fun toString(): String = str 312 | } 313 | data class ShortTmpl(val str: String) : Elem(){ 314 | override fun toString(): String = str 315 | } 316 | data class UnicodeEsc(val digits: String) : Elem(){ 317 | override fun toString(): String = digits 318 | } 319 | data class RegularEsc(val char: Char) : Elem(){ 320 | override fun toString(): String = char.toString() 321 | } 322 | data class LongTmpl(val expr: Expr) : Elem() 323 | } 324 | } 325 | data class Const( 326 | val value: String, 327 | val form: Form 328 | ) : Expr() { 329 | enum class Form { BOOLEAN, CHAR, INT, FLOAT, NULL } 330 | } 331 | data class Brace( 332 | val params: List, 333 | val block: Block? 334 | ) : Expr() { 335 | data class Param( 336 | // Multiple means destructure, null means underscore 337 | val vars: List, 338 | val destructType: Type? 339 | ) : Expr() 340 | } 341 | data class This( 342 | val label: String? 343 | ) : Expr() 344 | data class Super( 345 | val typeArg: Type?, 346 | val label: String? 347 | ) : Expr() 348 | data class When( 349 | val expr: Expr?, 350 | val entries: List 351 | ) : Expr() { 352 | data class Entry( 353 | val conds: List, 354 | val body: Expr 355 | ) : Node() 356 | sealed class Cond : Node() { 357 | data class Expr(val expr: Node.Expr) : Cond() 358 | data class In( 359 | val expr: Node.Expr, 360 | val not: Boolean 361 | ) : Cond() 362 | data class Is( 363 | val type: Type, 364 | val not: Boolean 365 | ) : Cond() 366 | } 367 | } 368 | data class Object( 369 | val parents: List, 370 | val members: List 371 | ) : Expr() 372 | data class Throw( 373 | val expr: Expr 374 | ) : Expr() 375 | data class Return( 376 | val label: String?, 377 | val expr: Expr? 378 | ) : Expr() 379 | data class Continue( 380 | val label: String? 381 | ) : Expr() 382 | data class Break( 383 | val label: String? 384 | ) : Expr() 385 | data class CollLit( 386 | val exprs: List 387 | ) : Expr() 388 | data class Name( 389 | val name: String 390 | ) : Expr() 391 | data class Labeled( 392 | val label: String, 393 | val expr: Expr 394 | ) : Expr() 395 | data class Annotated( 396 | override val anns: List, 397 | val expr: Expr 398 | ) : Expr(), WithAnnotations 399 | data class Call( 400 | val expr: Expr, 401 | val typeArgs: List, 402 | val args: List, 403 | val lambda: TrailLambda? 404 | ) : Expr() { 405 | data class TrailLambda( 406 | override val anns: List, 407 | val label: String?, 408 | val func: Brace 409 | ) : Node(), WithAnnotations 410 | } 411 | data class ArrayAccess( 412 | val expr: Expr, 413 | val indices: List 414 | ) : Expr() 415 | data class AnonFunc( 416 | val func: Decl.Func 417 | ) : Expr() 418 | // This is only present for when expressions and labeled expressions 419 | data class Property( 420 | val decl: Decl.Property 421 | ) : Expr() 422 | } 423 | 424 | data class Block(val stmts: List) : Node() 425 | sealed class Stmt : Node() { 426 | data class Decl(val decl: Node.Decl) : Stmt() 427 | data class Expr(val expr: Node.Expr) : Stmt() 428 | } 429 | 430 | sealed class Modifier : Node() { 431 | data class AnnotationSet( 432 | val target: Target?, 433 | val anns: List 434 | ) : Modifier() { 435 | enum class Target { 436 | FIELD, FILE, PROPERTY, GET, SET, RECEIVER, PARAM, SETPARAM, DELEGATE 437 | } 438 | data class Annotation( 439 | val names: List, 440 | val typeArgs: List, 441 | val args: List 442 | ) : Node() 443 | } 444 | data class Lit(val keyword: Keyword) : Modifier() 445 | enum class Keyword { 446 | ABSTRACT, FINAL, OPEN, ANNOTATION, SEALED, DATA, OVERRIDE, LATEINIT, INNER, 447 | PRIVATE, PROTECTED, PUBLIC, INTERNAL, 448 | IN, OUT, NOINLINE, CROSSINLINE, VARARG, REIFIED, 449 | TAILREC, OPERATOR, INFIX, INLINE, EXTERNAL, SUSPEND, CONST, 450 | ACTUAL, EXPECT 451 | } 452 | } 453 | 454 | } 455 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/psi/Parser.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.psi 2 | 3 | import com.intellij.openapi.util.Disposer 4 | import com.intellij.psi.PsiErrorElement 5 | import com.intellij.psi.PsiManager 6 | import com.intellij.testFramework.LightVirtualFile 7 | import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles 8 | import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment 9 | import org.jetbrains.kotlin.config.CompilerConfiguration 10 | import org.jetbrains.kotlin.idea.KotlinFileType 11 | import org.jetbrains.kotlin.psi.KtFile 12 | import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType 13 | 14 | /** 15 | * @author liaomin 16 | * @date 6/19/20 12:22 上午 17 | * @version 1.0 18 | */ 19 | open class Parser(val converter: Converter = Converter) { 20 | protected val proj by lazy { 21 | KotlinCoreEnvironment.createForProduction( 22 | Disposer.newDisposable(), 23 | CompilerConfiguration(), 24 | EnvironmentConfigFiles.JVM_CONFIG_FILES 25 | ).project 26 | } 27 | 28 | fun parseFile(code: String, throwOnError: Boolean = true) = converter.convertFile(parsePsiFile(code).also { file -> 29 | if (throwOnError) file.collectDescendantsOfType().let { 30 | if (it.isNotEmpty()) throw ParseError(file, it) 31 | } 32 | }) 33 | 34 | fun parsePsiFile(code: String) = 35 | PsiManager.getInstance(proj).findFile(LightVirtualFile("temp.kt", KotlinFileType.INSTANCE, code)) as KtFile 36 | 37 | data class ParseError( 38 | val file: KtFile, 39 | val errors: List 40 | ) : IllegalArgumentException("Failed with ${errors.size} errors, first: ${errors.first().errorDescription}") 41 | 42 | companion object : Parser() { 43 | init { 44 | // To hide annoying warning on Windows 45 | System.setProperty("idea.use.native.fs.for.win", "false") 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/tokenizer/KotlinTokenizer.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.tokenizer 2 | 3 | import java.io.File 4 | import java.lang.RuntimeException 5 | 6 | /** 7 | * @author liaomin 8 | * @date 6/4/20 4:31 下午 9 | * @version 1.0 10 | */ 11 | 12 | class KotlinTokenizer : DefaultTokenizer(){ 13 | 14 | override fun getFileExtensionName(): String { 15 | return ".kt" 16 | } 17 | 18 | override fun getDelim(): String { 19 | val c:Char = '\u000C' 20 | return " \t\n\r${c}" 21 | } 22 | 23 | override fun getOperator(): String { 24 | return ":,()[]{}+-*/%=.;" 25 | } 26 | 27 | override fun onParserChar(char: Char, index: Int, code: String, sourceFile: File?): Int { 28 | if(char === '"'){ 29 | var i = index 30 | if(i < code.length - 2 && code.get(i+1) === '"' && code.get(i+2) === '"'){ 31 | if(value.isNotEmpty()) 32 | throw RuntimeException("parse error") 33 | value.append(char) 34 | var i = index + 1 35 | val startLinNumber = lineNumber 36 | var startCharNumber = charNumber 37 | charNumber++ 38 | while (i < code.length){ 39 | val c = code.get(i) 40 | if(c === '\n'){ 41 | lineNumber++ 42 | charNumber = 0 43 | } 44 | if(c === char && i > index+2 && code.get(i-1) === '"' && code.get(i-2) === '"'){ 45 | value.append(c) 46 | val v = value.toString() 47 | tokens.add(Token(v,startLinNumber,startCharNumber,false,sourceFile)) 48 | value.clear() 49 | return i 50 | }else{ 51 | i++ 52 | value.append(c) 53 | charNumber++ 54 | } 55 | } 56 | } 57 | } 58 | if(char === '\'' || char === '\"'){ 59 | if(value.isNotEmpty()) 60 | throw RuntimeException("parse error") 61 | value.append(char) 62 | var i = index + 1 63 | charNumber++ 64 | while (i < code.length){ 65 | val c = code.get(i) 66 | if(c === char){ 67 | value.append(c) 68 | tokens.add(Token(value.toString(),lineNumber,charNumber,false,sourceFile)) 69 | value.clear() 70 | return i 71 | }else{ 72 | i++ 73 | value.append(c) 74 | charNumber++ 75 | } 76 | } 77 | } 78 | return super.onParserChar(char, index, code, sourceFile) 79 | } 80 | 81 | override fun onStartParserLine(char: Char, index: Int, code: String,sourceFile: File?): Int { 82 | if(value.isNotEmpty()) 83 | throw RuntimeException("parse error") 84 | var startChar = char 85 | var startIndex = index 86 | while (startChar === ' '){ 87 | startIndex ++ 88 | charNumber ++ 89 | if(startIndex < code.length){ 90 | startChar = code.get(startIndex) 91 | }else{ 92 | return index 93 | } 94 | } 95 | val annotate = isStartAnnotate(startChar,startIndex,code) 96 | if(annotate != null){ 97 | return offsetToEndAnnotate(annotate,startIndex,code,sourceFile) 98 | } 99 | if(startChar === 'i' 100 | && code.get(startIndex+1) === 'm' 101 | && code.get(startIndex+2) === 'p' 102 | && code.get(startIndex+3) === 'o' 103 | && code.get(startIndex+4) === 'r' 104 | && code.get(startIndex+5) === 't' 105 | && code.get(startIndex+6) === ' ' 106 | ){ 107 | tokens.add(Token("import",lineNumber,startIndex,false,sourceFile)) 108 | startIndex += 7 109 | while (startIndex < code.length){ 110 | val c = code.get(startIndex) 111 | if(c == '\n'){ 112 | tokens.add(Token(value.toString().trim(),lineNumber,charNumber,false,sourceFile)) 113 | value.clear() 114 | return startIndex 115 | } 116 | startIndex++ 117 | value.append(c) 118 | } 119 | } 120 | return index 121 | } 122 | 123 | private fun isStartAnnotate(char: Char, index: Int, code: String):String?{ 124 | val length = code.length 125 | if(char === '/'){ 126 | if(index < length - 1 && code.get(index+1) === '/'){ 127 | return "//" 128 | } 129 | if(index < length - 2 && code.get(index+1) === '*' && code.get(index+1) === '*'){ 130 | return "/**" 131 | } 132 | } 133 | return null 134 | } 135 | 136 | private fun offsetToEndAnnotate(annotate: String, index: Int, code: String,sourceFile: File?):Int{ 137 | val length = code.length 138 | var startIndex = index 139 | if(annotate == "//"){ 140 | while (startIndex < length){ 141 | val c = code.get(startIndex) 142 | if(c === '\n'){ 143 | tokens.add(Token(value.toString().substring(2),lineNumber,charNumber,true,sourceFile)) 144 | value.clear() 145 | return startIndex 146 | }else{ 147 | value.append(c) 148 | } 149 | startIndex++ 150 | } 151 | } 152 | if(annotate == "/**"){ 153 | val startLineNumber = lineNumber 154 | while (startIndex < length){ 155 | val c = code.get(startIndex) 156 | if(c === '\n'){ 157 | lineNumber++ 158 | charNumber = 0 159 | } 160 | if(c === '/' && code.get(startIndex-1) === '*'){ 161 | value.append(c) 162 | val v = value.toString() 163 | tokens.add(Token(v.substring(3,v.length-2),startLineNumber,charNumber,true,sourceFile)) 164 | value.clear() 165 | return ++startIndex 166 | }else{ 167 | value.append(c) 168 | } 169 | startIndex++ 170 | } 171 | } 172 | 173 | return length 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/tokenizer/Token.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.tokenizer 2 | 3 | import java.io.File 4 | 5 | /** 6 | * @author liaomin 7 | * @date 6/3/20 5:13 下午 8 | * @version 1.0 9 | */ 10 | data class Token(val value: String,val lineNumber:Int,val charNumber:Int,val isAnnotate:Boolean,val source:File? = null) { 11 | 12 | override fun toString(): String { 13 | return value 14 | // return "$value $lineNumber $charNumber $isAnnotate" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/tokenizer/Tokenizer.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.tokenizer 2 | 3 | import java.io.File 4 | import java.io.FileReader 5 | import java.lang.RuntimeException 6 | import kotlin.collections.ArrayList 7 | import kotlin.collections.HashMap 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/3/20 5:13 下午 12 | * @version 1.0 13 | */ 14 | abstract class Tokenizer { 15 | 16 | protected val tokens:ArrayList = ArrayList() 17 | 18 | private val delimCache:HashMap 19 | private val operatorCache:HashMap 20 | 21 | init { 22 | val s = getDelim() 23 | delimCache = HashMap(s.length) 24 | val operatorString = getOperator() 25 | operatorCache = HashMap(operatorString.length) 26 | val charArray = s.toCharArray() 27 | charArray.forEach { 28 | delimCache.put(it,it) 29 | } 30 | operatorString.toCharArray().forEach { 31 | operatorCache.put(it,it) 32 | } 33 | } 34 | 35 | fun isDelim(c:Char):Boolean{ 36 | return delimCache.containsKey(c) 37 | } 38 | 39 | fun isOperator(c:Char):Boolean{ 40 | return operatorCache.containsKey(c) 41 | } 42 | 43 | fun parser(sourceFile: File):Tokenizer{ 44 | var fr:FileReader? = null 45 | try { 46 | val reader = FileReader(sourceFile) 47 | val code = reader.readText() 48 | fr = reader 49 | return parser(code,sourceFile) 50 | }finally { 51 | fr?.close() 52 | } 53 | } 54 | 55 | abstract fun parser(code: String,sourceFile: File?= null):Tokenizer 56 | 57 | open fun onParserChar(char: Char,index:Int,code: String,sourceFile: File?):Int{ 58 | return index 59 | } 60 | 61 | open fun onStartParserLine(char: Char,index:Int,code: String,sourceFile: File?= null):Int{ 62 | return index 63 | } 64 | 65 | abstract fun getDelim():String 66 | 67 | abstract fun getOperator():String 68 | 69 | abstract fun getFileExtensionName():String 70 | } 71 | 72 | abstract class DefaultTokenizer : Tokenizer() { 73 | 74 | var lineNumber = 1 75 | 76 | var charNumber = 0 77 | 78 | val value = StringBuilder() 79 | 80 | fun addToken( sourceFile: File? ){ 81 | if(value.isNotEmpty()){ 82 | val v = value.toString() 83 | tokens.add(Token(v,lineNumber,charNumber - v.length ,false,sourceFile)) 84 | value.clear() 85 | } 86 | } 87 | 88 | override fun parser(code:String, sourceFile: File?):Tokenizer { 89 | var index = 0 90 | while (index < code.length){ 91 | var char = code.get(index) 92 | if(index == 0){ 93 | var i = onStartParserLine(char,index,code,sourceFile) 94 | if(i != index){ 95 | index = i 96 | continue 97 | } 98 | } 99 | if(isOperator(char)){ 100 | addToken(sourceFile) 101 | tokens.add(Token(char.toString(),lineNumber,charNumber - 1 ,false,sourceFile)) 102 | charNumber++ 103 | index++ 104 | continue 105 | } 106 | if(isDelim(char)){ 107 | addToken(sourceFile) 108 | if(char == '\n'){ 109 | lineNumber++ 110 | charNumber = 0 111 | index++ 112 | if(index < code.length){ 113 | char = code.get(index) 114 | index = onStartParserLine(char,index,code) 115 | } 116 | continue 117 | }else{ 118 | charNumber++ 119 | } 120 | index++ 121 | continue 122 | } 123 | charNumber++ 124 | var offset = onParserChar(char,index,code,sourceFile) 125 | if(offset != index){ 126 | index = offset 127 | }else{ 128 | value.append(char) 129 | } 130 | index++ 131 | } 132 | addToken(sourceFile) 133 | return this 134 | } 135 | 136 | override fun toString(): String { 137 | val builder = StringBuilder() 138 | tokens.forEach { 139 | builder.append("$it \n") 140 | } 141 | return builder.toString() 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/Handler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer 2 | 3 | import com.liam.ast.psi.Node 4 | 5 | /** 6 | * @author liaomin 7 | * @date 6/19/20 2:13 下午 8 | * @version 1.0 9 | */ 10 | interface Handler { 11 | fun getLanguage():Language 12 | fun onHandle(writer: LanguageWriter,node: T,statement: Statement) 13 | fun getHandleClass():Class 14 | 15 | /** 16 | * @return true will interrupt chain and only call beforeHandle method 17 | */ 18 | fun interrupt(node: T,statement:Statement):Boolean 19 | 20 | companion object{ 21 | fun isHandlerClass(c:Class<*>):Boolean{ 22 | var temp:Class<*>? = c 23 | while (true){ 24 | if(temp == null){ 25 | return false 26 | } 27 | val interfaces = temp.interfaces 28 | if( interfaces.contains(Handler::class.java)){ 29 | return true 30 | } 31 | temp = temp.superclass 32 | } 33 | return false 34 | } 35 | } 36 | } 37 | 38 | abstract class SwiftHandler : Handler { 39 | override fun getLanguage(): Language = Language.SWIFT 40 | override fun interrupt(node: T,statement:Statement): Boolean = false 41 | } 42 | 43 | abstract class ObjcHandler : Handler { 44 | override fun getLanguage(): Language = Language.OBJC 45 | override fun interrupt(node: T,statement:Statement): Boolean = false 46 | } 47 | 48 | fun notSupport(): Nothing = error("not support") 49 | 50 | class HandlerChain { 51 | 52 | private val chain:ArrayList> = ArrayList() 53 | 54 | fun addHandler(handler: Handler){ 55 | chain.add(handler) 56 | } 57 | 58 | fun onHandle(writer: LanguageWriter,node: T,statement: Statement){ 59 | for (hanlder in chain){ 60 | chain.forEach { 61 | it.onHandle(writer, node, statement) 62 | } 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/LanguageWriter.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer 2 | 3 | import com.liam.ast.psi.Node 4 | import java.util.concurrent.ConcurrentHashMap 5 | 6 | 7 | /** 8 | * @author liaomin 9 | * @date 6/19/20 2:25 下午 10 | * @version 1.0 11 | */ 12 | enum class Language(val value: String){ 13 | OBJC("objc"), 14 | SWIFT("swift") 15 | } 16 | 17 | abstract class LanguageWriter{ 18 | 19 | private val handlers = ConcurrentHashMap>() 20 | 21 | open fun write(file: Node.File, statement: Statement) = onWriteNode(file,statement) 22 | 23 | abstract fun getLanguage():Language 24 | 25 | open fun onWriteNode(node: Node, statement: Statement,parent:Node? = null) { 26 | parent?.also { node.parent = it } 27 | when(node){ 28 | is Node.Decl.Func.Body.Block -> defaultWriteNode(node, statement){ 29 | onWriteNode(node.block,statement,node) 30 | } 31 | is Node.Decl.Func.Body.Expr -> defaultWriteNode(node, statement){ 32 | onWriteNode(node.expr,statement,node) 33 | } 34 | is Node.Stmt.Decl -> defaultWriteNode(node,statement){ 35 | onWriteNode(node.decl,statement,node) 36 | } 37 | is Node.Stmt.Expr -> defaultWriteNode(node,statement){ 38 | onWriteNode(node.expr,statement,node) 39 | } 40 | is Node.Expr.Brace -> defaultWriteNode(node, statement){ 41 | node.params.forEach { 42 | 43 | } 44 | node.block?.also { onWriteNode(it,statement,node) } 45 | } 46 | else -> defaultWriteNode(node, statement) 47 | } 48 | } 49 | 50 | open fun defaultWriteNode(node: Node,statement: Statement,handle:(()->Unit)? = null){ 51 | val chain = getHandlerChain(node) 52 | if(node is Node.WithModifiers){ 53 | node.mods.forEach { 54 | onWriteNode(it,statement,node) 55 | } 56 | } 57 | if(node !is Node.WithModifiers && node is Node.WithAnnotations){ 58 | node.anns.forEach { 59 | onWriteNode(it,statement,node) 60 | } 61 | } 62 | chain.onHandle(this,node, statement) 63 | handle?.invoke() 64 | } 65 | 66 | fun getHandlerChain(node: T):HandlerChain{ 67 | val k = node::class.java 68 | return handlers.computeIfAbsent(k){ 69 | HandlerChain() 70 | } as HandlerChain 71 | } 72 | 73 | fun getHandlerChain(c: Class):HandlerChain{ 74 | val k = c 75 | return handlers.computeIfAbsent(k){ 76 | HandlerChain() 77 | } as HandlerChain 78 | } 79 | 80 | fun addHandler(handler: Handler) { 81 | if(handler.getLanguage() == getLanguage()){ 82 | val c = handler.getHandleClass() 83 | val chain = getHandlerChain(c) as HandlerChain 84 | chain.addHandler(handler as Handler) 85 | }else{ 86 | error("not same language") 87 | } 88 | } 89 | 90 | } 91 | 92 | abstract class BaseLanguageWriter : LanguageWriter(){ 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/Statement.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer 2 | 3 | import java.lang.StringBuilder 4 | 5 | /** 6 | * @author liaomin 7 | * @date 6/19/20 2:51 下午 8 | * @version 1.0 9 | */ 10 | open class Statement() { 11 | 12 | val lines = ArrayList() 13 | 14 | var currentLine = Line() 15 | 16 | init { 17 | lines.add(currentLine) 18 | } 19 | 20 | private var tabCount:Int = 0 21 | 22 | fun newStatement():Statement = Statement() 23 | 24 | fun nextLine(){ 25 | currentLine = Line() 26 | lines.add(currentLine) 27 | setPreFix(currentLine) 28 | } 29 | 30 | 31 | fun setPreFix(line: Line){ 32 | if(tabCount > 0 ){ 33 | val b = StringBuilder() 34 | for (i in 0 until tabCount){ 35 | b.append("\t") 36 | } 37 | line.preFix = b.toString() 38 | } 39 | } 40 | 41 | fun append(str:CharSequence?):Statement{ 42 | if(str != null){ 43 | currentLine.append(str) 44 | } 45 | return this 46 | } 47 | 48 | fun append(statement: Statement):Statement{ 49 | statement.lines.forEachIndexed { index, line -> 50 | append(line.toString()) 51 | if(index != statement.lines.size - 1){ 52 | nextLine() 53 | } 54 | } 55 | return this 56 | } 57 | 58 | fun appendBeforeHead(str:CharSequence):Statement{ 59 | currentLine.appendBeforeHead(str) 60 | return this 61 | } 62 | 63 | fun getLineSize():Int{ 64 | return lines.size 65 | } 66 | 67 | fun openQuote(){ 68 | tabCount++ 69 | nextLine() 70 | } 71 | 72 | fun closeQuote(){ 73 | tabCount-- 74 | nextLine() 75 | } 76 | 77 | override fun toString(): String { 78 | val builder = StringBuilder() 79 | lines.forEachIndexed { index, line -> 80 | builder.append(line.toString()) 81 | if(index != lines.size - 1){ 82 | builder.append("\n") 83 | } 84 | } 85 | return builder.toString() 86 | } 87 | 88 | open class Line{ 89 | val nodes = ArrayList() 90 | var preFix:String? = null 91 | 92 | fun appendBeforeHead(str:CharSequence){ 93 | nodes.add(0,str) 94 | } 95 | 96 | fun append(str: CharSequence){ 97 | nodes.add(str) 98 | } 99 | 100 | override fun toString(): String { 101 | val builder = StringBuilder() 102 | if(preFix != null) builder.append(preFix) 103 | nodes.forEach { 104 | builder.append(it) 105 | } 106 | return builder.toString() 107 | } 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/SwiftWriter.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.uitls.PackageUtils 5 | 6 | /** 7 | * @author liaomin 8 | * @date 6/19/20 2:04 下午 9 | * @version 1.0 10 | */ 11 | open class SwiftWriter : BaseLanguageWriter { 12 | 13 | val imports = ArrayList() 14 | 15 | constructor():super(){ 16 | PackageUtils.getClassesInPackage("com.liam.ast.writer.swift") 17 | .filter { Handler.isHandlerClass(it) } 18 | .forEach { try { 19 | addHandler(it.newInstance() as Handler) 20 | }catch (e:Exception){ 21 | e.printStackTrace() 22 | } } 23 | } 24 | 25 | override fun write(file: Node.File, statement: Statement) { 26 | imports.clear() 27 | super.write(file, statement) 28 | } 29 | 30 | // override fun onWriteImport(node: Node.Import, statement: Statement) { 31 | // if(node.names.size > 0){ 32 | // var path:String? = null 33 | // if(node.wildcard){ 34 | // path = node.names.last() 35 | // }else if(node.names.size > 1){ 36 | // path = node.names[node.names.size - 2] 37 | // } 38 | // path?.also { 39 | // if(!imports.contains(it)){ 40 | // imports.add(it) 41 | // statement.append("import $it\n") 42 | // } 43 | // } 44 | // } 45 | // } 46 | 47 | 48 | // override fun joinPropertyVarAndExpr(node: Node.Decl.Property, statement: Statement) { 49 | // statement.append(" = ") 50 | // } 51 | 52 | 53 | // override fun onWriteTypeNullable(node: Node.TypeRef.Nullable, statement: Statement) { 54 | // super.onWriteTypeNullable(node, statement) 55 | // statement.append("?") 56 | // } 57 | // 58 | 59 | 60 | // override fun onWriteExpConst(node: Node.Expr.Const, statement: Statement) { 61 | // val from = node.form 62 | // when(from){ 63 | // Node.Expr.Const.Form.NULL -> statement.append("nil") 64 | // Node.Expr.Const.Form.INT -> { 65 | // var v = node.value 66 | // if(v.endsWith("L")){ 67 | // statement.append(v.subSequence(0,v.length-1)) 68 | // }else{ 69 | // statement.append(v) 70 | // } 71 | // } 72 | // } 73 | // } 74 | 75 | override fun getLanguage(): Language = Language.SWIFT 76 | 77 | companion object : SwiftWriter() 78 | 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/FileHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/25/20 10:32 下午 12 | * @version 1.0 13 | */ 14 | open class FileHandler : SwiftHandler(){ 15 | 16 | override fun onHandle(writer: LanguageWriter, node: Node.File, statement: Statement) { 17 | node.pkg?.also { 18 | it.parent = node 19 | writer.onWriteNode(it,statement) 20 | } 21 | node.imports.forEach{ 22 | it.parent = node 23 | writer.onWriteNode(it,statement) 24 | } 25 | node.decls.forEach{ 26 | it.parent = node 27 | writer.onWriteNode(it,statement) 28 | } 29 | } 30 | 31 | override fun getHandleClass(): Class = Node.File::class.java 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/ModifierWriteHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/23/20 10:05 上午 12 | * @version 1.0 13 | */ 14 | open class ModifierKeywordHandler: SwiftHandler(){ 15 | 16 | override fun getHandleClass(): Class = Node.Modifier.Lit::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Modifier.Lit, statement: Statement) { 19 | when(node.keyword){ 20 | Node.Modifier.Keyword.ABSTRACT -> {} 21 | Node.Modifier.Keyword.FINAL -> {} 22 | Node.Modifier.Keyword.OPEN -> {} 23 | Node.Modifier.Keyword.ANNOTATION -> {} 24 | Node.Modifier.Keyword.SEALED -> {} 25 | Node.Modifier.Keyword.DATA -> {} 26 | Node.Modifier.Keyword.OVERRIDE -> {} 27 | Node.Modifier.Keyword.LATEINIT -> {} 28 | Node.Modifier.Keyword.INNER -> {} 29 | Node.Modifier.Keyword.PRIVATE -> { statement.append("private ") } 30 | Node.Modifier.Keyword.PROTECTED -> {} 31 | Node.Modifier.Keyword.PUBLIC -> {} 32 | Node.Modifier.Keyword.INTERNAL -> {} 33 | Node.Modifier.Keyword.IN -> {} 34 | Node.Modifier.Keyword.OUT -> {} 35 | Node.Modifier.Keyword.NOINLINE -> {} 36 | Node.Modifier.Keyword.CROSSINLINE -> {} 37 | Node.Modifier.Keyword.VARARG -> {} 38 | Node.Modifier.Keyword.REIFIED -> {} 39 | Node.Modifier.Keyword.TAILREC -> {} 40 | Node.Modifier.Keyword.OPERATOR -> {} 41 | Node.Modifier.Keyword.INFIX -> {} 42 | Node.Modifier.Keyword.INLINE -> {} 43 | Node.Modifier.Keyword.EXTERNAL -> {} 44 | Node.Modifier.Keyword.SUSPEND -> {} 45 | Node.Modifier.Keyword.CONST -> {} 46 | Node.Modifier.Keyword.ACTUAL -> {} 47 | Node.Modifier.Keyword.EXPECT -> {} 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/decl/BlockHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.decl 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/26/20 5:43 下午 11 | * @version 1.0 12 | */ 13 | 14 | class BlockHandler : SwiftHandler(){ 15 | override fun onHandle(writer: LanguageWriter, node: Node.Block, statement: Statement) { 16 | statement.append("{") 17 | statement.openQuote() 18 | node.stmts.forEach { 19 | writer.onWriteNode(it,statement,node) 20 | statement.nextLine() 21 | } 22 | statement.closeQuote() 23 | statement.append("}") 24 | } 25 | 26 | override fun getHandleClass(): Class = Node.Block::class.java 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/decl/ClassHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.decl 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | 7 | /** 8 | * @author liaomin 9 | * @date 6/26/20 2:45 下午 10 | * @version 1.0 11 | */ 12 | class ClassHandler { 13 | 14 | companion object{ 15 | fun onHandle(writer: LanguageWriter, node: Node.Decl.Structured, statement: Statement){ 16 | if(node.form == Node.Decl.Structured.Form.CLASS){ 17 | statement.append("class ${node.name} ") 18 | if(node.typeParams.size > 0){ 19 | statement.append("<") 20 | node.typeParams.forEachIndexed { index, typeParam -> 21 | if(index>0){ 22 | statement.append(",") 23 | } 24 | writer.onWriteNode(typeParam,statement) 25 | } 26 | statement.append("> ") 27 | } 28 | statement.append("{") 29 | statement.openQuote() 30 | 31 | node.members.forEach { 32 | it.parent = node 33 | writer.onWriteNode(it,statement) 34 | } 35 | statement.closeQuote() 36 | statement.append("}") 37 | statement.nextLine() 38 | } 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/decl/StructuredHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.decl 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/23/20 10:05 上午 11 | * @version 1.0 12 | */ 13 | open class StructuredHandler : SwiftHandler(){ 14 | 15 | override fun getHandleClass(): Class = Node.Decl.Structured::class.java 16 | 17 | override fun onHandle(writer: LanguageWriter, node: Node.Decl.Structured, statement: Statement) { 18 | when (node.form){ 19 | Node.Decl.Structured.Form.CLASS -> ClassHandler.onHandle(writer, node, statement) 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/decl/func/FuncHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.decl.func 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/24/20 4:01 下午 11 | * @version 1.0 12 | */ 13 | class FuncHandler : SwiftHandler(){ 14 | 15 | override fun getHandleClass(): Class = Node.Decl.Func::class.java 16 | 17 | override fun onHandle(writer: LanguageWriter, node: Node.Decl.Func, statement: Statement) { 18 | if(node.receiverType != null){ 19 | node.receiverType.parent = node 20 | error("not support") 21 | } 22 | statement.nextLine() 23 | statement.append("func ${node.name}") 24 | if(node.typeParams.size > 0){ 25 | statement.append("<") 26 | node.typeParams.forEachIndexed { index, typeParam -> 27 | if(index>0){ 28 | statement.append(",") 29 | } 30 | writer.onWriteNode(typeParam,statement) 31 | } 32 | statement.append(">") 33 | } 34 | statement.append("(") 35 | node.params.forEachIndexed { index, param -> 36 | if(index > 0){ 37 | statement.append(",") 38 | } 39 | statement.append("_ ") 40 | writer.onWriteNode(param,statement,node) 41 | } 42 | statement.append(")") 43 | node.type?.also { 44 | it.parent = node 45 | statement.append(" -> ") 46 | writer.onWriteNode(it,statement) 47 | } 48 | 49 | 50 | //TODO 51 | node.body?.also { 52 | val isExpr = it is Node.Decl.Func.Body.Expr 53 | if(isExpr){ 54 | statement.append(" {") 55 | statement.openQuote() 56 | } 57 | writer.onWriteNode(it,statement,node) 58 | if(isExpr){ 59 | statement.closeQuote() 60 | statement.append("}") 61 | } 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/decl/func/FuncParamHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.decl.func 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/29/20 10:55 上午 11 | * @version 1.0 12 | */ 13 | class FuncParamHandler : SwiftHandler(){ 14 | 15 | override fun onHandle(writer: LanguageWriter, node: Node.Decl.Func.Param, statement: Statement) { 16 | statement.append("${node.name}") 17 | node.type?.also { 18 | statement.append(":") 19 | writer.onWriteNode(it,statement,node) 20 | } 21 | node.default?.also { 22 | statement.append("=") 23 | writer.onWriteNode(it,statement,node) 24 | } 25 | 26 | } 27 | 28 | override fun getHandleClass(): Class = Node.Decl.Func.Param::class.java 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/CallHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/29/20 10:33 上午 11 | * @version 1.0 12 | */ 13 | class CallHandler : SwiftHandler(){ 14 | 15 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.Call, statement: Statement) { 16 | writer.onWriteNode(node.expr,statement,node) 17 | statement.append("(") 18 | node.args.forEachIndexed { index, valueArg -> 19 | if(index > 0){ 20 | statement.append(",") 21 | } 22 | writer.onWriteNode(valueArg,statement,node) 23 | } 24 | statement.append(")") 25 | } 26 | 27 | override fun getHandleClass(): Class = Node.Expr.Call::class.java 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/ConstHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class ConstHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.Const::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.Const, statement: Statement) { 19 | val from = node.form 20 | when(from){ 21 | Node.Expr.Const.Form.NULL -> statement.append("nil") 22 | Node.Expr.Const.Form.INT -> { 23 | var v = node.value.toLowerCase() 24 | if(v.endsWith("ul")){ 25 | statement.append(v.subSequence(0,v.length-2)) 26 | } else if(v.endsWith("l") || v.endsWith("u" )){ 27 | statement.append(v.subSequence(0,v.length-1)) 28 | }else{ 29 | statement.append(v) 30 | } 31 | } 32 | Node.Expr.Const.Form.FLOAT -> { 33 | var v = node.value 34 | if(v.endsWith("f")){ 35 | statement.append(v.subSequence(0,v.length-1)) 36 | }else{ 37 | statement.append(v) 38 | } 39 | } 40 | Node.Expr.Const.Form.CHAR -> { 41 | statement.append("\"${node.value.subSequence(1,2)}\"") 42 | } 43 | else -> { 44 | statement.append(node.value) 45 | } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/NameHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class NameHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.Name::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.Name, statement: Statement) { 19 | statement.append("${node.name}") 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/OperHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class OperHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.TypeOp::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.TypeOp, statement: Statement) { 19 | writer.onWriteNode(node.lhs,statement,node) 20 | writer.onWriteNode(node.oper,statement,node) 21 | writer.onWriteNode(node.rhs,statement,node) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/ReturnHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class ReturnHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.Return::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.Return, statement: Statement) { 19 | statement.append("return ") 20 | node.expr?.also { 21 | it.parent = node 22 | writer.onWriteNode(it,statement) 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/StringTmplHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | import java.lang.StringBuilder 9 | 10 | /** 11 | * @author liaomin 12 | * @date 6/22/20 9:53 上午 13 | * @version 1.0 14 | */ 15 | open class StringTmplHandler : SwiftHandler() { 16 | 17 | override fun getHandleClass(): Class = Node.Expr.StringTmpl::class.java 18 | 19 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.StringTmpl, statement: Statement) { 20 | val b = StringBuilder() 21 | node.elems.forEach { 22 | b.append(it.toString()) 23 | } 24 | if(node.raw){ 25 | statement.append("\"\"\"") 26 | }else{ 27 | statement.append("\"") 28 | } 29 | statement.append(b.toString()) 30 | if(node.raw){ 31 | statement.append("\"\"\"") 32 | }else{ 33 | statement.append("\"") 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/ThisHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class ThisHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.This::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.This, statement: Statement) { 19 | statement.append("self") 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/UnaryOpHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/22/20 9:53 上午 12 | * @version 1.0 13 | */ 14 | open class UnaryOpHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.Expr.UnaryOp::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.UnaryOp, statement: Statement) { 19 | node.expr.parent = node 20 | node.parent = node 21 | val toke = node.oper.token 22 | if(node.expr is Node.Expr.Name){ 23 | val name = node.expr.name 24 | if(toke == Node.Expr.UnaryOp.Token.INC || toke == Node.Expr.UnaryOp.Token.DEC){ 25 | val op = if(toke == Node.Expr.UnaryOp.Token.INC) "+" else "-" 26 | if(node.prefix){ 27 | // statement.insertBeforeLine("$name $op= 1") 28 | statement.append(name) 29 | }else{ 30 | statement.append(name) 31 | // statement.appendBeforeNewLine("$name $op= 1") 32 | } 33 | return 34 | } 35 | } 36 | if(node.prefix){ 37 | writer.onWriteNode(node.oper,statement) 38 | writer.onWriteNode(node.expr,statement) 39 | }else{ 40 | writer.onWriteNode(node.expr,statement) 41 | writer.onWriteNode(node.oper,statement) 42 | } 43 | } 44 | 45 | } 46 | 47 | open class UnaryOpOperHandler : SwiftHandler() { 48 | 49 | override fun getHandleClass(): Class = Node.Expr.UnaryOp.Oper::class.java 50 | 51 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.UnaryOp.Oper, statement: Statement) { 52 | when (node.token){ 53 | Node.Expr.UnaryOp.Token.NEG-> statement.append("-") 54 | Node.Expr.UnaryOp.Token.POS-> statement.append("+") 55 | // Node.Expr.UnaryOp.Token.INC-> statement.append("++") 56 | // Node.Expr.UnaryOp.Token.DEC-> statement.append("--") 57 | Node.Expr.UnaryOp.Token.NOT-> statement.append("!") 58 | Node.Expr.UnaryOp.Token.NULL_DEREF-> statement.append(" ! ") 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/ValueArgHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.* 5 | 6 | /** 7 | * @author liaomin 8 | * @date 6/22/20 9:53 上午 9 | * @version 1.0 10 | */ 11 | open class ValueArgHandler : SwiftHandler() { 12 | 13 | override fun getHandleClass(): Class = Node.ValueArg::class.java 14 | 15 | override fun onHandle(writer: LanguageWriter, node: Node.ValueArg, statement: Statement) { 16 | if(node.name != null){ 17 | notSupport() 18 | statement.append("${node.name}:") 19 | }else{ 20 | // notSupport() 21 | } 22 | writer.onWriteNode(node.expr,statement,node) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/binary/BinaryInfixHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp.binary 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/24/20 3:47 下午 12 | * @version 1.0 13 | */ 14 | class BinaryInfixHandler : SwiftHandler(){ 15 | 16 | override fun getHandleClass(): Class = Node.Expr.BinaryOp.Oper.Infix::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.BinaryOp.Oper.Infix, statement: Statement) { 19 | when (node.str) { 20 | "shl" -> statement.append(" << ") 21 | "shr" -> statement.append(" >> ") 22 | "ushr" -> statement.append(" >> ") 23 | "and" -> statement.append(" & ") 24 | "or" -> statement.append(" | ") 25 | "xor" -> statement.append(" ^ ") 26 | else ->{ 27 | try { 28 | error("un support infix ${node.str}") 29 | }catch (e:Exception){ 30 | e.printStackTrace() 31 | } 32 | } 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/binary/BinaryOpHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp.binary 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/26/20 2:12 下午 11 | * @version 1.0 12 | */ 13 | class BinaryOpHandler : SwiftHandler(){ 14 | 15 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.BinaryOp, statement: Statement) { 16 | if((node.lhs is Node.Expr.Const || node.lhs is Node.Expr.Name) 17 | && node.oper is Node.Expr.BinaryOp.Oper.Token 18 | && node.oper.token == Node.Expr.BinaryOp.Token.DOT 19 | && node.rhs is Node.Expr.Call 20 | && node.rhs.args.isEmpty() 21 | && node.rhs.expr is Node.Expr.Name) { 22 | val name = node.rhs.expr.name 23 | when (name) { 24 | "inv" -> { 25 | if(node.lhs is Node.Expr.Const){ 26 | statement.append("~${node.lhs.value}") 27 | }else if(node.lhs is Node.Expr.Name){ 28 | statement.append("~${node.lhs.name}") 29 | } 30 | return 31 | } 32 | "toByte" -> { 33 | if(node.lhs is Node.Expr.Const){ 34 | statement.append("Int8(${node.lhs.value})") 35 | }else if(node.lhs is Node.Expr.Name){ 36 | statement.append("Int8(${node.lhs.name})") 37 | } 38 | return 39 | } 40 | "toShort" -> { 41 | if(node.lhs is Node.Expr.Const){ 42 | statement.append("Int16(${node.lhs.value})") 43 | }else if(node.lhs is Node.Expr.Name){ 44 | statement.append("Int16(${node.lhs.name})") 45 | } 46 | return 47 | } 48 | "toInt" -> { 49 | if(node.lhs is Node.Expr.Const){ 50 | statement.append("Int(${node.lhs.value})") 51 | }else if(node.lhs is Node.Expr.Name){ 52 | statement.append("Int(${node.lhs.name})") 53 | } 54 | return 55 | } 56 | "toLong" -> { 57 | if(node.lhs is Node.Expr.Const){ 58 | statement.append("Int64(${node.lhs.value})") 59 | }else if(node.lhs is Node.Expr.Name){ 60 | statement.append("Int64(${node.lhs.name})") 61 | } 62 | return 63 | } 64 | "toFloat" -> { 65 | if(node.lhs is Node.Expr.Const){ 66 | statement.append("Float(${node.lhs.value})") 67 | }else if(node.lhs is Node.Expr.Name){ 68 | statement.append("Float(${node.lhs.name})") 69 | } 70 | return 71 | } 72 | "toDouble" -> { 73 | if(node.lhs is Node.Expr.Const){ 74 | statement.append("Double(${node.lhs.value})") 75 | }else if(node.lhs is Node.Expr.Name){ 76 | statement.append("Double(${node.lhs.name})") 77 | } 78 | return 79 | } 80 | "toChar" -> { 81 | if(node.lhs is Node.Expr.Const){ 82 | statement.append("${node.lhs.value}.toChar()") 83 | }else if(node.lhs is Node.Expr.Name){ 84 | statement.append("${node.lhs.name}.toChar()") 85 | } 86 | return 87 | } 88 | } 89 | } 90 | 91 | 92 | writer.onWriteNode(node.lhs,statement,node) 93 | writer.onWriteNode(node.oper,statement,node) 94 | writer.onWriteNode(node.rhs,statement,node) 95 | } 96 | 97 | override fun getHandleClass(): Class = Node.Expr.BinaryOp::class.java 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/binary/BinaryTokenHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp.binary 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/24/20 3:47 下午 12 | * @version 1.0 13 | */ 14 | class BinaryTokenHandler : SwiftHandler(){ 15 | 16 | override fun getHandleClass(): Class = Node.Expr.BinaryOp.Oper.Token::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.BinaryOp.Oper.Token, statement: Statement) { 19 | statement.append("${node.token.str}") 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/control/IFHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp.control 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | import com.liam.ast.writer.SwiftWriter 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/28/20 5:06 下午 12 | * @version 1.0 13 | */ 14 | class IFHandler : SwiftHandler(){ 15 | 16 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.If, statement: Statement) { 17 | val parent = node.parent 18 | if(parent != null 19 | && parent is Node.Expr.BinaryOp 20 | && parent.oper is Node.Expr.BinaryOp.Oper.Token 21 | && parent.oper.token == Node.Expr.BinaryOp.Token.ASSN ) { 22 | error(" if else assign not support yet, ${node.element?.text}") 23 | } 24 | 25 | statement.append("if (") 26 | writer.onWriteNode(node.expr,statement,node) 27 | statement.append(") ") 28 | if(node.body !is Node.Expr.Brace){ 29 | statement.append("{ ") 30 | statement.openQuote() 31 | statement.nextLine() 32 | } 33 | 34 | writer.onWriteNode(node.body,statement,node) 35 | if(node.body !is Node.Expr.Brace){ 36 | statement.closeQuote() 37 | statement.nextLine() 38 | statement.append("} ") 39 | } 40 | 41 | if(node.elseBody != null){ 42 | statement.append(" else ") 43 | if(node.elseBody is Node.Expr.Name){ 44 | statement.append("{") 45 | statement.openQuote() 46 | statement.nextLine() 47 | } 48 | writer.onWriteNode(node.elseBody,statement,node) 49 | if(node.elseBody is Node.Expr.Name){ 50 | statement.closeQuote() 51 | statement.nextLine() 52 | statement.append("}") 53 | } 54 | } 55 | statement.nextLine() 56 | } 57 | 58 | override fun getHandleClass(): Class = Node.Expr.If::class.java 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/exp/control/WhenHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.exp.control 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/28/20 5:06 下午 11 | * @version 1.0 12 | */ 13 | class WhenHandler : SwiftHandler(){ 14 | 15 | companion object{ 16 | private var index = 0 17 | private fun getName():String{ 18 | return "___when_temp_name_${index++}___" 19 | } 20 | } 21 | 22 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.When, statement: Statement) { 23 | val whenName = getName() 24 | node.expr?.also { 25 | statement.append("let $whenName = ") 26 | writer.onWriteNode(it,statement,node) 27 | statement.nextLine() 28 | val entriesSize = node.entries.size 29 | node.entries.forEachIndexed { index, entry -> 30 | var haveConds = true 31 | if( entriesSize == 1 && entry.conds.size == 0){ 32 | writeExpr(entry.body,writer,statement,entry,false) 33 | return 34 | }else{ 35 | if(index == 0){ 36 | statement.append("if($whenName") 37 | }else{ 38 | if(index == entriesSize - 1 && entry.conds.size == 0 ){ 39 | statement.append("else") 40 | haveConds = false 41 | }else{ 42 | statement.append("else if($whenName") 43 | } 44 | 45 | } 46 | } 47 | 48 | entry.conds.forEach { 49 | when (it){ 50 | is Node.Expr.When.Cond.Expr -> { 51 | 52 | } 53 | is Node.Expr.When.Cond.Is -> { 54 | if(it.not){ 55 | statement.append("!(") 56 | } 57 | statement.append(" is ") 58 | writer.onWriteNode(it.type,statement,node) 59 | if(it.not){ 60 | statement.append(")") 61 | } 62 | } 63 | is Node.Expr.When.Cond.In -> { 64 | println() 65 | } 66 | } 67 | } 68 | if(haveConds)statement.append(")") 69 | writeExpr(entry.body,writer,statement,entry) 70 | 71 | } 72 | } 73 | 74 | } 75 | 76 | fun writeExpr(body:Node.Expr,writer: LanguageWriter,statement: Statement,parent:Node,addOper:Boolean = true){ 77 | val isBlock = body is Node.Expr.Brace 78 | if(!isBlock && addOper){ 79 | statement.append(" {") 80 | statement.openQuote() 81 | statement.nextLine() 82 | } 83 | 84 | writer.onWriteNode(body,statement,parent) 85 | 86 | if(!isBlock && addOper){ 87 | statement.closeQuote() 88 | statement.nextLine() 89 | statement.append("}") 90 | } 91 | } 92 | 93 | override fun getHandleClass(): Class = Node.Expr.When::class.java 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/property/PropertyHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.property 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | import org.jetbrains.kotlin.psi.KtProperty 8 | import org.jetbrains.kotlin.resolve.calls.callUtil.getType 9 | 10 | /** 11 | * @author liaomin 12 | * @date 6/26/20 1:59 下午 13 | * @version 1.0 14 | */ 15 | open class PropertyHandler : SwiftHandler(){ 16 | 17 | override fun getHandleClass(): Class = Node.Decl.Property::class.java 18 | 19 | override fun onHandle(writer: LanguageWriter, node: Node.Decl.Property, statement: Statement) { 20 | if(node.readOnly){ 21 | statement.append("let") 22 | }else{ 23 | statement.append("var") 24 | } 25 | 26 | node.vars?.forEach { 27 | it?.also { 28 | writer.onWriteNode(it,statement,node) 29 | if(it.type == null && node.expr != null && node.expr is Node.Expr.Const && node.expr.form == Node.Expr.Const.Form.INT){ 30 | val expr = node.expr 31 | val v = expr.value.toLowerCase() 32 | if(v.endsWith("ul")){ 33 | statement.append(":UInt64") 34 | }else if(v.endsWith("l")){ 35 | statement.append(":Int64") 36 | }else if(v.endsWith("u")){ 37 | statement.append(":UInt") 38 | } 39 | } 40 | } 41 | } 42 | 43 | node.expr?.also { 44 | statement.append(" = ") 45 | writer.onWriteNode(it,statement,node) 46 | } 47 | 48 | statement.nextLine() 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/property/PropertyVarHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.property 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/26/20 1:59 下午 11 | * @version 1.0 12 | */ 13 | open class PropertyVarHandler : SwiftHandler(){ 14 | 15 | override fun getHandleClass(): Class = Node.Decl.Property.Var::class.java 16 | 17 | override fun onHandle(writer: LanguageWriter, node: Node.Decl.Property.Var, statement: Statement) { 18 | statement.append(" ${node.name}") 19 | 20 | node.type?.also { 21 | it.parent = node 22 | it.ref.parent = it 23 | statement.append(":") 24 | writer.onWriteNode(it.ref,statement) 25 | } 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/type/NullableHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.type 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/23/20 10:18 上午 12 | * @version 1.0 13 | */ 14 | open class NullableHandler : SwiftHandler() { 15 | 16 | override fun getHandleClass(): Class = Node.TypeRef.Nullable::class.java 17 | 18 | override fun onHandle(writer: LanguageWriter, node: Node.TypeRef.Nullable, statement: Statement) { 19 | node.type.parent = node 20 | writer.onWriteNode(node.type,statement) 21 | statement.append("?") 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/type/PieceHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.type 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * @author liaomin 11 | * @date 6/23/20 10:18 上午 12 | * @version 1.0 13 | */ 14 | 15 | open class PieceSimpleHandler : SwiftHandler() { 16 | 17 | override fun getHandleClass(): Class = Node.TypeRef.Simple::class.java 18 | 19 | override fun onHandle(writer: LanguageWriter, node: Node.TypeRef.Simple, statement: Statement) { 20 | node.pieces.forEach { 21 | it.parent = node 22 | writer.onWriteNode(it,statement) 23 | } 24 | 25 | } 26 | } 27 | 28 | open class PieceSimplePieceHandler : SwiftHandler() { 29 | 30 | override fun getHandleClass(): Class = Node.TypeRef.Simple.Piece::class.java 31 | 32 | override fun onHandle(writer: LanguageWriter, node: Node.TypeRef.Simple.Piece, statement: Statement) { 33 | val name = node.name 34 | when (name){ 35 | "Long" -> statement.append("Int64") 36 | "Byte" -> statement.append("Int8") 37 | "Short" -> statement.append("Int16") 38 | "ULong" -> statement.append("UInt64") 39 | "UByte" -> statement.append("UInt8") 40 | "UShort" -> statement.append("UInt16") 41 | "UInt" -> statement.append("UInt32") 42 | "Boolean" -> statement.append("Bool") 43 | "Char" -> statement.append("Character") 44 | else -> statement.append("$name") 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/type/TypeHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.type 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * 泛型 11 | * @author liaomin 12 | * @date 6/23/20 10:18 上午 13 | * @version 1.0 14 | */ 15 | open class TypeHandler : SwiftHandler() { 16 | 17 | override fun getHandleClass(): Class = Node.Type::class.java 18 | 19 | override fun onHandle(writer: LanguageWriter, node: Node.Type, statement: Statement) { 20 | writer.onWriteNode(node.ref,statement,node) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/type/TypeOPOper.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.type 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.LanguageWriter 5 | import com.liam.ast.writer.Statement 6 | import com.liam.ast.writer.SwiftHandler 7 | 8 | /** 9 | * @author liaomin 10 | * @date 6/26/20 9:03 下午 11 | * @version 1.0 12 | */ 13 | class TypeOPOper : SwiftHandler(){ 14 | 15 | override fun onHandle(writer: LanguageWriter, node: Node.Expr.TypeOp.Oper, statement: Statement) { 16 | when(node.token){ 17 | Node.Expr.TypeOp.Token.AS -> { 18 | val p = node.parent 19 | if(p is Node.Expr.TypeOp && p.rhs is Node.Type && p.rhs.ref is Node.TypeRef.Nullable){ 20 | statement.append(" as ") 21 | }else { 22 | statement.append(" as! ") 23 | } 24 | } 25 | Node.Expr.TypeOp.Token.AS_SAFE -> { 26 | val p = node.parent 27 | if(p is Node.Expr.TypeOp && p.rhs is Node.Type && p.rhs.ref is Node.TypeRef.Nullable){ 28 | statement.append(" as ") 29 | }else{ 30 | statement.append(" as? ") 31 | } 32 | } 33 | Node.Expr.TypeOp.Token.COL -> statement.append(":") 34 | Node.Expr.TypeOp.Token.IS -> statement.append(" is ") 35 | Node.Expr.TypeOp.Token.NOT_IS -> statement.append(" !is ") 36 | } 37 | } 38 | 39 | override fun getHandleClass() = Node.Expr.TypeOp.Oper::class.java 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/ast/writer/swift/type/TypeParamHandler.kt: -------------------------------------------------------------------------------- 1 | package com.liam.ast.writer.swift.type 2 | 3 | import com.liam.ast.psi.Node 4 | import com.liam.ast.writer.BaseLanguageWriter 5 | import com.liam.ast.writer.LanguageWriter 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftHandler 8 | 9 | /** 10 | * 泛型 11 | * @author liaomin 12 | * @date 6/23/20 10:18 上午 13 | * @version 1.0 14 | */ 15 | open class TypeParamHandler : SwiftHandler() { 16 | 17 | override fun getHandleClass(): Class = Node.TypeParam::class.java 18 | 19 | override fun onHandle(writer: LanguageWriter, node: Node.TypeParam, statement: Statement) { 20 | statement.append(node.name) 21 | node.type?.also { 22 | statement.append(":") 23 | writer.onWriteNode(it,statement) 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/SwiftCodeGen.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.intellij.openapi.vfs.VirtualFile 5 | import com.intellij.psi.PsiManager 6 | import org.jetbrains.kotlin.psi.KtFile 7 | 8 | 9 | open class SwiftCodeGen { 10 | 11 | fun genCode(project: Project){ 12 | // ProjectFileIndex.SERVICE.getInstance(e.getProject()).iterateContent(object : ContentIterator() { 13 | // fun processFile(fileInProject: VirtualFile): Boolean { 14 | // println(fileInProject.fileType) 15 | // val psiFile1 = PsiManager.getInstance(e.getProject()).findFile(fileInProject) 16 | // if (psiFile1 == null) println("IT'S NULL!") 17 | // println(psiFile1!!.text) 18 | // return true 19 | // } 20 | // }) 21 | } 22 | 23 | 24 | companion object:SwiftCodeGen() 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/CodeGen.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.liam.ast.writer.Statement 5 | import com.liam.gen.swift.expr.Class 6 | import com.liam.gen.swift.expr.Expr 7 | import com.liam.gen.swift.expr.Func 8 | import com.liam.gen.swift.property.Property 9 | import com.liam.gen.swift.scope.Scope 10 | import org.jetbrains.kotlin.psi.* 11 | import java.lang.RuntimeException 12 | 13 | fun notSupport(message:String = ""):String{ 14 | val msg = "not support $message" 15 | Logger.error(msg) 16 | try { 17 | throw RuntimeException(msg) 18 | }catch (e:Exception){ 19 | e.printStackTrace(); 20 | } 21 | return msg 22 | } 23 | 24 | interface Handler{ 25 | fun genCode(gen:CodeGen, v: T, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String? 26 | } 27 | 28 | 29 | abstract class CodeGen(val statement: Statement = Statement()){ 30 | 31 | abstract fun genCode() 32 | 33 | 34 | open fun genModifiers(modifierList: KtModifierList,target: KtElement,statement: Statement,scope: Scope){ 35 | //TODO 36 | } 37 | 38 | open fun genClassOrObject(classOrObject: KtClassOrObject, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean){ 39 | when(classOrObject){ 40 | is KtClass -> Class.genCode(this,classOrObject,statement,scope,targetType,expectType,shouldReturn) 41 | } 42 | } 43 | 44 | open fun genProperty(property: KtProperty, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean){ 45 | Property.genCode(this,property, statement, scope,targetType, expectType, shouldReturn) 46 | } 47 | 48 | open fun genExpr(v: KtExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 49 | return Expr.genCode(this,v,statement, scope,targetType,expectType,shouldReturn) 50 | } 51 | // 52 | // open fun genExpr(v: KtExpression,scope: Scope):Statement{ 53 | // val statement = Statement() 54 | // Expr.genCode(this,v,statement, scope) 55 | // return statement 56 | // } 57 | 58 | open fun genNamedFunction(func: KtNamedFunction, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean){ 59 | Func.genCode(this,func,statement, scope,targetType, expectType, shouldReturn) 60 | } 61 | 62 | 63 | open fun genType(v: KtTypeParameter, statement: Statement, scope: Scope, containBasicType:Boolean = true) { 64 | statement.append(v.name) 65 | v.extendsBound?.let { 66 | statement.append(":") 67 | val type = TypeUtils.getType(it) 68 | if(!containBasicType && TypeUtils.isBasicType(type)){ 69 | notSupport("basic type can't be here") 70 | } 71 | statement.append(type) 72 | } 73 | } 74 | 75 | open fun genDeclaration(v:KtDeclaration, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean){ 76 | when(v){ 77 | is KtClassOrObject -> genClassOrObject(v,statement,scope,targetType,expectType,shouldReturn) 78 | is KtProperty -> genProperty(v,statement,scope,targetType, expectType, shouldReturn) 79 | is KtNamedFunction -> genNamedFunction(v,statement, scope, targetType, expectType, shouldReturn) 80 | else ->{ 81 | notSupport() 82 | } 83 | } 84 | // is KtEnumEntry -> convertEnumEntry(v) 85 | // is KtClassOrObject -> convertStructured(v) 86 | // is KtAnonymousInitializer -> convertInit(v) 87 | // is KtNamedFunction -> convertFunc(v) 88 | // is KtDestructuringDeclaration -> convertProperty(v) 89 | // is KtProperty -> convertProperty(v) 90 | // is KtTypeAlias -> convertTypeAlias(v) 91 | // is KtSecondaryConstructor -> convertConstructor(v) 92 | // else -> error("Unrecognized declaration type for $v") 93 | } 94 | 95 | open fun genType(v: KtTypeProjection,statement: Statement,scope: Scope) = v.typeReference?.let { genType(it,statement,scope, it.modifierList) } 96 | 97 | open fun genType(v: KtTypeReference, statement: Statement, scope: Scope, modifierList: KtModifierList? = null):String?{ 98 | if(modifierList != null) notSupport() 99 | val type = TypeUtils.getType(v) 100 | statement.append(type) 101 | return type 102 | } 103 | 104 | 105 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/FileCodeGen.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift 2 | 3 | import com.liam.gen.swift.scope.Scope 4 | import org.jetbrains.kotlin.psi.* 5 | 6 | class FileCodeGen(val psiFile:KtFile) : CodeGen(){ 7 | 8 | val name = psiFile.name 9 | 10 | val packageName = psiFile.packageDirective?.takeIf { it.packageNames.isNotEmpty() }?.let { it.packageNames.first() }?.getReferencedName()?:"" 11 | 12 | val importes:ArrayList = ArrayList() 13 | 14 | override fun genCode() { 15 | val scope = Scope().discovery(psiFile) 16 | psiFile.importDirectives?.forEach { 17 | val packaes = StringBuilder() 18 | it.importedFqName?.pathSegments()?.forEachIndexed { index, name -> 19 | if(index > 0){ 20 | packaes.append(".") 21 | } 22 | packaes.append(name) 23 | } 24 | if(it.isAllUnder){ 25 | packaes.append(".*") 26 | } 27 | importes.add(packaes.toString()) 28 | } 29 | 30 | psiFile.declarations.forEach { 31 | when (it){ 32 | // is KtEnumEntry -> convertEnumEntry(v) 33 | is KtClassOrObject -> { 34 | statement.nextLine() 35 | genClassOrObject(it,statement, scope,null,null,false) 36 | } 37 | // is KtAnonymousInitializer -> convertInit(v) 38 | is KtNamedFunction -> { 39 | statement.nextLine() 40 | genNamedFunction(it,statement, scope,null,null,false) 41 | } 42 | // is KtDestructuringDeclaration -> convertProperty(v) 43 | is KtProperty -> { 44 | statement.nextLine() 45 | genProperty(it,statement, scope,null,null,false) 46 | } 47 | // is KtTypeAlias -> convertTypeAlias(v) 48 | // is KtSecondaryConstructor -> convertConstructor(v) 49 | // else -> error("Unrecognized declaration type for $it") 50 | } 51 | } 52 | 53 | println(scope) 54 | println(statement) 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/Logger.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift 2 | 3 | open class Logger { 4 | 5 | fun info(message:Any){ 6 | println(message) 7 | } 8 | 9 | fun error(message: Any){ 10 | System.err.println(message) 11 | } 12 | 13 | fun debug(message: Any) = info(message) 14 | 15 | companion object : Logger() 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/TypeUtils.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift 2 | 3 | import org.jetbrains.kotlin.psi.* 4 | 5 | open class TypeUtils { 6 | 7 | val basicTypes = arrayOf("Int","Int64","Int8","Int16","UInt8","UInt16","UInt","UInt64","Character","Bool") 8 | 9 | open fun getType(typeRef: KtTypeReference?):String?{ 10 | return getType(typeRef?.typeElement) 11 | } 12 | 13 | open fun getType(type: KtTypeElement?):String?{ 14 | type?.let { 15 | when(it){ 16 | is KtUserType -> { 17 | when (it.referencedName){ 18 | "Long" -> return "Int64" 19 | "Byte" -> return "Int8" 20 | "Short" -> return "Int16" 21 | "ULong" -> return "UInt64" 22 | "UByte" -> return "UInt8" 23 | "UShort" -> return "UInt16" 24 | "UInt" -> return "UInt" 25 | "Boolean" -> return "Bool" 26 | "Char" -> return "Character" 27 | else -> return it.referencedName 28 | } 29 | } 30 | is KtNullableType -> return getType(it.innerType)+"?" 31 | // is KtFunctionType -> { 32 | // //Block 33 | // Node.TypeRef.Func( 34 | // receiverType = v.receiverTypeReference?.let(::convertType), 35 | // params = v.parameters.map { 36 | // Node.TypeRef.Func.Param( 37 | // name = it.name, 38 | // type = convertType(it.typeReference ?: error("No param type")) 39 | // ).map(it) 40 | // }, 41 | // type = convertType(v.returnTypeReference ?: error("No return type")) 42 | // ) 43 | // } 44 | // KtDynamicType 45 | else -> { 46 | notSupport() 47 | } 48 | } 49 | } 50 | return null 51 | } 52 | 53 | fun isBasicType(type:String?) = basicTypes.contains(type) 54 | 55 | companion object : TypeUtils() 56 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/BinaryExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import com.liam.gen.swift.oper.Oper 8 | import org.jetbrains.kotlin.psi.KtBinaryExpression 9 | 10 | open class BinaryExpression : Handler { 11 | 12 | override fun genCode(gen: CodeGen, v: KtBinaryExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 13 | var expect= expectType 14 | val left = v.left ?: error("no left type") 15 | val right = v.right ?: error("no right type") 16 | val leftType = gen.genExpr(left,statement, scope,null,expectType,shouldReturn) 17 | expect = expect?:leftType 18 | Oper.genCode(gen,left,v.operationReference,right,statement, scope) 19 | val rightType = gen.genExpr(right,statement, scope,null,expectType,shouldReturn) 20 | return expect ?: rightType 21 | } 22 | 23 | companion object:BinaryExpression() 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/BinaryWithTypeRHS.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS 8 | 9 | open class BinaryWithTypeRHS : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtBinaryExpressionWithTypeRHS, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 12 | var expect= expectType 13 | val left = v.left ?: error("no left type") 14 | val right = v.right ?: error("no right type") 15 | gen.genExpr(left,statement, scope,null,expectType,shouldReturn) 16 | statement.append(" ${v.operationReference.text} ") 17 | val rightType = gen.genType(right,statement, scope) 18 | return expect ?: rightType 19 | } 20 | 21 | companion object:BinaryWithTypeRHS() 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/BlockExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class BlockExpression : Handler { 10 | 11 | companion object:BlockExpression() 12 | 13 | override fun genCode(gen: CodeGen, v: KtBlockExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 14 | val newScope = scope.newScope() 15 | var type:String? = null 16 | v.statements?.let { 17 | if(it.size > 0){ 18 | val lastIsReturnExpression = it.last() is KtReturnExpression 19 | it.forEachIndexed { index, ktExpression -> 20 | val s = statement.newStatement() 21 | val currentLine = statement.currentLine 22 | val isLast = index == it.size - 1 23 | if(isLast){ 24 | type = gen.genExpr(ktExpression,s,newScope,targetType,expectType,shouldReturn) 25 | if(shouldReturn && !lastIsReturnExpression){ 26 | statement.append("return ") 27 | } 28 | }else{ 29 | type = gen.genExpr(ktExpression,s,newScope,targetType,expectType,shouldReturn && !lastIsReturnExpression) 30 | } 31 | statement.append(s) 32 | if(!isLast && statement.currentLine == currentLine){ 33 | statement.nextLine() 34 | } 35 | } 36 | } 37 | 38 | } 39 | return type 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/CallExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.intellij.openapi.util.text.StringUtil 4 | import com.liam.ast.writer.Statement 5 | import com.liam.gen.swift.CodeGen 6 | import com.liam.gen.swift.Handler 7 | import com.liam.gen.swift.scope.Scope 8 | import com.liam.gen.swift.notSupport 9 | import org.jetbrains.kotlin.psi.KtCallExpression 10 | import java.util.* 11 | 12 | open class CallExpression : Handler { 13 | override fun genCode(gen: CodeGen, v: KtCallExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 14 | if(v.calleeExpression != null){ 15 | val nameStatement = statement.newStatement() 16 | val returnType = Expr.genCode(gen,v.calleeExpression!! , nameStatement, scope,targetType,expectType, shouldReturn) 17 | val funcName = nameStatement.toString() 18 | if(StringUtil.isEmpty(funcName)){ 19 | error("funcName is null") 20 | } 21 | statement.append(funcName) 22 | if(v.typeArguments.size > 0){ 23 | statement.append("<") 24 | v.typeArguments.forEachIndexed { index, ktTypeProjection -> 25 | if(index>0){ 26 | statement.append(",") 27 | } 28 | gen.genType(ktTypeProjection,statement, scope) 29 | } 30 | statement.append(">") 31 | } 32 | statement.append("(") 33 | v.valueArgumentList?.arguments?.let { 34 | val types = LinkedList() 35 | val s = statement.newStatement() 36 | it.forEach { 37 | it.getArgumentExpression()!!.let { 38 | val type = gen.genExpr(it,s, scope,targetType, expectType, shouldReturn) 39 | types.add(type) 40 | } 41 | } 42 | it.forEachIndexed { index, ktValueArgument -> 43 | if(index>0){ 44 | statement.append(" , ") 45 | } 46 | val name = ktValueArgument.getArgumentName()?.asName?.asString() ?: scope.getFunctionName(funcName,index,types) 47 | name?.let { statement.append("$it: ") } 48 | ktValueArgument.getArgumentExpression()?.let { gen.genExpr(it,statement, scope,targetType, expectType, shouldReturn) } 49 | } 50 | } 51 | statement.append(")") 52 | return returnType 53 | }else{ 54 | notSupport() 55 | } 56 | return null 57 | } 58 | 59 | companion object:CallExpression() 60 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/ConstantExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.KtNodeTypes 8 | import org.jetbrains.kotlin.psi.KtConstantExpression 9 | 10 | open class ConstantExpression : Handler { 11 | 12 | override fun genCode(gen: CodeGen, v: KtConstantExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 13 | when (v.node.elementType) { 14 | KtNodeTypes.BOOLEAN_CONSTANT -> { 15 | statement.append(v.text) 16 | return "Bool" 17 | } 18 | KtNodeTypes.CHARACTER_CONSTANT -> { 19 | val value = v.text 20 | if(expectType != null && expectType == "Character"){ 21 | statement.append("\"") 22 | statement.append(value.subSequence(1,value.length-1)) 23 | statement.append("\"") 24 | return "Character" 25 | } 26 | statement.append(v.text) 27 | return "String" 28 | } 29 | KtNodeTypes.INTEGER_CONSTANT -> { 30 | var v = v.text.toLowerCase() 31 | if (v.endsWith("ul")) { 32 | statement.append(v.subSequence(0, v.length - 2)) 33 | return "UInt64" 34 | } else if (v.endsWith("l")) { 35 | statement.append(v.subSequence(0, v.length - 1)) 36 | return "Int64" 37 | } else if (v.endsWith("u")) { 38 | statement.append(v.subSequence(0, v.length - 1)) 39 | return "UInt" 40 | } else { 41 | statement.append(v) 42 | return "Int" 43 | } 44 | } 45 | KtNodeTypes.FLOAT_CONSTANT -> { 46 | var v = v.text 47 | if (v.endsWith("f")) { 48 | statement.append(v.subSequence(0, v.length - 1)) 49 | } else { 50 | statement.append(v) 51 | } 52 | return "Float" 53 | } 54 | KtNodeTypes.NULL -> { 55 | statement.append("nil") 56 | return null 57 | } 58 | else -> error("Unrecognized const type for $v") 59 | } 60 | } 61 | 62 | companion object:ConstantExpression() 63 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/Expr.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import com.liam.gen.swift.property.Property 8 | import com.liam.gen.swift.notSupport 9 | import org.jetbrains.kotlin.psi.* 10 | 11 | open class Expr: Handler { 12 | 13 | override fun genCode(gen:CodeGen, v: KtExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 14 | return when(v){ 15 | is KtConstantExpression -> ConstantExpression.genCode(gen, v, statement, scope,targetType,expectType,shouldReturn) 16 | is KtCallExpression -> CallExpression.genCode(gen, v, statement, scope,targetType,expectType,shouldReturn) 17 | is KtNameReferenceExpression -> NameRefExpression.genCode(gen, v, statement, scope,targetType,expectType, shouldReturn) 18 | is KtBlockExpression -> BlockExpression.genCode(gen, v, statement, scope,targetType, expectType, shouldReturn) 19 | is KtProperty -> Property.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 20 | is KtReturnExpression -> ReturnExpression.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 21 | is KtStringTemplateExpression -> StringTemplateExpression.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 22 | is KtQualifiedExpression -> QualifiedExpression.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 23 | is KtIfExpression -> IFExpression.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 24 | // is KtTryExpression -> convertTry(v) 25 | is KtForExpression -> ForExpression.genCode(gen, v, statement, scope, targetType, expectType, shouldReturn) 26 | is KtWhileExpressionBase -> WhileExpression.genCode(gen,v,statement, scope, targetType, expectType, shouldReturn) 27 | is KtBinaryExpression -> BinaryExpression.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 28 | // is KtUnaryExpression -> convertUnaryOp(v) 29 | is KtBinaryExpressionWithTypeRHS -> BinaryWithTypeRHS.genCode(gen,v,statement, scope,targetType,expectType,shouldReturn) 30 | // is KtIsExpression -> convertTypeOp(v) 31 | // is KtCallableReferenceExpression -> convertDoubleColonRefCallable(v) 32 | // is KtClassLiteralExpression -> convertDoubleColonRefClass(v) 33 | // is KtParenthesizedExpression -> convertParen(v) 34 | // is KtFunctionLiteral -> convertBrace(v) 35 | // is KtLambdaExpression -> convertBrace(v) 36 | is KtThisExpression -> ThisExpression.genCode(gen, v, statement, scope, targetType, expectType, shouldReturn) 37 | // is KtSuperExpression -> convertSuper(v) 38 | is KtWhenExpression -> WhenExpression.genCode(gen, v, statement, scope, targetType, expectType, shouldReturn) 39 | // is KtObjectLiteralExpression -> convertObject(v) 40 | // is KtThrowExpression -> convertThrow(v) 41 | // is KtContinueExpression -> convertContinue(v) 42 | // is KtBreakExpression -> convertBreak(v) 43 | // is KtCollectionLiteralExpression -> convertCollLit(v) 44 | // is KtSimpleNameExpression -> StringTemplateExpression.genCode(gen,v,statement,scope) 45 | // is KtLabeledExpression -> convertLabeled(v) 46 | // is KtAnnotatedExpression -> convertAnnotated(v) 47 | // is KtCallExpression -> convertCall(v) 48 | // is KtArrayAccessExpression -> convertArrayAccess(v) 49 | is KtNamedFunction -> Func.genCode(gen, v, statement, scope, targetType, expectType, shouldReturn) 50 | // 51 | // is KtDestructuringDeclaration -> convertPropertyExpr(v) 52 | // // TODO: this is present in a recovery test where an interface decl is on rhs of a gt expr 53 | // is KtClass -> throw Converter.Unsupported("Class expressions not supported") 54 | else -> { 55 | notSupport("type for $v") 56 | } 57 | } 58 | } 59 | 60 | 61 | companion object:Expr() 62 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/ForExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class ForExpression : Handler { 10 | 11 | var index = 0 12 | 13 | fun genIfTempName():String{ 14 | return "___IF_TEMP_${++index}__" 15 | } 16 | 17 | 18 | override fun genCode(gen: CodeGen, v: KtForExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 19 | 20 | return null 21 | } 22 | 23 | companion object:ForExpression() 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/IFExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class IFExpression : Handler { 10 | 11 | var index = 0 12 | 13 | fun genIfTempName():String{ 14 | return "___IF_TEMP_${++index}___" 15 | } 16 | 17 | fun isTrinocularExpress(express:KtExpression):Boolean{ 18 | if(express is KtIfExpression){ 19 | return false 20 | } 21 | if(express is KtBlockExpression && express.statements.size > 1){ 22 | return false 23 | } 24 | return true 25 | } 26 | 27 | fun genTrinocularExpress(gen: CodeGen, v: KtExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 28 | var express = v 29 | if(v is KtBlockExpression){ 30 | express = v.statements[0] 31 | } 32 | return gen.genExpr(express, statement, scope, targetType, expectType, shouldReturn) 33 | } 34 | 35 | fun handlerTrinocularOperator(gen: CodeGen, v: KtIfExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 36 | val then = v.then ?: error("if no have condition") 37 | val `else` = v.`else` 38 | if(shouldReturn && `else` != null && isTrinocularExpress(then) && isTrinocularExpress(`else`)){ 39 | //三目运算 40 | var newScope = scope.newScope() 41 | gen.genExpr( v.condition ?: error("if no have condition"),statement, newScope,targetType,expectType,shouldReturn) 42 | statement.append(" ? ") 43 | newScope = scope.newScope() 44 | val type = genTrinocularExpress(gen,then,statement, newScope,targetType,expectType,shouldReturn) 45 | statement.append(" : ") 46 | newScope = scope.newScope() 47 | val elseType = genTrinocularExpress(gen,`else`,statement, newScope,targetType,expectType,shouldReturn) 48 | return type ?: elseType 49 | } 50 | return null 51 | } 52 | 53 | override fun genCode(gen: CodeGen, v: KtIfExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 54 | val trinocular = handlerTrinocularOperator(gen, v, statement, scope, targetType, expectType, shouldReturn) 55 | if(trinocular != null){ 56 | return trinocular 57 | } 58 | if(shouldReturn){ 59 | statement.append("{") 60 | statement.openQuote() 61 | } 62 | statement.append("if ") 63 | val conditionScope = scope.newScope() 64 | gen.genExpr( v.condition ?: error("if no have condition"),statement, conditionScope,targetType,expectType,shouldReturn) 65 | statement.append(" ") 66 | val then = v.then ?: error("if no have condition") 67 | val `else` = v.`else` 68 | statement.append("{") 69 | statement.openQuote() 70 | val thenScope = scope.newScope() 71 | val thenType = gen.genExpr( then ,statement, thenScope,targetType,expectType,shouldReturn) 72 | statement.closeQuote() 73 | statement.append("}") 74 | if(`else` != null){ 75 | statement.append(" else {") 76 | statement.openQuote() 77 | val elseScope = scope.newScope() 78 | if(shouldReturn && `else` !is BlockExpression && `else` !is ReturnExpression){ 79 | statement.append("return ") 80 | } 81 | gen.genExpr( `else`,statement, elseScope,targetType,expectType,shouldReturn) 82 | statement.closeQuote() 83 | statement.append("}") 84 | }else{ 85 | statement.nextLine() 86 | } 87 | if(shouldReturn){ 88 | statement.closeQuote() 89 | statement.append("}()") 90 | } 91 | return expectType?:thenType 92 | } 93 | 94 | companion object:IFExpression() 95 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/INExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.scope.Scope 6 | import com.liam.gen.swift.notSupport 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class INExpression { 10 | 11 | fun genWhenCode(gen: CodeGen, subject :String, v: KtWhenConditionInRange, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 12 | notSupport(" type in ") 13 | return null 14 | v.rangeExpression?.let { 15 | statement.append("$subject ") 16 | val range = it 17 | if(v.isNegated){ 18 | statement.append("!") 19 | } 20 | statement.append("in ") 21 | } 22 | } 23 | 24 | //for 25 | fun genForCode(gen: CodeGen, v: KtExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 26 | 27 | return null 28 | } 29 | companion object:INExpression() 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/NameRefExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class NameRefExpression : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtNameReferenceExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 12 | val name = v.getReferencedName() 13 | statement.append(name) 14 | val p = v.parent 15 | if(p is KtCallExpression){ 16 | val argTypeList = ArrayList() 17 | p.valueArgumentList?.arguments?.forEachIndexed { index, ktValueArgument -> 18 | ktValueArgument.getArgumentExpression()?.let { 19 | val s = statement.newStatement() 20 | val t = gen.genExpr(it,s, scope,targetType, expectType, shouldReturn) 21 | argTypeList.add(t!!) 22 | } 23 | } 24 | return scope.getFuncType(name,argTypeList) 25 | } 26 | return scope.getType(name,targetType) 27 | } 28 | 29 | companion object:NameRefExpression() 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/QualifiedExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.KtDotQualifiedExpression 8 | import org.jetbrains.kotlin.psi.KtQualifiedExpression 9 | 10 | open class QualifiedExpression : Handler { 11 | 12 | override fun genCode(gen: CodeGen, v: KtQualifiedExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 13 | val targetType = gen.genExpr(v.receiverExpression,statement, scope,targetType, expectType, shouldReturn) 14 | if(v is KtDotQualifiedExpression){ 15 | statement.append(".") 16 | }else{ 17 | statement.append("?.") 18 | } 19 | v.selectorExpression?.let { 20 | gen.genExpr(it,statement, scope,targetType,expectType, shouldReturn) 21 | } 22 | return null 23 | } 24 | 25 | companion object:QualifiedExpression() 26 | 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/ReturnExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class ReturnExpression : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtReturnExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 12 | val l = v.getLabelName() //return where 13 | v.returnedExpression?.let { 14 | statement.append("return ") 15 | return gen.genExpr(it,statement,scope,targetType, expectType, shouldReturn) 16 | } 17 | return null 18 | } 19 | 20 | companion object:ReturnExpression() 21 | 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/StringTemplateExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class StringTemplateExpression : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtStringTemplateExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 12 | val raw = v.text.startsWith("\"\"\"") 13 | if(raw){ 14 | statement.append("\"\"\"") 15 | }else{ 16 | statement.append("\"") 17 | } 18 | v.entries.forEach { 19 | when(it){ 20 | is KtLiteralStringTemplateEntry -> 21 | statement.append(it.text) 22 | is KtSimpleNameStringTemplateEntry -> 23 | statement.append(it.expression?.text ?: error("No short tmpl text")) 24 | is KtBlockStringTemplateEntry -> 25 | gen.genExpr(it.expression ?: error("No expr tmpl"),statement, scope,targetType, expectType, shouldReturn) 26 | is KtEscapeStringTemplateEntry -> 27 | if (v.text.startsWith("\\u")) 28 | statement.append(it.text.substring(2)) 29 | else 30 | statement.append(it.unescapedValue.first().toString()) 31 | else -> 32 | error("Unrecognized string template type for $v") 33 | } 34 | } 35 | if(raw){ 36 | statement.append("\"\"\"") 37 | }else{ 38 | statement.append("\"") 39 | } 40 | return "String" 41 | } 42 | 43 | 44 | companion object:StringTemplateExpression() 45 | 46 | 47 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/ThisExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class ThisExpression : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtThisExpression, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 12 | statement.append("self") 13 | return null 14 | } 15 | 16 | companion object:ThisExpression() 17 | 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/WhenExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import com.liam.gen.swift.notSupport 8 | import org.jetbrains.kotlin.psi.* 9 | 10 | open class WhenExpression : Handler { 11 | 12 | var index = 0 13 | 14 | fun genWhenTempName():String{ 15 | return "___WHEN_TEMP_${++index}___" 16 | } 17 | 18 | 19 | override fun genCode(gen: CodeGen, v: KtWhenExpression, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 20 | v.subjectExpression?.let { 21 | val s = statement.newStatement() 22 | gen.genExpr(it,s, scope, targetType, expectType, shouldReturn) 23 | val subject = s.toString() 24 | val entriesSize = v.entries.size 25 | v.entries.forEachIndexed { i,entry -> 26 | when (i){ 27 | 0 -> statement.append("if") 28 | entriesSize - 1 -> statement.append("else") 29 | else -> statement.append("else if") 30 | } 31 | val haveCondition = entry.conditions.isNotEmpty() 32 | if(haveCondition){ 33 | statement.append("(") 34 | } 35 | entry.conditions.forEachIndexed { index, ktWhenCondition -> 36 | when (ktWhenCondition){ 37 | // is KtWhenConditionWithExpression -> 38 | is KtWhenConditionInRange -> { 39 | INExpression.genWhenCode(gen, subject, ktWhenCondition, statement, scope, targetType, expectType, shouldReturn) 40 | } 41 | is KtWhenConditionIsPattern -> { 42 | if(ktWhenCondition.isNegated){ 43 | statement.append("!(") 44 | } 45 | statement.append("$subject is ") 46 | gen.genType( ktWhenCondition.typeReference!!,statement, scope) 47 | if(ktWhenCondition.isNegated){ 48 | statement.append(")") 49 | } 50 | } 51 | else -> notSupport("Unrecognized when cond of $v") 52 | } 53 | } 54 | if(haveCondition){ 55 | statement.append(")") 56 | } 57 | statement.append("{") 58 | if(entry.expression != null){ 59 | entry.expression?.let { 60 | statement.openQuote() 61 | gen.genExpr(it,statement, scope, targetType, expectType, shouldReturn) 62 | statement.closeQuote() 63 | } 64 | }else{ 65 | statement.nextLine() 66 | } 67 | statement.append("}") 68 | } 69 | } 70 | return null 71 | } 72 | 73 | companion object:WhenExpression() 74 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/expr/WhileExpression.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class WhileExpression : Handler { 10 | 11 | override fun genCode(gen: CodeGen, v: KtWhileExpressionBase, statement: Statement, scope: Scope, targetType:String?, expectType:String?, shouldReturn:Boolean):String?{ 12 | 13 | return null 14 | } 15 | 16 | companion object:WhileExpression() 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/func/Func.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.* 5 | import com.liam.gen.swift.scope.FuncInfo 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class Func : Handler { 10 | 11 | fun getFuncInfo(gen: CodeGen, func: KtNamedFunction, s: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): FuncInfo { 12 | val funcName = func.name!! 13 | val args = ArrayList() 14 | func.valueParameters.forEach { 15 | val name = it.name 16 | val type = it.typeReference?.let { TypeUtils.getType(it) } 17 | val default = it.defaultValue?.let { 18 | val statement = s.newStatement() 19 | gen.genExpr(it,statement ,scope, targetType, expectType, shouldReturn) 20 | statement.toString() 21 | } ?: null 22 | args.add(FuncInfo.Args(name!!,type!!,default)) 23 | } 24 | val returnType = func.typeReference?.let { TypeUtils.getType(it) } 25 | return FuncInfo(funcName, args, returnType); 26 | } 27 | 28 | override fun genCode(gen: CodeGen, v: KtNamedFunction, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 29 | if(v.receiverTypeReference != null){ 30 | //TODO 扩展类 31 | if(scope.parent != null){ 32 | notSupport() 33 | } 34 | }else{ 35 | return genNormalFunc(gen,v, statement, scope, targetType, expectType, shouldReturn) 36 | } 37 | return null 38 | } 39 | 40 | fun genNormalFunc(gen: CodeGen, func: KtNamedFunction, s: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String?{ 41 | val statement = s.newStatement() 42 | val newScope = scope.newScope() 43 | func.modifierList?.let { gen.genModifiers(it,func,statement,scope) } 44 | val funcInfo = getFuncInfo(gen,func,statement,scope, targetType, expectType, shouldReturn) 45 | scope.addFunc(funcInfo) 46 | statement.nextLine() 47 | statement.append("func ${funcInfo.name}") 48 | if(func.hasTypeParameterListBeforeFunctionName()){ 49 | statement.append("<") 50 | func.typeParameters.forEachIndexed { index, ktTypeParameter -> 51 | if(index > 0){ 52 | statement.append(", ") 53 | } 54 | gen.genType(ktTypeParameter,statement,newScope,false) 55 | } 56 | statement.append(">") 57 | } 58 | statement.append("(") 59 | funcInfo.args.forEachIndexed { index, args -> 60 | if(index>0){ 61 | statement.append(",") 62 | } 63 | statement.append("${args.name}: ${args.type}") 64 | newScope.setVariable(args.name,args.type) 65 | args.default?.let { 66 | statement.append(" = $it ") 67 | } 68 | } 69 | statement.append(")") 70 | funcInfo.returnType?.let { statement.append(" -> $it") } 71 | func.bodyExpression?.let { 72 | statement.append("{") 73 | statement.openQuote() 74 | gen.genExpr(it,statement, newScope,targetType, funcInfo.returnType, funcInfo.returnType != null) 75 | statement.closeQuote() 76 | statement.append("}") 77 | } 78 | s.append(statement) 79 | s.nextLine() 80 | return funcInfo.returnType 81 | } 82 | 83 | 84 | 85 | 86 | // open fun convertFuncBody(v: KtExpression) = 87 | // if (v is KtBlockExpression) Node.Decl.Func.Body.Block(convertBlock(v)).map(v) 88 | // else Node.Decl.Func.Body.Expr(convertExpr(v)).map(v) 89 | 90 | companion object:Func() 91 | 92 | 93 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/oper/Oper.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.oper 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.scope.Scope 6 | import org.jetbrains.kotlin.psi.KtExpression 7 | import org.jetbrains.kotlin.psi.KtOperationReferenceExpression 8 | 9 | open class Oper { 10 | 11 | fun genCode(gen: CodeGen, left: KtExpression, oper: KtOperationReferenceExpression, right:KtExpression, statement: Statement, scope: Scope){ 12 | statement.append(" ${oper.text} ") 13 | } 14 | 15 | companion object:Oper() 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/property/Property.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.property 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.CodeGen 5 | import com.liam.gen.swift.Handler 6 | import com.liam.gen.swift.scope.Scope 7 | import com.liam.gen.swift.TypeUtils 8 | import org.jetbrains.kotlin.psi.KtProperty 9 | 10 | open class Property: Handler { 11 | 12 | override fun genCode(gen: CodeGen, property: KtProperty, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 13 | property.modifierList?.also { 14 | gen.genModifiers(it,property,statement,scope) 15 | } 16 | if(property.isVar){ 17 | statement.append("var ") 18 | }else{ 19 | statement.append("let ") 20 | } 21 | var name = property.name!! 22 | statement.append("$name") 23 | var type = TypeUtils.getType(property.typeReference) 24 | 25 | val exprStatement = Statement() 26 | property.delegateExpressionOrInitializer?.let { 27 | val t = gen.genExpr(it,exprStatement,scope,null,type,true) 28 | if(type == null){ 29 | type = t 30 | } 31 | } 32 | if(type != null){ 33 | statement.append(":$type") 34 | } 35 | statement.append(" = ") 36 | statement.append(exprStatement) 37 | 38 | statement.nextLine() 39 | scope.setVariable(name,type) 40 | return type 41 | } 42 | 43 | companion object:Property() 44 | 45 | 46 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/scope/ClassDiscoverer.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.scope 2 | 3 | import org.jetbrains.kotlin.psi.KtClassOrObject 4 | 5 | open class ClassDiscoverer : Discoverer{ 6 | 7 | override fun onDiscovery(target: KtClassOrObject,scope: Scope) { 8 | 9 | } 10 | 11 | companion object:ClassDiscoverer() 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/scope/Discoverer.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.scope 2 | 3 | interface Discoverer { 4 | 5 | fun onDiscovery(target: T,scope: Scope) 6 | 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/scope/FileDiscoverer.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.scope 2 | 3 | import org.jetbrains.kotlin.psi.KtClassOrObject 4 | import org.jetbrains.kotlin.psi.KtFile 5 | import org.jetbrains.kotlin.psi.KtNamedFunction 6 | import org.jetbrains.kotlin.psi.KtProperty 7 | 8 | open class FileDiscoverer : Discoverer{ 9 | 10 | override fun onDiscovery(target: KtFile,scope: Scope) { 11 | target.declarations.forEach { 12 | when (it){ 13 | is KtClassOrObject -> { 14 | 15 | } 16 | is KtNamedFunction -> { 17 | 18 | } 19 | is KtProperty -> { 20 | 21 | } 22 | } 23 | } 24 | } 25 | 26 | companion object:FileDiscoverer() 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/scope/Scope.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.scope 2 | 3 | import com.alibaba.fastjson.JSON 4 | import com.intellij.psi.PsiElement 5 | import com.liam.ast.writer.Statement 6 | import com.liam.gen.swift.Logger 7 | import org.jetbrains.kotlin.psi.KtClassOrObject 8 | import org.jetbrains.kotlin.psi.KtDeclaration 9 | import org.jetbrains.kotlin.psi.KtFile 10 | import org.jetbrains.kotlin.psi.KtNamedFunction 11 | import java.util.concurrent.ConcurrentHashMap 12 | import kotlin.collections.HashMap 13 | 14 | data class FuncInfo(val name:String, val args:List, val returnType:String? = null){ 15 | data class Args(val name: String, val type: String, val default: String? = null) 16 | fun isSameType(argTypes: List):Boolean{ 17 | if(argTypes.size == args.size){ 18 | for (i in 0 until args.size){ 19 | if(!args[i].type.equals(argTypes[i])){ 20 | return false 21 | } 22 | } 23 | return true 24 | } 25 | return false 26 | } 27 | } 28 | 29 | data class PsiResult(val statement:Statement,val name:String?,val returnType:String?) 30 | 31 | open class Scope(val parent: Scope? = null, val name:String? = null) { 32 | 33 | val variableMap:HashMap = HashMap() 34 | 35 | val functions:ConcurrentHashMap> = ConcurrentHashMap() 36 | 37 | val structed:ConcurrentHashMap = ConcurrentHashMap() 38 | 39 | val cache:HashMap by lazy { HashMap() } 40 | 41 | fun getCachedResult(key:PsiElement):PsiResult? = parent?.getCachedResult(key) ?: cache.get(key) 42 | 43 | fun setCachedResult(key:PsiElement,value:PsiResult){ 44 | if(parent != null){ 45 | parent!!.cache[key] = value 46 | }else{ 47 | cache[key] = value 48 | } 49 | } 50 | 51 | fun addFunc(funcInfo: FuncInfo){ 52 | functions.computeIfAbsent(funcInfo.name){java.util.ArrayList()}.add(funcInfo) 53 | } 54 | 55 | fun getFunc(name: String):ArrayList{ 56 | return functions.computeIfAbsent(name){java.util.ArrayList()} 57 | } 58 | 59 | open fun setVariable(variable:String,type:String?) { 60 | variableMap[variable] = type 61 | } 62 | 63 | fun getFuncInfo(name: String,argTypes: List): FuncInfo?{ 64 | for (info in getFunc(name)){ 65 | if(info.isSameType(argTypes)){ 66 | return info 67 | } 68 | } 69 | if(parent != null){ 70 | return parent?.getFuncInfo(name,argTypes) 71 | } 72 | Logger.error("not find func info for $name") 73 | return null 74 | } 75 | 76 | fun getFuncType(name: String,argTypes: List):String?{ 77 | return getFuncInfo(name,argTypes)?.returnType ?: "Void" 78 | } 79 | 80 | open fun getType(variable:String,targetType:String? = null):String{ 81 | if(targetType != null){ 82 | return structed.computeIfAbsent(targetType, {k -> Scope(this, k) }).getType(variable) 83 | } 84 | var cacheType = variableMap[variable] ?: parent?.getType(variable) 85 | if(cacheType == null){ 86 | cacheType = getConstVariableType(variable) 87 | } 88 | if(cacheType == null) Logger.error("not find type for $variable in scope,scope name:$name") 89 | return cacheType ?: "Void" 90 | } 91 | 92 | open fun getFunctionName(funcName:String,index:Int,argTypes: List):String?{ 93 | getFuncInfo(funcName,argTypes)?.let { 94 | return it.args[index].name 95 | } 96 | return null 97 | } 98 | 99 | open fun getConstVariableType(variable:String):String?{ 100 | return null 101 | } 102 | 103 | open fun newScope(): Scope { 104 | val scope = Scope(this) 105 | return scope 106 | } 107 | 108 | open fun newClassScope(): Scope { 109 | val scope = ClassScope(this) 110 | return scope 111 | } 112 | 113 | override fun toString(): String { 114 | return JSON.toJSONString(this) 115 | } 116 | 117 | 118 | fun discovery(field:KtDeclaration):Scope{ 119 | when (field) { 120 | is KtClassOrObject -> { 121 | ClassDiscoverer.onDiscovery(field,this) 122 | } 123 | } 124 | return this 125 | } 126 | 127 | fun discovery(file:KtFile):Scope{ 128 | FileDiscoverer.onDiscovery(file,this) 129 | return this 130 | } 131 | 132 | class ClassScope(parent: Scope? = null, name:String? = null) : Scope(parent,name) 133 | } 134 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/gen/swift/structed/Class.kt: -------------------------------------------------------------------------------- 1 | package com.liam.gen.swift.expr 2 | 3 | import com.liam.ast.writer.Statement 4 | import com.liam.gen.swift.* 5 | import com.liam.gen.swift.scope.FuncInfo 6 | import com.liam.gen.swift.scope.Scope 7 | import org.jetbrains.kotlin.psi.* 8 | 9 | open class Class : Handler { 10 | 11 | fun genConstructor(gen: CodeGen,constructor:KtPrimaryConstructor,className: String,statement: Statement,scope: Scope){ 12 | val args = ArrayList() 13 | constructor.valueParameters.forEach { 14 | val name = it.name 15 | val type = it.typeReference?.let { TypeUtils.getType(it) } 16 | args.add(FuncInfo.Args(name!!,type!!)) 17 | } 18 | scope.addFunc(FuncInfo(className, args)) 19 | statement.nextLine() 20 | statement.append("init(") 21 | } 22 | 23 | fun genConstructor(gen: CodeGen,constructor:KtSecondaryConstructor,className: String,statement: Statement,scope: Scope){ 24 | 25 | } 26 | 27 | override fun genCode(gen: CodeGen, v: KtClass, statement: Statement, scope: Scope, targetType: String?, expectType: String?, shouldReturn: Boolean): String? { 28 | if(v.isEnum() || v.isInterface()){ 29 | notSupport() 30 | } 31 | val className = v.name!! 32 | statement.append("class $className") 33 | val newScope = scope.newClassScope() 34 | v.primaryConstructor?.let { genConstructor(gen,it,className,statement,scope) } 35 | v.declarations?.let { 36 | statement.append(" {") 37 | statement.openQuote() 38 | it.forEach { 39 | gen.genDeclaration(it,statement,newScope,targetType,expectType, shouldReturn) 40 | } 41 | statement.closeQuote() 42 | statement.append("}") 43 | print("") 44 | } 45 | statement.nextLine() 46 | return className 47 | } 48 | 49 | 50 | companion object:Class() 51 | 52 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/uitls/PackageUtils.kt: -------------------------------------------------------------------------------- 1 | package com.liam.uitls 2 | 3 | import java.io.File 4 | import java.io.FileInputStream 5 | import java.util.* 6 | import java.util.jar.JarInputStream 7 | import kotlin.collections.ArrayList 8 | 9 | 10 | /** 11 | * @author liaomin 12 | * @date 6/24/20 4:23 下午 13 | * @version 1.0 14 | */ 15 | class PackageUtils { 16 | companion object{ 17 | 18 | @Throws(Exception::class) 19 | fun getClassesInPackage(packageName: String) = with(packageName.replace(".", File.separator)) { 20 | System.getProperty("java.class.path") 21 | .split(System.getProperty("path.separator").toRegex()) 22 | .flatMap { classpathEntry -> 23 | if (classpathEntry.endsWith(".jar")) { 24 | JarInputStream(FileInputStream(File(classpathEntry))).use { s -> 25 | generateSequence { s.nextJarEntry } 26 | .map { it.name } 27 | .filter { this in it && it.endsWith(".class") } 28 | .map { it.substring(0, it.length - 6) } 29 | .map { it.replace('|', '.').replace('/', '.') } 30 | .map { Class.forName(it) } 31 | .toList() 32 | } 33 | } else { 34 | File(classpathEntry, this).list() 35 | ?.asSequence() 36 | ?.filter { it.endsWith(".class") } 37 | ?.map { it.substring(0, it.length - 6) } 38 | ?.map { Class.forName("$packageName.$it") } 39 | ?.toList() ?: emptyList() 40 | return getClassesInFile(packageName,File(classpathEntry, this)) 41 | } 42 | } 43 | } 44 | 45 | @Throws(Exception::class) 46 | fun getClassesInFile(prefix:String,file: File):List>{ 47 | val res = ArrayList>() 48 | val list = file.listFiles() 49 | for (f in list){ 50 | if(f.isDirectory){ 51 | var p = Optional.ofNullable(prefix).orElse("") 52 | res.addAll(getClassesInFile("$p.${f.name}",f)) 53 | }else{ 54 | var name = f.name 55 | if(name.endsWith(".class")){ 56 | name = name.substring(0, name.length - 6) 57 | } 58 | res.add(Class.forName("$prefix.$name")) 59 | } 60 | } 61 | return res 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/kotlin/com/liam/uitls/SourceFileWatch.kt: -------------------------------------------------------------------------------- 1 | package com.liam.uitls 2 | 3 | import com.sun.nio.file.SensitivityWatchEventModifier 4 | import java.io.File 5 | import java.lang.reflect.Field 6 | import java.nio.file.* 7 | import java.nio.file.FileSystems.getDefault 8 | import kotlin.concurrent.thread 9 | 10 | /** 11 | * @author liaomin 12 | * @date 6/3/20 5:23 下午 13 | * @version 1.0 14 | */ 15 | class SourceFileWatch(path:String = ".") { 16 | 17 | companion object{ 18 | var dirField:Field? = null 19 | } 20 | 21 | val ws: WatchService 22 | 23 | init { 24 | val fileSystem = getDefault() 25 | ws = fileSystem.newWatchService() 26 | val dir = File(path); 27 | register(dir) 28 | } 29 | 30 | fun register(file:File){ 31 | if(file.isDirectory){ 32 | file.listFiles().forEach(this::register) 33 | val path = Paths.get(file.absolutePath) 34 | path.register(ws, arrayOf(StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE), SensitivityWatchEventModifier.HIGH) 35 | } 36 | } 37 | 38 | fun getDirField(c:Class){ 39 | if(dirField == null){ 40 | try { 41 | val field = c.getDeclaredField("dir") 42 | dirField = field 43 | field.isAccessible = true 44 | }catch (e:Exception){ 45 | val sc = c.superclass 46 | if(sc != null){ 47 | getDirField(sc) 48 | } 49 | } 50 | 51 | } 52 | } 53 | 54 | fun watch(cb:(file:File, kind: WatchEvent.Kind)->Unit){ 55 | thread { 56 | while (true){ 57 | val key = ws.take() 58 | getDirField(key.javaClass) 59 | val path = dirField?.get(key) as Path 60 | val dir = path.toFile().absoluteFile 61 | val events = key.pollEvents() 62 | events.forEach { 63 | val name = it.context().toString() 64 | val file = File(dir,name) 65 | if(file.exists() && file.isFile){ 66 | cb(file,it.kind() as WatchEvent.Kind) 67 | } 68 | } 69 | key.reset() 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | 2 | import com.alibaba.fastjson.JSON 3 | import com.liam.ast.psi.Converter 4 | import com.liam.ast.psi.Node 5 | import com.liam.ast.psi.Parser 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftWriter 8 | import com.liam.gen.swift.FileCodeGen 9 | import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles 10 | import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment 11 | //import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer 12 | //import org.jetbrains.kotlin.com.intellij.psi.PsiElement 13 | import org.jetbrains.kotlin.config.CompilerConfiguration 14 | import java.io.File 15 | import java.io.FileReader 16 | import java.io.FileWriter 17 | 18 | /** 19 | * @author liaomin 20 | * @date 6/17/20 10:51 下午 21 | * @version 1.0 22 | */ 23 | 24 | fun main() { 25 | val sourceFile = File("/Users/liaomin/Documents/ideaProject/Kotlin2Swift/src/main/kotlin/Test.kt") 26 | val reader = FileReader(sourceFile) 27 | val code = reader.readText() 28 | val c = Converter() 29 | val ktFile = Parser().parsePsiFile(code) 30 | FileCodeGen(ktFile).genCode() 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/main2.kt: -------------------------------------------------------------------------------- 1 | 2 | import com.alibaba.fastjson.JSON 3 | import com.liam.ast.psi.Converter 4 | import com.liam.ast.psi.Node 5 | import com.liam.ast.psi.Parser 6 | import com.liam.ast.writer.Statement 7 | import com.liam.ast.writer.SwiftWriter 8 | import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles 9 | import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment 10 | //import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer 11 | //import org.jetbrains.kotlin.com.intellij.psi.PsiElement 12 | import org.jetbrains.kotlin.config.CompilerConfiguration 13 | import java.io.File 14 | import java.io.FileReader 15 | import java.io.FileWriter 16 | 17 | /** 18 | * @author liaomin 19 | * @date 6/17/20 10:51 下午 20 | * @version 1.0 21 | */ 22 | 23 | fun testWrite(swiftWriter: SwiftWriter, inFile:File, outFile:File){ 24 | if(inFile.exists()){ 25 | if(!outFile.parentFile.exists()){ 26 | outFile.parentFile.mkdirs() 27 | } 28 | if(inFile.isDirectory){ 29 | inFile.listFiles().forEach { 30 | var name = it.name 31 | if(name.endsWith(".kt")){ 32 | name = name.substring(0,name.length - 3) +".swift" 33 | } 34 | testWrite(swiftWriter, it, File(outFile,name)) 35 | } 36 | } 37 | if(inFile.isFile && inFile.name.endsWith(".kt")){ 38 | var of = outFile 39 | if(!outFile.name.endsWith(".swift")){ 40 | var name = inFile.name 41 | name = name.substring(0,name.length - 3) +".swift" 42 | of = File(outFile,name) 43 | } 44 | val sourceFile = inFile 45 | var fr: FileReader? = null 46 | var fw: FileWriter? = null 47 | try { 48 | val reader = FileReader(sourceFile) 49 | val code = reader.readText() 50 | fr = reader 51 | val f = Parser.parseFile(code) 52 | val s = Statement() 53 | val start = System.currentTimeMillis() 54 | swiftWriter.write(f,s) 55 | println(s) 56 | print(System.currentTimeMillis() - start) 57 | fw = FileWriter(of) 58 | fw.write(s.toString()) 59 | }finally { 60 | fw?.close() 61 | fr?.close() 62 | } 63 | } 64 | } 65 | } 66 | 67 | fun main() { 68 | 69 | var fr: FileReader? = null 70 | // val sourceFile = File("/Users/liaomin/Documents/ideaProject/Kotlin/kern/SharedCode/src/commonMain/kotlin/com/hitales/ui/View.kt") 71 | val sourceFile = File("/Users/liaomin/Documents/ideaProject/Kotlin2Swift/src/main/kotlin/Test.kt") 72 | // val sourceFile = File("/Users/liaomin/Documents/ideaProject/Kotlin2Swift/src/main/kotlin/com/liam/ast/psi/Node.kt") 73 | 74 | try { 75 | val reader = FileReader(sourceFile) 76 | val code = reader.readText() 77 | fr = reader 78 | val parser = Parser() 79 | val f = parser.parseFile(code) 80 | println(JSON.toJSONString(f)) 81 | // 82 | // 83 | // print("") 84 | // 85 | val writer = SwiftWriter() 86 | // val s = Statement() 87 | // val start = System.currentTimeMillis() 88 | // writer.write(f,s) 89 | // println(s) 90 | // print(System.currentTimeMillis() - start) 91 | 92 | val testDire = File("./src/main/kotlin/com/liam/test") 93 | testWrite(writer,testDire,File("/Users/liaomin/Documents/ioslearn/Learn/Learn/conver")) 94 | 95 | 96 | }finally { 97 | fr?.close() 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/kotlin/com/liam/test/GenTest.kt: -------------------------------------------------------------------------------- 1 | package com.liam.test 2 | 3 | import ControlFlow 4 | import com.liam.ast.psi.Converter 5 | import com.liam.ast.psi.Parser 6 | import com.liam.gen.swift.FileCodeGen 7 | import org.junit.BeforeClass 8 | import org.junit.Test; 9 | import java.io.File 10 | import java.io.FileReader 11 | import java.io.FileWriter 12 | 13 | open class GenTest { 14 | 15 | 16 | fun testGen(path: String){ 17 | val outFile = File("/Users/liaomin/Documents/ioslearn/Learn/Learn/conver/${path.replace(".kt",".swift")}") 18 | if(outFile.parentFile.exists()){ 19 | outFile.parentFile.mkdirs() 20 | } 21 | val file = File("./src/test/kotlin/${GenTest::class.java.`package`.name.replace(".","/")}",path) 22 | val sourceFile = file 23 | val reader = FileReader(sourceFile) 24 | val code = reader.readText() 25 | val ktFile = Parser().parsePsiFile(code) 26 | val codeGen = FileCodeGen(ktFile) 27 | codeGen.genCode() 28 | val fw = FileWriter(outFile) 29 | fw.write(codeGen.statement.toString()) 30 | fw.close() 31 | } 32 | 33 | @Test 34 | fun testBasicFunction(){ 35 | testGen("basic/Functions.kt") 36 | } 37 | 38 | @Test 39 | fun testBasicType(){ 40 | testGen("basic/Type.kt") 41 | } 42 | 43 | @Test 44 | fun testBasicControlFlow(){ 45 | val q = ControlFlow().hasPrefix(1) 46 | testGen("basic/ControlFlow.kt") 47 | } 48 | 49 | companion object{ 50 | @BeforeClass 51 | @JvmStatic 52 | fun setUpBeforeClass(){ 53 | println("222") 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/liam/test/basic/ControlFlow.kt: -------------------------------------------------------------------------------- 1 | //package com.liam.test.basic 2 | // 3 | //import org.jetbrains.kotlin.resolve.constants.evaluate.parseBoolean 4 | // 5 | ///** 6 | // * https://kotlinlang.org/docs/reference/control-flow.html 7 | // * @author liaomin 8 | // * @date 6/28/20 4:48 下午 9 | // * @version 1.0 10 | // */ 11 | 12 | fun a():Int{ 13 | return 1 14 | } 15 | 16 | fun b():Int{ 17 | return 1 18 | } 19 | 20 | fun c():Int{ 21 | if(a() > b()) return 1 22 | return 2 23 | } 24 | 25 | 26 | fun d():Int{ 27 | val t = if(a() > b()) 1 else 2 28 | val t2 = if(a() > b()) { 29 | c() 30 | b() 31 | } else 2 32 | return t2 33 | } 34 | 35 | fun println(s:String){ 36 | 37 | } 38 | 39 | 40 | val q2 = if (true) a() else b() 41 | 42 | val q3 = if (c() > 1) { a() } else b() 43 | val q4 = if (c() > 1) { 44 | var i = 1 45 | a() 46 | 47 | } else b() 48 | 49 | 50 | 51 | class ControlFlow { 52 | fun hasPrefix(x: Any) = when(x) { 53 | is String -> { 54 | println("") 55 | true 56 | } 57 | else -> false 58 | } 59 | fun ifExpression(){ 60 | whenExpression(1) 61 | // Traditional usage 62 | val a = 1 63 | val b = 2 64 | var max = a 65 | if (a < b) max = b 66 | if (a > b) { 67 | max = a 68 | } else if(b > a){ 69 | max = b 70 | }else{ 71 | max = 1 72 | } 73 | if (a > b) a else b 74 | if (a > b) { 75 | whenExpression(1) 76 | this.whenExpression(1) 77 | println("Choose a") 78 | a 79 | } else { 80 | whenExpression(1) 81 | this.whenExpression(1) 82 | println("Choose b") 83 | b 84 | } 85 | } 86 | 87 | fun whenExpression(x:Int=0,y:Int= 2){ 88 | fun hasPrefix(x: Any) = when(x) { 89 | is String -> true 90 | else -> false 91 | } 92 | when (x) { 93 | is Int -> println("x is Int") 94 | else -> { // Note the block 95 | println("x is neither 1 nor 2") 96 | } 97 | } 98 | } 99 | 100 | fun ForLoops(){ 101 | // for (i in 1..3) { 102 | // println(i) 103 | // } 104 | // for (i in 6 downTo 0 step 2) { 105 | // println(i) 106 | // } 107 | // val array = ArrayList() 108 | // for ((index, value) in array.withIndex()) { 109 | // println("the element at $index is $value") 110 | // } 111 | } 112 | 113 | fun WhileLoops(){ 114 | var x = 1000 115 | while (x > 0) { 116 | x-- 117 | } 118 | 119 | fun retrieveData():String{ 120 | return "" 121 | } 122 | 123 | do { 124 | val dqdq = q23 125 | val y = retrieveData() 126 | } while (y != null) // y is visible here! 127 | } 128 | 129 | val qee = 1 130 | } 131 | 132 | val q23 = 1 133 | -------------------------------------------------------------------------------- /src/test/kotlin/com/liam/test/basic/Functions.kt: -------------------------------------------------------------------------------- 1 | package com.liam.test.basic 2 | 3 | class Q { 4 | 5 | } 6 | 7 | //fun TE(int: Int = 1,string: String):Int{ 8 | // val intw = 1 9 | // val temp = intw as T 10 | // val ww= intw 11 | // return ww 12 | //} 13 | 14 | -------------------------------------------------------------------------------- /src/test/kotlin/com/liam/test/basic/Type.kt: -------------------------------------------------------------------------------- 1 | package com.liam.test.basic 2 | 3 | /** 4 | * test for https://kotlinlang.org/docs/reference/basic-types.html 5 | * @author liaomin 6 | * @date 6/27/20 10:56 上午 7 | * @version 1.0 8 | */ 9 | class BasicTypes { 10 | fun a(){ 11 | 12 | } 13 | 14 | val str1 = "dwdw" 15 | val str = """ 16 | for (c in "foo") 17 | print(c) 18 | """ 19 | // TODO convert 20 | val UL = 1UL 21 | val UI = 1U 22 | // val toB = UI.toByte() 23 | // val toB2 = !true 24 | // val toShort = 1.toShort() 25 | // val toChar = 1.toChar() 26 | // val toInt = 1.toInt() 27 | // val toLong = 1.toLong() 28 | // val toFloat = 1.toFloat() 29 | // val toDouble = 1.toDouble() 30 | // 31 | // 32 | // val inv = 1.inv() 33 | // val rq = 1 shl 1 34 | // val rOR = 1 or 1 35 | // val rAnd = 1 and 1 36 | // val rXOR = 1 xor 1 37 | // val rushr = 1 ushr 1 38 | // val shr = 1 shr 1 39 | // 40 | // 41 | // 42 | val c:Char = 'a' 43 | val byte:Byte = 1 44 | val short:Short = 1 45 | val int:Int = 1 46 | val long:Long = 1 47 | val ubyte:UByte = 1u 48 | val ushort:UShort = 1u 49 | val uint:UInt = 1u 50 | val ulong:ULong = 1u 51 | val float:Float = 1.0f 52 | val double:Double = 1.02 53 | 54 | val one = 1 // Int 55 | val threeBillion = 3000000000 // Long 56 | val oneLong = 1L // Long 57 | val oneByte: Byte = 1 58 | 59 | val pi = 3.14 // Double 60 | val e = 2.7182818284 // Double 61 | val eFloat = 2.7182818284f // Float, actual value is 2.7182817 62 | 63 | var bt:Boolean = true 64 | var bf:Boolean = false 65 | 66 | val l = 1L + 3 // Long + Int => Long 67 | } 68 | -------------------------------------------------------------------------------- /src/test/kotlin/com/liam/test/collections/In.kt: -------------------------------------------------------------------------------- 1 | package com.liam.test.collections 2 | 3 | --------------------------------------------------------------------------------