Package net.jangaroo.jooc.ast

Source Code of net.jangaroo.jooc.ast.ClassDeclaration

/*
* 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.CompilerError;
import net.jangaroo.jooc.DeclarationScope;
import net.jangaroo.jooc.JooSymbol;
import net.jangaroo.jooc.Jooc;
import net.jangaroo.jooc.Scope;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @author Andreas Gawecki
* @author Frank Wienberg
*/
public class ClassDeclaration extends IdeDeclaration {

  private JooSymbol symClass;
  private Extends optExtends;
  private Map<String, TypedIdeDeclaration> members = new LinkedHashMap<String, TypedIdeDeclaration>();
  private Map<String, TypedIdeDeclaration> staticMembers = new LinkedHashMap<String, TypedIdeDeclaration>();
  private Set<String> classInit = new HashSet<String>();
  private ClassBody body;
  private FunctionDeclaration constructor = null;
  private Type thisType;
  private Type superType;
  private List<VariableDeclaration> fieldsWithInitializer = new ArrayList<VariableDeclaration>();
  private List<IdeDeclaration> secondaryDeclarations = Collections.emptyList();
  private int inheritanceLevel = -1;

  private Implements optImplements;
  private Scope scope;

  public ClassDeclaration(JooSymbol[] modifiers, JooSymbol cls, Ide ide, Extends ext, Implements impl, ClassBody body) {
    super(modifiers, ide);
    this.symClass = cls;
    this.optExtends = ext;
    this.optImplements = impl;
    this.body = body;
  }

  @Override
  public List<? extends AstNode> getChildren() {
    return makeChildren(super.getChildren(), optExtends, optImplements, body);
  }

  public FunctionDeclaration getConstructor() {
    return constructor;
  }

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

  @Override
  protected int getAllowedModifiers() {
    return MODIFIER_ABSTRACT | MODIFIER_FINAL | MODIFIERS_SCOPE | MODIFIER_STATIC | MODIFIER_DYNAMIC;
  }

  public boolean isInterface() {
    return "interface".equals(getSymClass().getText());
  }

  public boolean isAbstract() {
    return isInterface() || super.isAbstract();
  }

  @Override
  public boolean isStatic() {
    return super.isStatic() || !isPrimaryDeclaration(); // secondary classes are always static!
  }

  @Override
  public boolean isClassMember() {
    return super.isClassMember() || !isPrimaryDeclaration(); // secondary classes are (static) class members!
  }

  public String getName() {
    return getIde().getName();
  }

  public void setConstructor(FunctionDeclaration methodDeclaration) {
    if (constructor != null) {
      throw Jooc.error(methodDeclaration, "Only one constructor allowed per class");
    }
//     if (methodDeclaration != body.declararations.get(0))
//       Jooc.error(methodDeclaration, "Constructor declaration must be the first declaration in a class");
    constructor = methodDeclaration;
  }

  public JooSymbol getSymClass() {
    return symClass;
  }

  public Extends getOptExtends() {
    return optExtends;
  }

  public Implements getOptImplements() {
    return optImplements;
  }

  public List<VariableDeclaration> getFieldsWithInitializer() {
    return fieldsWithInitializer;
  }

  public ClassBody getBody() {
    return body;
  }

  public List<IdeDeclaration> getSecondaryDeclarations() {
    return secondaryDeclarations;
  }

  public Map<String, TypedIdeDeclaration> getStaticMembers() {
    return staticMembers;
  }

  public Set<String> getClassInit() {
    return classInit;
  }

  @Override
  public void scope(final Scope scope) {
    this.scope = scope;
    // this declares this class's ide:
    super.scope(scope);

    // define these here so they get the right scope:
    thisType = new Type(new Ide(getIde().getSymbol()));
    superType = "Object".equals(getQualifiedNameStr()) ? null
            : new Type(getOptExtends() == null ? new Ide("Object") : getOptExtends().getSuperClass());

    thisType.scope(scope);
    if (superType != null) {
      superType.scope(scope);
    }
    if (getOptImplements() != null) {
      getOptImplements().scope(scope);
    }

    // one scope for static members...
    withNewDeclarationScope(this, scope, new Scoped() {
      @Override
      public void run(final Scope staticScope) {
        // ...and one scope for instance members!
        withNewDeclarationScope(ClassDeclaration.this, staticScope, new Scoped() {
          @Override
          public void run(final Scope instanceScope) {
            //todo ugly, maybe we should define ClassScope implements Scope to lookup inherited members
            if(instanceScope instanceof  DeclarationScope) {
              ((DeclarationScope) instanceScope).setIsInstanceScope(true);
            }
            body.scope(staticScope, instanceScope);
          }
        });
        for (IdeDeclaration secondaryDeclaration : secondaryDeclarations) {
          secondaryDeclaration.scope(staticScope); //todo is this the correct scope?!
        }
      }
    });
  }

  @Override
  public void handleDuplicateDeclaration(final Scope scope, final AstNode oldNode) {
    // allow same package import of this class
    if (!(oldNode instanceof ImportDirective)) { //todo check for same package import
      super.handleDuplicateDeclaration(scope, oldNode);
    }
  }

  public void analyze(AstNode parentNode) {
    super.analyze(parentNode);
    if (getOptExtends() != null) {
      getOptExtends().analyze(this);
      String packageName = getOptExtends().getSuperClass().getDeclaration().getPackageDeclaration().getQualifiedNameStr();
      if (packageName.length() > 0 && parentNode instanceof CompilationUnit) {
        ((CompilationUnit)parentNode).getAuxVarForPackage(scope, packageName);
      }
    }
    if (getOptImplements() != null) {
      getOptImplements().analyze(this);
    }
    body.analyze(this);
    for (IdeDeclaration secondaryDeclaration : secondaryDeclarations) {
      secondaryDeclaration.analyze(this);
    }
  }

  public void registerMember(TypedIdeDeclaration memberDeclaration) {
    String name = memberDeclaration.getName();
    if (name.length() != 0) {
      (memberDeclaration.isStatic() ? staticMembers : members).put(name, memberDeclaration);
    }
  }

  public TypedIdeDeclaration getMemberDeclaration(String memberName) {
    return members.get(memberName);
  }

  public TypedIdeDeclaration getStaticMemberDeclaration(String memberName) {
    return staticMembers.get(memberName);
  }

  public void addInitIfGlobalVar(Ide ide) {
    addInitIf(ide, false);
  }

  public void addInitIfClassOrGlobalVar(Ide ide) {
    addInitIf(ide, true);
  }

  private void addInitIf(Ide ide, boolean allowClass) {
    final IdeDeclaration decl = ide.getDeclaration(false);
    if (decl != this      // Classes should not try to init themselves. It does not help and it produces strange warnings.
      && (allowClass && decl instanceof ClassDeclaration || decl instanceof VariableDeclaration) // no init necessary for package-scope functions!
      && decl.isPrimaryDeclaration()) {
      CompilationUnit compilationUnit = decl.getIde().getScope().getCompilationUnit();
      if (compilationUnit.getAnnotation(Jooc.NATIVE_ANNOTATION_NAME) == null) {
        classInit.add(decl.getQualifiedNameStr());
      }
    }
  }

  public boolean isSubclassOf(final ClassDeclaration classDeclaration) {
    ClassDeclaration superTypeDeclaration = getSuperTypeDeclaration();
    return superTypeDeclaration != null &&
            (superTypeDeclaration == classDeclaration || superTypeDeclaration.isSubclassOf(classDeclaration)); // NOSONAR no equals here
  }

  public Type getThisType() {
    return thisType;
  }

  public Type getSuperType() {
    return superType;
  }

  public void setSecondaryDeclarations(List<IdeDeclaration> secondaryDeclarations) {
    this.secondaryDeclarations = secondaryDeclarations;
  }

  @Override
  public IdeDeclaration resolveDeclaration() {
    return this;
  }

  /**
   * Lookup a non-static member of the given name
   *
   * @param ide the member name
   * @return a non-static member if found, null otherwise
   */
  public IdeDeclaration resolvePropertyDeclaration(String ide) {
    return resolvePropertyDeclaration1(ide, this, new HashSet<ClassDeclaration>(), new LinkedList<ClassDeclaration>());
  }

  private IdeDeclaration resolvePropertyDeclaration1(String ide, ClassDeclaration classDecl, Set<ClassDeclaration> visited, Deque<ClassDeclaration> chain) {
    if (visited.contains(classDecl)) {
      if (chain.contains(classDecl)) {
        throw new CompilerError(classDecl.getSymbol(), "cyclic superclass chain");
      }
      return null;
    }
    visited.add(classDecl);
    final int chainSize = chain.size();
    chain.add(classDecl);
    IdeDeclaration declaration = classDecl.getMemberDeclaration(ide);
    if (declaration == null) {
      declaration = classDecl.getStaticMemberDeclaration(ide);
    }
    if (declaration == null && classDecl.getSuperType() != null) {
      declaration = resolvePropertyInSuper(ide, classDecl, visited, chain, classDecl.getSuperType().getIde());
    }
    if (declaration == null && classDecl.getOptImplements() != null) {
      CommaSeparatedList<Ide> implemented = classDecl.getOptImplements().getSuperTypes();
      while (implemented != null && declaration == null) {
        declaration = resolvePropertyInSuper(ide, classDecl, visited, chain, implemented.getHead());
        implemented = implemented.getTail();
      }
    }
    chain.removeLast();
    assert chainSize == chain.size();
    return declaration;
  }

  private IdeDeclaration resolvePropertyInSuper(final String ide,
                                                final ClassDeclaration classDecl,
                                                final Set<ClassDeclaration> visited,
                                                final Deque<ClassDeclaration> chain,
                                                final Ide superIde) {
    IdeDeclaration superClassDecl = superIde.getDeclaration(false);
    if (superClassDecl != null) {
      if (!(superClassDecl instanceof ClassDeclaration)) {
        throw new CompilerError(classDecl.getOptExtends().getSuperClass().getSymbol(), "expected class identifier");
      }
      return resolvePropertyDeclaration1(ide, (ClassDeclaration) superClassDecl, visited, chain);
    }
    return null;
  }

  public int getInheritanceLevel() {
    if (inheritanceLevel < 0) {
      inheritanceLevel = computeInheritanceLevel();
    }
    return inheritanceLevel;
  }

  private int computeInheritanceLevel() {
    if (superType == null) {
      return 0;
    }
    if ("Object".equals(superType.getIde().getQualifiedNameStr())) {
      return 1;
    }
    IdeDeclaration superClassDecl = superType.getIde().getDeclaration();
    if (!(superClassDecl instanceof ClassDeclaration)) {
      throw new CompilerError(getOptExtends().getSuperClass().getSymbol(), "expected class identifier");
    }
    return 1 + ((ClassDeclaration) superClassDecl).getInheritanceLevel();
  }


  public ClassDeclaration getSuperTypeDeclaration() {
    return superType == null ? null : (ClassDeclaration) superType.getIde().getDeclaration();
  }

  public void addFieldWithInitializer(VariableDeclaration fieldDeclaration) {
    fieldsWithInitializer.add(fieldDeclaration);
  }
}
TOP

Related Classes of net.jangaroo.jooc.ast.ClassDeclaration

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.