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

io.vertx.codetrans.JavaScriptLang Maven / Gradle / Ivy

There is a newer version: 4.1.0.Beta1
Show newest version
package io.vertx.codetrans;

import com.sun.source.tree.LambdaExpressionTree;
import io.vertx.codegen.Helper;
import io.vertx.codegen.TypeInfo;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * @author Julien Viet
 */
public class JavaScriptLang implements Lang {

  @Override
  public void renderBinary(ExpressionModel left, String op, ExpressionModel right, CodeWriter writer) {
    switch (op) {
      case "==":
        op = "===";
        break;
      case "!=":
        op = "!==";
        break;
    }
    Lang.super.renderBinary(left, op, right, writer);
  }

  @Override
  public Callable compile(ClassLoader loader, String path) throws Exception {
    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine engine = mgr.getEngineByName("nashorn");
    engine.put("__engine", engine);
    InputStream require = getClass().getClassLoader().getResourceAsStream("vertx-js/util/require.js");
    if (require == null) {
      throw new Exception("Not require.js");
    }
    engine.put(ScriptEngine.FILENAME, "require.js");
    engine.eval(new InputStreamReader(require));
    engine.eval("var console = require('vertx-js/util/console')");
    InputStream source = loader.getResourceAsStream(path + ".js");
    if (source == null) {
      throw new Exception("Could not find " + path + ".js");
    }
    return () -> engine.eval(new InputStreamReader(source));
  }

  static class JavaScriptRenderer extends CodeWriter {
    LinkedHashSet modules = new LinkedHashSet<>();
    JavaScriptRenderer(Lang lang) {
      super(lang);
    }
  }

  @Override
  public void renderBlock(List statements, CodeWriter writer) {
    if (writer instanceof JavaScriptRenderer) {
      Lang.super.renderBlock(statements, writer);
    } else {
      JavaScriptRenderer langRenderer = new JavaScriptRenderer(this);
      Lang.super.renderBlock(statements, langRenderer);
      for (TypeInfo.Class module : langRenderer.modules) {
        writer.append("var ").append(module.getSimpleName()).append(" = require(\"").
            append(module.getModuleName()).append("-js/").append(Helper.convertCamelCaseToUnderscores(module.getSimpleName())).append("\");\n");
      }
      writer.append(langRenderer.getBuffer());
    }
  }

  @Override
  public String getExtension() {
    return "js";
  }

  @Override
  public ExpressionModel classExpression(TypeInfo.Class type) {
    return ExpressionModel.render("Java.type(\"" + type.getName() + "\")");
  }

  @Override
  public ExpressionModel console(ExpressionModel expression) {
    return ExpressionModel.render(renderer -> {
      renderer.append("console.log(");
      expression.render(renderer);
      renderer.append(")");
    });
  }

  public void renderOptions(OptionsModel options, CodeWriter writer) {
    renderJsonObject(options.getMembers(), writer, false);
  }

  public void renderJsonObject(JsonObjectModel jsonObject, CodeWriter writer) {
    renderJsonObject(jsonObject.getMembers(), writer, true);
  }

  public void renderJsonArray(JsonArrayModel jsonArray, CodeWriter writer) {
    renderJsonArray(jsonArray.getValues(), writer);
  }

  private void renderJsonObject(Iterable members, CodeWriter writer, boolean unquote) {
    writer.append("{");
    for (Iterator iterator = members.iterator();iterator.hasNext();) {
      Member member = iterator.next();
      String name = member.name.render(writer.getLang());
      if (unquote) {
        name = io.vertx.codetrans.Helper.unwrapQuotedString(name);
      }
      writer.append("\"").append(name).append("\" : ");
      if (member instanceof Member.Single) {
        ((Member.Single) member).value.render(writer);
      } else {
        renderJsonArray(((Member.Array) member).values, writer);
      }
      if (iterator.hasNext()) {
        writer.append(", ");
      }
    }
    writer.append("}");
  }

  private void renderJsonArray(List values, CodeWriter writer) {
    writer.append('[');
    for (int i = 0;i < values.size();i++) {
      if (i > 0) {
        writer.append(", ");
      }
      values.get(i).render(writer);
    }
    writer.append(']');
  }

  @Override
  public ExpressionModel asyncResultHandler(LambdaExpressionTree.BodyKind bodyKind, String resultName, CodeModel body) {
    return lambda(null, null, Arrays.asList(resultName, resultName + "_err"), body);
  }

  @Override
  public ExpressionModel lambda(LambdaExpressionTree.BodyKind bodyKind, List parameterTypes, List parameterNames, CodeModel body) {
    return ExpressionModel.render((renderer) -> {
      renderer.append("function (");
      for (int i = 0; i < parameterNames.size(); i++) {
        if (i > 0) {
          renderer.append(", ");
        }
        renderer.append(parameterNames.get(i));
      }
      renderer.append(") {\n");
      renderer.indent();
      body.render(renderer);
      renderer.unindent();
      renderer.append("}");
    });
  }

  @Override
  public ExpressionModel staticFactory(TypeInfo.Class type, String methodName) {
    return ExpressionModel.render(renderer -> {
      JavaScriptRenderer jsRenderer = (JavaScriptRenderer) renderer;
      jsRenderer.modules.add(type);
      renderer.append(type.getSimpleName()).append('.').append(methodName);
    });
  }

  @Override
  public StatementModel variable(TypeInfo type, String name, ExpressionModel initializer) {
    return StatementModel.render(renderer -> {
      renderer.append("var ").append(name);
      if (initializer != null) {
        renderer.append(" = ");
        initializer.render(renderer);
      }
    });
  }

  @Override
  public StatementModel enhancedForLoop(String variableName, ExpressionModel expression, StatementModel body) {
    return StatementModel.render((renderer) -> {
      renderer.append("Array.prototype.forEach.call(");
      expression.render(renderer);
      renderer.append(", function(").append(variableName).append(") {\n");
      renderer.indent();
      body.render(renderer);
      renderer.unindent();
      renderer.append("})");
    });
  }

  @Override
  public StatementModel forLoop(StatementModel initializer, ExpressionModel condition, ExpressionModel update, StatementModel body) {
    return StatementModel.render((renderer) -> {
      renderer.append("for (");
      initializer.render(renderer);
      renderer.append(';');
      condition.render(renderer);
      renderer.append(';');
      update.render(renderer);
      renderer.append(") {\n");
      renderer.indent();
      body.render(renderer);
      renderer.unindent();
      renderer.append("}");
    });
  }

  @Override
  public ExpressionModel asyncResult(String identifier) {
    return ExpressionModel.forMemberSelect((member) -> {
      switch (member) {
        case "succeeded":
          return ExpressionModel.forMethodInvocation((args) -> ExpressionModel.render("(" + identifier + " != null)"));
        case "result":
          return ExpressionModel.forMethodInvocation((args) -> ExpressionModel.render(identifier));
        case "cause":
          return ExpressionModel.forMethodInvocation((args) -> ExpressionModel.render(identifier + "_err"));
        case "failed":
          return ExpressionModel.forMethodInvocation((args) -> ExpressionModel.render("(" + identifier + " == null)"));
        default:
          throw new UnsupportedOperationException("Not implemented");
      }
    });
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy