[JS IR] JS AST serialization
This commit is contained in:
committed by
teamcityserver
parent
95ab5e1b7e
commit
b1b88a0d11
+3
-2
@@ -175,7 +175,8 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
|||||||
override fun visitWhileLoop(loop: IrWhileLoop, context: JsGenerationContext): JsStatement {
|
override fun visitWhileLoop(loop: IrWhileLoop, context: JsGenerationContext): JsStatement {
|
||||||
//TODO what if body null?
|
//TODO what if body null?
|
||||||
val label = context.getNameForLoop(loop)
|
val label = context.getNameForLoop(loop)
|
||||||
val loopStatement = JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
val loopStatement = JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context),
|
||||||
|
loop.body?.accept(this, context) ?: JsEmpty)
|
||||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +184,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
|||||||
//TODO what if body null?
|
//TODO what if body null?
|
||||||
val label = context.getNameForLoop(loop)
|
val label = context.getNameForLoop(loop)
|
||||||
val loopStatement =
|
val loopStatement =
|
||||||
JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context) ?: JsEmpty)
|
||||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.backend.js.eliminateDeadDeclarations
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
import org.jetbrains.kotlin.ir.backend.js.export.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstSerializer
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
@@ -26,6 +28,9 @@ import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
|||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
|
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
|
||||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializer
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class IrModuleToJsTransformer(
|
class IrModuleToJsTransformer(
|
||||||
@@ -84,7 +89,26 @@ class IrModuleToJsTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fragments
|
// TODO remove serialization -> deserialization work
|
||||||
|
val serialized = mutableListOf<Pair<IrFile, ByteArray>>()
|
||||||
|
|
||||||
|
val serializer = JsIrAstSerializer()
|
||||||
|
fragments.entries.forEach { (file, fragment) ->
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
serializer.serialize(fragment, output)
|
||||||
|
val binaryAst = output.toByteArray()
|
||||||
|
serialized += file to binaryAst
|
||||||
|
}
|
||||||
|
|
||||||
|
val restoredMap = mutableMapOf<IrFile, JsIrProgramFragment>()
|
||||||
|
|
||||||
|
val deserializer = JsIrAstDeserializer()
|
||||||
|
|
||||||
|
serialized.forEach { (file, binaryAst) ->
|
||||||
|
restoredMap[file] = deserializer.deserialize(ByteArrayInputStream(binaryAst))
|
||||||
|
}
|
||||||
|
|
||||||
|
return restoredMap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateWrappedModuleBody(
|
private fun generateWrappedModuleBody(
|
||||||
|
|||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule
|
||||||
|
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstDeserializerBase
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class JsIrAstDeserializer : JsAstDeserializerBase() {
|
||||||
|
override val scope = emptyScope
|
||||||
|
|
||||||
|
fun deserialize(input: InputStream): JsIrProgramFragment {
|
||||||
|
return deserialize(Chunk.parseFrom(CodedInputStream.newInstance(input).apply { setRecursionLimit(4096) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserialize(proto: Chunk): JsIrProgramFragment {
|
||||||
|
stringTable += proto.stringTable.entryList
|
||||||
|
nameTable += proto.nameTable.entryList
|
||||||
|
nameCache += nameTable.map { null }
|
||||||
|
try {
|
||||||
|
return deserialize(proto.fragment)
|
||||||
|
} finally {
|
||||||
|
stringTable.clear()
|
||||||
|
nameTable.clear()
|
||||||
|
nameCache.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deserialize(proto: Fragment): JsIrProgramFragment {
|
||||||
|
val fragment = JsIrProgramFragment(proto.packageFqn)
|
||||||
|
|
||||||
|
fragment.importedModules += proto.importedModuleList.map { importedModuleProto ->
|
||||||
|
JsImportedModule(
|
||||||
|
deserializeString(importedModuleProto.externalNameId),
|
||||||
|
deserializeName(importedModuleProto.internalNameId),
|
||||||
|
if (importedModuleProto.hasPlainReference()) deserialize(importedModuleProto.plainReference) else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
proto.importEntryList.associateTo(fragment.imports) { importProto ->
|
||||||
|
deserializeString(importProto.signatureId) to deserialize(importProto.expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.hasDeclarationBlock()) {
|
||||||
|
fragment.declarations.statements += deserializeGlobalBlock(proto.declarationBlock).statements
|
||||||
|
}
|
||||||
|
if (proto.hasInitializerBlock()) {
|
||||||
|
fragment.initializers.statements += deserializeGlobalBlock(proto.initializerBlock).statements
|
||||||
|
}
|
||||||
|
if (proto.hasExportBlock()) {
|
||||||
|
fragment.exports.statements += deserializeGlobalBlock(proto.exportBlock).statements
|
||||||
|
}
|
||||||
|
|
||||||
|
proto.nameBindingList.associateTo(fragment.nameBindings) { nameBindingProto ->
|
||||||
|
deserializeString(nameBindingProto.signatureId) to deserializeName(nameBindingProto.nameId)
|
||||||
|
}
|
||||||
|
|
||||||
|
proto.irClassModelList.associateTo(fragment.classes) { clsProto -> deserialize(clsProto) }
|
||||||
|
|
||||||
|
if (proto.hasTestsInvocation()) {
|
||||||
|
fragment.testFunInvocation = deserialize(proto.testsInvocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.hasMainInvocation()) {
|
||||||
|
fragment.mainFunction = deserialize(proto.mainInvocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto.hasSuiteFunction()) {
|
||||||
|
fragment.suiteFn = deserializeName(proto.suiteFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment.dts = proto.dts
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deserialize(proto: IrClassModel): Pair<JsName, JsIrClassModel> {
|
||||||
|
return deserializeName(proto.nameId) to JsIrClassModel(proto.superClassesList.map { deserializeName(it) }).apply {
|
||||||
|
if (proto.hasPreDeclarationBlock()) {
|
||||||
|
preDeclarationBlock.statements += deserializeGlobalBlock(proto.preDeclarationBlock).statements
|
||||||
|
}
|
||||||
|
if (proto.hasPostDeclarationBlock()) {
|
||||||
|
postDeclarationBlock.statements += deserializeGlobalBlock(proto.postDeclarationBlock).statements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun embedSources(deserializedLocation: JsLocation, file: String): JsLocationWithSource? = null
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializerBase
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
class JsIrAstSerializer: JsAstSerializerBase() {
|
||||||
|
|
||||||
|
fun serialize(fragment: JsIrProgramFragment, output: OutputStream) {
|
||||||
|
importedNames.clear()
|
||||||
|
importedNames += fragment.imports.map { fragment.nameBindings[it.key]!! }
|
||||||
|
serialize(fragment).writeTo(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serialize(fragment: JsIrProgramFragment): Chunk {
|
||||||
|
try {
|
||||||
|
val chunkBuilder = Chunk.newBuilder()
|
||||||
|
chunkBuilder.fragment = serializeFragment(fragment)
|
||||||
|
chunkBuilder.nameTable = nameTableBuilder.build()
|
||||||
|
chunkBuilder.stringTable = stringTableBuilder.build()
|
||||||
|
return chunkBuilder.build()
|
||||||
|
} finally {
|
||||||
|
nameTableBuilder.clear()
|
||||||
|
stringTableBuilder.clear()
|
||||||
|
nameMap.clear()
|
||||||
|
stringMap.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serializeFragment(fragment: JsIrProgramFragment): Fragment {
|
||||||
|
val fragmentBuilder = Fragment.newBuilder()
|
||||||
|
|
||||||
|
fragmentBuilder.packageFqn = fragment.packageFqn
|
||||||
|
|
||||||
|
for (importedModule in fragment.importedModules) {
|
||||||
|
val importedModuleBuilder = ImportedModule.newBuilder()
|
||||||
|
importedModuleBuilder.externalNameId = serialize(importedModule.externalName)
|
||||||
|
importedModuleBuilder.internalNameId = serialize(importedModule.internalName)
|
||||||
|
importedModule.plainReference?.let { importedModuleBuilder.plainReference = serialize(it) }
|
||||||
|
fragmentBuilder.addImportedModule(importedModuleBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((signature, expression) in fragment.imports) {
|
||||||
|
val importBuilder = Import.newBuilder()
|
||||||
|
importBuilder.signatureId = serialize(signature)
|
||||||
|
importBuilder.expression = serialize(expression)
|
||||||
|
fragmentBuilder.addImportEntry(importBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fragmentBuilder.declarationBlock = serializeBlock(fragment.declarations)
|
||||||
|
fragmentBuilder.initializerBlock = serializeBlock(fragment.initializers)
|
||||||
|
fragmentBuilder.exportBlock = serializeBlock(fragment.exports)
|
||||||
|
|
||||||
|
for ((key, name) in fragment.nameBindings.entries) {
|
||||||
|
val nameBindingBuilder = NameBinding.newBuilder()
|
||||||
|
nameBindingBuilder.signatureId = serialize(key)
|
||||||
|
nameBindingBuilder.nameId = serialize(name)
|
||||||
|
fragmentBuilder.addNameBinding(nameBindingBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment.classes.entries.forEach { (name, model) -> fragmentBuilder.addIrClassModel(serialize(name, model)) }
|
||||||
|
|
||||||
|
fragment.testFunInvocation?.let {
|
||||||
|
fragmentBuilder.setTestsInvocation(serialize(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment.mainFunction?.let {
|
||||||
|
fragmentBuilder.setMainInvocation(serialize(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment.dts?.let {
|
||||||
|
fragmentBuilder.dts = it
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment.suiteFn?.let {
|
||||||
|
fragmentBuilder.setSuiteFunction(serialize(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragmentBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serialize(name: JsName, classModel: JsIrClassModel): IrClassModel {
|
||||||
|
val builder = IrClassModel.newBuilder()
|
||||||
|
builder.nameId = serialize(name)
|
||||||
|
classModel.superClasses.forEach { builder.addSuperClasses(serialize(it)) }
|
||||||
|
if (classModel.preDeclarationBlock.statements.isNotEmpty()) {
|
||||||
|
builder.preDeclarationBlock = serializeBlock(classModel.preDeclarationBlock)
|
||||||
|
}
|
||||||
|
if (classModel.postDeclarationBlock.statements.isNotEmpty()) {
|
||||||
|
builder.postDeclarationBlock = serializeBlock(classModel.postDeclarationBlock)
|
||||||
|
}
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractLocation(node: JsNode): JsLocation? {
|
||||||
|
return node.source.safeAs<JsLocationWithSource>()?.asSimpleLocation()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -253,6 +253,7 @@ message Statement {
|
|||||||
ForIn for_in_statement = 36;
|
ForIn for_in_statement = 36;
|
||||||
Try try_statement = 37;
|
Try try_statement = 37;
|
||||||
Empty empty = 38;
|
Empty empty = 38;
|
||||||
|
SingleLineComment single_line_comment = 39;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +373,10 @@ message Catch {
|
|||||||
message Empty {
|
message Empty {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SingleLineComment {
|
||||||
|
required string message = 1;
|
||||||
|
}
|
||||||
|
|
||||||
enum InlineStrategy {
|
enum InlineStrategy {
|
||||||
AS_FUNCTION = 0;
|
AS_FUNCTION = 0;
|
||||||
IN_PLACE = 1;
|
IN_PLACE = 1;
|
||||||
@@ -395,6 +400,9 @@ message Fragment {
|
|||||||
optional Statement tests_invocation = 11;
|
optional Statement tests_invocation = 11;
|
||||||
optional Statement main_invocation = 12;
|
optional Statement main_invocation = 12;
|
||||||
repeated InlinedLocalDeclarations inlined_local_declarations = 13;
|
repeated InlinedLocalDeclarations inlined_local_declarations = 13;
|
||||||
|
repeated IrClassModel ir_class_model = 14;
|
||||||
|
optional string dts = 15;
|
||||||
|
optional int32 suite_function = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InlinedLocalDeclarations {
|
message InlinedLocalDeclarations {
|
||||||
@@ -425,6 +433,13 @@ message ClassModel {
|
|||||||
optional GlobalBlock post_declaration_block = 3;
|
optional GlobalBlock post_declaration_block = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message IrClassModel {
|
||||||
|
required int32 name_id = 1;
|
||||||
|
repeated int32 super_classes = 2;
|
||||||
|
optional GlobalBlock pre_declaration_block = 3;
|
||||||
|
optional GlobalBlock post_declaration_block = 4;
|
||||||
|
}
|
||||||
|
|
||||||
message InlineModule {
|
message InlineModule {
|
||||||
required int32 signature_id = 1;
|
required int32 signature_id = 1;
|
||||||
required int32 expression_id = 2;
|
required int32 expression_id = 2;
|
||||||
|
|||||||
+15
-476
@@ -31,12 +31,9 @@ import java.io.InputStream
|
|||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<File>) {
|
class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<File>) : JsAstDeserializerBase() {
|
||||||
private val scope = JsRootScope(program)
|
|
||||||
private val stringTable = mutableListOf<String>()
|
override val scope: JsRootScope = JsRootScope(program)
|
||||||
private val nameTable = mutableListOf<Name>()
|
|
||||||
private val nameCache = mutableListOf<JsName?>()
|
|
||||||
private val fileStack: Deque<String> = ArrayDeque()
|
|
||||||
|
|
||||||
fun deserialize(input: InputStream): JsProgramFragment {
|
fun deserialize(input: InputStream): JsProgramFragment {
|
||||||
return deserialize(Chunk.parseFrom(CodedInputStream.newInstance(input).apply { setRecursionLimit(4096) }))
|
return deserialize(Chunk.parseFrom(CodedInputStream.newInstance(input).apply { setRecursionLimit(4096) }))
|
||||||
@@ -48,8 +45,7 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
nameCache += nameTable.map { null }
|
nameCache += nameTable.map { null }
|
||||||
try {
|
try {
|
||||||
return deserialize(proto.fragment)
|
return deserialize(proto.fragment)
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
stringTable.clear()
|
stringTable.clear()
|
||||||
nameTable.clear()
|
nameTable.clear()
|
||||||
nameCache.clear()
|
nameCache.clear()
|
||||||
@@ -60,10 +56,10 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
val fragment = JsProgramFragment(scope, proto.packageFqn)
|
val fragment = JsProgramFragment(scope, proto.packageFqn)
|
||||||
|
|
||||||
fragment.importedModules += proto.importedModuleList.map { importedModuleProto ->
|
fragment.importedModules += proto.importedModuleList.map { importedModuleProto ->
|
||||||
JsImportedModule(
|
JsImportedModule(
|
||||||
deserializeString(importedModuleProto.externalNameId),
|
deserializeString(importedModuleProto.externalNameId),
|
||||||
deserializeName(importedModuleProto.internalNameId),
|
deserializeName(importedModuleProto.internalNameId),
|
||||||
if (importedModuleProto.hasPlainReference()) deserialize(importedModuleProto.plainReference) else null
|
if (importedModuleProto.hasPlainReference()) deserialize(importedModuleProto.plainReference) else null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,470 +119,13 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deserialize(proto: Statement): JsStatement {
|
override fun embedSources(deserializedLocation: JsLocation, file: String): JsLocationWithSource? {
|
||||||
val statement = withLocation(
|
val contentFile = sourceRoots
|
||||||
fileId = if (proto.hasFileId()) proto.fileId else null,
|
.map { File(it, file) }
|
||||||
location = if (proto.hasLocation()) proto.location else null,
|
.firstOrNull { it.exists() }
|
||||||
action = { deserializeNoMetadata(proto) }
|
|
||||||
)
|
|
||||||
if (statement is HasMetadata) {
|
|
||||||
statement.synthetic = proto.synthetic
|
|
||||||
}
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeNoMetadata(proto: Statement): JsStatement = when (proto.statementCase) {
|
return if (contentFile != null) {
|
||||||
StatementCase.RETURN_STATEMENT -> {
|
JsLocationWithEmbeddedSource(deserializedLocation, null) { InputStreamReader(FileInputStream(contentFile), "UTF-8") }
|
||||||
val returnProto = proto.returnStatement
|
} else null
|
||||||
JsReturn(if (returnProto.hasValue()) deserialize(returnProto.value) else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.THROW_STATEMENT -> {
|
|
||||||
val throwProto = proto.throwStatement
|
|
||||||
JsThrow(deserialize(throwProto.exception))
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.BREAK_STATEMENT -> {
|
|
||||||
val breakProto = proto.breakStatement
|
|
||||||
JsBreak(if (breakProto.hasLabelId()) JsNameRef(deserializeName(breakProto.labelId)) else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.CONTINUE_STATEMENT -> {
|
|
||||||
val continueProto = proto.continueStatement
|
|
||||||
JsContinue(if (continueProto.hasLabelId()) JsNameRef(deserializeName(continueProto.labelId)) else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.DEBUGGER -> {
|
|
||||||
JsDebugger()
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.EXPRESSION -> {
|
|
||||||
val expressionProto = proto.expression
|
|
||||||
JsExpressionStatement(deserialize(expressionProto.expression)).also {
|
|
||||||
if (expressionProto.hasExportedTagId()) {
|
|
||||||
it.exportedTag = deserializeString(expressionProto.exportedTagId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.VARS -> {
|
|
||||||
deserializeVars(proto.vars)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.BLOCK -> {
|
|
||||||
val blockProto = proto.block
|
|
||||||
val block = JsBlock()
|
|
||||||
block.statements += blockProto.statementList.map { deserialize(it) }
|
|
||||||
block
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.GLOBAL_BLOCK -> {
|
|
||||||
deserializeGlobalBlock(proto.globalBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.LABEL -> {
|
|
||||||
val labelProto = proto.label
|
|
||||||
JsLabel(deserializeName(labelProto.nameId), deserialize(labelProto.innerStatement))
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.IF_STATEMENT -> {
|
|
||||||
val ifProto = proto.ifStatement
|
|
||||||
JsIf(
|
|
||||||
deserialize(ifProto.condition),
|
|
||||||
deserialize(ifProto.thenStatement),
|
|
||||||
if (ifProto.hasElseStatement()) deserialize(ifProto.elseStatement) else null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.SWITCH_STATEMENT -> {
|
|
||||||
val switchProto = proto.switchStatement
|
|
||||||
JsSwitch(
|
|
||||||
deserialize(switchProto.expression),
|
|
||||||
switchProto.entryList.map { entryProto ->
|
|
||||||
val member = withLocation(
|
|
||||||
fileId = if (entryProto.hasFileId()) entryProto.fileId else null,
|
|
||||||
location = if (entryProto.hasLocation()) entryProto.location else null
|
|
||||||
) {
|
|
||||||
if (entryProto.hasLabel()) {
|
|
||||||
JsCase().apply { caseExpression = deserialize(entryProto.label) }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
member.statements += entryProto.statementList.map { deserialize(it) }
|
|
||||||
member
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.WHILE_STATEMENT -> {
|
|
||||||
val whileProto = proto.whileStatement
|
|
||||||
JsWhile(deserialize(whileProto.condition), deserialize(whileProto.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.DO_WHILE_STATEMENT -> {
|
|
||||||
val doWhileProto = proto.doWhileStatement
|
|
||||||
JsDoWhile(deserialize(doWhileProto.condition), deserialize(doWhileProto.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.FOR_STATEMENT -> {
|
|
||||||
val forProto = proto.forStatement
|
|
||||||
val initVars = if (forProto.hasVariables()) deserialize(forProto.variables) as JsVars else null
|
|
||||||
val initExpr = if (forProto.hasExpression()) deserialize(forProto.expression) else null
|
|
||||||
val condition = if (forProto.hasCondition()) deserialize(forProto.condition) else null
|
|
||||||
val increment = if (forProto.hasIncrement()) deserialize(forProto.increment) else null
|
|
||||||
val body = deserialize(forProto.body)
|
|
||||||
if (initVars != null) {
|
|
||||||
JsFor(initVars, condition, increment, body)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsFor(initExpr, condition, increment, body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.FOR_IN_STATEMENT -> {
|
|
||||||
val forInProto = proto.forInStatement
|
|
||||||
val iterName = if (forInProto.hasNameId()) deserializeName(forInProto.nameId) else null
|
|
||||||
val iterExpr = if (forInProto.hasExpression()) deserialize(forInProto.expression) else null
|
|
||||||
val iterable = deserialize(forInProto.iterable)
|
|
||||||
val body = deserialize(forInProto.body)
|
|
||||||
JsForIn(iterName, iterExpr, iterable, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.TRY_STATEMENT -> {
|
|
||||||
val tryProto = proto.tryStatement
|
|
||||||
val tryBlock = deserialize(tryProto.tryBlock) as JsBlock
|
|
||||||
val catchBlock = if (tryProto.hasCatchBlock()) {
|
|
||||||
val catchProto = tryProto.catchBlock
|
|
||||||
JsCatch(deserializeName(catchProto.parameter.nameId)).apply {
|
|
||||||
body = deserialize(catchProto.body) as JsBlock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
val finallyBlock = if (tryProto.hasFinallyBlock()) deserialize(tryProto.finallyBlock) as JsBlock else null
|
|
||||||
JsTry(tryBlock, catchBlock, finallyBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementCase.EMPTY -> JsEmpty
|
|
||||||
|
|
||||||
StatementCase.STATEMENT_NOT_SET,
|
|
||||||
null -> error("Statement not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserialize(proto: Expression): JsExpression {
|
|
||||||
val expression = withLocation(
|
|
||||||
fileId = if (proto.hasFileId()) proto.fileId else null,
|
|
||||||
location = if (proto.hasLocation()) proto.location else null,
|
|
||||||
action = { deserializeNoMetadata(proto) }
|
|
||||||
)
|
|
||||||
expression.synthetic = proto.synthetic
|
|
||||||
expression.sideEffects = map(proto.sideEffects)
|
|
||||||
if (proto.hasLocalAlias()) {
|
|
||||||
expression.localAlias = deserializeJsImportedModule(proto.localAlias)
|
|
||||||
}
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeJsImportedModule(proto: JsAstProtoBuf.JsImportedModule): JsImportedModule {
|
|
||||||
return JsImportedModule(deserializeString(proto.externalName), deserializeName(proto.internalName), if (proto.hasPlainReference()) deserialize(proto.plainReference!!) else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeNoMetadata(proto: Expression): JsExpression = when (proto.expressionCase) {
|
|
||||||
ExpressionCase.THIS_LITERAL -> JsThisRef()
|
|
||||||
ExpressionCase.NULL_LITERAL -> JsNullLiteral()
|
|
||||||
ExpressionCase.TRUE_LITERAL -> JsBooleanLiteral(true)
|
|
||||||
ExpressionCase.FALSE_LITERAL -> JsBooleanLiteral(false)
|
|
||||||
ExpressionCase.STRING_LITERAL -> JsStringLiteral(deserializeString(proto.stringLiteral))
|
|
||||||
ExpressionCase.INT_LITERAL -> JsIntLiteral(proto.intLiteral)
|
|
||||||
ExpressionCase.DOUBLE_LITERAL -> JsDoubleLiteral(proto.doubleLiteral)
|
|
||||||
ExpressionCase.SIMPLE_NAME_REFERENCE -> JsNameRef(deserializeName(proto.simpleNameReference))
|
|
||||||
|
|
||||||
ExpressionCase.REG_EXP_LITERAL -> {
|
|
||||||
val regExpProto = proto.regExpLiteral
|
|
||||||
JsRegExp().apply {
|
|
||||||
pattern = deserializeString(regExpProto.patternStringId)
|
|
||||||
if (regExpProto.hasFlagsStringId()) {
|
|
||||||
flags = deserializeString(regExpProto.flagsStringId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.ARRAY_LITERAL -> {
|
|
||||||
val arrayProto = proto.arrayLiteral
|
|
||||||
JsArrayLiteral(arrayProto.elementList.map { deserialize(it) })
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.OBJECT_LITERAL -> {
|
|
||||||
val objectProto = proto.objectLiteral
|
|
||||||
JsObjectLiteral(
|
|
||||||
objectProto.entryList.map { entryProto ->
|
|
||||||
JsPropertyInitializer(deserialize(entryProto.key), deserialize(entryProto.value))
|
|
||||||
},
|
|
||||||
objectProto.multiline
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.FUNCTION -> {
|
|
||||||
val functionProto = proto.function
|
|
||||||
JsFunction(scope, deserialize(functionProto.body) as JsBlock, "").apply {
|
|
||||||
parameters += functionProto.parameterList.map { deserializeParameter(it) }
|
|
||||||
if (functionProto.hasNameId()) {
|
|
||||||
name = deserializeName(functionProto.nameId)
|
|
||||||
}
|
|
||||||
isLocal = functionProto.local
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.DOC_COMMENT -> {
|
|
||||||
val docCommentProto = proto.docComment
|
|
||||||
JsDocComment(docCommentProto.tagList.associate { tagProto ->
|
|
||||||
val name = deserializeString(tagProto.nameId)
|
|
||||||
val value: Any = if (tagProto.hasExpression()) {
|
|
||||||
deserialize(tagProto.expression)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
deserializeString(tagProto.valueStringId)
|
|
||||||
}
|
|
||||||
name to value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.BINARY -> {
|
|
||||||
val binaryProto = proto.binary
|
|
||||||
JsBinaryOperation(map(binaryProto.type), deserialize(binaryProto.left), deserialize(binaryProto.right))
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.UNARY -> {
|
|
||||||
val unaryProto = proto.unary
|
|
||||||
val type = map(unaryProto.type)
|
|
||||||
val operand = deserialize(unaryProto.operand)
|
|
||||||
if (unaryProto.postfix) JsPostfixOperation(type, operand) else JsPrefixOperation(type, operand)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.CONDITIONAL -> {
|
|
||||||
val conditionalProto = proto.conditional
|
|
||||||
JsConditional(
|
|
||||||
deserialize(conditionalProto.testExpression),
|
|
||||||
deserialize(conditionalProto.thenExpression),
|
|
||||||
deserialize(conditionalProto.elseExpression)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.ARRAY_ACCESS -> {
|
|
||||||
val arrayAccessProto = proto.arrayAccess
|
|
||||||
JsArrayAccess(deserialize(arrayAccessProto.array), deserialize(arrayAccessProto.index))
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.NAME_REFERENCE -> {
|
|
||||||
val nameRefProto = proto.nameReference
|
|
||||||
val qualifier = if (nameRefProto.hasQualifier()) deserialize(nameRefProto.qualifier) else null
|
|
||||||
JsNameRef(deserializeName(nameRefProto.nameId), qualifier).apply {
|
|
||||||
if (nameRefProto.hasInlineStrategy()) {
|
|
||||||
isInline = map(nameRefProto.inlineStrategy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.PROPERTY_REFERENCE -> {
|
|
||||||
val propertyRefProto = proto.propertyReference
|
|
||||||
val qualifier = if (propertyRefProto.hasQualifier()) deserialize(propertyRefProto.qualifier) else null
|
|
||||||
JsNameRef(deserializeString(propertyRefProto.stringId), qualifier).apply {
|
|
||||||
if (propertyRefProto.hasInlineStrategy()) {
|
|
||||||
isInline = map(propertyRefProto.inlineStrategy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.INVOCATION -> {
|
|
||||||
val invocationProto = proto.invocation
|
|
||||||
JsInvocation(
|
|
||||||
deserialize(invocationProto.qualifier),
|
|
||||||
invocationProto.argumentList.map { deserialize(it) }
|
|
||||||
).apply {
|
|
||||||
if (invocationProto.hasInlineStrategy()) {
|
|
||||||
isInline = map(invocationProto.inlineStrategy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionCase.INSTANTIATION -> {
|
|
||||||
val instantiationProto = proto.instantiation
|
|
||||||
JsNew(
|
|
||||||
deserialize(instantiationProto.qualifier),
|
|
||||||
instantiationProto.argumentList.map { deserialize(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
null,
|
|
||||||
ExpressionCase.EXPRESSION_NOT_SET -> error("Unknown expression")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeVars(proto: Vars): JsVars {
|
|
||||||
val vars = JsVars(proto.multiline)
|
|
||||||
for (declProto in proto.declarationList) {
|
|
||||||
vars.vars += withLocation(
|
|
||||||
fileId = if (declProto.hasFileId()) declProto.fileId else null,
|
|
||||||
location = if (declProto.hasLocation()) declProto.location else null
|
|
||||||
) {
|
|
||||||
val initialValue = if (declProto.hasInitialValue()) deserialize(declProto.initialValue) else null
|
|
||||||
JsVars.JsVar(deserializeName(declProto.nameId), initialValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (proto.hasExportedPackageId()) {
|
|
||||||
vars.exportedPackage = deserializeString(proto.exportedPackageId)
|
|
||||||
}
|
|
||||||
return vars
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeGlobalBlock(proto: GlobalBlock): JsGlobalBlock {
|
|
||||||
return JsGlobalBlock().apply { statements += proto.statementList.map { deserialize(it) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeParameter(proto: Parameter): JsParameter {
|
|
||||||
return JsParameter(deserializeName(proto.nameId)).apply {
|
|
||||||
hasDefaultValue = proto.hasDefaultValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeName(id: Int): JsName {
|
|
||||||
return nameCache[id] ?: let {
|
|
||||||
val nameProto = nameTable[id]
|
|
||||||
val identifier = deserializeString(nameProto.identifier)
|
|
||||||
val name = if (nameProto.temporary) {
|
|
||||||
JsScope.declareTemporaryName(identifier)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsDynamicScope.declareName(identifier)
|
|
||||||
}
|
|
||||||
if (nameProto.hasLocalNameId()) {
|
|
||||||
name.localAlias = deserializeLocalAlias(nameProto.localNameId)
|
|
||||||
}
|
|
||||||
if (nameProto.hasImported()) {
|
|
||||||
name.imported = nameProto.imported
|
|
||||||
}
|
|
||||||
if (nameProto.hasSpecialFunction()) {
|
|
||||||
name.specialFunction = map(nameProto.specialFunction)
|
|
||||||
}
|
|
||||||
nameCache[id] = name
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deserializeLocalAlias(localNameId: JsAstProtoBuf.LocalAlias): LocalAlias {
|
|
||||||
return LocalAlias(deserializeName(localNameId.localNameId),
|
|
||||||
if (localNameId.hasTag()) deserializeString(localNameId.tag) else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun deserializeString(id: Int): String = stringTable[id]
|
|
||||||
|
|
||||||
private fun map(op: BinaryOperation.Type) = when (op) {
|
|
||||||
BinaryOperation.Type.MUL -> JsBinaryOperator.MUL
|
|
||||||
BinaryOperation.Type.DIV -> JsBinaryOperator.DIV
|
|
||||||
BinaryOperation.Type.MOD -> JsBinaryOperator.MOD
|
|
||||||
BinaryOperation.Type.ADD -> JsBinaryOperator.ADD
|
|
||||||
BinaryOperation.Type.SUB -> JsBinaryOperator.SUB
|
|
||||||
BinaryOperation.Type.SHL -> JsBinaryOperator.SHL
|
|
||||||
BinaryOperation.Type.SHR -> JsBinaryOperator.SHR
|
|
||||||
BinaryOperation.Type.SHRU -> JsBinaryOperator.SHRU
|
|
||||||
BinaryOperation.Type.LT -> JsBinaryOperator.LT
|
|
||||||
BinaryOperation.Type.LTE -> JsBinaryOperator.LTE
|
|
||||||
BinaryOperation.Type.GT -> JsBinaryOperator.GT
|
|
||||||
BinaryOperation.Type.GTE -> JsBinaryOperator.GTE
|
|
||||||
BinaryOperation.Type.INSTANCEOF -> JsBinaryOperator.INSTANCEOF
|
|
||||||
BinaryOperation.Type.IN -> JsBinaryOperator.INOP
|
|
||||||
BinaryOperation.Type.EQ -> JsBinaryOperator.EQ
|
|
||||||
BinaryOperation.Type.NEQ -> JsBinaryOperator.NEQ
|
|
||||||
BinaryOperation.Type.REF_EQ -> JsBinaryOperator.REF_EQ
|
|
||||||
BinaryOperation.Type.REF_NEQ -> JsBinaryOperator.REF_NEQ
|
|
||||||
BinaryOperation.Type.BIT_AND -> JsBinaryOperator.BIT_AND
|
|
||||||
BinaryOperation.Type.BIT_XOR -> JsBinaryOperator.BIT_XOR
|
|
||||||
BinaryOperation.Type.BIT_OR -> JsBinaryOperator.BIT_OR
|
|
||||||
BinaryOperation.Type.AND -> JsBinaryOperator.AND
|
|
||||||
BinaryOperation.Type.OR -> JsBinaryOperator.OR
|
|
||||||
BinaryOperation.Type.ASG -> JsBinaryOperator.ASG
|
|
||||||
BinaryOperation.Type.ASG_ADD -> JsBinaryOperator.ASG_ADD
|
|
||||||
BinaryOperation.Type.ASG_SUB -> JsBinaryOperator.ASG_SUB
|
|
||||||
BinaryOperation.Type.ASG_MUL -> JsBinaryOperator.ASG_MUL
|
|
||||||
BinaryOperation.Type.ASG_DIV -> JsBinaryOperator.ASG_DIV
|
|
||||||
BinaryOperation.Type.ASG_MOD -> JsBinaryOperator.ASG_MOD
|
|
||||||
BinaryOperation.Type.ASG_SHL -> JsBinaryOperator.ASG_SHL
|
|
||||||
BinaryOperation.Type.ASG_SHR -> JsBinaryOperator.ASG_SHR
|
|
||||||
BinaryOperation.Type.ASG_SHRU -> JsBinaryOperator.ASG_SHRU
|
|
||||||
BinaryOperation.Type.ASG_BIT_AND -> JsBinaryOperator.ASG_BIT_AND
|
|
||||||
BinaryOperation.Type.ASG_BIT_OR -> JsBinaryOperator.ASG_BIT_OR
|
|
||||||
BinaryOperation.Type.ASG_BIT_XOR -> JsBinaryOperator.ASG_BIT_XOR
|
|
||||||
BinaryOperation.Type.COMMA -> JsBinaryOperator.COMMA
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(op: UnaryOperation.Type) = when (op) {
|
|
||||||
UnaryOperation.Type.BIT_NOT -> JsUnaryOperator.BIT_NOT
|
|
||||||
UnaryOperation.Type.DEC -> JsUnaryOperator.DEC
|
|
||||||
UnaryOperation.Type.DELETE -> JsUnaryOperator.DELETE
|
|
||||||
UnaryOperation.Type.INC -> JsUnaryOperator.INC
|
|
||||||
UnaryOperation.Type.NEG -> JsUnaryOperator.NEG
|
|
||||||
UnaryOperation.Type.POS -> JsUnaryOperator.POS
|
|
||||||
UnaryOperation.Type.NOT -> JsUnaryOperator.NOT
|
|
||||||
UnaryOperation.Type.TYPEOF -> JsUnaryOperator.TYPEOF
|
|
||||||
UnaryOperation.Type.VOID -> JsUnaryOperator.VOID
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(sideEffects: SideEffects) = when (sideEffects) {
|
|
||||||
SideEffects.AFFECTS_STATE -> SideEffectKind.AFFECTS_STATE
|
|
||||||
SideEffects.DEPENDS_ON_STATE -> SideEffectKind.DEPENDS_ON_STATE
|
|
||||||
SideEffects.PURE -> SideEffectKind.PURE
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(inlineStrategy: InlineStrategy) =
|
|
||||||
inlineStrategy == InlineStrategy.AS_FUNCTION || inlineStrategy == InlineStrategy.IN_PLACE
|
|
||||||
|
|
||||||
private fun map(specialFunction: JsAstProtoBuf.SpecialFunction) = when(specialFunction) {
|
|
||||||
JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION -> SpecialFunction.DEFINE_INLINE_FUNCTION
|
|
||||||
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
|
|
||||||
JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR -> SpecialFunction.TO_BOXED_CHAR
|
|
||||||
JsAstProtoBuf.SpecialFunction.UNBOX_CHAR -> SpecialFunction.UNBOX_CHAR
|
|
||||||
JsAstProtoBuf.SpecialFunction.SUSPEND_CALL -> SpecialFunction.SUSPEND_CALL
|
|
||||||
JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT -> SpecialFunction.COROUTINE_RESULT
|
|
||||||
JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER -> SpecialFunction.COROUTINE_CONTROLLER
|
|
||||||
JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER -> SpecialFunction.COROUTINE_RECEIVER
|
|
||||||
JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT -> SpecialFunction.SET_COROUTINE_RESULT
|
|
||||||
JsAstProtoBuf.SpecialFunction.GET_KCLASS -> SpecialFunction.GET_KCLASS
|
|
||||||
JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
|
|
||||||
val deserializedFile = fileId?.let { deserializeString(it) }
|
|
||||||
val file = deserializedFile ?: fileStack.peek()
|
|
||||||
val deserializedLocation = if (file != null && location != null) {
|
|
||||||
JsLocation(file, location.startLine, location.startChar)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val shouldUpdateFile = location != null && deserializedFile != null && deserializedFile != fileStack.peek()
|
|
||||||
if (shouldUpdateFile) {
|
|
||||||
fileStack.push(deserializedFile)
|
|
||||||
}
|
|
||||||
val node = action()
|
|
||||||
if (deserializedLocation != null) {
|
|
||||||
val contentFile = sourceRoots
|
|
||||||
.map { File(it, file) }
|
|
||||||
.firstOrNull { it.exists() }
|
|
||||||
node.source = if (contentFile != null) {
|
|
||||||
JsLocationWithEmbeddedSource(deserializedLocation, null) { InputStreamReader(FileInputStream(contentFile), "UTF-8") }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
deserializedLocation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shouldUpdateFile) {
|
|
||||||
fileStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
return node
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+481
@@ -0,0 +1,481 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.serialization.js.ast
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class JsAstDeserializerBase {
|
||||||
|
abstract val scope: JsScope
|
||||||
|
protected val stringTable = mutableListOf<String>()
|
||||||
|
protected val nameTable = mutableListOf<JsAstProtoBuf.Name>()
|
||||||
|
protected val nameCache = mutableListOf<JsName?>()
|
||||||
|
protected val fileStack: Deque<String> = ArrayDeque()
|
||||||
|
|
||||||
|
protected fun deserialize(proto: JsAstProtoBuf.Statement): JsStatement {
|
||||||
|
val statement = withLocation(
|
||||||
|
fileId = if (proto.hasFileId()) proto.fileId else null,
|
||||||
|
location = if (proto.hasLocation()) proto.location else null,
|
||||||
|
action = { deserializeNoMetadata(proto) }
|
||||||
|
)
|
||||||
|
if (statement is HasMetadata) {
|
||||||
|
statement.synthetic = proto.synthetic
|
||||||
|
}
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Statement): JsStatement = when (proto.statementCase) {
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.RETURN_STATEMENT -> {
|
||||||
|
val returnProto = proto.returnStatement
|
||||||
|
JsReturn(if (returnProto.hasValue()) deserialize(returnProto.value) else null)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.THROW_STATEMENT -> {
|
||||||
|
val throwProto = proto.throwStatement
|
||||||
|
JsThrow(deserialize(throwProto.exception))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.BREAK_STATEMENT -> {
|
||||||
|
val breakProto = proto.breakStatement
|
||||||
|
JsBreak(if (breakProto.hasLabelId()) JsNameRef(deserializeName(breakProto.labelId)) else null)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.CONTINUE_STATEMENT -> {
|
||||||
|
val continueProto = proto.continueStatement
|
||||||
|
JsContinue(if (continueProto.hasLabelId()) JsNameRef(deserializeName(continueProto.labelId)) else null)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.DEBUGGER -> {
|
||||||
|
JsDebugger()
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.EXPRESSION -> {
|
||||||
|
val expressionProto = proto.expression
|
||||||
|
JsExpressionStatement(deserialize(expressionProto.expression)).also {
|
||||||
|
if (expressionProto.hasExportedTagId()) {
|
||||||
|
it.exportedTag = deserializeString(expressionProto.exportedTagId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.VARS -> {
|
||||||
|
deserializeVars(proto.vars)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.BLOCK -> {
|
||||||
|
val blockProto = proto.block
|
||||||
|
val block = JsBlock()
|
||||||
|
block.statements += blockProto.statementList.map { deserialize(it) }
|
||||||
|
block
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.GLOBAL_BLOCK -> {
|
||||||
|
deserializeGlobalBlock(proto.globalBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.LABEL -> {
|
||||||
|
val labelProto = proto.label
|
||||||
|
JsLabel(deserializeName(labelProto.nameId), deserialize(labelProto.innerStatement))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.IF_STATEMENT -> {
|
||||||
|
val ifProto = proto.ifStatement
|
||||||
|
JsIf(
|
||||||
|
deserialize(ifProto.condition),
|
||||||
|
deserialize(ifProto.thenStatement),
|
||||||
|
if (ifProto.hasElseStatement()) deserialize(ifProto.elseStatement) else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.SWITCH_STATEMENT -> {
|
||||||
|
val switchProto = proto.switchStatement
|
||||||
|
JsSwitch(
|
||||||
|
deserialize(switchProto.expression),
|
||||||
|
switchProto.entryList.map { entryProto ->
|
||||||
|
val member = withLocation(
|
||||||
|
fileId = if (entryProto.hasFileId()) entryProto.fileId else null,
|
||||||
|
location = if (entryProto.hasLocation()) entryProto.location else null
|
||||||
|
) {
|
||||||
|
if (entryProto.hasLabel()) {
|
||||||
|
JsCase().apply { caseExpression = deserialize(entryProto.label) }
|
||||||
|
} else {
|
||||||
|
JsDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
member.statements += entryProto.statementList.map { deserialize(it) }
|
||||||
|
member
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.WHILE_STATEMENT -> {
|
||||||
|
val whileProto = proto.whileStatement
|
||||||
|
JsWhile(deserialize(whileProto.condition), deserialize(whileProto.body))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.DO_WHILE_STATEMENT -> {
|
||||||
|
val doWhileProto = proto.doWhileStatement
|
||||||
|
JsDoWhile(deserialize(doWhileProto.condition), deserialize(doWhileProto.body))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.FOR_STATEMENT -> {
|
||||||
|
val forProto = proto.forStatement
|
||||||
|
val initVars = if (forProto.hasVariables()) deserialize(forProto.variables) as JsVars else null
|
||||||
|
val initExpr = if (forProto.hasExpression()) deserialize(forProto.expression) else null
|
||||||
|
val condition = if (forProto.hasCondition()) deserialize(forProto.condition) else null
|
||||||
|
val increment = if (forProto.hasIncrement()) deserialize(forProto.increment) else null
|
||||||
|
val body = deserialize(forProto.body)
|
||||||
|
if (initVars != null) {
|
||||||
|
JsFor(initVars, condition, increment, body)
|
||||||
|
} else {
|
||||||
|
JsFor(initExpr, condition, increment, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.FOR_IN_STATEMENT -> {
|
||||||
|
val forInProto = proto.forInStatement
|
||||||
|
val iterName = if (forInProto.hasNameId()) deserializeName(forInProto.nameId) else null
|
||||||
|
val iterExpr = if (forInProto.hasExpression()) deserialize(forInProto.expression) else null
|
||||||
|
val iterable = deserialize(forInProto.iterable)
|
||||||
|
val body = deserialize(forInProto.body)
|
||||||
|
JsForIn(iterName, iterExpr, iterable, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.TRY_STATEMENT -> {
|
||||||
|
val tryProto = proto.tryStatement
|
||||||
|
val tryBlock = deserialize(tryProto.tryBlock) as JsBlock
|
||||||
|
val catchBlock = if (tryProto.hasCatchBlock()) {
|
||||||
|
val catchProto = tryProto.catchBlock
|
||||||
|
JsCatch(deserializeName(catchProto.parameter.nameId)).apply {
|
||||||
|
body = deserialize(catchProto.body) as JsBlock
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
val finallyBlock = if (tryProto.hasFinallyBlock()) deserialize(tryProto.finallyBlock) as JsBlock else null
|
||||||
|
JsTry(tryBlock, catchBlock, finallyBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.EMPTY -> JsEmpty
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.SINGLE_LINE_COMMENT -> JsSingleLineComment(proto.singleLineComment.message)
|
||||||
|
|
||||||
|
JsAstProtoBuf.Statement.StatementCase.STATEMENT_NOT_SET,
|
||||||
|
null -> error("Statement not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserialize(proto: JsAstProtoBuf.Expression): JsExpression {
|
||||||
|
val expression = withLocation(
|
||||||
|
fileId = if (proto.hasFileId()) proto.fileId else null,
|
||||||
|
location = if (proto.hasLocation()) proto.location else null,
|
||||||
|
action = { deserializeNoMetadata(proto) }
|
||||||
|
)
|
||||||
|
expression.synthetic = proto.synthetic
|
||||||
|
expression.sideEffects = map(proto.sideEffects)
|
||||||
|
if (proto.hasLocalAlias()) {
|
||||||
|
expression.localAlias = deserializeJsImportedModule(proto.localAlias)
|
||||||
|
}
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeJsImportedModule(proto: JsAstProtoBuf.JsImportedModule): JsImportedModule {
|
||||||
|
return JsImportedModule(
|
||||||
|
deserializeString(proto.externalName),
|
||||||
|
deserializeName(proto.internalName),
|
||||||
|
if (proto.hasPlainReference()) deserialize(proto.plainReference!!) else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Expression): JsExpression = when (proto.expressionCase) {
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.THIS_LITERAL -> JsThisRef()
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.NULL_LITERAL -> JsNullLiteral()
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.TRUE_LITERAL -> JsBooleanLiteral(true)
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.FALSE_LITERAL -> JsBooleanLiteral(false)
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.STRING_LITERAL -> JsStringLiteral(deserializeString(proto.stringLiteral))
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.INT_LITERAL -> JsIntLiteral(proto.intLiteral)
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.DOUBLE_LITERAL -> JsDoubleLiteral(proto.doubleLiteral)
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.SIMPLE_NAME_REFERENCE -> JsNameRef(deserializeName(proto.simpleNameReference))
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.REG_EXP_LITERAL -> {
|
||||||
|
val regExpProto = proto.regExpLiteral
|
||||||
|
JsRegExp().apply {
|
||||||
|
pattern = deserializeString(regExpProto.patternStringId)
|
||||||
|
if (regExpProto.hasFlagsStringId()) {
|
||||||
|
flags = deserializeString(regExpProto.flagsStringId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.ARRAY_LITERAL -> {
|
||||||
|
val arrayProto = proto.arrayLiteral
|
||||||
|
JsArrayLiteral(arrayProto.elementList.map { deserialize(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.OBJECT_LITERAL -> {
|
||||||
|
val objectProto = proto.objectLiteral
|
||||||
|
JsObjectLiteral(
|
||||||
|
objectProto.entryList.map { entryProto ->
|
||||||
|
JsPropertyInitializer(deserialize(entryProto.key), deserialize(entryProto.value))
|
||||||
|
},
|
||||||
|
objectProto.multiline
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.FUNCTION -> {
|
||||||
|
val functionProto = proto.function
|
||||||
|
JsFunction(scope, deserialize(functionProto.body) as JsBlock, "").apply {
|
||||||
|
parameters += functionProto.parameterList.map { deserializeParameter(it) }
|
||||||
|
if (functionProto.hasNameId()) {
|
||||||
|
name = deserializeName(functionProto.nameId)
|
||||||
|
}
|
||||||
|
isLocal = functionProto.local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.DOC_COMMENT -> {
|
||||||
|
val docCommentProto = proto.docComment
|
||||||
|
JsDocComment(docCommentProto.tagList.associate { tagProto ->
|
||||||
|
val name = deserializeString(tagProto.nameId)
|
||||||
|
val value: Any = if (tagProto.hasExpression()) {
|
||||||
|
deserialize(tagProto.expression)
|
||||||
|
} else {
|
||||||
|
deserializeString(tagProto.valueStringId)
|
||||||
|
}
|
||||||
|
name to value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.BINARY -> {
|
||||||
|
val binaryProto = proto.binary
|
||||||
|
JsBinaryOperation(map(binaryProto.type), deserialize(binaryProto.left), deserialize(binaryProto.right))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.UNARY -> {
|
||||||
|
val unaryProto = proto.unary
|
||||||
|
val type = map(unaryProto.type)
|
||||||
|
val operand = deserialize(unaryProto.operand)
|
||||||
|
if (unaryProto.postfix) JsPostfixOperation(type, operand) else JsPrefixOperation(type, operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.CONDITIONAL -> {
|
||||||
|
val conditionalProto = proto.conditional
|
||||||
|
JsConditional(
|
||||||
|
deserialize(conditionalProto.testExpression),
|
||||||
|
deserialize(conditionalProto.thenExpression),
|
||||||
|
deserialize(conditionalProto.elseExpression)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.ARRAY_ACCESS -> {
|
||||||
|
val arrayAccessProto = proto.arrayAccess
|
||||||
|
JsArrayAccess(deserialize(arrayAccessProto.array), deserialize(arrayAccessProto.index))
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.NAME_REFERENCE -> {
|
||||||
|
val nameRefProto = proto.nameReference
|
||||||
|
val qualifier = if (nameRefProto.hasQualifier()) deserialize(nameRefProto.qualifier) else null
|
||||||
|
JsNameRef(deserializeName(nameRefProto.nameId), qualifier).apply {
|
||||||
|
if (nameRefProto.hasInlineStrategy()) {
|
||||||
|
isInline = map(nameRefProto.inlineStrategy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.PROPERTY_REFERENCE -> {
|
||||||
|
val propertyRefProto = proto.propertyReference
|
||||||
|
val qualifier = if (propertyRefProto.hasQualifier()) deserialize(propertyRefProto.qualifier) else null
|
||||||
|
JsNameRef(deserializeString(propertyRefProto.stringId), qualifier).apply {
|
||||||
|
if (propertyRefProto.hasInlineStrategy()) {
|
||||||
|
isInline = map(propertyRefProto.inlineStrategy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.INVOCATION -> {
|
||||||
|
val invocationProto = proto.invocation
|
||||||
|
JsInvocation(
|
||||||
|
deserialize(invocationProto.qualifier),
|
||||||
|
invocationProto.argumentList.map { deserialize(it) }
|
||||||
|
).apply {
|
||||||
|
if (invocationProto.hasInlineStrategy()) {
|
||||||
|
isInline = map(invocationProto.inlineStrategy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.INSTANTIATION -> {
|
||||||
|
val instantiationProto = proto.instantiation
|
||||||
|
JsNew(
|
||||||
|
deserialize(instantiationProto.qualifier),
|
||||||
|
instantiationProto.argumentList.map { deserialize(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
null,
|
||||||
|
JsAstProtoBuf.Expression.ExpressionCase.EXPRESSION_NOT_SET -> error("Unknown expression")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeVars(proto: JsAstProtoBuf.Vars): JsVars {
|
||||||
|
val vars = JsVars(proto.multiline)
|
||||||
|
for (declProto in proto.declarationList) {
|
||||||
|
vars.vars += withLocation(
|
||||||
|
fileId = if (declProto.hasFileId()) declProto.fileId else null,
|
||||||
|
location = if (declProto.hasLocation()) declProto.location else null
|
||||||
|
) {
|
||||||
|
val initialValue = if (declProto.hasInitialValue()) deserialize(declProto.initialValue) else null
|
||||||
|
JsVars.JsVar(deserializeName(declProto.nameId), initialValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proto.hasExportedPackageId()) {
|
||||||
|
vars.exportedPackage = deserializeString(proto.exportedPackageId)
|
||||||
|
}
|
||||||
|
return vars
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeGlobalBlock(proto: JsAstProtoBuf.GlobalBlock): JsGlobalBlock {
|
||||||
|
return JsGlobalBlock().apply { statements += proto.statementList.map { deserialize(it) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeParameter(proto: JsAstProtoBuf.Parameter): JsParameter {
|
||||||
|
return JsParameter(deserializeName(proto.nameId)).apply {
|
||||||
|
hasDefaultValue = proto.hasDefaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeName(id: Int): JsName {
|
||||||
|
return nameCache[id] ?: let {
|
||||||
|
val nameProto = nameTable[id]
|
||||||
|
val identifier = deserializeString(nameProto.identifier)
|
||||||
|
val name = if (nameProto.temporary) {
|
||||||
|
JsScope.declareTemporaryName(identifier)
|
||||||
|
} else {
|
||||||
|
JsDynamicScope.declareName(identifier)
|
||||||
|
}
|
||||||
|
if (nameProto.hasLocalNameId()) {
|
||||||
|
name.localAlias = deserializeLocalAlias(nameProto.localNameId)
|
||||||
|
}
|
||||||
|
if (nameProto.hasImported()) {
|
||||||
|
name.imported = nameProto.imported
|
||||||
|
}
|
||||||
|
if (nameProto.hasSpecialFunction()) {
|
||||||
|
name.specialFunction = map(nameProto.specialFunction)
|
||||||
|
}
|
||||||
|
nameCache[id] = name
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun deserializeLocalAlias(localNameId: JsAstProtoBuf.LocalAlias): LocalAlias {
|
||||||
|
return LocalAlias(
|
||||||
|
deserializeName(localNameId.localNameId),
|
||||||
|
if (localNameId.hasTag()) deserializeString(localNameId.tag) else null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected fun deserializeString(id: Int): String = stringTable[id]
|
||||||
|
|
||||||
|
protected fun map(op: JsAstProtoBuf.BinaryOperation.Type) = when (op) {
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.MUL -> JsBinaryOperator.MUL
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.DIV -> JsBinaryOperator.DIV
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.MOD -> JsBinaryOperator.MOD
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ADD -> JsBinaryOperator.ADD
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.SUB -> JsBinaryOperator.SUB
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.SHL -> JsBinaryOperator.SHL
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.SHR -> JsBinaryOperator.SHR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.SHRU -> JsBinaryOperator.SHRU
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.LT -> JsBinaryOperator.LT
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.LTE -> JsBinaryOperator.LTE
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.GT -> JsBinaryOperator.GT
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.GTE -> JsBinaryOperator.GTE
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.INSTANCEOF -> JsBinaryOperator.INSTANCEOF
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.IN -> JsBinaryOperator.INOP
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.EQ -> JsBinaryOperator.EQ
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.NEQ -> JsBinaryOperator.NEQ
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.REF_EQ -> JsBinaryOperator.REF_EQ
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.REF_NEQ -> JsBinaryOperator.REF_NEQ
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.BIT_AND -> JsBinaryOperator.BIT_AND
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.BIT_XOR -> JsBinaryOperator.BIT_XOR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.BIT_OR -> JsBinaryOperator.BIT_OR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.AND -> JsBinaryOperator.AND
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.OR -> JsBinaryOperator.OR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG -> JsBinaryOperator.ASG
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_ADD -> JsBinaryOperator.ASG_ADD
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_SUB -> JsBinaryOperator.ASG_SUB
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_MUL -> JsBinaryOperator.ASG_MUL
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_DIV -> JsBinaryOperator.ASG_DIV
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_MOD -> JsBinaryOperator.ASG_MOD
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_SHL -> JsBinaryOperator.ASG_SHL
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_SHR -> JsBinaryOperator.ASG_SHR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_SHRU -> JsBinaryOperator.ASG_SHRU
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_AND -> JsBinaryOperator.ASG_BIT_AND
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_OR -> JsBinaryOperator.ASG_BIT_OR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_XOR -> JsBinaryOperator.ASG_BIT_XOR
|
||||||
|
JsAstProtoBuf.BinaryOperation.Type.COMMA -> JsBinaryOperator.COMMA
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(op: JsAstProtoBuf.UnaryOperation.Type) = when (op) {
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.BIT_NOT -> JsUnaryOperator.BIT_NOT
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.DEC -> JsUnaryOperator.DEC
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.DELETE -> JsUnaryOperator.DELETE
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.INC -> JsUnaryOperator.INC
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.NEG -> JsUnaryOperator.NEG
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.POS -> JsUnaryOperator.POS
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.NOT -> JsUnaryOperator.NOT
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.TYPEOF -> JsUnaryOperator.TYPEOF
|
||||||
|
JsAstProtoBuf.UnaryOperation.Type.VOID -> JsUnaryOperator.VOID
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(sideEffects: JsAstProtoBuf.SideEffects) = when (sideEffects) {
|
||||||
|
JsAstProtoBuf.SideEffects.AFFECTS_STATE -> SideEffectKind.AFFECTS_STATE
|
||||||
|
JsAstProtoBuf.SideEffects.DEPENDS_ON_STATE -> SideEffectKind.DEPENDS_ON_STATE
|
||||||
|
JsAstProtoBuf.SideEffects.PURE -> SideEffectKind.PURE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(inlineStrategy: JsAstProtoBuf.InlineStrategy) =
|
||||||
|
inlineStrategy == JsAstProtoBuf.InlineStrategy.AS_FUNCTION || inlineStrategy == JsAstProtoBuf.InlineStrategy.IN_PLACE
|
||||||
|
|
||||||
|
protected fun map(specialFunction: JsAstProtoBuf.SpecialFunction) = when (specialFunction) {
|
||||||
|
JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION -> SpecialFunction.DEFINE_INLINE_FUNCTION
|
||||||
|
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
|
||||||
|
JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR -> SpecialFunction.TO_BOXED_CHAR
|
||||||
|
JsAstProtoBuf.SpecialFunction.UNBOX_CHAR -> SpecialFunction.UNBOX_CHAR
|
||||||
|
JsAstProtoBuf.SpecialFunction.SUSPEND_CALL -> SpecialFunction.SUSPEND_CALL
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT -> SpecialFunction.COROUTINE_RESULT
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER -> SpecialFunction.COROUTINE_CONTROLLER
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER -> SpecialFunction.COROUTINE_RECEIVER
|
||||||
|
JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT -> SpecialFunction.SET_COROUTINE_RESULT
|
||||||
|
JsAstProtoBuf.SpecialFunction.GET_KCLASS -> SpecialFunction.GET_KCLASS
|
||||||
|
JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun <T : JsNode> withLocation(fileId: Int?, location: JsAstProtoBuf.Location?, action: () -> T): T {
|
||||||
|
val deserializedFile = fileId?.let { deserializeString(it) }
|
||||||
|
val file = deserializedFile ?: fileStack.peek()
|
||||||
|
val deserializedLocation = if (file != null && location != null) {
|
||||||
|
JsLocation(file, location.startLine, location.startChar)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val shouldUpdateFile = location != null && deserializedFile != null && deserializedFile != fileStack.peek()
|
||||||
|
if (shouldUpdateFile) {
|
||||||
|
fileStack.push(deserializedFile)
|
||||||
|
}
|
||||||
|
val node = action()
|
||||||
|
if (deserializedLocation != null) {
|
||||||
|
node.source = embedSources(deserializedLocation, file) ?: deserializedLocation
|
||||||
|
}
|
||||||
|
if (shouldUpdateFile) {
|
||||||
|
fileStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun embedSources(deserializedLocation: JsLocation, file: String): JsLocationWithSource?
|
||||||
|
}
|
||||||
+6811
-4934
File diff suppressed because it is too large
Load Diff
@@ -30,14 +30,10 @@ import java.io.File
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class JsAstSerializer(private val jsAstValidator: ((JsProgramFragment, Set<JsName>) -> Unit)?,
|
class JsAstSerializer(
|
||||||
private val pathResolver: (File) -> String) {
|
private val jsAstValidator: ((JsProgramFragment, Set<JsName>) -> Unit)?,
|
||||||
private val nameTableBuilder = NameTable.newBuilder()
|
private val pathResolver: (File) -> String
|
||||||
private val stringTableBuilder = StringTable.newBuilder()
|
) : JsAstSerializerBase() {
|
||||||
private val nameMap = mutableMapOf<JsName, Int>()
|
|
||||||
private val stringMap = mutableMapOf<String, Int>()
|
|
||||||
private val fileStack: Deque<String> = ArrayDeque()
|
|
||||||
private val importedNames = mutableSetOf<JsName>()
|
|
||||||
|
|
||||||
fun serialize(fragment: JsProgramFragment, output: OutputStream) {
|
fun serialize(fragment: JsProgramFragment, output: OutputStream) {
|
||||||
val namesBySignature = fragment.nameBindings.associateTo(mutableMapOf()) { it.key to it.name }
|
val namesBySignature = fragment.nameBindings.associateTo(mutableMapOf()) { it.key to it.name }
|
||||||
@@ -53,8 +49,7 @@ class JsAstSerializer(private val jsAstValidator: ((JsProgramFragment, Set<JsNam
|
|||||||
chunkBuilder.nameTable = nameTableBuilder.build()
|
chunkBuilder.nameTable = nameTableBuilder.build()
|
||||||
chunkBuilder.stringTable = stringTableBuilder.build()
|
chunkBuilder.stringTable = stringTableBuilder.build()
|
||||||
return chunkBuilder.build()
|
return chunkBuilder.build()
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
nameTableBuilder.clear()
|
nameTableBuilder.clear()
|
||||||
stringTableBuilder.clear()
|
stringTableBuilder.clear()
|
||||||
nameMap.clear()
|
nameMap.clear()
|
||||||
@@ -140,526 +135,7 @@ class JsAstSerializer(private val jsAstValidator: ((JsProgramFragment, Set<JsNam
|
|||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun serialize(statement: JsStatement): Statement {
|
override fun extractLocation(node: JsNode): JsLocation? {
|
||||||
val visitor = object : JsVisitor() {
|
|
||||||
val builder = Statement.newBuilder()
|
|
||||||
|
|
||||||
override fun visitReturn(x: JsReturn) {
|
|
||||||
val returnBuilder = Return.newBuilder()
|
|
||||||
x.expression?.let { returnBuilder.value = serialize(it) }
|
|
||||||
builder.returnStatement = returnBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitThrow(x: JsThrow) {
|
|
||||||
val throwBuilder = Throw.newBuilder()
|
|
||||||
throwBuilder.exception = serialize(x.expression)
|
|
||||||
builder.throwStatement = throwBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBreak(x: JsBreak) {
|
|
||||||
val breakBuilder = Break.newBuilder()
|
|
||||||
x.label?.let { breakBuilder.labelId = serialize(it.name!!) }
|
|
||||||
builder.breakStatement = breakBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitContinue(x: JsContinue) {
|
|
||||||
val continueBuilder = Continue.newBuilder()
|
|
||||||
x.label?.let { continueBuilder.labelId = serialize(it.name!!) }
|
|
||||||
builder.continueStatement = continueBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDebugger(x: JsDebugger) {
|
|
||||||
builder.debugger = Debugger.newBuilder().build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitExpressionStatement(x: JsExpressionStatement) {
|
|
||||||
val statementBuilder = ExpressionStatement.newBuilder()
|
|
||||||
statementBuilder.expression = serialize(x.expression)
|
|
||||||
val tag = x.exportedTag
|
|
||||||
if (tag != null) {
|
|
||||||
statementBuilder.exportedTagId = serialize(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.expression = statementBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVars(x: JsVars) {
|
|
||||||
builder.vars = serializeVars(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBlock(x: JsBlock) {
|
|
||||||
if (x is JsGlobalBlock) {
|
|
||||||
builder.globalBlock = serializeBlock(x)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val blockBuilder = Block.newBuilder()
|
|
||||||
for (part in x.statements) {
|
|
||||||
blockBuilder.addStatement(serialize(part))
|
|
||||||
}
|
|
||||||
builder.block = blockBuilder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLabel(x: JsLabel) {
|
|
||||||
val labelBuilder = Label.newBuilder()
|
|
||||||
labelBuilder.nameId = serialize(x.name)
|
|
||||||
labelBuilder.innerStatement = serialize(x.statement)
|
|
||||||
builder.label = labelBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitIf(x: JsIf) {
|
|
||||||
val ifBuilder = If.newBuilder()
|
|
||||||
ifBuilder.condition = serialize(x.ifExpression)
|
|
||||||
ifBuilder.thenStatement = serialize(x.thenStatement)
|
|
||||||
x.elseStatement?.let { ifBuilder.elseStatement = serialize(it) }
|
|
||||||
builder.ifStatement = ifBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(x: JsSwitch) {
|
|
||||||
val switchBuilder = Switch.newBuilder()
|
|
||||||
switchBuilder.expression = serialize(x.expression)
|
|
||||||
for (case in x.cases) {
|
|
||||||
val entryBuilder = SwitchEntry.newBuilder()
|
|
||||||
withLocation(case, { entryBuilder.fileId = it }, { entryBuilder.location = it }) {}
|
|
||||||
if (case is JsCase) {
|
|
||||||
entryBuilder.label = serialize(case.caseExpression)
|
|
||||||
}
|
|
||||||
for (part in case.statements) {
|
|
||||||
entryBuilder.addStatement(serialize(part))
|
|
||||||
}
|
|
||||||
switchBuilder.addEntry(entryBuilder)
|
|
||||||
}
|
|
||||||
builder.switchStatement = switchBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhile(x: JsWhile) {
|
|
||||||
val whileBuilder = While.newBuilder()
|
|
||||||
whileBuilder.condition = serialize(x.condition)
|
|
||||||
whileBuilder.body = serialize(x.body)
|
|
||||||
builder.whileStatement = whileBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDoWhile(x: JsDoWhile) {
|
|
||||||
val doWhileBuilder = DoWhile.newBuilder()
|
|
||||||
doWhileBuilder.condition = serialize(x.condition)
|
|
||||||
doWhileBuilder.body = serialize(x.body)
|
|
||||||
builder.doWhileStatement = doWhileBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFor(x: JsFor) {
|
|
||||||
val forBuilder = For.newBuilder()
|
|
||||||
when {
|
|
||||||
x.initVars != null -> forBuilder.variables = serialize(x.initVars)
|
|
||||||
x.initExpression != null -> forBuilder.expression = serialize(x.initExpression)
|
|
||||||
else -> forBuilder.empty = EmptyInit.newBuilder().build()
|
|
||||||
}
|
|
||||||
x.condition?.let { forBuilder.condition = serialize(it) }
|
|
||||||
x.incrementExpression?.let { forBuilder.increment = serialize(it) }
|
|
||||||
forBuilder.body = serialize(x.body ?: JsEmpty)
|
|
||||||
builder.forStatement = forBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitForIn(x: JsForIn) {
|
|
||||||
val forInBuilder = ForIn.newBuilder()
|
|
||||||
when {
|
|
||||||
x.iterVarName != null -> forInBuilder.nameId = serialize(x.iterVarName)
|
|
||||||
x.iterExpression != null -> forInBuilder.expression = serialize(x.iterExpression)
|
|
||||||
}
|
|
||||||
forInBuilder.iterable = serialize(x.objectExpression)
|
|
||||||
forInBuilder.body = serialize(x.body)
|
|
||||||
builder.forInStatement = forInBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitTry(x: JsTry) {
|
|
||||||
val tryBuilder = Try.newBuilder()
|
|
||||||
tryBuilder.tryBlock = serialize(x.tryBlock)
|
|
||||||
x.catches.firstOrNull()?.let { c ->
|
|
||||||
val catchBuilder = Catch.newBuilder()
|
|
||||||
catchBuilder.parameter = serializeParameter(c.parameter)
|
|
||||||
catchBuilder.body = serialize(c.body)
|
|
||||||
tryBuilder.catchBlock = catchBuilder.build()
|
|
||||||
}
|
|
||||||
x.finallyBlock?.let { tryBuilder.finallyBlock = serialize(it) }
|
|
||||||
builder.tryStatement = tryBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitEmpty(x: JsEmpty) {
|
|
||||||
builder.empty = Empty.newBuilder().build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
withLocation(statement, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
|
|
||||||
statement.accept(visitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statement is HasMetadata && statement.synthetic) {
|
|
||||||
visitor.builder.synthetic = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return visitor.builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serialize(expression: JsExpression): Expression {
|
|
||||||
val visitor = object : JsVisitor() {
|
|
||||||
val builder = Expression.newBuilder()
|
|
||||||
|
|
||||||
override fun visitThis(x: JsThisRef) {
|
|
||||||
builder.thisLiteral = ThisLiteral.newBuilder().build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitNull(x: JsNullLiteral) {
|
|
||||||
builder.nullLiteral = NullLiteral.newBuilder().build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBoolean(x: JsBooleanLiteral) {
|
|
||||||
if (x.value) {
|
|
||||||
builder.trueLiteral = TrueLiteral.newBuilder().build()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
builder.falseLiteral = FalseLiteral.newBuilder().build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitString(x: JsStringLiteral) {
|
|
||||||
builder.stringLiteral = serialize(x.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitRegExp(x: JsRegExp) {
|
|
||||||
val regExpBuilder = RegExpLiteral.newBuilder()
|
|
||||||
regExpBuilder.patternStringId = serialize(x.pattern)
|
|
||||||
x.flags?.let { regExpBuilder.flagsStringId = serialize(it) }
|
|
||||||
builder.regExpLiteral = regExpBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInt(x: JsIntLiteral) {
|
|
||||||
builder.intLiteral = x.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDouble(x: JsDoubleLiteral) {
|
|
||||||
builder.doubleLiteral = x.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitArray(x: JsArrayLiteral) {
|
|
||||||
val arrayBuilder = ArrayLiteral.newBuilder()
|
|
||||||
x.expressions.forEach { arrayBuilder.addElement(serialize(it)) }
|
|
||||||
builder.arrayLiteral = arrayBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitObjectLiteral(x: JsObjectLiteral) {
|
|
||||||
val objectBuilder = ObjectLiteral.newBuilder()
|
|
||||||
for (initializer in x.propertyInitializers) {
|
|
||||||
val entryBuilder = ObjectLiteralEntry.newBuilder()
|
|
||||||
entryBuilder.key = serialize(initializer.labelExpr)
|
|
||||||
entryBuilder.value = serialize(initializer.valueExpr)
|
|
||||||
objectBuilder.addEntry(entryBuilder)
|
|
||||||
}
|
|
||||||
objectBuilder.multiline = x.isMultiline
|
|
||||||
builder.objectLiteral = objectBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunction(x: JsFunction) {
|
|
||||||
val functionBuilder = JsAstProtoBuf.Function.newBuilder()
|
|
||||||
x.parameters.forEach { functionBuilder.addParameter(serializeParameter(it)) }
|
|
||||||
x.name?.let { functionBuilder.nameId = serialize(it) }
|
|
||||||
functionBuilder.body = serialize(x.body)
|
|
||||||
if (x.isLocal) {
|
|
||||||
functionBuilder.local = true
|
|
||||||
}
|
|
||||||
builder.function = functionBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDocComment(comment: JsDocComment) {
|
|
||||||
val commentBuilder = DocComment.newBuilder()
|
|
||||||
for ((name, value) in comment.tags) {
|
|
||||||
val tagBuilder = DocCommentTag.newBuilder()
|
|
||||||
tagBuilder.nameId = serialize(name)
|
|
||||||
when (value) {
|
|
||||||
is JsNameRef -> tagBuilder.expression = serialize(value)
|
|
||||||
is String -> tagBuilder.valueStringId = serialize(value)
|
|
||||||
}
|
|
||||||
commentBuilder.addTag(tagBuilder)
|
|
||||||
}
|
|
||||||
builder.docComment = commentBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBinaryExpression(x: JsBinaryOperation) {
|
|
||||||
val binaryBuilder = BinaryOperation.newBuilder()
|
|
||||||
binaryBuilder.left = serialize(x.arg1)
|
|
||||||
binaryBuilder.right = serialize(x.arg2)
|
|
||||||
binaryBuilder.type = map(x.operator)
|
|
||||||
builder.binary = binaryBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitPrefixOperation(x: JsPrefixOperation) {
|
|
||||||
builder.unary = serializeUnary(x, postfix = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitPostfixOperation(x: JsPostfixOperation) {
|
|
||||||
builder.unary = serializeUnary(x, postfix = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConditional(x: JsConditional) {
|
|
||||||
val conditionalBuilder = Conditional.newBuilder()
|
|
||||||
conditionalBuilder.testExpression = serialize(x.testExpression)
|
|
||||||
conditionalBuilder.thenExpression = serialize(x.thenExpression)
|
|
||||||
conditionalBuilder.elseExpression = serialize(x.elseExpression)
|
|
||||||
builder.conditional = conditionalBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitArrayAccess(x: JsArrayAccess) {
|
|
||||||
val arrayAccessBuilder = ArrayAccess.newBuilder()
|
|
||||||
arrayAccessBuilder.array = serialize(x.arrayExpression)
|
|
||||||
arrayAccessBuilder.index = serialize(x.indexExpression)
|
|
||||||
builder.arrayAccess = arrayAccessBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitNameRef(nameRef: JsNameRef) {
|
|
||||||
val name = nameRef.name
|
|
||||||
val qualifier = nameRef.qualifier
|
|
||||||
if (name != null) {
|
|
||||||
if (qualifier != null || nameRef.isInline == true) {
|
|
||||||
val nameRefBuilder = NameReference.newBuilder()
|
|
||||||
nameRefBuilder.nameId = serialize(name)
|
|
||||||
if (qualifier != null) {
|
|
||||||
nameRefBuilder.qualifier = serialize(qualifier)
|
|
||||||
}
|
|
||||||
nameRef.isInline?.let {
|
|
||||||
nameRefBuilder.inlineStrategy = if (it) InlineStrategy.IN_PLACE else InlineStrategy.NOT_INLINE
|
|
||||||
}
|
|
||||||
builder.nameReference = nameRefBuilder.build()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
builder.simpleNameReference = serialize(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val propertyRefBuilder = PropertyReference.newBuilder()
|
|
||||||
propertyRefBuilder.stringId = serialize(nameRef.ident)
|
|
||||||
qualifier?.let { propertyRefBuilder.qualifier = serialize(it) }
|
|
||||||
nameRef.isInline?.let {
|
|
||||||
propertyRefBuilder.inlineStrategy = if (it) InlineStrategy.IN_PLACE else InlineStrategy.NOT_INLINE
|
|
||||||
}
|
|
||||||
builder.propertyReference = propertyRefBuilder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInvocation(invocation: JsInvocation) {
|
|
||||||
val invocationBuilder = Invocation.newBuilder()
|
|
||||||
invocationBuilder.qualifier = serialize(invocation.qualifier)
|
|
||||||
invocation.arguments.forEach { invocationBuilder.addArgument(serialize(it)) }
|
|
||||||
if (invocation.isInline == true) {
|
|
||||||
invocationBuilder.inlineStrategy = InlineStrategy.IN_PLACE
|
|
||||||
}
|
|
||||||
builder.invocation = invocationBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitNew(x: JsNew) {
|
|
||||||
val instantiationBuilder = Instantiation.newBuilder()
|
|
||||||
instantiationBuilder.qualifier = serialize(x.constructorExpression)
|
|
||||||
x.arguments.forEach { instantiationBuilder.addArgument(serialize(it)) }
|
|
||||||
builder.instantiation = instantiationBuilder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
withLocation(expression, { visitor.builder.fileId = it }, {visitor.builder.location = it }) {
|
|
||||||
expression.accept(visitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
with (visitor.builder) {
|
|
||||||
synthetic = expression.synthetic
|
|
||||||
sideEffects = map(expression.sideEffects)
|
|
||||||
expression.localAlias?.let { localAlias = serialize(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return visitor.builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serialize(module: JsImportedModule): JsAstProtoBuf.JsImportedModule {
|
|
||||||
val moduleBuilder = JsAstProtoBuf.JsImportedModule.newBuilder()
|
|
||||||
moduleBuilder.externalName = serialize(module.externalName)
|
|
||||||
moduleBuilder.internalName = serialize(module.internalName)
|
|
||||||
module.plainReference?.let {
|
|
||||||
moduleBuilder.plainReference = serialize(it)
|
|
||||||
}
|
|
||||||
return moduleBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serializeParameter(parameter: JsParameter): Parameter {
|
|
||||||
val parameterBuilder = Parameter.newBuilder()
|
|
||||||
parameterBuilder.nameId = serialize(parameter.name)
|
|
||||||
if (parameter.hasDefaultValue) {
|
|
||||||
parameterBuilder.hasDefaultValue = true
|
|
||||||
}
|
|
||||||
return parameterBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serializeBlock(block: JsGlobalBlock): GlobalBlock {
|
|
||||||
val blockBuilder = GlobalBlock.newBuilder()
|
|
||||||
for (part in block.statements) {
|
|
||||||
blockBuilder.addStatement(serialize(part))
|
|
||||||
}
|
|
||||||
return blockBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serializeVars(vars: JsVars): Vars {
|
|
||||||
val varsBuilder = Vars.newBuilder()
|
|
||||||
for (varDecl in vars.vars) {
|
|
||||||
val declBuilder = VarDeclaration.newBuilder()
|
|
||||||
withLocation(varDecl, { declBuilder.fileId = it }, { declBuilder.location = it }) {
|
|
||||||
declBuilder.nameId = serialize(varDecl.name)
|
|
||||||
varDecl.initExpression?.let { declBuilder.initialValue = serialize(it) }
|
|
||||||
}
|
|
||||||
varsBuilder.addDeclaration(declBuilder)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vars.isMultiline) {
|
|
||||||
varsBuilder.multiline = true
|
|
||||||
}
|
|
||||||
vars.exportedPackage?.let { varsBuilder.exportedPackageId = serialize(it) }
|
|
||||||
|
|
||||||
return varsBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serializeUnary(x: JsUnaryOperation, postfix: Boolean): UnaryOperation {
|
|
||||||
val unaryBuilder = UnaryOperation.newBuilder()
|
|
||||||
unaryBuilder.operand = serialize(x.arg)
|
|
||||||
unaryBuilder.type = map(x.operator)
|
|
||||||
unaryBuilder.postfix = postfix
|
|
||||||
return unaryBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(op: JsBinaryOperator) = when (op) {
|
|
||||||
JsBinaryOperator.MUL -> MUL
|
|
||||||
JsBinaryOperator.DIV -> DIV
|
|
||||||
JsBinaryOperator.MOD -> MOD
|
|
||||||
JsBinaryOperator.ADD -> ADD
|
|
||||||
JsBinaryOperator.SUB -> SUB
|
|
||||||
JsBinaryOperator.SHL -> SHL
|
|
||||||
JsBinaryOperator.SHR -> SHR
|
|
||||||
JsBinaryOperator.SHRU -> SHRU
|
|
||||||
JsBinaryOperator.LT -> LT
|
|
||||||
JsBinaryOperator.LTE -> LTE
|
|
||||||
JsBinaryOperator.GT -> GT
|
|
||||||
JsBinaryOperator.GTE -> GTE
|
|
||||||
JsBinaryOperator.INSTANCEOF -> INSTANCEOF
|
|
||||||
JsBinaryOperator.INOP -> IN
|
|
||||||
JsBinaryOperator.EQ -> EQ
|
|
||||||
JsBinaryOperator.NEQ -> NEQ
|
|
||||||
JsBinaryOperator.REF_EQ -> REF_EQ
|
|
||||||
JsBinaryOperator.REF_NEQ -> REF_NEQ
|
|
||||||
JsBinaryOperator.BIT_AND -> BIT_AND
|
|
||||||
JsBinaryOperator.BIT_XOR -> BIT_XOR
|
|
||||||
JsBinaryOperator.BIT_OR -> BIT_OR
|
|
||||||
JsBinaryOperator.AND -> AND
|
|
||||||
JsBinaryOperator.OR -> OR
|
|
||||||
JsBinaryOperator.ASG -> ASG
|
|
||||||
JsBinaryOperator.ASG_ADD -> ASG_ADD
|
|
||||||
JsBinaryOperator.ASG_SUB -> ASG_SUB
|
|
||||||
JsBinaryOperator.ASG_MUL -> ASG_MUL
|
|
||||||
JsBinaryOperator.ASG_DIV -> ASG_DIV
|
|
||||||
JsBinaryOperator.ASG_MOD -> ASG_MOD
|
|
||||||
JsBinaryOperator.ASG_SHL -> ASG_SHL
|
|
||||||
JsBinaryOperator.ASG_SHR -> ASG_SHR
|
|
||||||
JsBinaryOperator.ASG_SHRU -> ASG_SHRU
|
|
||||||
JsBinaryOperator.ASG_BIT_AND -> ASG_BIT_AND
|
|
||||||
JsBinaryOperator.ASG_BIT_OR -> ASG_BIT_OR
|
|
||||||
JsBinaryOperator.ASG_BIT_XOR -> ASG_BIT_XOR
|
|
||||||
JsBinaryOperator.COMMA -> COMMA
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(op: JsUnaryOperator) = when (op) {
|
|
||||||
JsUnaryOperator.BIT_NOT -> BIT_NOT
|
|
||||||
JsUnaryOperator.DEC -> DEC
|
|
||||||
JsUnaryOperator.DELETE -> DELETE
|
|
||||||
JsUnaryOperator.INC -> INC
|
|
||||||
JsUnaryOperator.NEG -> NEG
|
|
||||||
JsUnaryOperator.POS -> POS
|
|
||||||
JsUnaryOperator.NOT -> NOT
|
|
||||||
JsUnaryOperator.TYPEOF -> TYPEOF
|
|
||||||
JsUnaryOperator.VOID -> VOID
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(sideEffects: SideEffectKind) = when (sideEffects) {
|
|
||||||
SideEffectKind.AFFECTS_STATE -> SideEffects.AFFECTS_STATE
|
|
||||||
SideEffectKind.DEPENDS_ON_STATE -> SideEffects.DEPENDS_ON_STATE
|
|
||||||
SideEffectKind.PURE -> SideEffects.PURE
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun map(specialFunction: SpecialFunction) = when (specialFunction) {
|
|
||||||
SpecialFunction.DEFINE_INLINE_FUNCTION -> JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION
|
|
||||||
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
|
|
||||||
SpecialFunction.TO_BOXED_CHAR -> JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR
|
|
||||||
SpecialFunction.UNBOX_CHAR -> JsAstProtoBuf.SpecialFunction.UNBOX_CHAR
|
|
||||||
SpecialFunction.SUSPEND_CALL -> JsAstProtoBuf.SpecialFunction.SUSPEND_CALL
|
|
||||||
SpecialFunction.COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT
|
|
||||||
SpecialFunction.COROUTINE_CONTROLLER -> JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER
|
|
||||||
SpecialFunction.COROUTINE_RECEIVER -> JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER
|
|
||||||
SpecialFunction.SET_COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT
|
|
||||||
SpecialFunction.GET_KCLASS -> JsAstProtoBuf.SpecialFunction.GET_KCLASS
|
|
||||||
SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
|
|
||||||
val builder = Name.newBuilder()
|
|
||||||
builder.identifier = serialize(name.ident)
|
|
||||||
builder.temporary = name.isTemporary
|
|
||||||
name.localAlias?.let {
|
|
||||||
builder.localNameId = serialize(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.imported && name !in importedNames) {
|
|
||||||
builder.imported = true
|
|
||||||
}
|
|
||||||
|
|
||||||
name.specialFunction?.let {
|
|
||||||
builder.specialFunction = map(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = nameTableBuilder.entryCount
|
|
||||||
nameTableBuilder.addEntry(builder)
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serialize(alias: LocalAlias): JsAstProtoBuf.LocalAlias {
|
|
||||||
val builder = JsAstProtoBuf.LocalAlias.newBuilder()
|
|
||||||
builder.localNameId = serialize(alias.name)
|
|
||||||
alias.tag?.let {
|
|
||||||
builder.tag = serialize(it)
|
|
||||||
}
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serialize(string: String) = stringMap.getOrPut(string) {
|
|
||||||
val result = stringTableBuilder.entryCount
|
|
||||||
stringTableBuilder.addEntry(string)
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun withLocation(node: JsNode, fileConsumer: (Int) -> Unit, locationConsumer: (Location) -> Unit, inner: () -> Unit) {
|
|
||||||
val location = extractLocation(node)
|
|
||||||
var fileChanged = false
|
|
||||||
if (location != null) {
|
|
||||||
val lastFile = fileStack.peek()
|
|
||||||
val newFile = location.file
|
|
||||||
fileChanged = lastFile != newFile
|
|
||||||
if (fileChanged) {
|
|
||||||
fileConsumer(serialize(newFile))
|
|
||||||
fileStack.push(location.file)
|
|
||||||
}
|
|
||||||
val locationBuilder = Location.newBuilder()
|
|
||||||
locationBuilder.startLine = location.startLine
|
|
||||||
locationBuilder.startChar = location.startChar
|
|
||||||
locationConsumer(locationBuilder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
inner()
|
|
||||||
|
|
||||||
if (fileChanged) {
|
|
||||||
fileStack.pop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractLocation(node: JsNode): JsLocation? {
|
|
||||||
val source = node.source
|
val source = node.source
|
||||||
return when (source) {
|
return when (source) {
|
||||||
is JsLocationWithSource -> source.asSimpleLocation()
|
is JsLocationWithSource -> source.asSimpleLocation()
|
||||||
|
|||||||
+546
@@ -0,0 +1,546 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.serialization.js.ast
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class JsAstSerializerBase {
|
||||||
|
|
||||||
|
protected val nameTableBuilder = JsAstProtoBuf.NameTable.newBuilder()
|
||||||
|
protected val stringTableBuilder = JsAstProtoBuf.StringTable.newBuilder()
|
||||||
|
protected val nameMap = mutableMapOf<JsName, Int>()
|
||||||
|
protected val stringMap = mutableMapOf<String, Int>()
|
||||||
|
protected val fileStack: Deque<String> = ArrayDeque()
|
||||||
|
protected val importedNames = mutableSetOf<JsName>()
|
||||||
|
|
||||||
|
protected fun serialize(statement: JsStatement): JsAstProtoBuf.Statement {
|
||||||
|
val visitor = object : JsVisitor() {
|
||||||
|
val builder = JsAstProtoBuf.Statement.newBuilder()
|
||||||
|
|
||||||
|
override fun visitReturn(x: JsReturn) {
|
||||||
|
val returnBuilder = JsAstProtoBuf.Return.newBuilder()
|
||||||
|
x.expression?.let { returnBuilder.value = serialize(it) }
|
||||||
|
builder.returnStatement = returnBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitThrow(x: JsThrow) {
|
||||||
|
val throwBuilder = JsAstProtoBuf.Throw.newBuilder()
|
||||||
|
throwBuilder.exception = serialize(x.expression)
|
||||||
|
builder.throwStatement = throwBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBreak(x: JsBreak) {
|
||||||
|
val breakBuilder = JsAstProtoBuf.Break.newBuilder()
|
||||||
|
x.label?.let { breakBuilder.labelId = serialize(it.name!!) }
|
||||||
|
builder.breakStatement = breakBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitContinue(x: JsContinue) {
|
||||||
|
val continueBuilder = JsAstProtoBuf.Continue.newBuilder()
|
||||||
|
x.label?.let { continueBuilder.labelId = serialize(it.name!!) }
|
||||||
|
builder.continueStatement = continueBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDebugger(x: JsDebugger) {
|
||||||
|
builder.debugger = JsAstProtoBuf.Debugger.newBuilder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitExpressionStatement(x: JsExpressionStatement) {
|
||||||
|
val statementBuilder = JsAstProtoBuf.ExpressionStatement.newBuilder()
|
||||||
|
statementBuilder.expression = serialize(x.expression)
|
||||||
|
val tag = x.exportedTag
|
||||||
|
if (tag != null) {
|
||||||
|
statementBuilder.exportedTagId = serialize(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.expression = statementBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVars(x: JsVars) {
|
||||||
|
builder.vars = serializeVars(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(x: JsBlock) {
|
||||||
|
if (x is JsGlobalBlock) {
|
||||||
|
builder.globalBlock = serializeBlock(x)
|
||||||
|
} else {
|
||||||
|
val blockBuilder = JsAstProtoBuf.Block.newBuilder()
|
||||||
|
for (part in x.statements) {
|
||||||
|
blockBuilder.addStatement(serialize(part))
|
||||||
|
}
|
||||||
|
builder.block = blockBuilder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLabel(x: JsLabel) {
|
||||||
|
val labelBuilder = JsAstProtoBuf.Label.newBuilder()
|
||||||
|
labelBuilder.nameId = serialize(x.name)
|
||||||
|
labelBuilder.innerStatement = serialize(x.statement)
|
||||||
|
builder.label = labelBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIf(x: JsIf) {
|
||||||
|
val ifBuilder = JsAstProtoBuf.If.newBuilder()
|
||||||
|
ifBuilder.condition = serialize(x.ifExpression)
|
||||||
|
ifBuilder.thenStatement = serialize(x.thenStatement)
|
||||||
|
x.elseStatement?.let { ifBuilder.elseStatement = serialize(it) }
|
||||||
|
builder.ifStatement = ifBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visit(x: JsSwitch) {
|
||||||
|
val switchBuilder = JsAstProtoBuf.Switch.newBuilder()
|
||||||
|
switchBuilder.expression = serialize(x.expression)
|
||||||
|
for (case in x.cases) {
|
||||||
|
val entryBuilder = JsAstProtoBuf.SwitchEntry.newBuilder()
|
||||||
|
withLocation(case, { entryBuilder.fileId = it }, { entryBuilder.location = it }) {}
|
||||||
|
if (case is JsCase) {
|
||||||
|
entryBuilder.label = serialize(case.caseExpression)
|
||||||
|
}
|
||||||
|
for (part in case.statements) {
|
||||||
|
entryBuilder.addStatement(serialize(part))
|
||||||
|
}
|
||||||
|
switchBuilder.addEntry(entryBuilder)
|
||||||
|
}
|
||||||
|
builder.switchStatement = switchBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhile(x: JsWhile) {
|
||||||
|
val whileBuilder = JsAstProtoBuf.While.newBuilder()
|
||||||
|
whileBuilder.condition = serialize(x.condition)
|
||||||
|
whileBuilder.body = serialize(x.body)
|
||||||
|
builder.whileStatement = whileBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoWhile(x: JsDoWhile) {
|
||||||
|
val doWhileBuilder = JsAstProtoBuf.DoWhile.newBuilder()
|
||||||
|
doWhileBuilder.condition = serialize(x.condition)
|
||||||
|
doWhileBuilder.body = serialize(x.body)
|
||||||
|
builder.doWhileStatement = doWhileBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFor(x: JsFor) {
|
||||||
|
val forBuilder = JsAstProtoBuf.For.newBuilder()
|
||||||
|
when {
|
||||||
|
x.initVars != null -> forBuilder.variables = serialize(x.initVars)
|
||||||
|
x.initExpression != null -> forBuilder.expression = serialize(x.initExpression)
|
||||||
|
else -> forBuilder.empty = JsAstProtoBuf.EmptyInit.newBuilder().build()
|
||||||
|
}
|
||||||
|
x.condition?.let { forBuilder.condition = serialize(it) }
|
||||||
|
x.incrementExpression?.let { forBuilder.increment = serialize(it) }
|
||||||
|
forBuilder.body = serialize(x.body ?: JsEmpty)
|
||||||
|
builder.forStatement = forBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitForIn(x: JsForIn) {
|
||||||
|
val forInBuilder = JsAstProtoBuf.ForIn.newBuilder()
|
||||||
|
when {
|
||||||
|
x.iterVarName != null -> forInBuilder.nameId = serialize(x.iterVarName)
|
||||||
|
x.iterExpression != null -> forInBuilder.expression = serialize(x.iterExpression)
|
||||||
|
}
|
||||||
|
forInBuilder.iterable = serialize(x.objectExpression)
|
||||||
|
forInBuilder.body = serialize(x.body)
|
||||||
|
builder.forInStatement = forInBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTry(x: JsTry) {
|
||||||
|
val tryBuilder = JsAstProtoBuf.Try.newBuilder()
|
||||||
|
tryBuilder.tryBlock = serialize(x.tryBlock)
|
||||||
|
x.catches.firstOrNull()?.let { c ->
|
||||||
|
val catchBuilder = JsAstProtoBuf.Catch.newBuilder()
|
||||||
|
catchBuilder.parameter = serializeParameter(c.parameter)
|
||||||
|
catchBuilder.body = serialize(c.body)
|
||||||
|
tryBuilder.catchBlock = catchBuilder.build()
|
||||||
|
}
|
||||||
|
x.finallyBlock?.let { tryBuilder.finallyBlock = serialize(it) }
|
||||||
|
builder.tryStatement = tryBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEmpty(x: JsEmpty) {
|
||||||
|
builder.empty = JsAstProtoBuf.Empty.newBuilder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSingleLineComment(comment: JsSingleLineComment) {
|
||||||
|
builder.singleLineComment = JsAstProtoBuf.SingleLineComment.newBuilder().setMessage(comment.text).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
withLocation(statement, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
|
||||||
|
statement.accept(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statement is HasMetadata && statement.synthetic) {
|
||||||
|
visitor.builder.synthetic = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitor.builder.statementCase == JsAstProtoBuf.Statement.StatementCase.STATEMENT_NOT_SET) {
|
||||||
|
error("Unknown statement type: ${statement::class.qualifiedName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return visitor.builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serialize(expression: JsExpression): JsAstProtoBuf.Expression {
|
||||||
|
val visitor = object : JsVisitor() {
|
||||||
|
val builder = JsAstProtoBuf.Expression.newBuilder()
|
||||||
|
|
||||||
|
override fun visitThis(x: JsThisRef) {
|
||||||
|
builder.thisLiteral = JsAstProtoBuf.ThisLiteral.newBuilder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNull(x: JsNullLiteral) {
|
||||||
|
builder.nullLiteral = JsAstProtoBuf.NullLiteral.newBuilder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBoolean(x: JsBooleanLiteral) {
|
||||||
|
if (x.value) {
|
||||||
|
builder.trueLiteral = JsAstProtoBuf.TrueLiteral.newBuilder().build()
|
||||||
|
} else {
|
||||||
|
builder.falseLiteral = JsAstProtoBuf.FalseLiteral.newBuilder().build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitString(x: JsStringLiteral) {
|
||||||
|
builder.stringLiteral = serialize(x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitRegExp(x: JsRegExp) {
|
||||||
|
val regExpBuilder = JsAstProtoBuf.RegExpLiteral.newBuilder()
|
||||||
|
regExpBuilder.patternStringId = serialize(x.pattern)
|
||||||
|
x.flags?.let { regExpBuilder.flagsStringId = serialize(it) }
|
||||||
|
builder.regExpLiteral = regExpBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInt(x: JsIntLiteral) {
|
||||||
|
builder.intLiteral = x.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDouble(x: JsDoubleLiteral) {
|
||||||
|
builder.doubleLiteral = x.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitArray(x: JsArrayLiteral) {
|
||||||
|
val arrayBuilder = JsAstProtoBuf.ArrayLiteral.newBuilder()
|
||||||
|
x.expressions.forEach { arrayBuilder.addElement(serialize(it)) }
|
||||||
|
builder.arrayLiteral = arrayBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitObjectLiteral(x: JsObjectLiteral) {
|
||||||
|
val objectBuilder = JsAstProtoBuf.ObjectLiteral.newBuilder()
|
||||||
|
for (initializer in x.propertyInitializers) {
|
||||||
|
val entryBuilder = JsAstProtoBuf.ObjectLiteralEntry.newBuilder()
|
||||||
|
entryBuilder.key = serialize(initializer.labelExpr)
|
||||||
|
entryBuilder.value = serialize(initializer.valueExpr)
|
||||||
|
objectBuilder.addEntry(entryBuilder)
|
||||||
|
}
|
||||||
|
objectBuilder.multiline = x.isMultiline
|
||||||
|
builder.objectLiteral = objectBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(x: JsFunction) {
|
||||||
|
val functionBuilder = JsAstProtoBuf.Function.newBuilder()
|
||||||
|
x.parameters.forEach { functionBuilder.addParameter(serializeParameter(it)) }
|
||||||
|
x.name?.let { functionBuilder.nameId = serialize(it) }
|
||||||
|
functionBuilder.body = serialize(x.body)
|
||||||
|
if (x.isLocal) {
|
||||||
|
functionBuilder.local = true
|
||||||
|
}
|
||||||
|
builder.function = functionBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDocComment(comment: JsDocComment) {
|
||||||
|
val commentBuilder = JsAstProtoBuf.DocComment.newBuilder()
|
||||||
|
for ((name, value) in comment.tags) {
|
||||||
|
val tagBuilder = JsAstProtoBuf.DocCommentTag.newBuilder()
|
||||||
|
tagBuilder.nameId = serialize(name)
|
||||||
|
when (value) {
|
||||||
|
is JsNameRef -> tagBuilder.expression = serialize(value)
|
||||||
|
is String -> tagBuilder.valueStringId = serialize(value)
|
||||||
|
}
|
||||||
|
commentBuilder.addTag(tagBuilder)
|
||||||
|
}
|
||||||
|
builder.docComment = commentBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBinaryExpression(x: JsBinaryOperation) {
|
||||||
|
val binaryBuilder = JsAstProtoBuf.BinaryOperation.newBuilder()
|
||||||
|
binaryBuilder.left = serialize(x.arg1)
|
||||||
|
binaryBuilder.right = serialize(x.arg2)
|
||||||
|
binaryBuilder.type = map(x.operator)
|
||||||
|
builder.binary = binaryBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPrefixOperation(x: JsPrefixOperation) {
|
||||||
|
builder.unary = serializeUnary(x, postfix = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPostfixOperation(x: JsPostfixOperation) {
|
||||||
|
builder.unary = serializeUnary(x, postfix = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConditional(x: JsConditional) {
|
||||||
|
val conditionalBuilder = JsAstProtoBuf.Conditional.newBuilder()
|
||||||
|
conditionalBuilder.testExpression = serialize(x.testExpression)
|
||||||
|
conditionalBuilder.thenExpression = serialize(x.thenExpression)
|
||||||
|
conditionalBuilder.elseExpression = serialize(x.elseExpression)
|
||||||
|
builder.conditional = conditionalBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitArrayAccess(x: JsArrayAccess) {
|
||||||
|
val arrayAccessBuilder = JsAstProtoBuf.ArrayAccess.newBuilder()
|
||||||
|
arrayAccessBuilder.array = serialize(x.arrayExpression)
|
||||||
|
arrayAccessBuilder.index = serialize(x.indexExpression)
|
||||||
|
builder.arrayAccess = arrayAccessBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNameRef(nameRef: JsNameRef) {
|
||||||
|
val name = nameRef.name
|
||||||
|
val qualifier = nameRef.qualifier
|
||||||
|
if (name != null) {
|
||||||
|
if (qualifier != null || nameRef.isInline == true) {
|
||||||
|
val nameRefBuilder = JsAstProtoBuf.NameReference.newBuilder()
|
||||||
|
nameRefBuilder.nameId = serialize(name)
|
||||||
|
if (qualifier != null) {
|
||||||
|
nameRefBuilder.qualifier = serialize(qualifier)
|
||||||
|
}
|
||||||
|
nameRef.isInline?.let {
|
||||||
|
nameRefBuilder.inlineStrategy = if (it) JsAstProtoBuf.InlineStrategy.IN_PLACE else JsAstProtoBuf.InlineStrategy.NOT_INLINE
|
||||||
|
}
|
||||||
|
builder.nameReference = nameRefBuilder.build()
|
||||||
|
} else {
|
||||||
|
builder.simpleNameReference = serialize(name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val propertyRefBuilder = JsAstProtoBuf.PropertyReference.newBuilder()
|
||||||
|
propertyRefBuilder.stringId = serialize(nameRef.ident)
|
||||||
|
qualifier?.let { propertyRefBuilder.qualifier = serialize(it) }
|
||||||
|
nameRef.isInline?.let {
|
||||||
|
propertyRefBuilder.inlineStrategy = if (it) JsAstProtoBuf.InlineStrategy.IN_PLACE else JsAstProtoBuf.InlineStrategy.NOT_INLINE
|
||||||
|
}
|
||||||
|
builder.propertyReference = propertyRefBuilder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInvocation(invocation: JsInvocation) {
|
||||||
|
val invocationBuilder = JsAstProtoBuf.Invocation.newBuilder()
|
||||||
|
invocationBuilder.qualifier = serialize(invocation.qualifier)
|
||||||
|
invocation.arguments.forEach { invocationBuilder.addArgument(serialize(it)) }
|
||||||
|
if (invocation.isInline == true) {
|
||||||
|
invocationBuilder.inlineStrategy = JsAstProtoBuf.InlineStrategy.IN_PLACE
|
||||||
|
}
|
||||||
|
builder.invocation = invocationBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNew(x: JsNew) {
|
||||||
|
val instantiationBuilder = JsAstProtoBuf.Instantiation.newBuilder()
|
||||||
|
instantiationBuilder.qualifier = serialize(x.constructorExpression)
|
||||||
|
x.arguments.forEach { instantiationBuilder.addArgument(serialize(it)) }
|
||||||
|
builder.instantiation = instantiationBuilder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
withLocation(expression, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
|
||||||
|
expression.accept(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
with(visitor.builder) {
|
||||||
|
synthetic = expression.synthetic
|
||||||
|
sideEffects = map(expression.sideEffects)
|
||||||
|
expression.localAlias?.let { localAlias = serialize(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return visitor.builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serialize(module: JsImportedModule): JsAstProtoBuf.JsImportedModule {
|
||||||
|
val moduleBuilder = JsAstProtoBuf.JsImportedModule.newBuilder()
|
||||||
|
moduleBuilder.externalName = serialize(module.externalName)
|
||||||
|
moduleBuilder.internalName = serialize(module.internalName)
|
||||||
|
module.plainReference?.let {
|
||||||
|
moduleBuilder.plainReference = serialize(it)
|
||||||
|
}
|
||||||
|
return moduleBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serializeParameter(parameter: JsParameter): JsAstProtoBuf.Parameter {
|
||||||
|
val parameterBuilder = JsAstProtoBuf.Parameter.newBuilder()
|
||||||
|
parameterBuilder.nameId = serialize(parameter.name)
|
||||||
|
if (parameter.hasDefaultValue) {
|
||||||
|
parameterBuilder.hasDefaultValue = true
|
||||||
|
}
|
||||||
|
return parameterBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serializeBlock(block: JsGlobalBlock): JsAstProtoBuf.GlobalBlock {
|
||||||
|
val blockBuilder = JsAstProtoBuf.GlobalBlock.newBuilder()
|
||||||
|
for (part in block.statements) {
|
||||||
|
blockBuilder.addStatement(serialize(part))
|
||||||
|
}
|
||||||
|
return blockBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serializeVars(vars: JsVars): JsAstProtoBuf.Vars {
|
||||||
|
val varsBuilder = JsAstProtoBuf.Vars.newBuilder()
|
||||||
|
for (varDecl in vars.vars) {
|
||||||
|
val declBuilder = JsAstProtoBuf.VarDeclaration.newBuilder()
|
||||||
|
withLocation(varDecl, { declBuilder.fileId = it }, { declBuilder.location = it }) {
|
||||||
|
declBuilder.nameId = serialize(varDecl.name)
|
||||||
|
varDecl.initExpression?.let { declBuilder.initialValue = serialize(it) }
|
||||||
|
}
|
||||||
|
varsBuilder.addDeclaration(declBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vars.isMultiline) {
|
||||||
|
varsBuilder.multiline = true
|
||||||
|
}
|
||||||
|
vars.exportedPackage?.let { varsBuilder.exportedPackageId = serialize(it) }
|
||||||
|
|
||||||
|
return varsBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serializeUnary(x: JsUnaryOperation, postfix: Boolean): JsAstProtoBuf.UnaryOperation {
|
||||||
|
val unaryBuilder = JsAstProtoBuf.UnaryOperation.newBuilder()
|
||||||
|
unaryBuilder.operand = serialize(x.arg)
|
||||||
|
unaryBuilder.type = map(x.operator)
|
||||||
|
unaryBuilder.postfix = postfix
|
||||||
|
return unaryBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(op: JsBinaryOperator) = when (op) {
|
||||||
|
JsBinaryOperator.MUL -> JsAstProtoBuf.BinaryOperation.Type.MUL
|
||||||
|
JsBinaryOperator.DIV -> JsAstProtoBuf.BinaryOperation.Type.DIV
|
||||||
|
JsBinaryOperator.MOD -> JsAstProtoBuf.BinaryOperation.Type.MOD
|
||||||
|
JsBinaryOperator.ADD -> JsAstProtoBuf.BinaryOperation.Type.ADD
|
||||||
|
JsBinaryOperator.SUB -> JsAstProtoBuf.BinaryOperation.Type.SUB
|
||||||
|
JsBinaryOperator.SHL -> JsAstProtoBuf.BinaryOperation.Type.SHL
|
||||||
|
JsBinaryOperator.SHR -> JsAstProtoBuf.BinaryOperation.Type.SHR
|
||||||
|
JsBinaryOperator.SHRU -> JsAstProtoBuf.BinaryOperation.Type.SHRU
|
||||||
|
JsBinaryOperator.LT -> JsAstProtoBuf.BinaryOperation.Type.LT
|
||||||
|
JsBinaryOperator.LTE -> JsAstProtoBuf.BinaryOperation.Type.LTE
|
||||||
|
JsBinaryOperator.GT -> JsAstProtoBuf.BinaryOperation.Type.GT
|
||||||
|
JsBinaryOperator.GTE -> JsAstProtoBuf.BinaryOperation.Type.GTE
|
||||||
|
JsBinaryOperator.INSTANCEOF -> JsAstProtoBuf.BinaryOperation.Type.INSTANCEOF
|
||||||
|
JsBinaryOperator.INOP -> JsAstProtoBuf.BinaryOperation.Type.IN
|
||||||
|
JsBinaryOperator.EQ -> JsAstProtoBuf.BinaryOperation.Type.EQ
|
||||||
|
JsBinaryOperator.NEQ -> JsAstProtoBuf.BinaryOperation.Type.NEQ
|
||||||
|
JsBinaryOperator.REF_EQ -> JsAstProtoBuf.BinaryOperation.Type.REF_EQ
|
||||||
|
JsBinaryOperator.REF_NEQ -> JsAstProtoBuf.BinaryOperation.Type.REF_NEQ
|
||||||
|
JsBinaryOperator.BIT_AND -> JsAstProtoBuf.BinaryOperation.Type.BIT_AND
|
||||||
|
JsBinaryOperator.BIT_XOR -> JsAstProtoBuf.BinaryOperation.Type.BIT_XOR
|
||||||
|
JsBinaryOperator.BIT_OR -> JsAstProtoBuf.BinaryOperation.Type.BIT_OR
|
||||||
|
JsBinaryOperator.AND -> JsAstProtoBuf.BinaryOperation.Type.AND
|
||||||
|
JsBinaryOperator.OR -> JsAstProtoBuf.BinaryOperation.Type.OR
|
||||||
|
JsBinaryOperator.ASG -> JsAstProtoBuf.BinaryOperation.Type.ASG
|
||||||
|
JsBinaryOperator.ASG_ADD -> JsAstProtoBuf.BinaryOperation.Type.ASG_ADD
|
||||||
|
JsBinaryOperator.ASG_SUB -> JsAstProtoBuf.BinaryOperation.Type.ASG_SUB
|
||||||
|
JsBinaryOperator.ASG_MUL -> JsAstProtoBuf.BinaryOperation.Type.ASG_MUL
|
||||||
|
JsBinaryOperator.ASG_DIV -> JsAstProtoBuf.BinaryOperation.Type.ASG_DIV
|
||||||
|
JsBinaryOperator.ASG_MOD -> JsAstProtoBuf.BinaryOperation.Type.ASG_MOD
|
||||||
|
JsBinaryOperator.ASG_SHL -> JsAstProtoBuf.BinaryOperation.Type.ASG_SHL
|
||||||
|
JsBinaryOperator.ASG_SHR -> JsAstProtoBuf.BinaryOperation.Type.ASG_SHR
|
||||||
|
JsBinaryOperator.ASG_SHRU -> JsAstProtoBuf.BinaryOperation.Type.ASG_SHRU
|
||||||
|
JsBinaryOperator.ASG_BIT_AND -> JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_AND
|
||||||
|
JsBinaryOperator.ASG_BIT_OR -> JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_OR
|
||||||
|
JsBinaryOperator.ASG_BIT_XOR -> JsAstProtoBuf.BinaryOperation.Type.ASG_BIT_XOR
|
||||||
|
JsBinaryOperator.COMMA -> JsAstProtoBuf.BinaryOperation.Type.COMMA
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(op: JsUnaryOperator) = when (op) {
|
||||||
|
JsUnaryOperator.BIT_NOT -> JsAstProtoBuf.UnaryOperation.Type.BIT_NOT
|
||||||
|
JsUnaryOperator.DEC -> JsAstProtoBuf.UnaryOperation.Type.DEC
|
||||||
|
JsUnaryOperator.DELETE -> JsAstProtoBuf.UnaryOperation.Type.DELETE
|
||||||
|
JsUnaryOperator.INC -> JsAstProtoBuf.UnaryOperation.Type.INC
|
||||||
|
JsUnaryOperator.NEG -> JsAstProtoBuf.UnaryOperation.Type.NEG
|
||||||
|
JsUnaryOperator.POS -> JsAstProtoBuf.UnaryOperation.Type.POS
|
||||||
|
JsUnaryOperator.NOT -> JsAstProtoBuf.UnaryOperation.Type.NOT
|
||||||
|
JsUnaryOperator.TYPEOF -> JsAstProtoBuf.UnaryOperation.Type.TYPEOF
|
||||||
|
JsUnaryOperator.VOID -> JsAstProtoBuf.UnaryOperation.Type.VOID
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(sideEffects: SideEffectKind) = when (sideEffects) {
|
||||||
|
SideEffectKind.AFFECTS_STATE -> JsAstProtoBuf.SideEffects.AFFECTS_STATE
|
||||||
|
SideEffectKind.DEPENDS_ON_STATE -> JsAstProtoBuf.SideEffects.DEPENDS_ON_STATE
|
||||||
|
SideEffectKind.PURE -> JsAstProtoBuf.SideEffects.PURE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun map(specialFunction: SpecialFunction) = when (specialFunction) {
|
||||||
|
SpecialFunction.DEFINE_INLINE_FUNCTION -> JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION
|
||||||
|
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
|
||||||
|
SpecialFunction.TO_BOXED_CHAR -> JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR
|
||||||
|
SpecialFunction.UNBOX_CHAR -> JsAstProtoBuf.SpecialFunction.UNBOX_CHAR
|
||||||
|
SpecialFunction.SUSPEND_CALL -> JsAstProtoBuf.SpecialFunction.SUSPEND_CALL
|
||||||
|
SpecialFunction.COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT
|
||||||
|
SpecialFunction.COROUTINE_CONTROLLER -> JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER
|
||||||
|
SpecialFunction.COROUTINE_RECEIVER -> JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER
|
||||||
|
SpecialFunction.SET_COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT
|
||||||
|
SpecialFunction.GET_KCLASS -> JsAstProtoBuf.SpecialFunction.GET_KCLASS
|
||||||
|
SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
|
||||||
|
val builder = JsAstProtoBuf.Name.newBuilder()
|
||||||
|
builder.identifier = serialize(name.ident)
|
||||||
|
builder.temporary = name.isTemporary
|
||||||
|
name.localAlias?.let {
|
||||||
|
builder.localNameId = serialize(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.imported && name !in importedNames) {
|
||||||
|
builder.imported = true
|
||||||
|
}
|
||||||
|
|
||||||
|
name.specialFunction?.let {
|
||||||
|
builder.specialFunction = map(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = nameTableBuilder.entryCount
|
||||||
|
nameTableBuilder.addEntry(builder)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serialize(alias: LocalAlias): JsAstProtoBuf.LocalAlias {
|
||||||
|
val builder = JsAstProtoBuf.LocalAlias.newBuilder()
|
||||||
|
builder.localNameId = serialize(alias.name)
|
||||||
|
alias.tag?.let {
|
||||||
|
builder.tag = serialize(it)
|
||||||
|
}
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun serialize(string: String) = stringMap.getOrPut(string) {
|
||||||
|
val result = stringTableBuilder.entryCount
|
||||||
|
stringTableBuilder.addEntry(string)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun withLocation(node: JsNode, fileConsumer: (Int) -> Unit, locationConsumer: (JsAstProtoBuf.Location) -> Unit, inner: () -> Unit) {
|
||||||
|
val location = extractLocation(node)
|
||||||
|
var fileChanged = false
|
||||||
|
if (location != null) {
|
||||||
|
val lastFile = fileStack.peek()
|
||||||
|
val newFile = location.file
|
||||||
|
fileChanged = lastFile != newFile
|
||||||
|
if (fileChanged) {
|
||||||
|
fileConsumer(serialize(newFile))
|
||||||
|
fileStack.push(location.file)
|
||||||
|
}
|
||||||
|
val locationBuilder = JsAstProtoBuf.Location.newBuilder()
|
||||||
|
locationBuilder.startLine = location.startLine
|
||||||
|
locationBuilder.startChar = location.startChar
|
||||||
|
locationConsumer(locationBuilder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner()
|
||||||
|
|
||||||
|
if (fileChanged) {
|
||||||
|
fileStack.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun extractLocation(node: JsNode): JsLocation?
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user