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

org.teavm.jso.impl.JSAliasRenderer Maven / Gradle / Ivy

There is a newer version: 0.10.2
Show newest version
/*
 *  Copyright 2015 Alexey Andreev.
 *
 *  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.teavm.jso.impl;

import java.io.IOException;
import java.util.Map;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.RenderingContext;
import org.teavm.jso.impl.JSDependencyListener.ExposedClass;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodDescriptor;
import org.teavm.vm.BuildTarget;
import org.teavm.vm.spi.RendererListener;

/**
 *
 * @author Alexey Andreev
 */
class JSAliasRenderer implements RendererListener {
    private static String variableChars = "abcdefghijklmnopqrstuvwxyz";
    private JSDependencyListener dependencyListener;
    private SourceWriter writer;
    private ClassReaderSource classSource;

    public JSAliasRenderer(JSDependencyListener dependencyListener) {
        this.dependencyListener = dependencyListener;
    }

    @Override
    public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
        writer = context.getWriter();
        classSource = context.getClassSource();
    }

    @Override
    public void complete() throws IOException {
        if (!dependencyListener.isAnyAliasExists()) {
            return;
        }

        writer.append("(function()").ws().append("{").softNewLine().indent();
        writer.append("var c;").softNewLine();
        for (Map.Entry entry : dependencyListener.getExposedClasses().entrySet()) {
            ExposedClass cls = entry.getValue();
            ClassReader classReader = classSource.get(entry.getKey());
            if (classReader == null || cls.methods.isEmpty()) {
                continue;
            }
            boolean first = true;
            for (Map.Entry aliasEntry : cls.methods.entrySet()) {
                if (classReader.getMethod(aliasEntry.getKey()) == null) {
                    continue;
                }
                if (first) {
                    writer.append("c").ws().append("=").ws().appendClass(entry.getKey()).append(".prototype;")
                            .softNewLine();
                    first = false;
                }
                if (isKeyword(aliasEntry.getValue())) {
                    writer.append("c[\"").append(aliasEntry.getValue()).append("\"]");
                } else {
                    writer.append("c.").append(aliasEntry.getValue());
                }
                writer.ws().append("=").ws().append("c.").appendMethod(aliasEntry.getKey()).append(";").softNewLine();
            }

            if (cls.functorField != null) {
                writeFunctor(cls);
            }
        }
        writer.outdent().append("})();").newLine();
    }

    private boolean isKeyword(String id) {
        switch (id) {
            case "with":
            case "delete":
            case "in":
            case "undefined":
            case "debugger":
            case "export":
            case "function":
            case "let":
            case "var":
            case "typeof":
            case "yield":
                return true;
            default:
                return false;
        }
    }

    private void writeFunctor(ExposedClass cls) throws IOException {
        String alias = cls.methods.get(cls.functorMethod);
        if (alias == null) {
            return;
        }

        writer.append("c.jso$functor$").append(alias).ws().append("=").ws().append("function()").ws().append("{")
                .indent().softNewLine();
        writer.append("if").ws().append("(!this.").appendField(cls.functorField).append(")").ws().append("{")
                .indent().softNewLine();
        writer.append("var self").ws().append('=').ws().append("this;").softNewLine();

        writer.append("this.").appendField(cls.functorField).ws().append('=').ws().append("function(");
        appendArguments(cls.functorMethod.parameterCount());
        writer.append(")").ws().append('{').indent().softNewLine();
        writer.append("return self.").appendMethod(cls.functorMethod).append('(');
        appendArguments(cls.functorMethod.parameterCount());
        writer.append(");").softNewLine();
        writer.outdent().append("};").softNewLine();

        writer.outdent().append("}").softNewLine();
        writer.append("return this.").appendField(cls.functorField).append(';').softNewLine();
        writer.outdent().append("};").softNewLine();
    }

    private void appendArguments(int count) throws IOException {
        for (int i = 0; i < count; ++i) {
            if (i > 0) {
                writer.append(',').ws();
            }
            writer.append(variableName(i));
        }
    }

    private String variableName(int index) {
        StringBuilder sb = new StringBuilder();
        sb.append(variableChars.charAt(index % variableChars.length()));
        index /= variableChars.length();
        if (index > 0) {
            sb.append(index);
        }
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy