Package net.jangaroo.jooc.backend

Source Code of net.jangaroo.jooc.backend.ActionScriptCodeGeneratingModelVisitor

package net.jangaroo.jooc.backend;

import net.jangaroo.jooc.model.ActionScriptModel;
import net.jangaroo.jooc.model.AnnotatedModel;
import net.jangaroo.jooc.model.AnnotationModel;
import net.jangaroo.jooc.model.AnnotationPropertyModel;
import net.jangaroo.jooc.model.ClassModel;
import net.jangaroo.jooc.model.CompilationUnitModel;
import net.jangaroo.jooc.model.FieldModel;
import net.jangaroo.jooc.model.MemberModel;
import net.jangaroo.jooc.model.MethodModel;
import net.jangaroo.jooc.model.MethodType;
import net.jangaroo.jooc.model.ModelVisitor;
import net.jangaroo.jooc.model.NamespaceModel;
import net.jangaroo.jooc.model.NamespacedModel;
import net.jangaroo.jooc.model.ParamModel;
import net.jangaroo.jooc.model.PropertyModel;
import net.jangaroo.jooc.model.ReturnModel;
import net.jangaroo.jooc.model.TypedModel;
import net.jangaroo.jooc.model.ValuedModel;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
* A ClassModel visitor that generates ActionScript (API) code.
*/
public class ActionScriptCodeGeneratingModelVisitor implements ModelVisitor {
  private final PrintWriter output;
  private CompilationUnitModel compilationUnitModel;
  private boolean skipAsDoc;
  private String indent = "";

  public ActionScriptCodeGeneratingModelVisitor(Writer writer) {
    output = writer instanceof PrintWriter ? (PrintWriter)writer : new PrintWriter(writer);
  }

  public ActionScriptCodeGeneratingModelVisitor(Writer writer, boolean skipAsDoc) {
    this(writer);
    this.skipAsDoc = skipAsDoc;
  }

  public void setCompilationUnitModel(CompilationUnitModel compilationUnitModel) {
    this.compilationUnitModel = compilationUnitModel;
  }

  @Override
  public void visitCompilationUnit(CompilationUnitModel compilationUnitModel) {
    setCompilationUnitModel(compilationUnitModel);
    output.printf("package %s {%n", compilationUnitModel.getPackage());
    indent = "";
    for (String anImport : compilationUnitModel.getImports()) {
      output.printf("import %s;%n", anImport);
    }
    output.println();
    compilationUnitModel.getPrimaryDeclaration().visit(this);
    indent = "";
    output.print("}");
    output.close();
  }

  @Override
  public void visitClass(ClassModel classModel) {
    visitAnnotations(classModel);
    printAsdoc(classModel.getAsdoc());
    printToken(classModel.getNamespace());
    printTokenIf(classModel.isFinal(), "final");
    printTokenIf(classModel.isDynamic(), "dynamic");
    printToken(classModel.isInterface(), "interface", "class");
    printToken(classModel.getName());
    if (!classModel.isInterface() && !isEmpty(classModel.getSuperclass())) {
      output.printf("extends %s ", classModel.getSuperclass());
    }
    if (!classModel.getInterfaces().isEmpty()) {
      printToken(classModel.isInterface(), "extends", "implements");
      List<String> tokens = classModel.getInterfaces();
      output.print(tokens.get(0));
      for (String token : tokens.subList(1, tokens.size())) {
        output.print(", ");
        output.print(token);
      }
      output.print(" ");
    }
    output.print("{");
    indent = "  ";
    for (MemberModel member : classModel.getMembers()) {
      output.println();
      member.visit(this);
    }
    indent = "";
    output.println("}");
  }

  @Override
  public void visitNamespace(NamespaceModel namespaceModel) {
    visitAnnotations(namespaceModel);
    printAsdoc(namespaceModel.getAsdoc());
    printToken(namespaceModel.getNamespace());
    printToken("namespace");
    output.print(namespaceModel.getName());
    generateValue(namespaceModel);
    output.println(";");
  }

  private void visitAnnotations(AnnotatedModel annotatedModel) {
    for (AnnotationModel annotation : annotatedModel.getAnnotations()) {
      annotation.visit(this);
    }
  }

  private void printParameterList(List<? extends ActionScriptModel> models) {
    output.print("(");
    boolean first = true;
    for (ActionScriptModel model : models) {
      if (first) {
        first = false;
      } else {
        output.print(", ");
      }
      model.visit(this);
    }
    output.print(")");
  }

  private void printCommaSeparatedList(List<String> tokens) {
    output.print(tokens.get(0));
    for (String token : tokens.subList(1, tokens.size())) {
      output.print(", ");
      output.print(token);
    }
  }

  private void printTokenIf(boolean flag, String token) {
    if (flag) {
      printToken(token);
    }
  }

  private void printToken(boolean flag, String trueToken, String falseToken) {
    printToken(flag ? trueToken : falseToken);
  }

  private void printToken(String token) {
    output.printf("%s ", token);
  }

  private void indent() {
    output.print(indent);
  }

  public void flush() {
    output.flush();
  }

  @Override
  public void visitField(FieldModel fieldModel) {
    visitAnnotations(fieldModel);
    printAsdoc(fieldModel.getAsdoc());
    indent();
    printToken(fieldModel.getNamespace());
    printTokenIf(fieldModel.isStatic(), "static");
    printToken(fieldModel.isConst(), "const", "var");
    output.print(fieldModel.getName());
    generateType(fieldModel);
    generateValue(fieldModel);
    output.println(";");
  }

  @Override
  public void visitProperty(PropertyModel propertyModel) {
    throw new IllegalStateException("PropertyModel should not be visited by code generator.");
  }

  private static List<String> PARAM_SUPPRESSING_ASDOC_TAGS = Arrays.asList("@inheritDoc", "@private");

  @Override
  public void visitMethod(MethodModel methodModel) {
    visitAnnotations(methodModel);
    StringBuilder asdoc = new StringBuilder();
    if (methodModel.getAsdoc() != null) {
      asdoc.append(methodModel.getAsdoc());
    }
    if (!PARAM_SUPPRESSING_ASDOC_TAGS.contains(asdoc.toString())) {
      for (ParamModel paramModel : methodModel.getParams()) {
        if (!isEmpty(paramModel.getAsdoc())) {
          asdoc.append("\n  @param ").append(paramModel.getName()).append(" ").append(paramModel.getAsdoc());
        }
      }
      String returnAsDoc = methodModel.getReturnModel().getAsdoc();
      if (!isEmpty(returnAsDoc)) {
        asdoc.append("\n  @return ").append(returnAsDoc);
      }
    }
    printAsdoc(asdoc.toString());
    indent();
    printTokenIf(methodModel.isOverride(), "override");
    String methodBody = methodModel.getBody();
    if (!isPrimaryDeclarationAnInterface()) {
      printToken(methodModel.getNamespace());
      printTokenIf(methodModel.isStatic(), "static");
      printTokenIf(methodModel.isFinal(), "final");
      printTokenIf(methodBody == null, "native");
    }
    printToken("function");
    if (methodModel.getMethodType() != null) {
      printToken(methodModel.getMethodType().toString());
    }
    output.print(methodModel.getName());
    printParameterList(methodModel.getParams());
    methodModel.getReturnModel().visit(this);
    if (methodBody != null) {
      output.printf(" {%n    %s%n  }%n", methodModel.getBody());
    } else {
      output.println(";");
    }
  }

  @Override
  public void visitParam(ParamModel paramModel) {
    if (paramModel.isRest()) {
      output.print("...");
    }
    output.print(paramModel.getName());
    generateType(paramModel);
    if (!paramModel.isRest()) {
      generateValue(paramModel);
    }
  }

  @Override
  public void visitReturn(ReturnModel returnModel) {
    generateType(returnModel);
  }

  @Override
  public void visitAnnotation(AnnotationModel annotationModel) {
    printAsdoc(annotationModel.getAsdoc());
    indent(); output.print("[" + annotationModel.getName());
    if (!annotationModel.getProperties().isEmpty()) {
      printParameterList(annotationModel.getProperties());
    }
    output.println("]");
  }

  @Override
  public void visitAnnotationProperty(AnnotationPropertyModel annotationPropertyModel) {
    if (isEmpty(annotationPropertyModel.getName())) {
      output.print(annotationPropertyModel.getValue());
    } else if (isEmpty(annotationPropertyModel.getValue())) {
      output.print(annotationPropertyModel.getName());
    } else {
      output.printf("%s = %s", annotationPropertyModel.getName(), annotationPropertyModel.getValue());
    }
  }

  private void printAsdoc(String asdoc) {
    if (!skipAsDoc && asdoc != null && asdoc.trim().length() > 0) {
      indent(); output.println("/**");
      indent(); output.println(" * " + asdoc);
      indent(); output.println(" */");
    }
  }

  private boolean isPrimaryDeclarationAnInterface() {
    return compilationUnitModel.getPrimaryDeclaration() instanceof ClassModel
      && ((ClassModel)compilationUnitModel.getPrimaryDeclaration()).isInterface();
  }

  private void generateType(TypedModel typedModel) {
    if (!isEmpty(typedModel.getType())) {
      output.print(":" + typedModel.getType());
    }
  }

  private void generateValue(ValuedModel valuedModel) {
    if (!isEmpty(valuedModel.getValue())) {
      output.print(" = " + valuedModel.getValue());
    }
  }

  private static boolean isEmpty(String string) {
    return string == null || string.trim().length() == 0;
  }

  public static void main(String[] args) {
    // TODO: move to unit test!
    ClassModel classModel = new ClassModel("com.acme.Foo");
    classModel.setAsdoc("This is the Foo class.");

    AnnotationModel annotation = new AnnotationModel("ExtConfig",
      new AnnotationPropertyModel("target", "'foo.Bar'"));
    classModel.addAnnotation(annotation);

    FieldModel field = new FieldModel("FOOBAR");
    field.setType("String");
    field.setConst(true);
    field.setStatic(true);
    field.setNamespace(NamespacedModel.PRIVATE);
    field.setAsdoc("A constant for foo bar.");
    field.setValue("'foo bar baz'");
    classModel.addMember(field);

    MethodModel method = new MethodModel();
    method.setName("doFoo");
    method.setAsdoc("Some method.");
    method.setBody("trace('foo');");
    ParamModel param = new ParamModel();
    param.setName("foo");
    param.setType("com.acme.sub.Bar");
    param.setValue("null");
    method.setParams(Collections.singletonList(param));
    method.setType("int");
    classModel.addMember(method);

    PropertyModel propertyModel = new PropertyModel();
    propertyModel.setName("baz");
    propertyModel.setType("String");
    propertyModel.setAsdoc("The baz is a string.");
    classModel.addMember(propertyModel);

    StringWriter stringWriter = new StringWriter();
    classModel.visit(new ActionScriptCodeGeneratingModelVisitor(stringWriter));
    System.out.println("Result:\n" + stringWriter);
  }
}
TOP

Related Classes of net.jangaroo.jooc.backend.ActionScriptCodeGeneratingModelVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.