diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsFirstExpressionVisitor.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsFirstExpressionVisitor.java index 68a07ea7c49..e28b8ed1e88 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsFirstExpressionVisitor.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsFirstExpressionVisitor.java @@ -35,7 +35,7 @@ public class JsFirstExpressionVisitor extends RecursiveJsVisitor { public static boolean exec(JsExpressionStatement statement) { JsExpression expression = statement.getExpression(); // Pure function declarations do not need parentheses - if (expression instanceof JsFunction) { + if (expression instanceof JsFunction || expression instanceof JsClass) { return false; } diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java index f40ed375b8b..31b2112a950 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java @@ -21,11 +21,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { private static final char[] CHARS_BREAK = "break".toCharArray(); private static final char[] CHARS_CASE = "case".toCharArray(); private static final char[] CHARS_CATCH = "catch".toCharArray(); + private static final char[] CHARS_CLASS = "class".toCharArray(); + private static final char[] CHARS_CONSTRUCTOR = "constructor".toCharArray(); private static final char[] CHARS_CONTINUE = "continue".toCharArray(); private static final char[] CHARS_DEBUGGER = "debugger".toCharArray(); private static final char[] CHARS_DEFAULT = "default".toCharArray(); private static final char[] CHARS_DO = "do".toCharArray(); private static final char[] CHARS_ELSE = "else".toCharArray(); + private static final char[] CHARS_EXTENDS = "extends".toCharArray(); private static final char[] CHARS_FALSE = "false".toCharArray(); private static final char[] CHARS_FINALLY = "finally".toCharArray(); private static final char[] CHARS_FOR = "for".toCharArray(); @@ -609,6 +612,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { p.print(CHARS_FUNCTION); space(); + + printFunction(x); + + popSourceInfo(); + } + + // name() { } + private void printFunction(@NotNull JsFunction x) { if (x.getName() != null) { nameOf(x); } @@ -630,6 +641,50 @@ public class JsToStringGenerationVisitor extends JsVisitor { sourceLocationConsumer.popSourceInfo(); needSemi = true; + } + + @Override + public void visitClass(@NotNull JsClass x) { + pushSourceInfo(x.getSource()); + + p.print(CHARS_CLASS); + space(); + if (x.getName() != null) { + nameOf(x); + } + + if (x.getBaseClass() != null) { + space(); + p.print(CHARS_EXTENDS); + space(); + accept(x.getBaseClass()); + } + + space(); + + if (x.getConstructor() == null && x.getMembers().isEmpty()) { + p.print("{}"); + newline(); + } else { + blockOpen(); + + if (x.getConstructor() != null) { + p.print(CHARS_CONSTRUCTOR); + x.getConstructor().setName(null); + printFunction(x.getConstructor()); + // TODO newLineOpt ? + newline(); + } + + for (JsFunction m : x.getMembers()) { + printFunction(m); + newline(); + } + + blockClose(); + } + + needSemi = false; popSourceInfo(); } diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClass.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClass.kt new file mode 100644 index 00000000000..564978f8032 --- /dev/null +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsClass.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2020 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.js.backend.ast + +import org.jetbrains.kotlin.js.common.Symbol + +class JsClass( + private var name: JsName? = null, + var baseClass: JsNameRef? = null, + var constructor: JsFunction? = null, + val members: MutableList = mutableListOf() +) : JsLiteral(), HasName { + override fun getName(): JsName? { + return name + } + + override fun getSymbol(): Symbol? { + return name + } + + override fun setName(name: JsName?) { + this.name = name + } + + override fun accept(v: JsVisitor) { + v.visitClass(this) + } + + override fun acceptChildren(visitor: JsVisitor) { + visitor.accept(constructor) + } + + override fun traverse(v: JsVisitorWithContext, ctx: JsContext<*>) { + if (v.visit(this, ctx)) { + constructor = v.accept(constructor) + v.acceptList(members) + } + v.endVisit(this, ctx) + } + + override fun deepCopy(): JsClass { + val classCopy = JsClass(name, baseClass, constructor?.deepCopy(), members.mapTo(mutableListOf()) { it.deepCopy() }) + + return classCopy.withMetadataFrom(this) + } +} diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt index 123d3ad12c6..d9a1c022303 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt @@ -51,6 +51,9 @@ abstract class JsVisitor { open fun visitCatch(x: JsCatch): Unit = visitElement(x) + open fun visitClass(x: JsClass): Unit = + visitElement(x) + open fun visitConditional(x: JsConditional): Unit = visitElement(x) diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java index d51aabfce8b..ba922290e38 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java @@ -90,6 +90,10 @@ public abstract class JsVisitorWithContext { public void endVisit(@NotNull JsCatch x, @NotNull JsContext ctx) { } + public void endVisit(@NotNull JsClass x, @NotNull JsContext ctx) { + endVisit((JsExpression) x, ctx); + } + public void endVisit(@NotNull JsConditional x, @NotNull JsContext ctx) { endVisit((JsExpression) x, ctx); } @@ -246,6 +250,10 @@ public abstract class JsVisitorWithContext { return true; } + public boolean visit(@NotNull JsClass x, @NotNull JsContext ctx) { + return true; + } + public boolean visit(@NotNull JsConditional x, @NotNull JsContext ctx) { return true; }