예제 #1
0
void InterfaceStatement::analyzeProgram(AnalysisResultPtr ar) {
    ClassScopeRawPtr classScope = getClassScope();
    if (m_stmt) {
        m_stmt->analyzeProgram(ar);
    }

    checkVolatile(ar);

    if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
    vector<string> bases;
    if (m_base) m_base->getStrings(bases);
    for (unsigned int i = 0; i < bases.size(); i++) {
        ClassScopePtr cls = ar->findClass(bases[i]);
        if (cls) {
            if (!cls->isInterface()) {
                Compiler::Error(
                    Compiler::InvalidDerivation,
                    shared_from_this(),
                    cls->getOriginalName() + " must be an interface");
            }
            if (cls->isUserClass()) {
                cls->addUse(classScope, BlockScope::UseKindParentRef);
            }
        }
    }
}
예제 #2
0
void ClassStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  vector<string> bases;
  if (!m_parent.empty()) bases.push_back(m_parent);
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    string className = bases[i];
    addUserClass(ar, bases[i]);
  }

  checkVolatile(ar);

  if (m_stmt) {
    m_stmt->analyzeProgram(ar);
  }
  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) ||
          (cls->isInterface() && (!m_parent.empty() && i == 0 ))) {
        Compiler::Error(Compiler::InvalidDerivation, shared_from_this(),
                        cls->getOriginalName());
      }
      if (cls->isUserClass()) {
        cls->addUse(getScope(), BlockScope::UseKindParentRef);
      }
    }
  }
}
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  ClassScopeRawPtr classScope = getClassScope();
  if (m_stmt) {
    classScope->setIncludeLevel(ar->getIncludeLevel());
    m_stmt->analyzeProgram(ar);
  }
  ar->recordClassSource(m_name, m_loc, getFileScope()->getName());

  checkVolatile(ar);

  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
  vector<string> bases;
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    addUserClass(ar, bases[i]);
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if (!cls->isInterface()) {
        Compiler::Error(Compiler::InvalidDerivation, shared_from_this(),
                        cls->getOriginalName());
      }
      if (cls->isUserClass()) {
        cls->addUse(classScope, BlockScope::UseKindParentRef);
      }
    }
  }
}
예제 #4
0
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
  std::vector<std::string> bases;
  auto const hasParent = !m_originalParent.empty();
  if (hasParent) bases.push_back(m_originalParent);
  if (m_base) m_base->getStrings(bases);

  checkVolatile(ar);

  if (m_stmt) {
    m_stmt->analyzeProgram(ar);
  }

  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;

  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      auto const expectClass = hasParent && i == 0;
      if (expectClass == cls->isInterface() || cls->isTrait()) {
        Compiler::Error(Compiler::InvalidDerivation,
                        shared_from_this(),
                        "You are extending " + cls->getOriginalName() +
                          " which is an interface or a trait");
      }
      if (cls->isUserClass()) {
        cls->addUse(getScope(), BlockScope::UseKindParentRef);
      }
    }
  }
}
예제 #5
0
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
  vector<string> bases;
  if (!m_parent.empty()) bases.push_back(m_parent);
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    string className = bases[i];
    addUserClass(ar, bases[i]);
  }

  checkVolatile(ar);

  if (m_stmt) {
    m_stmt->analyzeProgram(ar);
  }

  ClassScopePtr clsScope = getClassScope();

  // Check that every trait stmt is either a method, class_var, or trait_use
  if (clsScope->isTrait()) {
    StatementListPtr stmts = getStmts();
    if (stmts) {
      for (int s = 0; s < stmts->getCount(); s++) {
        StatementPtr stmt = (*stmts)[s];
        if(!dynamic_pointer_cast<UseTraitStatement>(stmt) &&
           !dynamic_pointer_cast<MethodStatement>(stmt) &&
           !dynamic_pointer_cast<ClassVariable>(stmt)) {
          Compiler::Error(Compiler::InvalidTraitStatement, stmt);
        }
      }
    }
  }

  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;

  clsScope->importUsedTraits(ar);

  ar->recordClassSource(m_name, m_loc, getFileScope()->getName());
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) ||
          (cls->isInterface() && (!m_parent.empty() && i == 0 )) ||
          (cls->isTrait())) {
        Compiler::Error(Compiler::InvalidDerivation, shared_from_this(),
                        cls->getOriginalName());
      }
      if (cls->isUserClass()) {
        cls->addUse(getScope(), BlockScope::UseKindParentRef);
      }
    }
  }
}
예제 #6
0
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }
  if (m_class) {
    updateClassName();
    if (m_class) {
      return ExpressionPtr();
    }
  }

  ClassScopePtr cls = resolveClass();
  if (!cls || (cls->isVolatile() && !isPresent())) {
    if (cls && !m_depsSet) {
      cls->addUse(getScope(), BlockScope::UseKindConstRef);
      m_depsSet = true;
    }
    return ExpressionPtr();
  }

  ConstantTablePtr constants = cls->getConstants();
  ClassScopePtr defClass = cls;
  ConstructPtr decl = constants->getValueRecur(ar, m_varName, defClass);
  if (decl) {
    BlockScope::s_constMutex.lock();
    ExpressionPtr value = dynamic_pointer_cast<Expression>(decl);
    BlockScope::s_constMutex.unlock();

    if (!value->isScalar() &&
        (value->is(KindOfClassConstantExpression) ||
         value->is(KindOfConstantExpression))) {
      std::set<ExpressionPtr> seen;
      do {
        if (!seen.insert(value).second) return ExpressionPtr();
        value = value->preOptimize(ar);
        if (!value) return ExpressionPtr();
      } while (!value->isScalar() &&
               (value->is(KindOfClassConstantExpression) ||
                value->is(KindOfConstantExpression)));
    }

    ExpressionPtr rep = Clone(value, getScope());
    rep->setComment(getText());
    copyLocationTo(rep);
    return replaceValue(rep);
  }
  return ExpressionPtr();
}
TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar,
                                             TypePtr type, bool coerce) {
  m_valid = false;

  ConstructPtr self = shared_from_this();
  TypePtr objectType = m_object->inferAndCheck(ar, Type::Some, false);

  if (!m_property->is(Expression::KindOfScalarExpression)) {
    m_property->inferAndCheck(ar, Type::String, false);

    // we also lost track of which class variable an expression is about, hence
    // any type inference could be wrong. Instead, we just force variants on
    // all class variables.
    if (m_context & (LValue | RefValue)) {
      ar->forceClassVariants(getOriginalClass(), false);
    }

    return Type::Variant; // we have to use a variant to hold dynamic value
  }

  ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
  string name = exp->getString();
  ASSERT(!name.empty());

  m_property->inferAndCheck(ar, Type::String, false);

  ClassScopePtr cls;
  if (objectType && !objectType->getName().empty()) {
    // what object-> has told us
    cls = ar->findExactClass(shared_from_this(), objectType->getName());
  } else {
    if ((m_context & LValue) && objectType &&
        !objectType->is(Type::KindOfObject) &&
        !objectType->is(Type::KindOfVariant) &&
        !objectType->is(Type::KindOfSome) &&
        !objectType->is(Type::KindOfAny)) {
      m_object->inferAndCheck(ar, Type::Object, true);
    }
  }

  if (!cls) {
    if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) {
      ar->forceClassVariants(name, getOriginalClass(), false);
    }
    return Type::Variant;
  }

  int prop = hasContext(AssignmentLHS) ? ClassScope::MayHaveUnknownPropSetter :
    hasContext(ExistContext) ? ClassScope::MayHaveUnknownPropTester :
    hasContext(UnsetContext) && hasContext(LValue) ?
    ClassScope::MayHavePropUnsetter : ClassScope::MayHaveUnknownPropGetter;
  if ((m_context & (AssignmentLHS|OprLValue)) ||
      !cls->implementsAccessor(prop)) {
    clearEffect(AccessorEffect);
  }

  // resolved to this class
  if (m_context & RefValue) {
    type = Type::Variant;
    coerce = true;
  }

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr func = m_object->getOriginalFunction();
    if (!func || func->isStatic()) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::MissingObjectContext, self);
      }
      m_actualType = Type::Variant;
      return m_actualType;
    }
  }

  if (!m_propSym || cls != m_objectClass.lock()) {
    m_objectClass = cls;
    ClassScopePtr parent;
    m_propSym = cls->findProperty(parent, name, ar, self);
    assert(m_propSym);
    if (!parent) {
      parent = cls;
    }
    m_propSymValid = m_propSym->isPresent() &&
      (!m_propSym->isPrivate() ||
       getOriginalClass() == parent) &&
      !m_propSym->isStatic();

    if (m_propSymValid) {
      parent->addUse(getScope(), BlockScope::UseKindNonStaticRef);
    }
  }

  TypePtr ret;
  if (m_propSymValid && (!cls->derivesFromRedeclaring() ||
                         m_propSym->isPrivate())) {
    ret = cls->checkProperty(m_propSym, type, coerce, ar);
    assert(m_object->getType()->isSpecificObject());
    m_valid = true;

    clearEffect(AccessorEffect);
    clearEffect(CreateEffect);
    return ret;
  } else {
    m_actualType = Type::Variant;
    return m_actualType;
  }
}