Esempio n. 1
0
void CatchStatement::inferTypes(AnalysisResultPtr ar) {
  ClassScopePtr cls = ar->findClass(m_className);
  TypePtr type;
  m_valid = cls;
  if (!m_valid) {
    if (ar->isFirstPass()) {
      ConstructPtr self = shared_from_this();
      ar->getCodeError()->record(self, CodeError::UnknownClass, self);
    }
    type = NEW_TYPE(Object);
  } else if (cls->isRedeclaring()) {
    type = NEW_TYPE(Object);
  } else {
    type = Type::CreateObjectType(m_className);
  }

  BlockScopePtr scope = ar->getScope();
  VariableTablePtr variables = scope->getVariables();
  variables->add(m_variable, type, false, ar, shared_from_this(),
                 ModifierExpressionPtr(), false);
  if (ar->isFirstPass()) {
    FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope);
    if (func && variables->isParameter(m_variable)) {
      variables->addLvalParam(m_variable);
    }
  }
  if (m_stmt) m_stmt->inferTypes(ar);
}
Esempio n. 2
0
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        Compiler::Error(Compiler::DeclaredVariableTwice, exp);
        m_declaration->removeElement(i--);
      } else {
        assignment->onParseRecur(ar, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        Compiler::Error(Compiler::DeclaredVariableTwice, exp);
        m_declaration->removeElement(i--);
      } else {
        variables->add(name, Type::Variant, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
Esempio n. 3
0
void ClassVariable::onParse(AnalysisResultPtr ar) {
  ModifierExpressionPtr modifiers =
    ar->getScope()->setModifiers(m_modifiers);

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = ar->getScope()->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        ar->getCodeError()->record(CodeError::DeclaredVariableTwice, exp);
      }
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>(exp);
      ph->onParse(ar);
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        ar->getCodeError()->record(CodeError::DeclaredVariableTwice, exp);
      }
      variables->add(name, TypePtr(), false, ar, exp, m_modifiers);
    }
  }

  ar->getScope()->setModifiers(modifiers);
}
Esempio n. 4
0
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
  m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name);
  m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name);

  VariableTablePtr variables = getScope()->getVariables();
  if (m_superGlobal) {
    variables->setAttribute(VariableTable::NeedGlobalPointer);
  } else if (m_name == "GLOBALS") {
    m_globals = true;
  } else {
    m_sym = variables->addSymbol(m_name);
  }

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    if (FunctionScopePtr func = getFunctionScope()) {
      if (m_name == "this" && getClassScope()) {
        func->setContainsThis();
        m_this = true;
        if (!hasContext(ObjectContext)) {
          func->setContainsBareThis();
          if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) {
            ClassScopePtr cls = getClassScope();
            TypePtr t = cls->isRedeclaring() ?
              Type::Variant : Type::CreateObjectType(cls->getName());
            variables->add(m_sym, t, true, ar, shared_from_this(),
                           getScope()->getModifiers());
          }
        }
      }
      if (m_sym && !(m_context & AssignmentLHS) &&
          !((m_context & UnsetContext) && (m_context & LValue))) {
        m_sym->setUsed();
      }
    }
  } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
    if (m_sym && !m_sym->isSystem() &&
        !(getContext() &
          (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) &&
        m_sym->getDeclaration().get() == this &&
        !variables->getAttribute(VariableTable::ContainsLDynamicVariable) &&
        !getScope()->is(BlockScope::ClassScope)) {
      if (getScope()->inPseudoMain()) {
        Compiler::Error(Compiler::UseUndeclaredGlobalVariable,
                        shared_from_this());
      } else {
        Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this());
      }
    }
  }
}
Esempio n. 5
0
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  if (m_modifiers->isAbstract()) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Properties cannot be declared abstract");
  }

  if (m_modifiers->isFinal()) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Properties cannot be declared final");
  }

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        assignment->onParseRecur(ar, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        variables->add(name, Type::Null, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
TypePtr ParameterExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                        bool coerce) {
  ASSERT(type->is(Type::KindOfSome) || type->is(Type::KindOfAny));
  TypePtr ret = getTypeSpec(ar, true);

  VariableTablePtr variables = getScope()->getVariables();
  // Functions that can be called dynamically have to have
  // variant parameters, even if they have a type hint
  if (getFunctionScope()->isDynamic() ||
      getFunctionScope()->isRedeclaring() ||
      getFunctionScope()->isVirtual()) {
    if (Option::HardTypeHints &&
        (ret->is(Type::KindOfArray) || ret->is(Type::KindOfObject))) {
    } else {
      variables->forceVariant(ar, m_name, VariableTable::AnyVars);
      ret = Type::Variant;
    }
  }

  if (m_defaultValue && !m_ref) {
    ret = m_defaultValue->inferAndCheck(ar, ret, false);
  }

  // parameters are like variables, but we need to remember these are
  // parameters so when variable table is generated, they are not generated
  // as declared variables.
  if (getScope()->isFirstPass()) {
    ret = variables->add(m_name, ret, false, ar,
                         shared_from_this(), ModifierExpressionPtr());
  } else {
    int p;
    ret = variables->checkVariable(m_name, ret, true, ar,
                                   shared_from_this(), p);
    if (ret->is(Type::KindOfSome)) {
      // This is probably too conservative. The problem is that
      // a function never called will have parameter types of Any.
      // Functions that it calls won't be able to accept variant unless
      // it is forced here.
      variables->forceVariant(ar, m_name, VariableTable::AnyVars);
      ret = Type::Variant;
    }
  }
  return ret;
}
Esempio n. 7
0
void ClassVariable::addTraitPropsToScope(AnalysisResultPtr ar,
                                         ClassScopePtr scope) {
  ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers);
  VariableTablePtr variables = scope->getVariables();

  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];

    SimpleVariablePtr var;
    ExpressionPtr value;
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      value = assignment->getValue();
    } else {
      var = dynamic_pointer_cast<SimpleVariable>(exp);
      value = makeConstant(ar, "null");
    }

    const string &name = var->getName();
    Symbol *sym;
    ClassScopePtr prevScope = variables->isPresent(name) ? scope :
      scope->getVariables()->findParent(ar, name, sym);

    if (prevScope &&
        !isEquivRedecl(name, exp, m_modifiers,
                       prevScope->getVariables()->getSymbol(name))) {
      Compiler::Error(Compiler::DeclaredVariableTwice, exp);
      m_declaration->removeElement(i--);
    } else {
      if (prevScope != scope) { // Property is new or override, so add it
        variables->add(name, Type::Variant, false, ar, exp, m_modifiers);
        variables->getSymbol(name)->setValue(exp);
        variables->setClassInitVal(name, value);
        variables->markOverride(ar, name);
      } else {
        m_declaration->removeElement(i--);
      }
    }
  }
  scope->setModifiers(modifiers);
}
Esempio n. 8
0
void BuiltinSymbols::ImportExtProperties(AnalysisResultPtr ar,
                                         VariableTablePtr dest,
                                         ClassInfo *cls) {
  ClassInfo::PropertyVec src = cls->getPropertiesVec();
  for (auto it = src.begin(); it != src.end(); ++it) {
    ClassInfo::PropertyInfo *pinfo = *it;
    int attrs = pinfo->attribute;
    ModifierExpressionPtr modifiers(
      new ModifierExpression(BlockScopePtr(), LocationPtr()));
    if (attrs & ClassInfo::IsPrivate) {
      modifiers->add(T_PRIVATE);
    } else if (attrs & ClassInfo::IsProtected) {
      modifiers->add(T_PROTECTED);
    }
    if (attrs & ClassInfo::IsStatic) {
      modifiers->add(T_STATIC);
    }

    dest->add(pinfo->name.data(),
              typePtrFromDataType(pinfo->type, Type::Variant),
              false, ar, ExpressionPtr(), modifiers);
  }
}
Esempio n. 9
0
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  TypePtr ret;
  ConstructPtr construct = shared_from_this();
  BlockScopePtr scope = getScope();
  VariableTablePtr variables = scope->getVariables();

  // check function parameter that can occur in lval context
  if (m_sym && m_sym->isParameter() &&
      m_context & (LValue | RefValue | DeepReference |
                   UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) {
    m_sym->setLvalParam();
  }
  if (m_this) {
    ClassScopePtr cls = getOriginalClass();
    if (!hasContext(ObjectContext) && cls->derivedByDynamic()) {
      ret = Type::Object;
    } else {
      ret = Type::CreateObjectType(cls->getName());
    }
    if (!hasContext(ObjectContext) &&
        variables->getAttribute(VariableTable::ContainsDynamicVariable)) {
      ret = variables->add(m_sym, ret, true, ar,
                           construct, scope->getModifiers());
    }
  } else if ((m_context & (LValue|Declaration)) &&
             !(m_context & (ObjectContext|RefValue))) {
    if (m_globals) {
      ret = Type::Variant;
    } else if (m_superGlobal) {
      ret = m_superGlobalType;
    } else if (m_superGlobalType) { // For system
      ret = variables->add(m_sym, m_superGlobalType,
                           ((m_context & Declaration) != Declaration), ar,
                           construct, scope->getModifiers());
    } else {
      ret = variables->add(m_sym, type,
                           ((m_context & Declaration) != Declaration), ar,
                           construct, scope->getModifiers());
    }
  } else {
    if (m_superGlobalType) {
      ret = m_superGlobalType;
    } else if (m_globals) {
      ret = Type::Array;
    } else if (scope->is(BlockScope::ClassScope)) {
      // ClassVariable expression will come to this block of code
      ret = getClassScope()->checkProperty(m_sym, type, true, ar);
    } else {
      TypePtr tmpType = type;
      if (m_context & RefValue) {
        tmpType = Type::Variant;
        coerce = true;
      }
      int p;
      ret = variables->checkVariable(m_sym, tmpType, coerce,
                                     ar, construct, p);
    }
  }

  TypePtr actual = propagateTypes(ar, ret);
  setTypes(ar, actual, type);
  if (Type::SameType(actual, ret)) {
    m_implementedType.reset();
  } else {
    m_implementedType = ret;
  }
  return actual;
}
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();


      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            ar->getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            ConstructPtr decl = vars->getDeclaration(m_globalName);
            if (decl) {
              ar->getDependencyGraph()->
                add(DependencyGraph::KindOfGlobalVariable,
                    ar->getName(),
                    m_globalName, self, m_globalName, decl);
            }
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            ar->getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }


      if (hasContext(LValue) || hasContext(RefValue)) {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseLDynamicVariable,
                                     self);
        }
        ar->getVariables()->forceVariants(ar);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      } else {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseRDynamicVariable,
                                     self);
        }
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, NEW_TYPE(Primitive), false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, NEW_TYPE(Sequence), false);
    m_offset->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::InvalidArrayElement,
                                   self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  if (hasContext(LValue) || hasContext(RefValue)) setEffect(CreateEffect);

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());

  resetTypes();
  TypePtr ret;
  ConstructPtr construct = shared_from_this();
  BlockScopePtr scope = getScope();
  VariableTablePtr variables = scope->getVariables();

  // check function parameter that can occur in lval context
  if (m_sym && m_sym->isParameter() &&
      m_context & (LValue | RefValue | DeepReference |
                   UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) {
    m_sym->setLvalParam();
  }

  if (coerce && m_sym && type && type->is(Type::KindOfAutoSequence)) {
    TypePtr t = m_sym->getType();
    if (!t || t->is(Type::KindOfVoid) ||
        t->is(Type::KindOfSome) || t->is(Type::KindOfArray)) {
      type = Type::Array;
    }
  }

  if (m_this) {
    ret = Type::Object;
    ClassScopePtr cls = getOriginalClass();
    if (cls && (hasContext(ObjectContext) || !cls->derivedByDynamic())) {
      ret = Type::CreateObjectType(cls->getName());
    }
    if (!hasContext(ObjectContext) &&
        variables->getAttribute(VariableTable::ContainsDynamicVariable)) {
      if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) {
        ret = Type::Variant;
      }
      ret = variables->add(m_sym, ret, true, ar,
                           construct, scope->getModifiers());
    }
  } else if ((m_context & (LValue|Declaration)) &&
             !(m_context & (ObjectContext|RefValue))) {
    if (m_globals) {
      ret = Type::Array;
    } else if (m_superGlobal) {
      ret = m_superGlobalType;
    } else if (m_superGlobalType) { // For system
      ret = variables->add(m_sym, m_superGlobalType,
                           ((m_context & Declaration) != Declaration), ar,
                           construct, scope->getModifiers());
    } else {
      ret = variables->add(m_sym, type,
                           ((m_context & Declaration) != Declaration), ar,
                           construct, scope->getModifiers());
    }
  } else {
    if (m_superGlobalType) {
      ret = m_superGlobalType;
    } else if (m_globals) {
      ret = Type::Array;
    } else if (scope->is(BlockScope::ClassScope)) {
      assert(getClassScope().get() == scope.get());
      // ClassVariable expression will come to this block of code
      ret = getClassScope()->checkProperty(getScope(), m_sym, type, true, ar);
    } else {
      TypePtr tmpType = type;
      if (m_context & RefValue) {
        tmpType = Type::Variant;
        coerce = true;
      }
      ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct);
      if (ret && (ret->is(Type::KindOfSome) || ret->is(Type::KindOfAny))) {
        ret = Type::Variant;
      }
    }
  }

  // if m_assertedType is set, then this is a type assertion node
  TypePtr inType = m_assertedType ?
    GetAssertedInType(ar, m_assertedType, ret) : ret;
  TypePtr actual = propagateTypes(ar, inType);
  setTypes(ar, actual, type);
  if (Type::SameType(actual, ret)) {
    m_implementedType.reset();
  } else {
    m_implementedType = ret;
  }
  return actual;
}
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
  m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name);
  m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name);

  VariableTablePtr variables = getScope()->getVariables();
  if (m_superGlobal) {
    variables->setAttribute(VariableTable::NeedGlobalPointer);
  } else if (m_name == "GLOBALS") {
    m_globals = true;
  } else {
    m_sym = variables->addDeclaredSymbol(m_name, shared_from_this());
  }

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    if (FunctionScopePtr func = getFunctionScope()) {
      if (m_name == "this" && func->mayContainThis()) {
        func->setContainsThis();
        m_this = true;
        if (!hasContext(ObjectContext)) {
          bool unset = hasAllContext(UnsetContext | LValue);
          func->setContainsBareThis(
            true,
            hasAnyContext(RefValue | RefAssignmentLHS) ||
            m_sym->isRefClosureVar() || unset);
          if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) {
            ClassScopePtr cls = getClassScope();
            TypePtr t = !cls || cls->isRedeclaring() ?
              Type::Variant : Type::CreateObjectType(cls->getName());
            variables->add(m_sym, t, true, ar, shared_from_this(),
                           getScope()->getModifiers());
          }
        }
      }
      if (m_sym && !(m_context & AssignmentLHS) &&
          !((m_context & UnsetContext) && (m_context & LValue))) {
        m_sym->setUsed();
      }
    }
  } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
    if (m_sym && !m_this) {
      if (!m_sym->isSystem() &&
          !(getContext() &
            (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) &&
          m_sym->getDeclaration().get() == this) {
        assert(!m_sym->isParameter());

        if (!variables->getAttribute(VariableTable::ContainsLDynamicVariable) &&
            !getScope()->is(BlockScope::ClassScope)) {
          if (getScope()->inPseudoMain()) {
            Compiler::Error(Compiler::UseUndeclaredGlobalVariable,
                            shared_from_this());
          } else if (!m_sym->isClosureVar()) {
            Compiler::Error(Compiler::UseUndeclaredVariable,
                            shared_from_this());
          }
        }
      }
      // check function parameter that can occur in lval context
      if (m_sym->isParameter() &&
          m_context & (LValue | RefValue | DeepReference |
                       UnsetContext | InvokeArgument | OprLValue |
                       DeepOprLValue)) {
        m_sym->setLvalParam();
      }
    }
  }
}
Esempio n. 13
0
void ClassVariable::onParseRecur(AnalysisResultConstRawPtr ar,
                                 FileScopeRawPtr fs,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  if (m_modifiers->isAbstract()) {
    m_modifiers->parseTimeFatal(fs,
                                Compiler::InvalidAttribute,
                                "Properties cannot be declared abstract");
  }

  if (m_modifiers->isFinal()) {
    m_modifiers->parseTimeFatal(fs,
                                Compiler::InvalidAttribute,
                                "Properties cannot be declared final");
  }

  if (!m_modifiers->isStatic() && scope->isStaticUtil()) {
    m_modifiers->parseTimeFatal(
      fs,
      Compiler::InvalidAttribute,
      "Class %s contains non-static property declaration and "
      "therefore cannot be declared 'abstract final'",
      scope->getOriginalName().c_str()
    );
  }

  if ((m_modifiers->isExplicitlyPublic() +
       m_modifiers->isProtected() +
       m_modifiers->isPrivate()) > 1) {
    m_modifiers->parseTimeFatal(
      fs,
      Compiler::InvalidAttribute,
      "%s: properties of %s",
      Strings::PICK_ACCESS_MODIFIER,
      scope->getOriginalName().c_str()
    );
  }

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      auto assignment = dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const auto& name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(fs,
                            Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        assignment->onParseRecur(ar, fs, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(fs,
                            Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        variables->add(name, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
Esempio n. 14
0
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  TypePtr ret;
  ConstructPtr construct = shared_from_this();
  BlockScopePtr scope = ar->getScope();
  VariableTablePtr variables = scope->getVariables();

  // check function parameter that can occur in lval context
  if (m_context & (LValue | RefValue | UnsetContext | InvokeArgument)) {
    FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope);
    if (func) {
      if (variables->isParameter(m_name)) {
        variables->addLvalParam(m_name);
      }
    }
  }
  if (m_name == "this") {
    ClassScopePtr cls = getOriginalScope(ar);
    if (cls) {
      bool isStaticFunc = false;
      FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope);
      if (func->isStatic()) isStaticFunc = true;
      if (cls->isRedeclaring()) {
        ret = Type::Variant;
      } else {
        ret = Type::CreateObjectType(cls->getName());
      }
      if (!isStaticFunc || (m_context & ObjectContext)) m_this = true;
    }
  }
  if ((m_context & (LValue|Declaration)) && !(m_context & ObjectContext)) {
    if (m_superGlobal) {
      ret = m_superGlobalType;
    } else if (m_superGlobalType) { // For system
      if (!m_this) {
        ret = variables->add(m_name, m_superGlobalType,
                             ((m_context & Declaration) != Declaration), ar,
                             construct, scope->getModifiers());
      }
    } else {
      if (m_globals) {
        ret = Type::Variant; // this can happen with "unset($GLOBALS)"
      } else if (!m_this) {
        ret = variables->add(m_name, type,
                             ((m_context & Declaration) != Declaration), ar,
                             construct, scope->getModifiers());
      }
    }
  } else {
    if (!m_this) {
      if (m_superGlobalType) {
        ret = m_superGlobalType;
      } else if (m_globals) {
        ret = Type::Array;
      } else if (scope->is(BlockScope::ClassScope)) {
        // ClassVariable expression will come to this block of code
        int properties;
        ret = variables->checkProperty(m_name, type, true, ar, construct,
                                       properties);
      } else {
        TypePtr tmpType = type;
        if (m_context & RefValue) {
          tmpType = Type::Variant;
          coerce = true;
        }
        int p;
        ret = variables->checkVariable(m_name, tmpType, coerce, ar, construct,
                                       p);
      }
    }
  }

  TypePtr actual = propagateTypes(ar, ret);
  setTypes(actual, type);
  if (Type::SameType(actual, ret)) {
    m_implementedType.reset();
  } else {
    m_implementedType = ret;
  }
  return actual;
}
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  if (m_offset &&
      !(m_context & (UnsetContext | ExistContext |
                     InvokeArgument | LValue | RefValue))) {
    setEffect(DiagnosticEffect);
  }
  if (m_context & (AssignmentLHS|OprLValue)) {
    clearEffect(AccessorEffect);
  } else if (m_context & (LValue | RefValue)) {
    setEffect(CreateEffect);
  }

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();

      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            clearEffect(DiagnosticEffect);
            getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }

      if (hasContext(LValue) || hasContext(RefValue)) {
        ar->getVariables()->forceVariants(ar, VariableTable::AnyVars);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, Type::Primitive, false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, coerce ? Type::AutoSequence :
                                        Type::Sequence, coerce);
    m_offset->inferAndCheck(ar, Type::Some, false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::InvalidArrayElement, self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}