diff --git a/j2k/Makefile b/j2k/Makefile
new file mode 100644
index 00000000000..b906e3b09f6
--- /dev/null
+++ b/j2k/Makefile
@@ -0,0 +1,14 @@
+move-tmp-to-kt:
+ rename -f s/.kt.tmp/.kt/ `find "testData" -name "*.kt.tmp"`
+
+remove-tmp:
+ rm `find "testData" -name "*.kt.tmp"`
+
+disable-sandbox:
+ cd ~/.IdeaIC11/system/ && mv plugins-sandbox plugins-sandbox.tmp
+
+enable-sandbox:
+ cd ~/.IdeaIC11/system/ && rm -rf plugins-sandbox && mv plugins-sandbox.tmp ./plugins-sandbox
+
+release-patch:
+ cp ~/src/jet/.git/patches/master/j2k ~/src/jet-contrib/upstream-patches/
\ No newline at end of file
diff --git a/j2k/j2k.iml b/j2k/j2k.iml
new file mode 100644
index 00000000000..2b7c256c235
--- /dev/null
+++ b/j2k/j2k.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/j2k/j2k.ipr b/j2k/j2k.ipr
new file mode 100644
index 00000000000..f91fa7f6738
--- /dev/null
+++ b/j2k/j2k.ipr
@@ -0,0 +1,646 @@
+
+
+
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/j2k_jar
+
+
+
+
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/java2kotlin_jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ kotlin
+ nullable
+ ushr
+
+
+
+
+
+
+
+
+
+ http://www.w3.org/1999/xhtml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/j2k/lib/commons-cli-1.2.jar b/j2k/lib/commons-cli-1.2.jar
new file mode 100644
index 00000000000..ce4b9fffe40
Binary files /dev/null and b/j2k/lib/commons-cli-1.2.jar differ
diff --git a/j2k/lib/commons-io-2.1.jar b/j2k/lib/commons-io-2.1.jar
new file mode 100644
index 00000000000..b5c7d692fe5
Binary files /dev/null and b/j2k/lib/commons-io-2.1.jar differ
diff --git a/j2k/src/META-INF/MANIFEST.MF b/j2k/src/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..e71f8509eeb
--- /dev/null
+++ b/j2k/src/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: org.jetbrains.jet.j2k.JavaToKotlinCli
+
diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.java b/j2k/src/org/jetbrains/jet/j2k/Converter.java
new file mode 100644
index 00000000000..3d7a86624bb
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/Converter.java
@@ -0,0 +1,754 @@
+package org.jetbrains.jet.j2k;
+
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.j2k.ast.*;
+import org.jetbrains.jet.j2k.ast.Class;
+import org.jetbrains.jet.j2k.ast.Enum;
+import org.jetbrains.jet.j2k.util.AstUtil;
+import org.jetbrains.jet.j2k.visitors.*;
+
+import java.util.*;
+
+import static org.jetbrains.jet.j2k.ConverterUtil.countWritingAccesses;
+import static org.jetbrains.jet.j2k.ConverterUtil.createMainFunction;
+import static org.jetbrains.jet.j2k.visitors.TypeVisitor.*;
+
+/**
+ * @author ignatov
+ */
+public class Converter {
+ @NotNull
+ final static Set NOT_NULL_ANNOTATIONS = new HashSet() {
+ {
+ add("org.jetbrains.annotations.NotNull");
+ add("com.sun.istack.internal.NotNull");
+ add("javax.annotation.Nonnull");
+ }
+ };
+ @NotNull
+ private static Set ourClassIdentifiers = new HashSet();
+ @NotNull
+ private static final Dispatcher ourDispatcher = new Dispatcher();
+ @Nullable
+ private static PsiType ourMethodReturnType = null;
+
+ @NotNull
+ private static Set settings = new HashSet();
+
+ private Converter() {
+ }
+
+ public static boolean addSetting(@NotNull String value) {
+ return settings.add(value);
+ }
+
+ public static boolean hasSetting(@NotNull String value) {
+ return settings.contains(value);
+ }
+
+ public static void setClassIdentifiers(@NotNull Set identifiers) {
+ ourClassIdentifiers = identifiers;
+ }
+
+ @NotNull
+ public static Set getClassIdentifiers() {
+ return new HashSet(ourClassIdentifiers);
+ }
+
+ @Nullable
+ public static PsiType getMethodReturnType() {
+ return ourMethodReturnType;
+ }
+
+ public static void clearClassIdentifiers() {
+ ourClassIdentifiers.clear();
+ }
+
+ @NotNull
+ public static String elementToKotlin(@NotNull PsiElement element) {
+ if (element instanceof PsiJavaFile)
+ return fileToFile((PsiJavaFile) element).toKotlin();
+
+ if (element instanceof PsiClass)
+ return classToClass((PsiClass) element).toKotlin();
+
+ if (element instanceof PsiMethod)
+ return methodToFunction((PsiMethod) element).toKotlin();
+
+ if (element instanceof PsiField) {
+ PsiField field = (PsiField) element;
+ return fieldToField(field, field.getContainingClass()).toKotlin();
+ }
+
+ if (element instanceof PsiStatement)
+ return statementToStatement((PsiStatement) element).toKotlin();
+
+ if (element instanceof PsiExpression)
+ return expressionToExpression((PsiExpression) element).toKotlin();
+
+ return "";
+ }
+
+ @NotNull
+ public static File fileToFile(@NotNull PsiJavaFile javaFile) {
+ return fileToFile(javaFile, Collections.emptyList());
+ }
+
+ @NotNull
+ public static File fileToFileWithCompatibilityImport(@NotNull PsiJavaFile javaFile) {
+ return fileToFile(javaFile, Collections.singletonList("std.compatibility.*"));
+ }
+
+ @NotNull
+ private static File fileToFile(PsiJavaFile javaFile, List additionalImports) {
+ final PsiImportList importList = javaFile.getImportList();
+ List imports = importList == null ? Collections.emptyList() : importsToImportList(importList.getAllImportStatements());
+ for (String i : additionalImports)
+ imports.add(new Import(i));
+ return new File(quoteKeywords(javaFile.getPackageName()), imports, classesToClassList(javaFile.getClasses()), createMainFunction(javaFile));
+ }
+
+ @NotNull
+ private static String quoteKeywords(@NotNull String packageName) {
+ List result = new LinkedList();
+ for (String part : packageName.split("\\."))
+ result.add(new IdentifierImpl(part).toKotlin());
+ return AstUtil.join(result, ".");
+ }
+
+ @NotNull
+ private static List classesToClassList(@NotNull PsiClass[] classes) {
+ List result = new LinkedList();
+ for (PsiClass t : classes) result.add(classToClass(t));
+ return result;
+ }
+
+ @NotNull
+ public static AnonymousClass anonymousClassToAnonymousClass(@NotNull PsiAnonymousClass anonymousClass) {
+ return new AnonymousClass(getMembers(anonymousClass));
+ }
+
+ @NotNull
+ private static List getMembers(@NotNull PsiClass psiClass) {
+ List members = new LinkedList();
+ for (PsiElement e : psiClass.getChildren()) {
+ if (e instanceof PsiMethod) members.add(methodToFunction((PsiMethod) e, true));
+ else if (e instanceof PsiField) members.add(fieldToField((PsiField) e, psiClass));
+ else if (e instanceof PsiClass) members.add(classToClass((PsiClass) e));
+ else if (e instanceof PsiClassInitializer) members.add(initializerToInitializer((PsiClassInitializer) e));
+ else if (e instanceof PsiMember) System.out.println(e.getClass() + " " + e.getText());
+ }
+ return members;
+ }
+
+ @NotNull
+ private static List getFinalOrWithEmptyInitializer(@NotNull List extends Field> fields) {
+ List result = new LinkedList();
+ for (Field f : fields)
+ if (f.isVal() || f.getInitializer().toKotlin().isEmpty())
+ result.add(f);
+ return result;
+ }
+
+ @NotNull
+ private static List createParametersFromFields(@NotNull List extends Field> fields) {
+ List result = new LinkedList();
+ for (Field f : fields)
+ result.add(new Parameter(new IdentifierImpl("_" + f.getIdentifier().getName()), f.getType()));
+ return result;
+ }
+
+ @NotNull
+ private static List createInitStatementsFromFields(@NotNull List extends Field> fields) {
+ List result = new LinkedList();
+ for (Field f : fields) {
+ final String identifierToKotlin = f.getIdentifier().toKotlin();
+ result.add(new DummyStringExpression(identifierToKotlin + " = " + "_" + identifierToKotlin));
+ }
+ return result;
+ }
+
+ @NotNull
+ private static String createPrimaryConstructorInvocation(@NotNull String s, @NotNull List extends Field> fields, @NotNull Map initializers) {
+ List result = new LinkedList();
+ for (Field f : fields) {
+ final String id = f.getIdentifier().toKotlin();
+ result.add(initializers.get(id));
+ }
+ return s + "(" + AstUtil.join(result, ", ") + ")";
+ }
+
+ @NotNull
+ private static Class classToClass(@NotNull PsiClass psiClass) {
+ final Set modifiers = modifiersListToModifiersSet(psiClass.getModifierList());
+ final List fields = fieldsToFieldList(psiClass.getFields(), psiClass);
+ final List typeParameters = elementsToElementList(psiClass.getTypeParameters());
+ final List implementsTypes = typesToNotNullableTypeList(psiClass.getImplementsListTypes());
+ final List extendsTypes = typesToNotNullableTypeList(psiClass.getExtendsListTypes());
+ final IdentifierImpl name = new IdentifierImpl(psiClass.getName());
+ final List baseClassParams = new LinkedList();
+
+ List members = getMembers(psiClass);
+
+ // we try to find super() call and generate class declaration like that: class A(name: String, i : Int) : Base(name)
+ final SuperVisitor visitor = new SuperVisitor();
+ psiClass.accept(visitor);
+ final HashSet resolvedSuperCallParameters = visitor.getResolvedSuperCallParameters();
+ if (resolvedSuperCallParameters.size() == 1)
+ baseClassParams.addAll(
+ expressionsToExpressionList(
+ resolvedSuperCallParameters.toArray(new PsiExpressionList[1])[0].getExpressions()
+ )
+ );
+
+ // we create primary constructor from all non final fields and fields without initializers
+ if (!psiClass.isEnum() && !psiClass.isInterface() && psiClass.getConstructors().length > 1 && getPrimaryConstructorForThisCase(psiClass) == null) {
+ final List finalOrWithEmptyInitializer = getFinalOrWithEmptyInitializer(fields);
+ final Map initializers = new HashMap();
+
+ for (final Member m : members) {
+ // and modify secondaries
+ if (m.getKind() == INode.Kind.CONSTRUCTOR) {
+ Function f = (Function) m;
+ if (!((Constructor) f).isPrimary()) {
+ for (Field fo : finalOrWithEmptyInitializer) {
+ String init = getDefaultInitializer(fo);
+ initializers.put(fo.getIdentifier().toKotlin(), init);
+ }
+
+ final List newStatements = new LinkedList();
+
+ for (Statement s : f.getBlock().getStatements()) {
+ boolean isRemoved = false;
+
+ if (s.getKind() == INode.Kind.ASSIGNMENT_EXPRESSION) {
+ final AssignmentExpression assignmentExpression = (AssignmentExpression) s;
+ if (assignmentExpression.getLeft().getKind() == INode.Kind.CALL_CHAIN) {
+ for (Field fo : finalOrWithEmptyInitializer) {
+ final String id = fo.getIdentifier().toKotlin();
+ if (((CallChainExpression) assignmentExpression.getLeft()).getIdentifier().toKotlin().endsWith("." + id)) {
+ initializers.put(id, assignmentExpression.getRight().toKotlin());
+ isRemoved = true;
+ }
+ }
+ }
+ }
+ if (!isRemoved) {
+ newStatements.add(s);
+ }
+ }
+
+ newStatements.add(
+ 0,
+ new DummyStringExpression(
+ "val __ = " + createPrimaryConstructorInvocation(
+ name.toKotlin(),
+ finalOrWithEmptyInitializer,
+ initializers)));
+
+ f.setBlock(new Block(newStatements));
+ }
+ }
+ }
+
+ members.add(
+ new Constructor(
+ Identifier.EMPTY_IDENTIFIER,
+ Collections.emptySet(),
+ new ClassType(name),
+ Collections.emptyList(),
+ new ParameterList(createParametersFromFields(finalOrWithEmptyInitializer)),
+ new Block(createInitStatementsFromFields(finalOrWithEmptyInitializer)),
+ true
+ )
+ );
+ }
+
+ if (psiClass.isInterface())
+ return new Trait(name, modifiers, typeParameters, extendsTypes, Collections.emptyList(), implementsTypes, members);
+ if (psiClass.isEnum())
+ return new Enum(name, modifiers, typeParameters, Collections.emptyList(), Collections.emptyList(), implementsTypes, members);
+ return new Class(name, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, members);
+ }
+
+ @NotNull
+ private static Initializer initializerToInitializer(@NotNull PsiClassInitializer i) {
+ return new Initializer(
+ blockToBlock(i.getBody(), true),
+ modifiersListToModifiersSet(i.getModifierList())
+ );
+ }
+
+ @NotNull
+ public static String getDefaultInitializer(@NotNull Field f) {
+ if (f.getType().isNullable())
+ return "null";
+ else {
+ final String typeToKotlin = f.getType().toKotlin();
+ if (typeToKotlin.equals("Boolean")) return "false";
+ if (typeToKotlin.equals("Char")) return "' '";
+ if (typeToKotlin.equals("Double")) return "0.dbl";
+ if (typeToKotlin.equals("Float")) return "0.flt";
+ return "0";
+ }
+ }
+
+ @NotNull
+ private static List fieldsToFieldList(@NotNull PsiField[] fields, PsiClass psiClass) {
+ List result = new LinkedList();
+ for (PsiField f : fields) result.add(fieldToField(f, psiClass));
+ return result;
+ }
+
+ @NotNull
+ private static Field fieldToField(@NotNull PsiField field, PsiClass psiClass) {
+ Set modifiers = modifiersListToModifiersSet(field.getModifierList());
+ if (field instanceof PsiEnumConstant) // TODO: remove instanceof
+ return new EnumConstant(
+ new IdentifierImpl(field.getName()), // TODO
+ modifiers,
+ typeToType(field.getType()),
+ elementToElement(((PsiEnumConstant) field).getArgumentList())
+ );
+ return new Field(
+ new IdentifierImpl(field.getName()), // TODO
+ modifiers,
+ typeToType(field.getType()),
+ createSureCallOnlyForChain(field.getInitializer(), field.getType()), // TODO: add modifiers
+ countWritingAccesses(field, psiClass)
+ );
+ }
+
+ @Nullable
+ private static PsiMethod getPrimaryConstructorForThisCase(@NotNull PsiClass psiClass) {
+ ThisVisitor tv = new ThisVisitor();
+ psiClass.accept(tv);
+ return tv.getPrimaryConstructor();
+ }
+
+ public static boolean isConstructorPrimary(@NotNull PsiMethod constructor) {
+ if (constructor.getParent() instanceof PsiClass) {
+ final PsiClass parent = (PsiClass) constructor.getParent();
+ if (parent.getConstructors().length == 1)
+ return true;
+ else {
+ PsiMethod c = getPrimaryConstructorForThisCase(parent); // TODO: move up to classToClass() method
+ if (c != null && c.hashCode() == constructor.hashCode())
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @NotNull
+ private static List removeEmpty(@NotNull List statements) {
+ List result = new LinkedList();
+ for (Statement s : statements)
+ if (s != Statement.EMPTY_STATEMENT && s != Expression.EMPTY_EXPRESSION)
+ result.add(s);
+ return result;
+ }
+
+ @NotNull
+ private static Function methodToFunction(@NotNull PsiMethod method) {
+ return methodToFunction(method, true);
+ }
+
+ @NotNull
+ private static Function methodToFunction(@NotNull PsiMethod method, boolean notEmpty) {
+ if (isOverrideObjectDirect(method))
+ ourDispatcher.setExpressionVisitor(new ExpressionVisitorForDirectObjectInheritors());
+ else
+ ourDispatcher.setExpressionVisitor(new ExpressionVisitor());
+
+ ourMethodReturnType = method.getReturnType();
+
+ final IdentifierImpl identifier = new IdentifierImpl(method.getName());
+ final Type returnType = typeToType(method.getReturnType(), ConverterUtil.isAnnotatedAsNotNull(method.getModifierList()));
+ final Block body = hasSetting("declarations-only") ? Block.EMPTY_BLOCK : blockToBlock(method.getBody(), notEmpty); // #TODO
+ final Element params = createFunctionParameters(method);
+ final List typeParameters = elementsToElementList(method.getTypeParameters());
+
+ final Set modifiers = modifiersListToModifiersSet(method.getModifierList());
+ if (isOverrideAnyMethodExceptMethodsFromObject(method))
+ modifiers.add(Modifier.OVERRIDE);
+ if (method.getParent() instanceof PsiClass && ((PsiClass) method.getParent()).isInterface())
+ modifiers.remove(Modifier.ABSTRACT);
+ if (isNotOpenMethod(method))
+ modifiers.add(Modifier.NOT_OPEN);
+
+ if (method.isConstructor()) { // TODO: simplify
+ boolean isPrimary = isConstructorPrimary(method);
+ return new Constructor(
+ identifier,
+ modifiers,
+ returnType,
+ typeParameters,
+ params,
+ new Block(removeEmpty(body.getStatements()), false),
+ isPrimary
+ );
+ }
+ return new Function(
+ identifier,
+ modifiers,
+ returnType,
+ typeParameters,
+ params,
+ body
+ );
+ }
+
+ @NotNull
+ private static ParameterList createFunctionParameters(@NotNull PsiMethod method) {
+ List result = new LinkedList();
+ for (PsiParameter parameter : method.getParameterList().getParameters()) {
+ result.add(new Parameter(
+ new IdentifierImpl(parameter.getName()),
+ typeToType(parameter.getType(), ConverterUtil.isAnnotatedAsNotNull(parameter.getModifierList())),
+ ConverterUtil.isReadOnly(parameter, method.getBody())
+ ));
+ }
+ return new ParameterList(result);
+ }
+
+ private static boolean isNotOpenMethod(@NotNull final PsiMethod method) {
+ if (method.getParent() instanceof PsiClass) {
+ final PsiModifierList parentModifierList = ((PsiClass) method.getParent()).getModifierList();
+ if ((parentModifierList != null && parentModifierList.hasExplicitModifier(Modifier.FINAL)) || ((PsiClass) method.getParent()).isEnum())
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isOverrideAnyMethodExceptMethodsFromObject(@NotNull PsiMethod method) {
+ boolean counter = normalCase(method);
+ if (counter)
+ return true;
+ if (isInheritFromObject(method))
+ return caseForObject(method);
+ return false;
+ }
+
+ private static boolean caseForObject(@NotNull PsiMethod method) {
+ PsiClass containing = method.getContainingClass();
+ if (containing != null) {
+ for (PsiClassType s : containing.getSuperTypes()) {
+ String canonicalText = s.getCanonicalText();
+ if (!canonicalText.equals(JAVA_LANG_OBJECT) && !getClassIdentifiers().contains(canonicalText)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean normalCase(@NotNull PsiMethod method) {
+ int counter = 0;
+ for (HierarchicalMethodSignature s : method.getHierarchicalMethodSignature().getSuperSignatures()) {
+ PsiClass containingClass = s.getMethod().getContainingClass();
+ String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
+ if (qualifiedName != null && !qualifiedName.equals(JAVA_LANG_OBJECT))
+ counter++;
+ }
+ return counter > 0;
+ }
+
+ private static boolean isInheritFromObject(@NotNull PsiMethod method) {
+ List superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures();
+ for (HierarchicalMethodSignature s : superSignatures) {
+ PsiClass containingClass = s.getMethod().getContainingClass();
+ String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
+ if (qualifiedName != null && qualifiedName.equals(JAVA_LANG_OBJECT))
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isOverrideObjectDirect(@NotNull final PsiMethod method) {
+ List superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures();
+ if (superSignatures.size() == 1) {
+ final PsiClass containingClass = superSignatures.get(0).getMethod().getContainingClass();
+ final String qualifiedName = containingClass != null ? containingClass.getQualifiedName() : "";
+ if (qualifiedName != null && qualifiedName.equals(JAVA_LANG_OBJECT))
+ return true;
+ }
+ return false;
+ }
+
+ @NotNull
+ public static Block blockToBlock(@Nullable PsiCodeBlock block, boolean notEmpty) {
+ if (block == null) return Block.EMPTY_BLOCK;
+ return new Block(statementsToStatementList(block.getStatements()), notEmpty);
+ }
+
+ @NotNull
+ public static Block blockToBlock(@Nullable PsiCodeBlock block) {
+ return blockToBlock(block, true);
+ }
+
+ @NotNull
+ public static List statementsToStatementList(@NotNull PsiStatement[] statements) {
+ List result = new LinkedList();
+ for (PsiStatement t : statements) result.add(statementToStatement(t));
+ return result;
+ }
+
+ @NotNull
+ public static List statementsToStatementList(@NotNull List statements) {
+ List result = new LinkedList();
+ for (PsiStatement t : statements) result.add(statementToStatement(t));
+ return result;
+ }
+
+ @NotNull
+ public static Statement statementToStatement(@Nullable PsiStatement s) {
+ if (s == null) return Statement.EMPTY_STATEMENT;
+ final StatementVisitor statementVisitor = new StatementVisitor();
+ s.accept(statementVisitor);
+ return statementVisitor.getResult();
+ }
+
+ @NotNull
+ public static List expressionsToExpressionList(@NotNull PsiExpression[] expressions) {
+ List result = new LinkedList();
+ for (PsiExpression e : expressions) result.add(expressionToExpression(e));
+ return result;
+ }
+
+ @NotNull
+ public static Expression expressionToExpression(@Nullable PsiExpression e) {
+ if (e == null) return Expression.EMPTY_EXPRESSION;
+ final ExpressionVisitor expressionVisitor = ourDispatcher.getExpressionVisitor();
+ e.accept(expressionVisitor);
+ return expressionVisitor.getResult();
+ }
+
+ @NotNull
+ public static Element elementToElement(@Nullable PsiElement e) {
+ if (e == null) return Element.EMPTY_ELEMENT;
+ final ElementVisitor elementVisitor = new ElementVisitor();
+ e.accept(elementVisitor);
+ return elementVisitor.getResult();
+ }
+
+ @NotNull
+ public static List elementsToElementList(@NotNull PsiElement[] elements) {
+ List result = new LinkedList();
+ for (PsiElement e : elements) result.add(elementToElement(e));
+ return result;
+ }
+
+ @NotNull
+ public static Type typeToType(@Nullable PsiType type) {
+ if (type == null) return Type.EMPTY_TYPE;
+ TypeVisitor typeVisitor = new TypeVisitor();
+ type.accept(typeVisitor);
+ return typeVisitor.getResult();
+ }
+
+ @NotNull
+ public static List typesToTypeList(@NotNull PsiType[] types) {
+ List result = new LinkedList();
+ for (PsiType t : types) result.add(typeToType(t));
+ return result;
+ }
+
+ @NotNull
+ public static Type typeToType(PsiType type, boolean notNull) {
+ Type result = typeToType(type);
+ if (notNull)
+ result.convertedToNotNull();
+ return result;
+ }
+
+ @NotNull
+ private static List typesToNotNullableTypeList(@NotNull PsiType[] types) {
+ List result = new LinkedList(typesToTypeList(types));
+ for (Type p : result) p.convertedToNotNull();
+ return result;
+ }
+
+ @NotNull
+ private static List importsToImportList(@NotNull PsiImportStatementBase[] imports) {
+ List result = new LinkedList();
+ for (PsiImportStatementBase i : imports) {
+ Import anImport = importToImport(i);
+ String name = anImport.getName();
+ if (!name.isEmpty() && !NOT_NULL_ANNOTATIONS.contains(name))
+ result.add(anImport);
+ }
+ return result;
+ }
+
+ @NotNull
+ private static Import importToImport(@NotNull PsiImportStatementBase i) {
+ final PsiJavaCodeReferenceElement reference = i.getImportReference();
+ if (reference != null)
+ return new Import(quoteKeywords(reference.getQualifiedName()) + (i.isOnDemand() ? ".*" : ""));
+ return new Import("");
+ }
+
+ @NotNull
+ public static List parametersToParameterList(@NotNull PsiParameter[] parameters) {
+ List result = new LinkedList();
+ for (PsiParameter t : parameters) result.add(parameterToParameter(t));
+ return result;
+ }
+
+ @NotNull
+ public static Parameter parameterToParameter(@NotNull PsiParameter parameter) {
+ return new Parameter(
+ new IdentifierImpl(parameter.getName()),
+ typeToType(parameter.getType(), ConverterUtil.isAnnotatedAsNotNull(parameter.getModifierList()))
+ );
+ }
+
+ @NotNull
+ public static Identifier identifierToIdentifier(@Nullable PsiIdentifier identifier) {
+ if (identifier == null) return Identifier.EMPTY_IDENTIFIER;
+ return new IdentifierImpl(identifier.getText());
+ }
+
+ @NotNull
+ public static Set modifiersListToModifiersSet(@Nullable PsiModifierList modifierList) {
+ HashSet modifiersSet = new HashSet();
+ if (modifierList != null) {
+ if (modifierList.hasExplicitModifier(PsiModifier.ABSTRACT)) modifiersSet.add(Modifier.ABSTRACT);
+ if (modifierList.hasModifierProperty(PsiModifier.FINAL)) modifiersSet.add(Modifier.FINAL);
+ if (modifierList.hasModifierProperty(PsiModifier.STATIC)) modifiersSet.add(Modifier.STATIC);
+ if (modifierList.hasExplicitModifier(PsiModifier.PUBLIC)) modifiersSet.add(Modifier.PUBLIC);
+ if (modifierList.hasExplicitModifier(PsiModifier.PROTECTED)) modifiersSet.add(Modifier.PROTECTED);
+ if (modifierList.hasExplicitModifier(PsiModifier.PACKAGE_LOCAL)) modifiersSet.add(Modifier.INTERNAL);
+ if (modifierList.hasExplicitModifier(PsiModifier.PRIVATE)) modifiersSet.add(Modifier.PRIVATE);
+ }
+ return modifiersSet;
+ }
+
+ @NotNull
+ public static List createConversions(@NotNull PsiCallExpression expression) {
+ PsiExpressionList argumentList = expression.getArgumentList();
+ PsiExpression[] arguments = argumentList != null ? argumentList.getExpressions() : new PsiExpression[]{};
+ List conversions = new LinkedList();
+ //noinspection UnusedDeclaration
+ for (final PsiExpression a : arguments) {
+ conversions.add("");
+ }
+
+ PsiMethod resolve = expression.resolveMethod();
+ if (resolve != null) {
+ List expectedTypes = new LinkedList();
+ List actualTypes = new LinkedList();
+
+ for (PsiParameter p : resolve.getParameterList().getParameters())
+ expectedTypes.add(p.getType());
+
+ for (PsiExpression e : arguments)
+ actualTypes.add(e.getType());
+
+ if (conversions.size() == actualTypes.size() && actualTypes.size() == expectedTypes.size()) {
+ for (int i = 0; i < actualTypes.size(); i++)
+ conversions.set(i, createConversionForExpression(arguments[i], expectedTypes.get(i)));
+ }
+ }
+ return conversions;
+ }
+
+ @NotNull
+ public static List createConversions(@NotNull PsiPolyadicExpression expression, PsiType expectedType) {
+ PsiExpression[] arguments = expression.getOperands();
+ int length = arguments.length;
+ List conversions = new LinkedList();
+
+ List expectedTypes = Collections.nCopies(length, expectedType);
+ List actualTypes = new LinkedList();
+
+ for (PsiExpression e : arguments)
+ actualTypes.add(e.getType());
+
+ assert actualTypes.size() == expectedTypes.size() : "The type list must have the same length";
+
+ for (int i = 0; i < actualTypes.size(); i++)
+ conversions.add(i, createConversionForExpression(arguments[i], expectedTypes.get(i)));
+
+ return conversions;
+ }
+
+ @NotNull
+ private static String createConversionForExpression(@Nullable PsiExpression expression, @NotNull PsiType expectedType) {
+ String conversion = "";
+ if (expression != null) {
+ PsiType actualType = expression.getType();
+ boolean isPrimitiveTypeOrNull = actualType == null || Node.PRIMITIVE_TYPES.contains(actualType.getCanonicalText());
+ boolean isRef = (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression) expression).isQualified() || expression instanceof PsiMethodCallExpression);
+ boolean containsQuestDot = expressionToExpression(expression).toKotlin().contains("?.");
+
+ if (isPrimitiveTypeOrNull && isRef && containsQuestDot)
+ conversion += ".sure()";
+
+ if (actualType != null)
+ if (isConversionNeeded(actualType, expectedType))
+ conversion += getPrimitiveTypeConversion(expectedType.getCanonicalText());
+ }
+ return conversion;
+ }
+
+ private static boolean isConversionNeeded(@Nullable final PsiType actual, @Nullable final PsiType expected) {
+ if (actual == null || expected == null)
+ return false;
+ Map typeMap = new HashMap();
+ typeMap.put(JAVA_LANG_BYTE, "byte");
+ typeMap.put(JAVA_LANG_SHORT, "short");
+ typeMap.put(JAVA_LANG_INTEGER, "int");
+ typeMap.put(JAVA_LANG_LONG, "long");
+ typeMap.put(JAVA_LANG_FLOAT, "float");
+ typeMap.put(JAVA_LANG_DOUBLE, "double");
+ typeMap.put(JAVA_LANG_CHARACTER, "char");
+ String expectedStr = expected.getCanonicalText();
+ String actualStr = actual.getCanonicalText();
+ boolean o1 = AstUtil.getOrElse(typeMap, actualStr, "").equals(expectedStr);
+ boolean o2 = AstUtil.getOrElse(typeMap, expectedStr, "").equals(actualStr);
+ return !actualStr.equals(expectedStr) && (!(o1 ^ o2));
+ }
+
+ @NotNull
+ private static String getPrimitiveTypeConversion(@NotNull String type) {
+ Map conversions = new HashMap();
+ conversions.put("byte", "byt");
+ conversions.put("short", "sht");
+ conversions.put("int", "int");
+ conversions.put("long", "lng");
+ conversions.put("float", "flt");
+ conversions.put("double", "dbl");
+ conversions.put("char", "chr");
+
+ conversions.put(JAVA_LANG_BYTE, "byt");
+ conversions.put(JAVA_LANG_SHORT, "sht");
+ conversions.put(JAVA_LANG_INTEGER, "int");
+ conversions.put(JAVA_LANG_LONG, "lng");
+ conversions.put(JAVA_LANG_FLOAT, "flt");
+ conversions.put(JAVA_LANG_DOUBLE, "dbl");
+ conversions.put(JAVA_LANG_CHARACTER, "chr");
+
+ if (conversions.containsKey(type))
+ return "." + conversions.get(type);
+ return "";
+ }
+
+// @NotNull
+// private static String applyConversion(Expression expression, String conversion) {
+// if (conversion.isEmpty())
+// return expression.toKotlin();
+// return "(" + expression.toKotlin() + ")" + conversion;
+// }
+
+ @NotNull
+ public static SureCallChainExpression createSureCallOnlyForChain(@Nullable PsiExpression expression, @NotNull PsiType type) {
+ String conversion = (expression != null && (expression instanceof PsiReferenceExpression || expression instanceof PsiMethodCallExpression)) ?
+ createConversionForExpression(expression, type) : "";
+ return new SureCallChainExpression(expressionToExpression(expression), conversion);
+ }
+
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ConverterUtil.java b/j2k/src/org/jetbrains/jet/j2k/ConverterUtil.java
new file mode 100644
index 00000000000..a979ff61be1
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ConverterUtil.java
@@ -0,0 +1,116 @@
+package org.jetbrains.jet.j2k;
+
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.text.MessageFormat;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.jetbrains.jet.j2k.Converter.NOT_NULL_ANNOTATIONS;
+
+/**
+ * @author ignatov
+ */
+public class ConverterUtil {
+ private ConverterUtil() {
+ }
+
+ @NotNull
+ public static String createMainFunction(@NotNull PsiFile file) {
+ List> classNamesWithMains = new LinkedList>();
+
+ for (PsiClass c : ((PsiJavaFile) file).getClasses()) {
+ PsiMethod main = findMainMethod(c);
+ if (main != null) {
+ classNamesWithMains.add(new Pair(c.getName(), main));
+ }
+ }
+ if (classNamesWithMains.size() > 0) {
+ String className = classNamesWithMains.get(0).getFirst();
+ return MessageFormat.format("fun main(args : Array?) = {0}.main(args)", className);
+ }
+ return "";
+ }
+
+ @Nullable
+ private static PsiMethod findMainMethod(@NotNull PsiClass aClass) {
+ if (isMainClass(aClass)) {
+ final PsiMethod[] mainMethods = aClass.findMethodsByName("main", false);
+ return findMainMethod(mainMethods);
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PsiMethod findMainMethod(@NotNull PsiMethod[] mainMethods) {
+ for (PsiMethod mainMethod : mainMethods) {
+ if (isMainMethod(mainMethod)) return mainMethod;
+ }
+ return null;
+ }
+
+ private static boolean isMainClass(@NotNull PsiClass psiClass) {
+ if (psiClass instanceof PsiAnonymousClass) return false;
+ if (psiClass.isInterface()) return false;
+ return psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC);
+ }
+
+ public static boolean isMainMethod(@Nullable PsiMethod method) {
+ if (method == null || method.getContainingClass() == null) return false;
+ if (PsiType.VOID != method.getReturnType()) return false;
+ if (!method.hasModifierProperty(PsiModifier.STATIC)) return false;
+ if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false;
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ if (parameters.length != 1) return false;
+ final PsiType type = parameters[0].getType();
+ if (!(type instanceof PsiArrayType)) return false;
+ final PsiType componentType = ((PsiArrayType) type).getComponentType();
+ return componentType.equalsToText("java.lang.String");
+ }
+
+ public static int countWritingAccesses(@Nullable PsiElement element, @Nullable PsiElement container) {
+ int counter = 0;
+ if (container != null) {
+ ReferenceCollector visitor = new ReferenceCollector();
+ container.accept(visitor);
+ for (PsiReferenceExpression e : visitor.getCollectedReferences())
+ if (e.isReferenceTo(element) && PsiUtil.isAccessedForWriting(e))
+ counter++;
+ }
+ return counter;
+ }
+
+ static boolean isReadOnly(PsiElement element, PsiElement container) {
+ return countWritingAccesses(element, container) == 0;
+ }
+
+ public static boolean isAnnotatedAsNotNull(@Nullable PsiModifierList modifierList) {
+ if (modifierList != null) {
+ PsiAnnotation[] annotations = modifierList.getAnnotations();
+ for (PsiAnnotation a : annotations) {
+ String qualifiedName = a.getQualifiedName();
+ if (qualifiedName != null && NOT_NULL_ANNOTATIONS.contains(qualifiedName))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static class ReferenceCollector extends JavaRecursiveElementVisitor {
+ public List getCollectedReferences() {
+ return myCollectedReferences;
+ }
+
+ private List myCollectedReferences = new LinkedList();
+
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ super.visitReferenceExpression(expression);
+ myCollectedReferences.add(expression);
+ }
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinCli.java b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinCli.java
new file mode 100644
index 00000000000..1f322e030ee
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinCli.java
@@ -0,0 +1,147 @@
+package org.jetbrains.jet.j2k;
+
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import org.apache.commons.cli.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.commons.io.FileUtils.writeStringToFile;
+
+/**
+ * @author ignatov
+ */
+@SuppressWarnings({"CallToPrintStackTrace", "UseOfSystemOutOrSystemErr"})
+public class JavaToKotlinCli {
+ private static final Logger myLogger = Logger.getAnonymousLogger();
+
+ private JavaToKotlinCli() {
+ }
+
+ public static void main(String[] args) {
+ CommandLineParser parser = new BasicParser();
+ Options options = new Options()
+ .addOption("h", "help", false, "Print usage information")
+ .addOption("f", "from", true, "Directory with Java sources")
+ .addOption("t", "to", true, "Directory with Kotlin sources")
+ .addOption("p", "public-only", false, "Only public and protected members")
+ .addOption("fqn", "fqn", false, "Full qualified names")
+ .addOption("d", "declarations-only", false, "Declarations only")
+ ;
+
+ try {
+ CommandLine commandLine = parser.parse(options, args);
+
+ if (commandLine.hasOption("help"))
+ showHelpAndExit();
+
+ if (commandLine.hasOption("from") && commandLine.hasOption("to")) {
+ String from = commandLine.getOptionValue("from");
+ String to = commandLine.getOptionValue("to");
+
+ for (Option o : commandLine.getOptions()) {
+ Converter.addSetting(o.getLongOpt());
+ }
+
+ if (!from.isEmpty() && !to.isEmpty())
+ convertSourceTree(from, to);
+ else
+ showHelpAndExit();
+ } else
+ showHelpAndExit();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ private static void convertSourceTree(String javaPath, String kotlinPath) {
+ try {
+ File javaDir = new File(javaPath);
+ File kotlinDir = new File(kotlinPath);
+
+ if (kotlinDir.exists())
+ kotlinDir.delete();
+
+ if (!kotlinDir.exists() && !kotlinDir.mkdir())
+ myLogger.warning("Creation failed: " + kotlinDir.getAbsolutePath());
+
+ for (File f : getJavaFiles(javaDir.getAbsolutePath())) {
+ String relative = javaDir.toURI().relativize(f.toURI()).getPath().replace(".java", ".kt");
+ File file = new File(kotlinPath, relative);
+
+ if (file.exists())
+ file.delete();
+
+ if (f.isDirectory())
+ if (!file.exists() && !file.mkdir())
+ myLogger.warning("Creation failed: " + file.getAbsolutePath());
+
+ if (f.isFile()) {
+ writeStringToFile(file, fileToKotlin(f));
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @NotNull
+ private static String fileToKotlin(File f) throws IOException {
+ final String javaCode = readJavaFileToString(f);
+ return generateKotlinCode(JavaToKotlinTranslator.createFile(JavaToKotlinTranslator.setUpJavaCoreEnvironment(), javaCode));
+ }
+
+ @NotNull
+ private static String generateKotlinCode(@Nullable PsiFile file) {
+ if (file != null && file instanceof PsiJavaFile) {
+ JavaToKotlinTranslator.setClassIdentifiers(file);
+ return JavaToKotlinTranslator.prettify(Converter.fileToFile((PsiJavaFile) file).toKotlin());
+ }
+ return "";
+ }
+
+ @NotNull
+ private static String readJavaFileToString(@NotNull File javaFile) throws IOException {
+ return Pattern.compile("\\s*/\\*.*\\*/", Pattern.DOTALL).matcher(readFileToString(javaFile)).replaceAll("");
+ }
+
+ private static void showHelpAndExit() {
+ System.err.println("Usage: java -jar java2kotlin.jar -f -t ");
+ System.exit(1);
+ }
+
+ static public List getJavaFiles(String startDirName) throws FileNotFoundException {
+ return getJavaFiles(new File(startDirName));
+ }
+
+ private static List getJavaFiles(File start) throws FileNotFoundException {
+ List result = new ArrayList();
+
+ if (start.isFile())
+ return Arrays.asList(start);
+
+ for (File file : Arrays.asList(start.listFiles())) {
+ if ((file.isFile() && file.getName().endsWith(".java")) || file.isDirectory())
+ result.add(file);
+
+ if (file.isDirectory()) {
+ List deeperList = getJavaFiles(file);
+ result.addAll(deeperList);
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.java b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.java
new file mode 100644
index 00000000000..f87a8952a6e
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.jet.j2k;
+
+import com.intellij.core.JavaCoreEnvironment;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.util.Function;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.j2k.visitors.ClassVisitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * @author ignatov
+ */
+public class JavaToKotlinTranslator {
+ private JavaToKotlinTranslator() {
+ }
+
+ @Nullable
+ private static PsiFile createFile(@NotNull String text) {
+ JavaCoreEnvironment javaCoreEnvironment = setUpJavaCoreEnvironment();
+ return PsiFileFactory.getInstance(javaCoreEnvironment.getProject()).createFileFromText(
+ "test.java", JavaLanguage.INSTANCE, text
+ );
+ }
+
+ @Nullable
+ static PsiFile createFile(@NotNull JavaCoreEnvironment javaCoreEnvironment, @NotNull String text) {
+ return PsiFileFactory.getInstance(javaCoreEnvironment.getProject()).createFileFromText(
+ "test.java", JavaLanguage.INSTANCE, text
+ );
+ }
+
+ @NotNull
+ static JavaCoreEnvironment setUpJavaCoreEnvironment() {
+ JavaCoreEnvironment javaCoreEnvironment = new JavaCoreEnvironment(new Disposable() {
+ @Override
+ public void dispose() {
+ }
+ });
+
+ javaCoreEnvironment.addToClasspath(findRtJar());
+ File annotations = findAnnotations();
+ if (annotations != null && annotations.exists()) {
+ javaCoreEnvironment.addToClasspath(annotations);
+ }
+ return javaCoreEnvironment;
+ }
+
+ @NotNull
+ static String prettify(@Nullable String code) {
+ if (code == null)
+ return "";
+ return code
+ .trim()
+ .replaceAll("\r\n", "\n")
+ .replaceAll(" \n", "\n")
+ .replaceAll("\n ", "\n")
+ .replaceAll("\n+", "\n")
+ .replaceAll(" +", " ")
+ .trim()
+ ;
+ }
+
+ @Nullable
+ private static File findRtJar() {
+ String javaHome = System.getenv("JAVA_HOME");
+ File rtJar;
+ if (javaHome == null) {
+ rtJar = findActiveRtJar(true);
+
+ if (rtJar == null) {
+ throw new SetupJavaCoreEnvironmentException("JAVA_HOME environment variable needs to be defined");
+ }
+ } else {
+ rtJar = findRtJar(javaHome);
+ }
+
+ if (rtJar == null || !rtJar.exists()) {
+ rtJar = findActiveRtJar(true);
+
+ if ((rtJar == null || !rtJar.exists())) {
+ throw new SetupJavaCoreEnvironmentException("No rt.jar found under JAVA_HOME=" + javaHome);
+ }
+ }
+ return rtJar;
+ }
+
+ @Nullable
+ private static File findRtJar(String javaHome) {
+ File rtJar = new File(javaHome, "jre/lib/rt.jar");
+ if (rtJar.exists()) {
+ return rtJar;
+ }
+
+ File classesJar = new File(new File(javaHome).getParentFile().getAbsolutePath(), "Classes/classes.jar");
+ if (classesJar.exists()) {
+ return classesJar;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static File findAnnotations() {
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+ if (systemClassLoader instanceof URLClassLoader) {
+ URLClassLoader loader = (URLClassLoader) systemClassLoader;
+ for (URL url : loader.getURLs())
+ if ("file".equals(url.getProtocol()) && url.getFile().endsWith("/annotations.jar"))
+ return new File(url.getFile());
+ }
+ return null;
+ }
+
+ @Nullable
+ private static File findActiveRtJar(boolean failOnError) {
+ ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+ if (systemClassLoader instanceof URLClassLoader) {
+ URLClassLoader loader = (URLClassLoader) systemClassLoader;
+ for (URL url : loader.getURLs()) {
+ if ("file".equals(url.getProtocol())) {
+ if (url.getFile().endsWith("/lib/rt.jar")) {
+ return new File(url.getFile());
+ }
+ if (url.getFile().endsWith("/Classes/classes.jar")) {
+ return new File(url.getFile()).getAbsoluteFile();
+ }
+ }
+ }
+ if (failOnError) {
+ throw new SetupJavaCoreEnvironmentException("Could not find rt.jar in system class loader: " + StringUtil.join(loader.getURLs(), new Function() {
+ @NotNull
+ @Override
+ public String fun(@NotNull URL url) {
+ return url.toString() + "\n";
+ }
+ }, ", "));
+ }
+ } else if (failOnError) {
+ throw new SetupJavaCoreEnvironmentException("System class loader is not an URLClassLoader: " + systemClassLoader);
+ }
+ return null;
+ }
+
+ static void setClassIdentifiers(@NotNull PsiElement psiFile) {
+ ClassVisitor c = new ClassVisitor();
+ psiFile.accept(c);
+ Converter.clearClassIdentifiers();
+ Converter.setClassIdentifiers(c.getClassIdentifiers());
+ }
+
+ @NotNull
+ static String generateKotlinCode(@NotNull String javaCode) {
+ PsiFile file = createFile(javaCode);
+ if (file != null && file instanceof PsiJavaFile) {
+ setClassIdentifiers(file);
+ return prettify(Converter.fileToFile((PsiJavaFile) file).toKotlin());
+ }
+ return "";
+ }
+
+ @NotNull
+ static String generateKotlinCodeWithCompatibilityImport(@NotNull String javaCode) {
+ PsiFile file = createFile(javaCode);
+ if (file != null && file instanceof PsiJavaFile) {
+ setClassIdentifiers(file);
+ return prettify(Converter.fileToFileWithCompatibilityImport((PsiJavaFile) file).toKotlin());
+ }
+ return "";
+ }
+
+ public static void main(@NotNull String[] args) throws IOException {
+ //noinspection UseOfSystemOutOrSystemErr
+ final PrintStream out = System.out;
+ if (args.length == 1) {
+ String kotlinCode = "";
+ try {
+ kotlinCode = generateKotlinCode(args[0]);
+ } catch (Exception e) {
+ out.println("EXCEPTION: " + e.getMessage());
+ }
+ if (kotlinCode.isEmpty())
+ out.println("EXCEPTION: generated code is empty.");
+ else
+ out.println(kotlinCode);
+ } else {
+ out.println("EXCEPTION: wrong number of arguments (should be 1).");
+ }
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/SetupJavaCoreEnvironmentException.java b/j2k/src/org/jetbrains/jet/j2k/SetupJavaCoreEnvironmentException.java
new file mode 100644
index 00000000000..bbe7e064ac8
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/SetupJavaCoreEnvironmentException.java
@@ -0,0 +1,9 @@
+package org.jetbrains.jet.j2k;
+
+/**
+ * @author ignatov
+ */
+public class SetupJavaCoreEnvironmentException extends RuntimeException {
+ public SetupJavaCoreEnvironmentException(String s) {
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.java b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.java
new file mode 100644
index 00000000000..c5524a0bb91
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.java
@@ -0,0 +1,28 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class AnonymousClass extends Class {
+ public AnonymousClass(List members) {
+ super(new IdentifierImpl("anonClass"),
+ Collections.emptySet(),
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Collections.emptyList(),
+ Collections.emptyList(),
+ getMembers(members)
+ );
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return bodyToKotlin();
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayAccessExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayAccessExpression.java
new file mode 100644
index 00000000000..4a511b713b9
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayAccessExpression.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ArrayAccessExpression extends Expression {
+ private final Expression myExpression;
+ private final Expression myIndex;
+
+ public ArrayAccessExpression(Expression expression, Expression index) {
+ myExpression = expression;
+ myIndex = index;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myExpression.toKotlin() + "[" + myIndex.toKotlin() + "]";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayInitializerExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayInitializerExpression.java
new file mode 100644
index 00000000000..b08f1b7bf6b
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayInitializerExpression.java
@@ -0,0 +1,70 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.*;
+
+/**
+ * @author ignatov
+ */
+public class ArrayInitializerExpression extends Expression {
+ private final Type myType;
+ private final List myInitializers;
+
+ public ArrayInitializerExpression(final Type type, List initializers) {
+ myType = type;
+ myInitializers = initializers;
+ }
+
+ @NotNull
+ private static String createArrayFunction(@NotNull final Type type) {
+ String sType = innerTypeStr(type);
+ if (PRIMITIVE_TYPES.contains(sType))
+ return sType + "Array"; // intArray
+ return AstUtil.lowerFirstCharacter(type.convertedToNotNull().toKotlin()); // array
+ }
+
+ @NotNull
+ private static String innerTypeStr(@NotNull final Type type) {
+ return type.convertedToNotNull().toKotlin().replace("Array", "").toLowerCase();
+ }
+
+ @NotNull
+ private static String createInitializers(@NotNull final Type type, @NotNull final List initializers) {
+ List arguments = new LinkedList();
+ for (Expression i : initializers)
+ arguments.add(explicitConvertIfNeeded(type, i));
+ return AstUtil.join(arguments, COMMA_WITH_SPACE);
+ }
+
+ @NotNull
+ private static String explicitConvertIfNeeded(@NotNull final Type type, @NotNull final Expression i) {
+ Set doubleOrFloatTypes = new HashSet(
+ Arrays.asList("double", "float", "java.lang.double", "java.lang.float")
+ );
+ String afterReplace = innerTypeStr(type).replace(">", "").replace("<", "").replace("?", "");
+ if (doubleOrFloatTypes.contains(afterReplace)) {
+ if (i.getKind() == Kind.LITERAL) {
+ if (i.toKotlin().contains("."))
+ return i.toKotlin();
+ return i.toKotlin() + DOT + ZERO;
+ }
+ return "(" + i.toKotlin() + ")" + getConversion(afterReplace);
+ }
+ return i.toKotlin();
+ }
+
+ @NotNull
+ private static String getConversion(@NotNull final String afterReplace) {
+ if (afterReplace.contains("double")) return DOT + "dbl";
+ if (afterReplace.contains("float")) return DOT + "flt";
+ return "";
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return createArrayFunction(myType) + "(" + createInitializers(myType, myInitializers) + ")";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayType.java b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayType.java
new file mode 100644
index 00000000000..d78994faf55
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayType.java
@@ -0,0 +1,32 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ArrayType extends Type {
+ private final Type myType;
+
+ public ArrayType(Type type) {
+ myType = type;
+ }
+
+ public Type getInnerType() {
+ return myType;
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.ARRAY_TYPE;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (PRIMITIVE_TYPES.contains(myType.toKotlin().toLowerCase()))
+ return myType.toKotlin() + "Array" + isNullableStr(); // returns IntArray, BooleanArray, etc.
+ return "Array" + "<" + myType.toKotlin() + ">" + isNullableStr();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.java
new file mode 100644
index 00000000000..44169fca924
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.java
@@ -0,0 +1,53 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class ArrayWithoutInitializationExpression extends Expression {
+ private final Type myType;
+ private final List myExpressions;
+
+ public ArrayWithoutInitializationExpression(Type type, List expressions) {
+ myType = type;
+ myExpressions = expressions;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (myType.getKind() == Kind.ARRAY_TYPE)
+ return constructInnerType((ArrayType) myType, myExpressions);
+ return getConstructorName(myType);
+ }
+
+ @NotNull
+ private static String constructInnerType(@NotNull ArrayType hostType, @NotNull List expressions) {
+ if (expressions.size() == 1)
+ return oneDim(hostType, expressions.get(0));
+ Type innerType = hostType.getInnerType();
+ if (expressions.size() > 1 && innerType.getKind() == Kind.ARRAY_TYPE)
+ return oneDim(hostType, expressions.get(0), "{" + constructInnerType((ArrayType) innerType, expressions.subList(1, expressions.size())) + "}");
+ return getConstructorName(hostType);
+ }
+
+ @NotNull
+ private static String oneDim(@NotNull Type type, @NotNull Expression size) {
+ return oneDim(type, size, EMPTY);
+ }
+
+ @NotNull
+ private static String oneDim(@NotNull Type type, @NotNull Expression size, @NotNull String init) {
+ String commaWithInit = init.isEmpty() ? EMPTY : COMMA_WITH_SPACE + init;
+ return getConstructorName(type) + "(" + size.toKotlin() + commaWithInit + ")";
+ }
+
+ @NotNull
+ private static String getConstructorName(@NotNull Type type) {
+ return AstUtil.replaceLastQuest(type.toKotlin());
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.java
new file mode 100644
index 00000000000..829f7953948
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class AssertStatement extends Statement {
+ private final Expression myCondition;
+ private final Expression myDetail;
+
+ public AssertStatement(Expression condition, Expression detail) {
+ myCondition = condition;
+ myDetail = detail;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ String detail = myDetail != Expression.EMPTY_EXPRESSION ? "(" + myDetail.toKotlin() + ")" : EMPTY;
+ return "assert" + detail + SPACE + "{" + myCondition.toKotlin() + "}";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AssignmentExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/AssignmentExpression.java
new file mode 100644
index 00000000000..34d1fcb7b20
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/AssignmentExpression.java
@@ -0,0 +1,38 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class AssignmentExpression extends Expression {
+ private final Expression myLeft;
+ private final Expression myRight;
+ private final String myOp;
+
+ public Expression getLeft() {
+ return myLeft;
+ }
+
+ public Expression getRight() {
+ return myRight;
+ }
+
+ public AssignmentExpression(Expression left, Expression right, String op) {
+ myLeft = left;
+ myRight = right;
+ myOp = op;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myLeft.toKotlin() + SPACE + myOp + SPACE + myRight.toKotlin();
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.ASSIGNMENT_EXPRESSION;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/BinaryExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/BinaryExpression.java
new file mode 100644
index 00000000000..2df6bfd2dd6
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/BinaryExpression.java
@@ -0,0 +1,35 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class BinaryExpression extends Expression {
+ private final Expression myLeft;
+ private final Expression myRight;
+ private final String myOp;
+ private final List myConversions;
+
+ public BinaryExpression(Expression left, Expression right, String op) {
+ this(left, right, op, Arrays.asList("", ""));
+ }
+
+ public BinaryExpression(Expression left, Expression right, String op, List conversions) {
+ myLeft = left;
+ myRight = right;
+ myOp = op;
+ myConversions = conversions;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ List expressionsWithConversions = AstUtil.applyConversions(AstUtil.nodesToKotlin(Arrays.asList(myLeft, myRight)), myConversions);
+ return AstUtil.join(expressionsWithConversions, SPACE + myOp + SPACE);
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.java b/j2k/src/org/jetbrains/jet/j2k/ast/Block.java
new file mode 100644
index 00000000000..3e22f8fb775
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.java
@@ -0,0 +1,51 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class Block extends Statement {
+ @NotNull
+ public final static Block EMPTY_BLOCK = new Block();
+
+ private List myStatements;
+ private boolean myNotEmpty = false;
+
+ private Block() {
+ myStatements = new LinkedList();
+ }
+
+ public Block(List statements) {
+ myStatements = new LinkedList();
+ myStatements = statements;
+ }
+
+ public Block(List statements, boolean notEmpty) {
+ myStatements = new LinkedList();
+ myStatements = statements;
+ myNotEmpty = notEmpty;
+ }
+
+ public boolean isEmpty() {
+ return !myNotEmpty && myStatements.size() == 0;
+ }
+
+ public List getStatements() {
+ return myStatements;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (!isEmpty())
+ return "{" + N +
+ AstUtil.joinNodes(myStatements, N) + N +
+ "}";
+ return EMPTY;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/BreakStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/BreakStatement.java
new file mode 100644
index 00000000000..e48b8ad5b5d
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/BreakStatement.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class BreakStatement extends Statement {
+ private Identifier myLabel = Identifier.EMPTY_IDENTIFIER;
+
+ public BreakStatement(Identifier label) {
+ myLabel = label;
+ }
+
+ public BreakStatement() {
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.BREAK;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (myLabel.isEmpty())
+ return "break";
+ return "break" + AT + myLabel.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java
new file mode 100644
index 00000000000..d98463f24c1
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java
@@ -0,0 +1,42 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class CallChainExpression extends Expression {
+ private final Expression myExpression;
+ private final Expression myIdentifier;
+
+ public Expression getIdentifier() {
+ return myIdentifier;
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.CALL_CHAIN;
+ }
+
+ public CallChainExpression(Expression expression, Expression identifier) {
+ myExpression = expression;
+ myIdentifier = identifier;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return myIdentifier.isNullable();
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (!myExpression.isEmpty())
+ if (myExpression.isNullable())
+ return myExpression.toKotlin() + QUESTDOT + myIdentifier.toKotlin();
+ else
+ return myExpression.toKotlin() + DOT + myIdentifier.toKotlin();
+ return myIdentifier.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/CaseContainer.java b/j2k/src/org/jetbrains/jet/j2k/ast/CaseContainer.java
new file mode 100644
index 00000000000..b96b7be351f
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/CaseContainer.java
@@ -0,0 +1,30 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class CaseContainer extends Statement {
+ private final List myCaseStatement;
+ private final Block myBlock;
+
+ public CaseContainer(final List caseStatement, @NotNull final List statements) {
+ myCaseStatement = caseStatement;
+ List newStatements = new LinkedList();
+ for (Statement s : statements)
+ if (s.getKind() != Kind.BREAK && s.getKind() != Kind.CONTINUE)
+ newStatements.add(s);
+ myBlock = new Block(newStatements);
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return AstUtil.joinNodes(myCaseStatement, COMMA_WITH_SPACE) + SPACE + "->" + SPACE + myBlock.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/CatchStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/CatchStatement.java
new file mode 100644
index 00000000000..7db33c91163
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/CatchStatement.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class CatchStatement extends Statement {
+ private final Parameter myVariable;
+ private final Block myBlock;
+
+ public CatchStatement(Parameter variable, Block block) {
+ myVariable = variable;
+ myBlock = block;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "catch" + SPACE + "(" + myVariable.toKotlin() + ")" + SPACE + myBlock.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.java b/j2k/src/org/jetbrains/jet/j2k/ast/Class.java
new file mode 100644
index 00000000000..dbc9e9fa710
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.java
@@ -0,0 +1,236 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.j2k.Converter;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static org.jetbrains.jet.j2k.util.AstUtil.*;
+
+/**
+ * @author ignatov
+ */
+public class Class extends Member {
+ @NotNull
+ String TYPE = "class";
+ final Identifier myName;
+ private final List myBaseClassParams;
+ private final List myMembers;
+ private final List myTypeParameters;
+ private final List myExtendsTypes;
+ private final List myImplementsTypes;
+
+ public Class(Identifier name, Set modifiers, List typeParameters, List extendsTypes,
+ List baseClassParams, List implementsTypes, List members) {
+ myName = name;
+ myBaseClassParams = baseClassParams;
+ myModifiers = modifiers;
+ myTypeParameters = typeParameters;
+ myExtendsTypes = extendsTypes;
+ myImplementsTypes = implementsTypes;
+ myMembers= getMembers(members);
+ }
+
+ static List getMembers(List members) {
+ List withoutPrivate = new LinkedList();
+ if (Converter.hasSetting("public-only")) {
+ for (Member m : members) {
+ if (m.accessModifier().equals("public") || m.accessModifier().equals("protected")) {
+ withoutPrivate.add(m);
+ }
+ }
+ } else {
+ withoutPrivate = members;
+ }
+ return withoutPrivate;
+ }
+
+
+ @Nullable
+ private Constructor getPrimaryConstructor() {
+ for (Member m : myMembers)
+ if (m.getKind() == Kind.CONSTRUCTOR)
+ if (((Constructor) m).isPrimary())
+ return (Constructor) m;
+ return null;
+ }
+
+ String primaryConstructorSignatureToKotlin() {
+ Constructor maybeConstructor = getPrimaryConstructor();
+ if (maybeConstructor != null)
+ return maybeConstructor.primarySignatureToKotlin();
+ return "(" + ")";
+ }
+
+ String primaryConstructorBodyToKotlin() {
+ Constructor maybeConstructor = getPrimaryConstructor();
+ if (maybeConstructor != null && !maybeConstructor.getBlock().isEmpty())
+ return maybeConstructor.primaryBodyToKotlin();
+ return EMPTY;
+ }
+
+ private boolean hasWhere() {
+ for (Element t : myTypeParameters)
+ if (t instanceof TypeParameter && ((TypeParameter) t).hasWhere())
+ return true;
+ return false;
+ }
+
+ @NotNull
+ String typeParameterWhereToKotlin() {
+ if (hasWhere()) {
+ List wheres = new LinkedList();
+ for (Element t : myTypeParameters)
+ if (t instanceof TypeParameter)
+ wheres.add(((TypeParameter) t).getWhereToKotlin());
+ return SPACE + "where" + SPACE + join(wheres, COMMA_WITH_SPACE) + SPACE;
+ }
+ return EMPTY;
+ }
+
+ @NotNull
+ LinkedList membersExceptConstructors() {
+ final LinkedList result = new LinkedList();
+ for (Member m : myMembers)
+ if (m.getKind() != Kind.CONSTRUCTOR)
+ result.add(m);
+ return result;
+ }
+
+ @NotNull
+ List secondaryConstructorsAsStaticInitFunction() {
+ final LinkedList result = new LinkedList();
+ for (Member m : myMembers)
+ if (m.getKind() == Kind.CONSTRUCTOR && !((Constructor) m).isPrimary()) {
+ Function f = (Function) m;
+ Set modifiers = new HashSet(m.myModifiers);
+ modifiers.add(Modifier.STATIC);
+
+ final List statements = f.getBlock().getStatements();
+ statements.add(new ReturnStatement(new IdentifierImpl("__"))); // TODO: move to one place, find other __ usages
+ final Block block = new Block(statements);
+
+ final List typeParameters = new LinkedList();
+ if (f.getTypeParameters().size() == 0)
+ typeParameters.addAll(myTypeParameters);
+ else {
+ typeParameters.addAll(myTypeParameters);
+ typeParameters.addAll(f.getTypeParameters());
+ }
+
+ result.add(new Function(
+ new IdentifierImpl("init"),
+ modifiers,
+ new ClassType(myName, typeParameters, false),
+ typeParameters,
+ f.getParams(),
+ block
+ ));
+ }
+ return result;
+ }
+
+ @NotNull
+ String typeParametersToKotlin() {
+ return myTypeParameters.size() > 0 ? "<" + AstUtil.joinNodes(myTypeParameters, COMMA_WITH_SPACE) + ">" : EMPTY;
+ }
+
+ List baseClassSignatureWithParams() {
+ if (TYPE.equals("class") && myExtendsTypes.size() == 1) {
+ LinkedList result = new LinkedList();
+ result.add(myExtendsTypes.get(0).toKotlin() + "(" + joinNodes(myBaseClassParams, COMMA_WITH_SPACE) + ")");
+ return result;
+ } else
+ return nodesToKotlin(myExtendsTypes);
+ }
+
+ @NotNull
+ String implementTypesToKotlin() {
+ List allTypes = new LinkedList() {
+ {
+ addAll(baseClassSignatureWithParams());
+ addAll(nodesToKotlin(myImplementsTypes));
+ }
+ };
+ return allTypes.size() == 0 ? EMPTY : SPACE + COLON + SPACE + join(allTypes, COMMA_WITH_SPACE);
+ }
+
+ @NotNull
+ String modifiersToKotlin() {
+ List modifierList = new LinkedList();
+
+ if (needAbstractModifier())
+ modifierList.add(Modifier.ABSTRACT);
+
+ modifierList.add(accessModifier());
+
+ if (needOpenModifier())
+ modifierList.add(Modifier.OPEN);
+
+ if (modifierList.size() > 0)
+ return join(modifierList, SPACE) + SPACE;
+
+ return EMPTY;
+ }
+
+ boolean needOpenModifier() {
+ return !myModifiers.contains(Modifier.FINAL);
+ }
+
+ boolean needAbstractModifier() {
+ return isAbstract();
+ }
+
+ @NotNull
+ String bodyToKotlin() {
+ return SPACE + "{" + N +
+ AstUtil.joinNodes(getNonStatic(membersExceptConstructors()), N) + N +
+ primaryConstructorBodyToKotlin() + N +
+ classObjectToKotlin() + N +
+ "}";
+ }
+
+ @NotNull
+ private static List getStatic(@NotNull List extends Member> members) {
+ List result = new LinkedList();
+ for (Member m : members)
+ if (m.isStatic())
+ result.add(m);
+ return result;
+ }
+
+ @NotNull
+ private static List getNonStatic(@NotNull List extends Member> members) {
+ List result = new LinkedList();
+ for (Member m : members)
+ if (!m.isStatic())
+ result.add(m);
+ return result;
+ }
+
+ @NotNull
+ private String classObjectToKotlin() {
+ final List staticMembers = new LinkedList(secondaryConstructorsAsStaticInitFunction());
+ staticMembers.addAll(getStatic(membersExceptConstructors()));
+ if (staticMembers.size() > 0) {
+ return "class" + SPACE + "object" + SPACE + "{" + N +
+ AstUtil.joinNodes(staticMembers, N) + N +
+ "}";
+ }
+ return EMPTY;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return modifiersToKotlin() + TYPE + SPACE + myName.toKotlin() + typeParametersToKotlin() + primaryConstructorSignatureToKotlin() +
+ implementTypesToKotlin() +
+ typeParameterWhereToKotlin() +
+ bodyToKotlin();
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassObjectAccessExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/ClassObjectAccessExpression.java
new file mode 100644
index 00000000000..b16fedbf19e
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassObjectAccessExpression.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ClassObjectAccessExpression extends Expression {
+ private final Element myTypeElement;
+
+ public ClassObjectAccessExpression(Element typeElement) {
+ myTypeElement = typeElement;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "getJavaClass" + "<" + myTypeElement.toKotlin() + ">";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassType.java b/j2k/src/org/jetbrains/jet/j2k/ast/ClassType.java
new file mode 100644
index 00000000000..5e330877280
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassType.java
@@ -0,0 +1,39 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class ClassType extends Type {
+ private final Identifier myType;
+ private final List extends Element> myParameters;
+
+ public ClassType(Identifier type, List extends Element> parameters, boolean nullable) {
+ myType = type;
+ myParameters = parameters;
+ myNullable = nullable;
+ }
+
+ public ClassType(Identifier type, List extends Element> parameters) {
+ myType = type;
+ myParameters = parameters;
+ }
+
+ public ClassType(Identifier type) {
+ myType = type;
+ myNullable = false;
+ myParameters = Collections.emptyList();
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ String params = myParameters.size() == 0 ? EMPTY : "<" + AstUtil.joinNodes(myParameters, COMMA_WITH_SPACE) + ">";
+ return myType.toKotlin() + params + isNullableStr();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructor.java b/j2k/src/org/jetbrains/jet/j2k/ast/Constructor.java
new file mode 100644
index 00000000000..758928b7295
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructor.java
@@ -0,0 +1,38 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class Constructor extends Function {
+ private final boolean myIsPrimary;
+
+ public Constructor(Identifier identifier, Set modifiers, Type type, List typeParameters, Element params, Block block, boolean isPrimary) {
+ super(identifier, modifiers, type, typeParameters, params, block);
+ myIsPrimary = isPrimary;
+ }
+
+ @NotNull
+ public String primarySignatureToKotlin() {
+ return "(" + myParams.toKotlin() + ")";
+ }
+
+ @NotNull
+ public String primaryBodyToKotlin() {
+ return myBlock.toKotlin();
+ }
+
+ public boolean isPrimary() {
+ return myIsPrimary;
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.CONSTRUCTOR;
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ContinueStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/ContinueStatement.java
new file mode 100644
index 00000000000..bfed924d439
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ContinueStatement.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ContinueStatement extends Statement {
+ private Identifier myLabel = Identifier.EMPTY_IDENTIFIER;
+
+ public ContinueStatement(Identifier label) {
+ myLabel = label;
+ }
+
+ public ContinueStatement() {
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.CONTINUE;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (myLabel.isEmpty())
+ return "continue";
+ return "continue" + AT + myLabel.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DeclarationStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/DeclarationStatement.java
new file mode 100644
index 00000000000..d9bbcb5f7d8
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/DeclarationStatement.java
@@ -0,0 +1,40 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class DeclarationStatement extends Statement {
+ private final List myElements;
+
+ public DeclarationStatement(List elements) {
+ myElements = elements;
+ }
+
+ @NotNull
+ private static List toStringList(@NotNull List elements) {
+ List result = new LinkedList();
+ for (Element e : elements) {
+ if (e instanceof LocalVariable) {
+ LocalVariable v = (LocalVariable) e;
+
+ final String varKeyword = v.hasModifier(Modifier.FINAL) ? "val" : "var";
+ result.add(
+ varKeyword + SPACE + e.toKotlin()
+ );
+ }
+ }
+ return result;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return AstUtil.join(toStringList(myElements), N);
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DefaultSwitchLabelStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/DefaultSwitchLabelStatement.java
new file mode 100644
index 00000000000..a148197da77
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/DefaultSwitchLabelStatement.java
@@ -0,0 +1,14 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class DefaultSwitchLabelStatement extends Statement {
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "else";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DoWhileStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/DoWhileStatement.java
new file mode 100644
index 00000000000..02d4f64d58d
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/DoWhileStatement.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class DoWhileStatement extends WhileStatement {
+ public DoWhileStatement(Expression condition, Statement statement) {
+ super(condition, statement);
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "do" + N +
+ myStatement.toKotlin() + N +
+ "while" + SPACE + "(" + myCondition.toKotlin() + ")";
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyMethodCallExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/DummyMethodCallExpression.java
new file mode 100644
index 00000000000..e304161c987
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyMethodCallExpression.java
@@ -0,0 +1,24 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class DummyMethodCallExpression extends Expression {
+ private final Element myWho;
+ private final String myMethodName;
+ private final Element myWhat;
+
+ public DummyMethodCallExpression(Element who, String methodName, Element what) {
+ myWho = who;
+ myMethodName = methodName;
+ myWhat = what;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myWho.toKotlin() + DOT + myMethodName + "(" + myWhat.toKotlin() + ")";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.java
new file mode 100644
index 00000000000..0c3eb6717db
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class DummyStringExpression extends Expression {
+ private final String myString;
+
+ public DummyStringExpression(String string) {
+ myString = string;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myString;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.java b/j2k/src/org/jetbrains/jet/j2k/ast/Element.java
new file mode 100644
index 00000000000..56bf2c4daa5
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public abstract class Element extends Node {
+ @NotNull
+ public static final Element EMPTY_ELEMENT = new EmptyElement();
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /**
+ * @author ignatov
+ */
+ private static class EmptyElement extends Element {
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return EMPTY;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.java b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.java
new file mode 100644
index 00000000000..cbf2cc7872c
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.java
@@ -0,0 +1,39 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class Enum extends Class {
+ public Enum(Identifier name, Set modifiers, List typeParameters, List extendsTypes,
+ List baseClassParams, List implementsTypes, List members) {
+ super(name, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, getMembers(members));
+ }
+
+ String primaryConstructorSignatureToKotlin() {
+ String s = super.primaryConstructorSignatureToKotlin();
+ return s.equals("()") ? EMPTY : s;
+ }
+
+ @Override
+ boolean needOpenModifier() {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return modifiersToKotlin() + "enum class" + SPACE + myName.toKotlin() + primaryConstructorSignatureToKotlin() +
+ typeParametersToKotlin() + implementTypesToKotlin() + SPACE + "{" + N +
+ AstUtil.joinNodes(membersExceptConstructors(), N) + N +
+ primaryConstructorBodyToKotlin() + N +
+ "public fun name() : String { return \"\" }" + N + // TODO : remove hack
+ "public fun order() : Int { return 0 }" + N +
+ "}";
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.java b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.java
new file mode 100644
index 00000000000..d9aba8ef463
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class EnumConstant extends Field {
+ public EnumConstant(Identifier identifier, Set modifiers, @NotNull Type type, Element params) {
+ super(identifier, modifiers, type.convertedToNotNull(), params, 0);
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (myInitializer.toKotlin().isEmpty())
+ return myIdentifier.toKotlin();
+ return myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin() + "(" + myInitializer.toKotlin() + ")";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.java b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.java
new file mode 100644
index 00000000000..d3a98436c8b
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public abstract class Expression extends Statement {
+ @NotNull
+ public static final Expression EMPTY_EXPRESSION = new EmptyExpression();
+
+ /**
+ * @author ignatov
+ */
+ private static class EmptyExpression extends Expression {
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return EMPTY;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+ }
+
+ boolean isNullable() {
+ return false;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.java b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.java
new file mode 100644
index 00000000000..ae3c1358f58
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.java
@@ -0,0 +1,27 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class ExpressionList extends Expression {
+ private final List myExpressions;
+
+ public ExpressionList(List expressions, List types) {
+ myExpressions = expressions;
+ }
+
+ public ExpressionList(List expressions) {
+ myExpressions = expressions;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return AstUtil.joinNodes(myExpressions, COMMA_WITH_SPACE);
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionListStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionListStatement.java
new file mode 100644
index 00000000000..1c67340e655
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionListStatement.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class ExpressionListStatement extends Expression {
+ private final List myExpressions;
+
+ public ExpressionListStatement(List expressions) {
+ myExpressions = expressions;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return AstUtil.joinNodes(myExpressions, N);
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.java b/j2k/src/org/jetbrains/jet/j2k/ast/Field.java
new file mode 100644
index 00000000000..35e364aa09f
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.java
@@ -0,0 +1,77 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static org.jetbrains.jet.j2k.Converter.getDefaultInitializer;
+
+/**
+ * @author ignatov
+ */
+public class Field extends Member {
+ final Identifier myIdentifier;
+ private final int myWritingAccesses;
+ final Type myType;
+ final Element myInitializer;
+
+ public Field(Identifier identifier, Set modifiers, Type type, Element initializer, int writingAccesses) {
+ myIdentifier = identifier;
+ myWritingAccesses = writingAccesses;
+ myModifiers = modifiers;
+ myType = type;
+ myInitializer = initializer;
+ }
+
+ public Element getInitializer() {
+ return myInitializer;
+ }
+
+ public Identifier getIdentifier() {
+ return myIdentifier;
+ }
+
+ public Type getType() {
+ return myType;
+ }
+
+ @NotNull
+ String modifiersToKotlin() {
+ List modifierList = new LinkedList();
+
+ if (isAbstract())
+ modifierList.add(Modifier.ABSTRACT);
+
+ modifierList.add(accessModifier());
+
+ modifierList.add(isVal() ? "val" : "var");
+
+ if (modifierList.size() > 0)
+ return AstUtil.join(modifierList, SPACE) + SPACE;
+
+ return EMPTY;
+ }
+
+ public boolean isVal() {
+ return myModifiers.contains(Modifier.FINAL);
+ }
+
+ @Override
+ public boolean isStatic() {
+ return myModifiers.contains(Modifier.STATIC);
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ final String declaration = modifiersToKotlin() + myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin();
+
+ if (myInitializer.isEmpty())
+ return declaration + (isVal() && !isStatic() && myWritingAccesses == 1 ? EMPTY : SPACE + EQUAL + SPACE + getDefaultInitializer(this));
+
+ return declaration + SPACE + EQUAL + SPACE + myInitializer.toKotlin();
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.java b/j2k/src/org/jetbrains/jet/j2k/ast/File.java
new file mode 100644
index 00000000000..0dd63fa4fd6
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.java
@@ -0,0 +1,33 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class File extends Node {
+ private final String myPackageName;
+ private final List myImports;
+ private final List myClasses;
+ private final String myMainFunction;
+
+ public File(String packageName, List imports, List classes, String mainFunction) {
+ myPackageName = packageName;
+ myImports = imports;
+ myClasses = classes;
+ myMainFunction = mainFunction;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ final String common = AstUtil.joinNodes(myImports, N) + N2 + AstUtil.joinNodes(myClasses, N) + N + myMainFunction;
+ if (myPackageName.isEmpty())
+ return common;
+ return "package" + SPACE + myPackageName + N +
+ common;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ForeachStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/ForeachStatement.java
new file mode 100644
index 00000000000..08f2a457b11
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ForeachStatement.java
@@ -0,0 +1,25 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ForeachStatement extends Statement {
+ private final Parameter myVariable;
+ private final Expression myExpression;
+ private final Statement myStatement;
+
+ public ForeachStatement(Parameter variable, Expression expression, Statement statement) {
+ myVariable = variable;
+ myExpression = expression;
+ myStatement = statement;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "for" + SPACE + "(" + myVariable.toKotlin() + SPACE + IN + SPACE + myExpression.toKotlin() + ")" + N +
+ myStatement.toKotlin();
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ForeachWithRangeStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/ForeachWithRangeStatement.java
new file mode 100644
index 00000000000..b6aa9e622e0
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ForeachWithRangeStatement.java
@@ -0,0 +1,29 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class ForeachWithRangeStatement extends Statement {
+ private final Expression myStart;
+ private final IdentifierImpl myIdentifier;
+ private final Expression myEnd;
+ private final Statement myBody;
+
+ public ForeachWithRangeStatement(IdentifierImpl identifier, Expression start, Expression end, Statement body) {
+ myStart = start;
+ myIdentifier = identifier;
+ myEnd = end;
+ myBody = body;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "for" + SPACE + "(" +
+ myIdentifier.toKotlin() + SPACE + "in" + SPACE + myStart.toKotlin() + ".." + myEnd.toKotlin() +
+ ")" + SPACE +
+ myBody.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.java b/j2k/src/org/jetbrains/jet/j2k/ast/Function.java
new file mode 100644
index 00000000000..cf03d2de8a7
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.java
@@ -0,0 +1,103 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class Function extends Member {
+ private final Identifier myName;
+ private final Type myType;
+ private final List myTypeParameters;
+ final Element myParams;
+
+ // TODO: maybe remove it?
+ public void setBlock(Block block) {
+ myBlock = block;
+ }
+
+ Block myBlock;
+
+ public Function(Identifier name, Set modifiers, Type type, List typeParameters, Element params, Block block) {
+ myName = name;
+ myModifiers = modifiers;
+ myType = type;
+ myTypeParameters = typeParameters;
+ myParams = params;
+ myBlock = block;
+ }
+
+ public List getTypeParameters() {
+ return myTypeParameters;
+ }
+
+ public Element getParams() {
+ return myParams;
+ }
+
+ public Block getBlock() {
+ return myBlock;
+ }
+
+ @NotNull
+ private String typeParametersToKotlin() {
+ return myTypeParameters.size() > 0 ? "<" + AstUtil.joinNodes(myTypeParameters, COMMA_WITH_SPACE) + ">" : EMPTY;
+ }
+
+ private boolean hasWhere() {
+ for (Element t : myTypeParameters)
+ if (t instanceof TypeParameter && ((TypeParameter) t).hasWhere())
+ return true;
+ return false;
+ }
+
+ private String typeParameterWhereToKotlin() {
+ if (hasWhere()) {
+ List wheres = new LinkedList();
+ for (Element t : myTypeParameters)
+ if (t instanceof TypeParameter)
+ wheres.add(((TypeParameter) t).getWhereToKotlin());
+ return SPACE + "where" + SPACE + AstUtil.join(wheres, COMMA_WITH_SPACE) + SPACE;
+ }
+ return EMPTY;
+ }
+
+ String modifiersToKotlin() {
+ List modifierList = new LinkedList();
+
+ if (isAbstract())
+ modifierList.add(Modifier.ABSTRACT);
+
+ if (myModifiers.contains(Modifier.OVERRIDE))
+ modifierList.add(Modifier.OVERRIDE);
+
+ if (!myModifiers.contains(Modifier.OVERRIDE) && !myModifiers.contains(Modifier.FINAL))
+ modifierList.add(Modifier.OPEN);
+
+ if (myModifiers.contains(Modifier.NOT_OPEN))
+ modifierList.remove(Modifier.OPEN);
+
+ String accessModifier = accessModifier();
+ if (!accessModifier.isEmpty())
+ modifierList.add(accessModifier);
+
+ if (modifierList.size() > 0)
+ return AstUtil.join(modifierList, SPACE) + SPACE;
+
+ return EMPTY;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return modifiersToKotlin() + "fun" + SPACE + myName.toKotlin() + typeParametersToKotlin() + "(" + myParams.toKotlin() + ")" + SPACE + COLON +
+ SPACE + myType.toKotlin() + SPACE +
+ typeParameterWhereToKotlin() +
+ myBlock.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/IMember.java b/j2k/src/org/jetbrains/jet/j2k/ast/IMember.java
new file mode 100644
index 00000000000..3ac5ac6c31b
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/IMember.java
@@ -0,0 +1,10 @@
+package org.jetbrains.jet.j2k.ast;
+
+/**
+ * @author ignatov
+ */
+public interface IMember extends INode {
+ boolean isStatic();
+
+ boolean isAbstract();
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/INode.java b/j2k/src/org/jetbrains/jet/j2k/ast/INode.java
new file mode 100644
index 00000000000..d4c23a7a484
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/INode.java
@@ -0,0 +1,18 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public interface INode {
+ @NotNull
+ String toKotlin();
+
+ @NotNull
+ Kind getKind();
+
+ enum Kind {
+ UNDEFINED, TYPE, CONSTRUCTOR, BREAK, CONTINUE, VARARG, TRAIT, ASSIGNMENT_EXPRESSION, CALL_CHAIN, LITERAL, ARRAY_TYPE,
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.java b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.java
new file mode 100644
index 00000000000..8191f63b0c2
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public interface Identifier extends INode {
+ @NotNull
+ Identifier EMPTY_IDENTIFIER = new IdentifierImpl("");
+
+ boolean isEmpty();
+
+ String getName();
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/IdentifierImpl.java b/j2k/src/org/jetbrains/jet/j2k/ast/IdentifierImpl.java
new file mode 100644
index 00000000000..6a1b4fbff11
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/IdentifierImpl.java
@@ -0,0 +1,59 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class IdentifierImpl extends Expression implements Identifier {
+ private final String myName;
+ private boolean myIsNullable = true;
+ private boolean myQuotingNeeded = true;
+
+ public IdentifierImpl(String name) {
+ myName = name;
+ }
+
+ public IdentifierImpl(String name, boolean isNullable) {
+ myName = name;
+ myIsNullable = isNullable;
+ }
+
+ public IdentifierImpl(String name, boolean isNullable, boolean quotingNeeded) {
+ myName = name;
+ myIsNullable = isNullable;
+ myQuotingNeeded = quotingNeeded;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return myName.length() == 0;
+ }
+
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ @NotNull
+ private static String quote(String str) {
+ return BACKTICK + str + BACKTICK;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return myIsNullable;
+ }
+
+ private String ifNeedQuote() {
+ if (myQuotingNeeded && (ONLY_KOTLIN_KEYWORDS.contains(myName) || myName.contains("$")))
+ return quote(myName);
+ return myName;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return ifNeedQuote();
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/IfStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/IfStatement.java
new file mode 100644
index 00000000000..3e45436d036
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/IfStatement.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class IfStatement extends Expression {
+ private final Expression myCondition;
+ private final Statement myThenStatement;
+ private final Statement myElseStatement;
+
+ public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement) {
+ myCondition = condition;
+ myThenStatement = thenStatement;
+ myElseStatement = elseStatement;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ String result = "if" + SPACE + "(" + myCondition.toKotlin() + ")" + N + myThenStatement.toKotlin() + N;
+
+ if (myElseStatement != Statement.EMPTY_STATEMENT)
+ return result +
+ "else" + N +
+ myElseStatement.toKotlin();
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Import.java b/j2k/src/org/jetbrains/jet/j2k/ast/Import.java
new file mode 100644
index 00000000000..854b2fa3534
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Import.java
@@ -0,0 +1,24 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class Import extends Node {
+ private final String myName;
+
+ public String getName() {
+ return myName;
+ }
+
+ public Import(String name) {
+ myName = name;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "import" + SPACE + myName;
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/InProjectionType.java b/j2k/src/org/jetbrains/jet/j2k/ast/InProjectionType.java
new file mode 100644
index 00000000000..17d2b63cc04
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/InProjectionType.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class InProjectionType extends Type {
+ private final Type myBound;
+
+ public InProjectionType(Type bound) {
+ myBound = bound;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "in" + SPACE + myBound.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.java b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.java
new file mode 100644
index 00000000000..d49dc13c1e2
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.java
@@ -0,0 +1,23 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class Initializer extends Member {
+ private final Block myBlock;
+
+ public Initializer(Block block, Set modifiers) {
+ myBlock = block;
+ myModifiers = modifiers;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myBlock.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/IsOperator.java b/j2k/src/org/jetbrains/jet/j2k/ast/IsOperator.java
new file mode 100644
index 00000000000..98c6c3abcac
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/IsOperator.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class IsOperator extends Expression {
+ private final Expression myExpression;
+ private final Element myTypeElement;
+
+ public IsOperator(Expression expression, Element typeElement) {
+ myExpression = expression;
+ myTypeElement = typeElement;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return "(" + myExpression.toKotlin() + SPACE + "is" + SPACE + myTypeElement.toKotlin() + ")";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LabelStatement.java b/j2k/src/org/jetbrains/jet/j2k/ast/LabelStatement.java
new file mode 100644
index 00000000000..9908938b4d1
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/LabelStatement.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class LabelStatement extends Statement {
+ private final Identifier myName;
+ private final Statement myStatement;
+
+ public LabelStatement(Identifier name, Statement statement) {
+ myName = name;
+ myStatement = statement;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return AT + myName.toKotlin() + SPACE + myStatement.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LiteralExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/LiteralExpression.java
new file mode 100644
index 00000000000..451f22757d0
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/LiteralExpression.java
@@ -0,0 +1,26 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public class LiteralExpression extends Expression {
+ private final Identifier myIdentifier;
+
+ public LiteralExpression(Identifier identifier) {
+ myIdentifier = identifier;
+ }
+
+ @NotNull
+ @Override
+ public Kind getKind() {
+ return Kind.LITERAL;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ return myIdentifier.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.java b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.java
new file mode 100644
index 00000000000..0c561827a18
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.java
@@ -0,0 +1,36 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public class LocalVariable extends Expression {
+ private final Identifier myIdentifier;
+ private final Set myModifiersSet;
+ private final Type myType;
+ private final Expression myInitializer;
+
+ public LocalVariable(Identifier identifier, Set modifiersSet, Type type, Expression initializer) {
+ myIdentifier = identifier;
+ myModifiersSet = modifiersSet;
+ myType = type;
+ myInitializer = initializer;
+ }
+
+ public boolean hasModifier(String modifier) {
+ return myModifiersSet.contains(modifier);
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ if (myInitializer.isEmpty())
+ return myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin();
+
+ return myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin() + SPACE +
+ EQUAL + SPACE + myInitializer.toKotlin();
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Member.java b/j2k/src/org/jetbrains/jet/j2k/ast/Member.java
new file mode 100644
index 00000000000..ade895c672c
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Member.java
@@ -0,0 +1,30 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author ignatov
+ */
+public abstract class Member extends Node implements IMember {
+ Set myModifiers;
+
+ @NotNull
+ String accessModifier() {
+ for (String m : myModifiers)
+ if (m.equals(Modifier.PUBLIC) || m.equals(Modifier.PROTECTED) || m.equals(Modifier.PRIVATE))
+ return m;
+ return EMPTY; // package local converted to internal, but we use internal by default
+ }
+
+ @Override
+ public boolean isAbstract() {
+ return myModifiers.contains(Modifier.ABSTRACT);
+ }
+
+ @Override
+ public boolean isStatic() {
+ return myModifiers.contains(Modifier.STATIC);
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.java
new file mode 100644
index 00000000000..c8e64c21e2e
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.java
@@ -0,0 +1,42 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class MethodCallExpression extends Expression {
+ private final Expression myMethodCall;
+ private final List myArguments;
+ private final List myConversions;
+ private final boolean myIsResultNullable;
+ private final List myTypeParameters;
+
+ public MethodCallExpression(Expression methodCall, List arguments, List typeParameters) {
+ this(methodCall, arguments, AstUtil.createListWithEmptyString(arguments), false, typeParameters);
+ }
+
+ public MethodCallExpression(Expression methodCall, List arguments, List conversions, boolean nullable, List typeParameters) {
+ myMethodCall = methodCall;
+ myArguments = arguments;
+ myConversions = conversions;
+ myIsResultNullable = nullable;
+ myTypeParameters = typeParameters;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return myIsResultNullable;
+ }
+
+ @NotNull
+ @Override
+ public String toKotlin() {
+ String typeParamsToKotlin = myTypeParameters.size() > 0 ? "<" + AstUtil.joinNodes(myTypeParameters, COMMA_WITH_SPACE) + ">" : EMPTY;
+ List applyConversions = AstUtil.applyConversions(AstUtil.nodesToKotlin(myArguments), myConversions);
+ return myMethodCall.toKotlin() + typeParamsToKotlin + "(" + AstUtil.join(applyConversions, COMMA_WITH_SPACE) + ")";
+ }
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.java b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.java
new file mode 100644
index 00000000000..8329fcbc02a
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.java
@@ -0,0 +1,29 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author ignatov
+ */
+public abstract class Modifier {
+ @NotNull
+ public static final String PUBLIC = "public";
+ @NotNull
+ public static final String PROTECTED = "protected";
+ @NotNull
+ public static final String PRIVATE = "private";
+ @NotNull
+ public static final String INTERNAL = "internal";
+ @NotNull
+ public static final String STATIC = "static";
+ @NotNull
+ public static final String ABSTRACT = "abstract";
+ @NotNull
+ public static final String FINAL = "final";
+ @NotNull
+ public static final String OPEN = "open";
+ @NotNull
+ public static final String NOT_OPEN = "not open";
+ @NotNull
+ public static final String OVERRIDE = "override";
+}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.java
new file mode 100644
index 00000000000..35b4d0239cd
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.java
@@ -0,0 +1,46 @@
+package org.jetbrains.jet.j2k.ast;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.j2k.util.AstUtil;
+
+import java.util.List;
+
+/**
+ * @author ignatov
+ */
+public class NewClassExpression extends Expression {
+ private final Element myName;
+ private final List myArguments;
+ private Expression myQualifier;
+ private List myConversions;
+ @Nullable
+ private AnonymousClass myAnonymousClass = null;
+
+ private NewClassExpression(Element name, List arguments) {
+ myName = name;
+ myQualifier = EMPTY_EXPRESSION;
+ myArguments = arguments;
+ myConversions = AstUtil.createListWithEmptyString(arguments);
+ }
+
+ public NewClassExpression(@NotNull Expression qualifier, @NotNull Element name, @NotNull List arguments,
+ @NotNull List