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

net.jangaroo.jooc.ast.CompilationUnit Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2008 CoreMedia AG
 * 
 * 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 net.jangaroo.jooc.ast;

import net.jangaroo.jooc.JangarooParser;
import net.jangaroo.jooc.JooSymbol;
import net.jangaroo.jooc.Jooc;
import net.jangaroo.jooc.Scope;
import net.jangaroo.jooc.input.InputSource;
import net.jangaroo.utils.AS3Type;
import net.jangaroo.utils.CompilerUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author Andreas Gawecki
 * @author Frank Wienberg
 */
public class CompilationUnit extends NodeImplBase {
  protected PackageDeclaration packageDeclaration;
  private JooSymbol lBrace;
  private List directives;
  protected IdeDeclaration primaryDeclaration;
  private JooSymbol rBrace;

  private Set compileDependencies = new HashSet<>();
  private List resourceDependencies = new ArrayList<>();
  private Set publicApiDependencies = new HashSet<>();
  private Set usesDependencies = new HashSet<>();
  private Set requiresDependencies = new HashSet<>();
  private Set usedBuiltInIdentifiers = new TreeSet<>();
  private Scope scope;

  public CompilationUnit(PackageDeclaration packageDeclaration, JooSymbol lBrace, List directives, IdeDeclaration primaryDeclaration, JooSymbol rBrace, List secondaryDeclarations) {
    this.packageDeclaration = packageDeclaration;
    this.lBrace = lBrace;
    this.directives = directives;
    this.primaryDeclaration = primaryDeclaration;
    if (primaryDeclaration instanceof ClassDeclaration) {
      ((ClassDeclaration) primaryDeclaration).setSecondaryDeclarations(secondaryDeclarations);
      if (secondaryDeclarations != null) {
        for (IdeDeclaration secondaryDeclaration : secondaryDeclarations) {
          if (secondaryDeclaration instanceof ClassDeclaration) {
            this.directives.addAll(((ClassDeclaration) secondaryDeclaration).getDirectives());
          }
        }
      }
    }
    this.rBrace = rBrace;
  }

  public String getQualifiedNameStr() {
    return CompilerUtils.qName(getPackageDeclaration().getQualifiedNameStr(), getPrimaryDeclaration().getName());
  }

  public boolean isClass() {
    return getPrimaryDeclaration() instanceof ClassDeclaration;
  }

  @Override
  public List getChildren() {
    List result = new ArrayList<>(makeChildren(super.getChildren(), packageDeclaration, directives, primaryDeclaration));
    if (primaryDeclaration instanceof ClassDeclaration) {
      result.addAll(((ClassDeclaration) primaryDeclaration).getSecondaryDeclarations());
    }
    return result;
  }

  public List getDirectives() {
    return directives;
  }

  @Override
  public void visit(AstVisitor visitor) throws IOException {
    visitor.visitCompilationUnit(this);
  }

  private void addStarImport(final Ide packageIde) {
    ImportDirective importDirective = new ImportDirective(packageIde, AS3Type.ANY.toString());
    directives.add(0, importDirective);
  }

  @Override
  public void scope(final Scope scope) {
    withNewDeclarationScope(this, scope, new Scoped() {
      @Override
      public void run(final Scope scope) {
        Ide packageIde = packageDeclaration.getIde();
        packageDeclaration.scope(scope);
        if (packageIde != null) {
          // add implicit same package import
          addStarImport(packageIde);
        }
        // add implicit toplevel package import
        addStarImport(null);
        for (AstNode node : getDirectives()) {
          node.scope(scope);
        }
        withNewDeclarationScope(packageDeclaration, scope, new Scoped() {
          @Override
          public void run(final Scope scope) {
            CompilationUnit.this.scope = scope;
            primaryDeclaration.scope(scope);
          }
        });
      }
    });
  }

  public PackageDeclaration getPackageDeclaration() {
    return packageDeclaration;
  }

  public IdeDeclaration getPrimaryDeclaration() {
    return primaryDeclaration;
  }

  public JooSymbol getLBrace() {
    return lBrace;
  }

  public JooSymbol getRBrace() {
    return rBrace;
  }

  public List getResourceDependencies() {
    return resourceDependencies;
  }

  public Set getPublicApiDependencies() {
    return publicApiDependencies;
  }

  public Set getRuntimeDependencies() {
    Set runtimeDependencies = new HashSet<>(requiresDependencies);
    runtimeDependencies.addAll(usesDependencies);
    return runtimeDependencies;
  }

  public Set getRuntimeDependencies(boolean required) {
    return required ? requiresDependencies : usesDependencies;
  }

  public Set getCompileDependencies() {
    return compileDependencies;
  }

  public InputSource getInputSource() {
    return scope.getCompiler().getInputSource(this);
  }

  public void analyze(AstNode parentNode) {
    super.analyze(parentNode);
    packageDeclaration.analyze(this);
    analyze(packageDeclaration, directives);
    primaryDeclaration.analyze(this);
  }

  public List getAnnotations() {
    return getPrimaryDeclaration().getAnnotations();
  }

  public JooSymbol getSymbol() {
    return packageDeclaration.getSymbol();
  }

  public static CompilationUnit mapMixinInterface(CompilationUnit compilationUnit) {
    if (compilationUnit != null && compilationUnit.getPrimaryDeclaration() instanceof ClassDeclaration
            && ((ClassDeclaration)compilationUnit.getPrimaryDeclaration()).isInterface()) {
      CompilationUnit mixinCompilationUnit = getMixinCompilationUnit(compilationUnit.getPrimaryDeclaration());
      if (mixinCompilationUnit != null) {
        return mixinCompilationUnit;
      }
    }
    return compilationUnit;
  }

  public static CompilationUnit getMixinCompilationUnit(Declaration declaration) {
    Annotation mixinAnnotation = declaration.getAnnotation(Jooc.MIXIN_ANNOTATION_NAME);
    if (mixinAnnotation != null) {
      Iterator mixinClassNames = getAnnotationDefaultParameterStringValues(mixinAnnotation).iterator();
      if (mixinClassNames.hasNext()) {
        String mixinClassName = mixinClassNames.next();
        CompilationUnit mixinCompilationUnit = mixinAnnotation.getIde().getScope().getCompiler().getCompilationUnit(mixinClassName);
        if (mixinCompilationUnit == null) {
          throw Jooc.error(declaration, "Mixin annotation refers to unresolvable class '" + mixinClassName + "'.");
        }
        return mixinCompilationUnit;
      }
    }
    return null;
  }

  public void addDependency(CompilationUnit otherUnit, Boolean required) {
    otherUnit = mapMixinInterface(otherUnit);
    // Predefined ides have a null unit.
    // Self dependencies are ignored.
    if (otherUnit != null && otherUnit != this) {
      String qName = otherUnit.getPrimaryDeclaration().getQualifiedNameStr();
      compileDependencies.add(qName);
      // not a type-only dependency and not already required:
      if (required != null && !requiresDependencies.contains(qName)) {
        // Dependencies on other modules may always be considered required,
        // because they cannot lead to cycles.
        if (required || !otherUnit.isInSourcePath()) {
          requiresDependencies.add(qName);
          usesDependencies.remove(qName); // required implied used
        } else {
          usesDependencies.add(qName);
        }
      }
    }
  }

  private static List getAnnotationDefaultParameterStringValues(Annotation annotation) {
    List values = new ArrayList<>();
    CommaSeparatedList current = annotation.getOptAnnotationParameters();
    while (current != null) {
      AnnotationParameter head = current.getHead();
      if (head.getOptName() == null) {
        AstNode value = head.getValue();
        if (value instanceof LiteralExpr) {
          LiteralExpr literal = (LiteralExpr) value;
          Object jooValue = literal.getSymbol().getJooValue();
          if (jooValue instanceof String) {
            values.add((String)jooValue);
          }
        }
      }
      current = current.getTail();
    }
    return values;
  }

  public void addPublicApiDependency(CompilationUnit otherUnit) {
    // predefined ides have a null unit
    if (otherUnit != null && otherUnit != this) {
      //todo extend runtime to load units with primary decls other than classes
      final IdeDeclaration otherUnitPrimaryDeclaration = otherUnit.getPrimaryDeclaration();
      if (otherUnitPrimaryDeclaration instanceof ClassDeclaration
        || otherUnitPrimaryDeclaration instanceof NamespaceDeclaration) {
        // It is a class ...
        String qname = otherUnitPrimaryDeclaration.getQualifiedNameStr();
        if (qname.indexOf('.') != -1) {
          // ... outside of the root package.
          publicApiDependencies.add(qname);
        }
      }
    }
  }

  @Override
  public String toString() {
    return "CompilationUnit{" +
            "packageDeclaration=" + packageDeclaration +
            ", primaryDeclaration=" + primaryDeclaration +
            '}';
  }

  public boolean isInSourcePath() {
    return getInputSource().isInSourcePath();
  }

  public void addBuiltInIdentifierUsage(String builtInIdentifier) {
    usedBuiltInIdentifiers.add(builtInIdentifier);
  }

  public Set getUsedBuiltInIdentifiers() {
    return usedBuiltInIdentifiers;
  }

  public String cutOffExtNamespace(String targetName) {
    String extNamespace = getInputSource().getExtNamespace();
    if (extNamespace != null && !extNamespace.isEmpty()) {
      if (targetName.equals(extNamespace)) {
        // top-level namespace export like "Ext":
        targetName = "";
      } else {
        if (!targetName.startsWith(extNamespace + ".")) {
          throw JangarooParser.error("Source file fully-qualified name " + targetName + " does not start with configured extNamespace " + extNamespace);
        }
        // also cut off the ".":
        targetName = targetName.substring(extNamespace.length() + 1);
      }
    }
    return targetName;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy