Package net.jangaroo.jooc

Source Code of net.jangaroo.jooc.DeclarationScope

/*
* Copyright 2010 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;

import net.jangaroo.utils.AS3Type;
import net.jangaroo.jooc.ast.AstNode;
import net.jangaroo.jooc.ast.ClassDeclaration;
import net.jangaroo.jooc.ast.CompilationUnit;
import net.jangaroo.jooc.ast.FunctionDeclaration;
import net.jangaroo.jooc.ast.FunctionExpr;
import net.jangaroo.jooc.ast.Ide;
import net.jangaroo.jooc.ast.IdeDeclaration;
import net.jangaroo.jooc.ast.ImportDirective;
import net.jangaroo.jooc.ast.PackageDeclaration;
import net.jangaroo.jooc.ast.QualifiedIde;
import net.jangaroo.jooc.ast.VariableDeclaration;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
* @author Andreas Gawecki
*/
public class DeclarationScope extends ScopeImplBase {

  private static final Pattern AUX_VAR_NAME_PATTERN = Pattern.compile("\\$([0-9]+)");

  private AstNode definingNode;
  private Set<String> packages = new HashSet<String>();
  private Map<String, IdeDeclaration> ides = new HashMap<String, IdeDeclaration>();
  private Map<String, List<ImportDirective>> importsByName = new HashMap<String, List<ImportDirective>>();
  private Map<String, ImportDirective> importsByQualifiedName = new HashMap<String, ImportDirective>();
  private boolean isInstanceScope = false;

  public boolean isPackage(String fullyQualifiedName) {
    return packages.contains(fullyQualifiedName) || super.isPackage(fullyQualifiedName);
  }

  public DeclarationScope(AstNode definingNode, Scope parent) {
    super(parent);
    this.definingNode = definingNode;
  }

  @Override
  public AstNode getDefiningNode() {
    return definingNode;
  }

  @Override
  public void addImport(final ImportDirective importDirective) {
    Ide ide = importDirective.getIde();
    String name = ide.getName();
    Ide packageIde = ide.getQualifier();
    String packageName = "";
    final CompilationUnit compilationUnit = getCompilationUnit();
    if (packageIde != null) {
      packageName = packageIde.getQualifiedNameStr();
      packages.add(packageName);
    }
    if (AS3Type.ANY.toString().equals(name)) {
      final List<String> packageIdes = compilationUnit.getCompiler().getPackageIdes(packageName);
      for (String typeToImport : packageIdes) {
        ImportDirective implicitImport = new ImportDirective(packageIde, typeToImport);
        implicitImport.scope(this);
      }
    } else {
      if (importsByName.containsKey(name)) {
        final List<ImportDirective> directiveList = importsByName.get(name);
        if (isImportAlreadyAdded(directiveList, importDirective)) {
          return;
        }
        directiveList.add(importDirective);
      } else {
        List<ImportDirective> list = new LinkedList<ImportDirective>();
        list.add(importDirective);
        importsByName.put(name, list);
      }
      if (ides.containsKey(name)) {
        // name clash with value ide - error according to adobe
        throw new CompilerError(importDirective.getIde().getSymbol(), "attempt to redefine identifier " + name + " by import");
      }
      // define the fully qualified name if not (might be the same string for top level imports):
      final String qualifiedName = ide.getQualifiedNameStr();
      importsByQualifiedName.put(qualifiedName, importDirective);
    }
  }

  private boolean isImportAlreadyAdded(final List<ImportDirective> directiveList, final ImportDirective importDirective) {
    final String qname = importDirective.getQualifiedName();
    for (ImportDirective directive : directiveList) {
      if (directive.getQualifiedName().equals(qname)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public IdeDeclaration declareIde(IdeDeclaration decl) {
    final Ide ide = decl.getIde();
    final String name = ide.getName();
    if (importsByName.containsKey(name)) {
      throw new CompilerError(ide.getSymbol(), "attempt to redefine an imported identifier " + name);
    }
    if (AUX_VAR_NAME_PATTERN.matcher(name).matches()) {
      DeclarationScope packageDeclarationScope = getPackageDeclarationScope();
      if (packageDeclarationScope != null && packageDeclarationScope != this) {
        // also declare local auxiliary vars in package scope to reserve them so they are not used for package names:
        new VariableDeclaration(null, new Ide(name), null).scope(packageDeclarationScope);
      }
    }
    return ides.put(name, decl);
  }

  @Override
  public IdeDeclaration lookupDeclaration(Ide ide) {
    IdeDeclaration decl = null;
    if (ide instanceof QualifiedIde) {
      String qname = ide.getQualifiedNameStr();
      if (importsByQualifiedName.containsKey(qname)) {
        return resolveImport(importsByQualifiedName.get(qname));
      }
      if (ide.isQualifiedByThis()) {
        return getClassDeclaration().resolvePropertyDeclaration(ide.getName());
      }
      if (ide.isQualifiedBySuper()) {
        final IdeDeclaration superTypeDeclaration = getClassDeclaration().getSuperTypeDeclaration();
        return superTypeDeclaration == null ? null : superTypeDeclaration.resolvePropertyDeclaration(ide.getName());
      }
    } else {
      final String name = ide.getName();
      final List<ImportDirective> importsOfThisIde = importsByName.get(name);
      if (importsOfThisIde != null) {
        if (importsOfThisIde.size() > 1) {
          ambigousImport(ide, importsOfThisIde);
        }
        return resolveImport(importsOfThisIde.get(0));
      }
      decl = ides.get(ide.getName());
      if (decl == null && getDefiningNode() != null && getClassDeclaration() == getDefiningNode()) {
        decl = getClassDeclaration().resolvePropertyDeclaration(ide.getName());
        if (decl != null && !isInstanceScope && !decl.isStatic()) {
          decl = null;
        }
      }
    }
    return decl != null ? decl : super.lookupDeclaration(ide);
  }


  private IdeDeclaration resolveImport(final ImportDirective importDirective) {
    return getCompilationUnit().getCompiler().resolveImport(importDirective);
  }

  private void ambigousImport(Ide ide, Collection<ImportDirective> importsOfThisIde) {
    boolean isFirst = true;
    StringBuilder msg = new StringBuilder();
    msg.append("Can not resolve a multiname reference unambiguously: ");
    for (ImportDirective importDirective : importsOfThisIde) {
      if (!isFirst) {
        msg.append(" and ");
      }
      isFirst = false;
      msg.append(importDirective.getQualifiedName());
      JooSymbol importedIdeSymbol = resolveImport(importDirective).getSymbol();
      msg.append("(").append(importedIdeSymbol.getFileName()).append(":").append(importedIdeSymbol.getLine()).append(",").append(importedIdeSymbol.getColumn());
    }
    msg.append(" are available.");
    throw new CompilerError(ide.getSymbol(), msg.toString());
  }

  public boolean isDeclared(Ide ide) {
    return ides.containsKey(ide.getQualifiedNameStr()) || super.isDeclared(ide);
  }

  @Override
  public Ide findFreeAuxVar() {
    int i = 1;
    while (true) {
      String auxVarName = "$" + i;
      Ide auxVar = new Ide(new JooSymbol(auxVarName));
      if (lookupDeclaration(auxVar) == null) {
        return auxVar;
      }
      ++i;
    }
  }

  @Override
  public Ide createAuxVar(Scope lookupScope) {
    Ide auxVar = findFreeAuxVar();
    new VariableDeclaration(null, auxVar, null).scope(this);
    return auxVar;
  }

  @Override
  public CompilationUnit getCompilationUnit() {
    if (definingNode instanceof CompilationUnit) {
      return (CompilationUnit) definingNode;
    }
    return super.getCompilationUnit();
  }

  @Override
  public PackageDeclaration getPackageDeclaration() {
    if (definingNode instanceof PackageDeclaration) {
      return (PackageDeclaration) definingNode;
    }
    return super.getPackageDeclaration();
  }

  @Override
  public ClassDeclaration getClassDeclaration() {
    if (definingNode instanceof ClassDeclaration) {
      return (ClassDeclaration) definingNode;
    }
    return super.getClassDeclaration();
  }

  @Override
  public DeclarationScope getPackageDeclarationScope() {
    return definingNode instanceof PackageDeclaration ? this : super.getPackageDeclarationScope();
  }

  @Override
  public FunctionDeclaration getMethodDeclaration() {
    if (definingNode instanceof FunctionDeclaration) {
      final FunctionDeclaration functionDeclaration = (FunctionDeclaration) definingNode;
      if (functionDeclaration.isClassMember()) {
        return functionDeclaration;
      }
    }
    return super.getMethodDeclaration();
  }

  @Override
  public FunctionExpr getFunctionExpr() {
    if (definingNode instanceof FunctionExpr) {
      return (FunctionExpr) definingNode;
    }
    return super.getFunctionExpr();
  }

  public void setIsInstanceScope(boolean b) {
    isInstanceScope = true;
  }
}
TOP

Related Classes of net.jangaroo.jooc.DeclarationScope

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.