All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jtransc.gen.as3.As3Target.kt Maven / Gradle / Ivy

Go to download

JVM AOT compiler currently generating JavaScript, C++, Haxe, with initial focus on Kotlin and games.

There is a newer version: 0.6.8
Show newest version
package com.jtransc.gen.as3

import com.jtransc.ConfigOutputFile
import com.jtransc.ConfigTargetDirectory
import com.jtransc.ast.*
import com.jtransc.ast.feature.method.GotosFeature
import com.jtransc.ast.feature.method.SwitchFeature
import com.jtransc.ds.getOrPut2
import com.jtransc.error.invalidOp
import com.jtransc.gen.GenTargetDescriptor
import com.jtransc.gen.TargetBuildTarget
import com.jtransc.gen.common.*
import com.jtransc.injector.Injector
import com.jtransc.injector.Singleton
import com.jtransc.io.ProcessResult2
import com.jtransc.lang.map
import com.jtransc.text.Indenter
import com.jtransc.text.quote
import com.jtransc.vfs.*
import java.io.File

// Supports GOTO keyword
// Supports static fields and methods on interfaces
class As3Target : GenTargetDescriptor() {
	override val name = "as3"
	override val longName = "ActionScript3"
	override val sourceExtension = "as"
	override val outputExtension = "swf"
	override val extraLibraries = listOf()
	override val extraClasses = listOf()
	override val runningAvailable = true
	override val programFeatures: Set> = setOf()

	override val buildTargets: List = listOf(
		TargetBuildTarget("as3", "as3", "program.as", minimizeNames = false)
	)

	@Suppress("ConvertLambdaToReference")
	override fun getGenerator(injector: Injector): CommonGenerator {
		val settings = injector.get()
		val configTargetDirectory = injector.get()
		val configOutputFile = injector.get()
		val targetFolder = LocalVfsEnsureDirs(File("${configTargetDirectory.targetDirectory}/jtransc-as3"))
		injector.mapInstance(CommonGenFolders(settings.assets.map { LocalVfs(it) }))
		injector.mapInstance(ConfigTargetFolder(targetFolder))
		injector.mapInstance(ConfigSrcFolder(targetFolder))
		injector.mapInstance(ConfigOutputFile2(targetFolder[configOutputFile.outputFileBaseName].realfile))
		return injector.get()
	}

	override fun getTargetByExtension(ext: String): String? = when (ext) {
		"swf" -> "as3"
		else -> null
	}
}

@Singleton
class As3Generator(injector: Injector) : CommonGenerator(injector) {
	override val SINGLE_FILE: Boolean = false

	//class DGenerator(injector: Injector) : FilePerClassCommonGenerator(injector) {
	override val methodFeatures = setOf(SwitchFeature::class.java, GotosFeature::class.java)
	override val methodFeaturesWithTraps = setOf(SwitchFeature::class.java)
	override val stringPoolType: StringPool.Type = StringPool.Type.GLOBAL
	override val interfacesSupportStaticMembers: Boolean = false

	override val keywords = setOf(
		"abstract", "alias", "align", "asm", "assert", "auto",
		"body", "bool", "break", "byte",
		"case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class", "const", "continue", "creal",
		"dchar", "debug", "default", "delegate", "delete", "deprecated", "do", "double",
		"else", "enum", "export", "extern",
		"false", "final", "finally", "float", "for", "foreach", "foreach_reverse", "function",
		"goto",
		"internal",
		"idouble", "if", "ifloat", "immutable", "import", "in", "inout", "int", "interface", "invariant", "ireal", "is",
		"lazy", "long",
		"macro", "mixin", "module",
		"new", "nothrow", "null",
		"out", "override",
		"package", "pragma", "private", "protected", "public", "pure",
		"real", "ref", "return",
		"scope", "shared", "short", "static", "struct", "super", "switch", "synchronized",
		"template", "this", "throw", "true", "try", "typedef", "typeid", "typeof",
		"ubyte", "ucent", "uint", "ulong", "union", "unittest", "ushort",
		"version", "void", "volatile",
		"wchar", "while", "with",
		"__FILE__", "__FILE_FULL_PATH__", "__MODULE__", "__LINE__", "__FUNCTION__", "__PRETTY_FUNCTION__", "static", "__traits", "__vector", "__parameters",

		// Known Object symbols
		"clone", "toString",
		"std", "core"
	)

	override val languageRequiresDefaultInSwitch = true
	override val defaultGenStmSwitchHasBreaks = true

	override fun genCompilerCommand(programFile: File, debug: Boolean, libs: List): List {
		return As3Compiler.genCommand(programFile.parentFile, File(programFile.parentFile, "Main.as"), debug, libs)
	}

	override fun setTemplateParamsAfterBuildingSource() {
		super.setTemplateParamsAfterBuildingSource()
		params["AIRSDK_VERSION_INT"] = As3Compiler.AIRSDK_VERSION_INT
		params["BASE_CLASSES_FQNAMES"] = getClassesForStaticConstruction().map { it.name.targetName }
		params["STATIC_CONSTRUCTORS"] = genStaticConstructorsSortedLines()
	}

	@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
	private fun _getActualFqName(name: FqName): FqName {
		val realclass = if (name in program) program[name] else null
		return FqName(classNames.getOrPut2(name) {
			if (realclass?.nativeName != null) {
				realclass!!.nativeName!!
			} else {
				FqName(name.packageParts.map { if (it in keywords) "${it}_" else it }.map(String::decapitalize), "${name.simpleName.replace('$', '_')}_".capitalize()).fqname
			}
		})
	}

	//override fun getClassBaseFilename(clazz: AstClass): String = clazz.actualFqName.fqname.replace('.', '/').replace('$', '_')
	//override fun getClassBaseFilename(clazz: AstClass): String = clazz.actualFqName.fqname.replace('.', '/').replace('$', '_')
	override fun getClassBaseFilename(clazz: AstClass): String = clazz.fqname.replace('.', '_').replace('$', '_')
	override fun getClassFilename(clazz: AstClass) = getClassBaseFilename(clazz) + ".as"

	override val FqName.targetName: String get() = this.fqname.replace('.', '_').replace('$', '_')
	//override val FqName.targetName: String get() = this.actualFqName.fqname.replace('$', '_')

	override fun run(redirect: Boolean): ProcessResult2 {
		val names = listOf("Main.xml")
		val outFile = names.map { configTargetFolder.targetFolder[it] }.firstOrNull { it.exists } ?: invalidOp("Not generated output file $names")

		val cmdAndArgs = listOf(As3Compiler.ADL, outFile.realpathOS)

		return ProcessResult2(RootLocalVfs().exec(cmdAndArgs, ExecOptions(passthru = redirect, sysexec = true)))
	}

	override fun writeClasses(output: SyncVfsFile) {
		//println(program.resourcesVfs)
		super.writeClasses(output)
		println(output)
	}

	override fun genField(field: AstField): Indenter = Indenter.gen {
		val static = field.isStatic.map("static ", "")

		line("public ${static}var ${field.targetName}: ${field.type.targetName} = ${field.type.getNull().escapedConstant};")
	}

	override fun genClass(clazz: AstClass): Indenter = Indenter {
		line("package") {
			line(super.genClass(clazz))
		}
	}

	//override fun genClasses(output: SyncVfsFile): Indenter = Indenter.gen {
	//	val StringFqName = buildTemplateClass("java.lang.String".fqname)
	//	val classesStr = super.genClasses(output)
	//	line(classesStr)
	//	line("class Bootstrap") {
	//		for (lit in getGlobalStrings()) {
	//			line("static public $StringFqName ${lit.name};")
	//		}
	//		line("static public void __initStrings()") {
	//			for (lit in getGlobalStrings()) {
	//				// STRINGLIT_
	//				line("${lit.name} = N.strLitEscape(${lit.str.quote()});")
	//			}
	//		}
	//		val entryPointFqName = program.entrypoint
	//		val entryPointClass = program[entryPointFqName]
	//		line("static void Main(string[] args)") {
	//			line("try {")
	//			indent {
	//				line("N.init();")
	//				line("__initStrings();")
	//				line(genStaticConstructorsSorted())
	//				//line(buildStaticInit(entryPointFqName))
	//				val mainMethod = entryPointClass[AstMethodRef(entryPointFqName, "main", AstType.METHOD(AstType.VOID, ARRAY(AstType.STRING)))]
	//				line(buildMethod(mainMethod, static = true) + "(N.strArray(args));")
	//			}
	//			line("} catch (WrappedThrowable e) {")
	//			indent {
	//				line("Console.WriteLine(e.t.ToString());")
	//				line("Console.WriteLine(e.ToString());")
	//			}
	//			line("} catch (Exception e) {")
	//			indent {
	//				line("Console.WriteLine(e.ToString());")
	//			}
	//			line("}")
	//		}
	//	}
	//}

	override fun N_ASET_T(arrayType: AstType.ARRAY, elementType: AstType, array: String, index: String, value: String): String {
		if (elementType is AstType.Primitive) {
			return "$array[$index] = ($value) as ${elementType.targetName};"
		} else {
			return "$array[$index] = ($value) as ${AstType.OBJECT.targetName};"
		}
	}

	override fun genClassDecl(clazz: AstClass, kind: MemberTypes): String {
		val CLASS = if (clazz.isInterface) "interface" else "class"
		var decl = "public $CLASS ${clazz.name.targetSimpleName}"
		decl += genClassDeclExtendsImplements(clazz, kind)
		return decl
	}

	override val AstLocal.decl: String get() = "var ${this.targetName}: ${this.type.localDeclType} = ${this.type.nativeDefaultString};"
	override val AstArgument.decl: String get() = "${this.targetName}: ${this.type.localDeclType}"

	override fun genMetodDecl(method: AstMethod): String {
		val args = method.methodType.args.map { it.decl }

		//if (method.isInstanceInit) mods += "final "

		val mods = genMethodDeclModifiers(method)
		return "$mods function ${method.targetName}(${args.joinToString(", ")}): ${method.actualRetType.targetName}"
	}

	override fun genMethodDeclModifiers(method: AstMethod): String {
		if (method.containingClass.isInterface) {
			return "public " + method.isStatic.map("static ", "")
		} else {
			var mods = ""
			if (!method.isStatic && method.targetIsOverriding) mods += "override "
			if (method.isStatic) mods += "static "
			mods += "public "
			return mods
		}
	}

	override fun genExprIntArrayLit(e: AstExpr.INTARRAY_LITERAL): String {
		return "JA_I${staticAccessOperator}T(new[ " + e.values.joinToString(",") + " ])"
	}

	override fun N_f2d(str: String) = "Number($str)"
	override fun N_d2f(str: String) = "Number($str)"

	override fun N_is(a: String, b: String): String = "(($a) is $b)"

	override val NullType by lazy { AstType.OBJECT.targetName }
	override val VoidType = "void"
	override val BoolType = "boolean"
	override val IntType = "int"
	override val ShortType = "int"
	override val CharType = "int"
	override val ByteType = "int"
	override val FloatType = "Number"
	override val DoubleType = "Number"
	override val LongType = "Long"

	override val FqName.targetSimpleName: String get() = this.targetName

	override fun N_c(str: String, from: AstType, to: AstType) = "(($str) as ${to.targetName})"

	override fun genExprArrayLength(e: AstExpr.ARRAY_LENGTH): String = "(${e.array.genNotNull()} as $BaseArrayType).length"
	override fun genStmThrow(stm: AstStm.THROW) = Indenter("throw new WrappedThrowable(${stm.value.genExpr()});")

	override fun genStmLabelCore(stm: AstStm.STM_LABEL) = "${stm.label.name}:"

	override fun genSIMethod(clazz: AstClass): Indenter = Indenter.gen {
		if (clazz.isJavaLangObject) {
			line("override public string ToString()") {
				val toStringMethodName = buildMethod(clazz.getMethodWithoutOverrides("toString")!!, static = false)
				line("return N.istr($toStringMethodName());")
			}
		}

		if (!clazz.isInterface) {
			if (clazz.isJavaLangObject) {
				line("public __AS3__CLASS_ID: int;")
				line("public function ${clazz.name.targetName}(CLASS_ID: int = ${clazz.classId}) { this.__AS3__CLASS_ID = CLASS_ID; }")
			} else {
				line("public function ${clazz.name.targetName}(CLASS_ID: int = ${clazz.classId}) { super(CLASS_ID); }")
			}
		}
		if (clazz.staticConstructor != null) {
			line("static public function SI(): void") {
				val clazzName = if (clazz.isInterface) clazz.name.targetNameForStatic else clazz.name.targetName
				for (field in clazz.fields.filter { it.isStatic }) {
					line("$clazzName.${field.targetName} = ${field.escapedConstantValue};")
				}
				line(genSIMethodBody(clazz))
			}
		} else {
			line("static public function SI(): void { }")
		}
	}

	//override fun N_i(str: String) = "((int)($str))"
	override fun N_i(str: String) = "($str)"

	//override fun N_f2i(str: String) = "((int)($str))"
	override fun N_d2i(str: String) = "int($str)"

	override fun N_c_eq(l: String, r: String) = "($l == $r)"
	override fun N_c_ne(l: String, r: String) = "($l != $r)"

	override fun N_i2f(str: String) = "Number($str)"
	override fun N_i2d(str: String) = "Number($str)"

	override fun N_l2f(str: String) = "Number($str)"
	override fun N_l2d(str: String) = "Number($str)"

	//override fun N_c_div(l: String, r: String) = "unchecked($l / $r)"

	override fun N_idiv(l: String, r: String): String = "N.idiv($l, $r)"
	override fun N_irem(l: String, r: String): String = "N.irem($l, $r)"

	override fun N_lnew(value: Long): String = "((long)(${value}L))"

	override fun genMissingBody(method: AstMethod): Indenter = Indenter.gen {
		val message = "Missing body ${method.containingClass.name}.${method.name}${method.desc}"
		line("throw new Error(${message.quote()});")
	}

	override fun genStmTryCatch(stm: AstStm.TRY_CATCH) = indent {
		line("try") {
			line(stm.trystm.genStm())
		}
		line("catch (WrappedThrowable J__i__exception__)") {
			line("J__exception__ = J__i__exception__.t;")
			line(stm.catch.genStm())
		}
	}

	override fun N_c_ushr(l: String, r: String) = "int((uint($l)) >> $r)"

	override fun createArrayMultisure(e: AstExpr.NEW_ARRAY, desc: String): String {
		return "$ObjectArrayType${staticAccessOperator}createMultiSure(\"$desc\", ${e.counts.map { it.genExpr() }.joinToString(", ")})"
	}

	override val NegativeInfinityString = "Double.NegativeInfinity"
	override val PositiveInfinityString = "Double.PositiveInfinity"
	//override val NanString = "Double.NaN"
	override val NanString = "N.DoubleNaN"

	override val String.escapeString: String get() = "Bootstrap.STRINGLIT_${allocString(currentClass, this)}"

	override fun AstExpr.genNotNull(): String {
		if (debugVersion) {
			return "(" + genExpr2(this) + ")"
		} else {
			return genExpr2(this)
		}
	}

	override fun escapedConstant(v: Any?): String = when (v) {
		is Float -> if (v.isInfinite()) if (v < 0) NegativeInfinityString else PositiveInfinityString else if (v.isNaN()) NanString else "${v}f"
		else -> super.escapedConstant(v)
	}

	override fun genExprCallBaseSuper(e2: AstExpr.CALL_SUPER, clazz: AstType.REF, refMethodClass: AstClass, method: AstMethodRef, methodAccess: String, args: List): String {
		return "base$methodAccess(${args.joinToString(", ")})"
	}

	override fun genStmMonitorEnter(stm: AstStm.MONITOR_ENTER) = indent {
		line("N.monitorEnter(" + stm.expr.genExpr() + ");")
	}

	override fun genStmMonitorExit(stm: AstStm.MONITOR_EXIT) = indent {
		line("N.monitorExit(" + stm.expr.genExpr() + ");")
	}

	override fun buildStaticInit(clazzName: FqName): String? = null
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy