void ArrayElementExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_variable->analyzeProgram(ar);
  if (m_offset) m_offset->analyzeProgram(ar);
  if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
    if (!m_global && (m_context & AccessContext) &&
        !(m_context & (LValue|RefValue|DeepReference|
                       UnsetContext|RefParameter|InvokeArgument))) {
      TypePtr type = m_variable->getActualType();
      if (!type ||
          (!type->is(Type::KindOfString) && !type->is(Type::KindOfArray))) {
        FunctionScopePtr scope = getFunctionScope();
        if (scope) scope->setNeedsRefTemp();
      }
    }
    if (m_global) {
      if (getContext() & (LValue|RefValue|DeepReference)) {
        setContext(NoLValueWrapper);
      } else if (!m_dynamicGlobal &&
          !(getContext() &
            (LValue|RefValue|RefParameter|DeepReference|
             UnsetContext|ExistContext))) {
        VariableTablePtr vars = ar->getVariables();
        Symbol *sym = vars->getSymbol(m_globalName);
        if (!sym || sym->getDeclaration().get() == this) {
          Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this());
        }
      }
    }
  }
}
void ArrayElementExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_variable->analyzeProgram(ar);
  if (m_offset) m_offset->analyzeProgram(ar);
  if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
    if (m_global) {
      if (getContext() & (LValue|RefValue|DeepReference)) {
        setContext(NoLValueWrapper);
      } else if (!m_dynamicGlobal &&
          !(getContext() &
            (LValue|RefValue|RefParameter|DeepReference|
             UnsetContext|ExistContext))) {
        VariableTablePtr vars = ar->getVariables();
        Symbol *sym = vars->getSymbol(m_globalName);
        if (!sym || sym->getDeclaration().get() == this) {
          Compiler::Error(Compiler::UseUndeclaredGlobalVariable,
                          shared_from_this());
        }
      }
    } else {
      TypePtr at(m_variable->getActualType());
      TypePtr et(m_variable->getExpectedType());
      if (et &&
          (et->is(Type::KindOfSequence) ||
           et->is(Type::KindOfAutoSequence)) &&
          at && at->isExactType()) {
        // since Sequence maps to Variant in the runtime,
        // using Sequence for the expected type will
        // never allow the necessary casts to be generated.
        m_variable->setExpectedType(at);
      }
    }
  }
}
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_func->analyzeProgram(ar);
  if (m_vars) {
    m_values->analyzeProgram(ar);

    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
      getFunctionScope()->addUse(m_func->getFunctionScope(),
                                 BlockScope::UseKindClosure);
      m_func->getFunctionScope()->setClosureVars(m_vars);

      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      VariableTablePtr containing = getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();
        {
          Symbol *containingSym = containing->addDeclaredSymbol(name, param);
          containingSym->setPassClosureVar();

          Symbol *sym = variables->addDeclaredSymbol(name, param);
          sym->setClosureVar();
          sym->setDeclaration(ConstructPtr());
          if (param->isRef()) {
            sym->setRefClosureVar();
            sym->setUsed();
          } else {
            sym->clearRefClosureVar();
            sym->clearUsed();
          }
        }
      }
      return;
    }
    if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        // so we can assign values to them, instead of seeing CVarRef
        Symbol *sym = variables->getSymbol(name);
        if (sym && sym->isParameter()) {
          sym->setLvalParam();
        }
      }
    }
  }

  FunctionScopeRawPtr container = 
    getFunctionScope()->getContainingNonClosureFunction();
  if (container && container->isStatic()) {
    m_func->getModifiers()->add(T_STATIC);
  }

}
Esempio n. 4
0
void ArrayElementExpression::analyzeProgram(AnalysisResultPtr ar) {
    m_variable->analyzeProgram(ar);
    if (m_offset) m_offset->analyzeProgram(ar);
    if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
        if (m_global && !m_dynamicGlobal &&
                !(getContext() &
                  (LValue|RefValue|RefParameter|UnsetContext|ExistContext))) {
            VariableTablePtr vars = ar->getVariables();
            Symbol *sym = vars->getSymbol(m_globalName);
            if (!sym || sym->getDeclaration().get() == this) {
                Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this());
            }
        }
    }
}
Esempio n. 5
0
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_func->analyzeProgram(ar);

  if (m_vars) {
    m_values->analyzeProgram(ar);

    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
      m_func->getFunctionScope()->setClosureVars(m_vars);

      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();
        {
          Symbol *sym = variables->addSymbol(name);
          sym->setClosureVar();
          if (param->isRef()) {
            sym->setRefClosureVar();
          } else {
            sym->clearRefClosureVar();
          }
        }
      }
      return;
    }
    if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();

        // so we can assign values to them, instead of seeing CVarRef
        Symbol *sym = variables->getSymbol(name);
        if (sym && sym->isParameter()) {
          sym->setLvalParam();
        }
      }
    }
  }
}
Esempio n. 6
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);
}
void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  FunctionScopePtr func = getFunctionScope();
  VariableTablePtr variables = func->getVariables();
  Symbol *sym = variables->getSymbol(m_name);
  assert(sym && sym->isParameter());

  bool inHeader = cg.isFileOrClassHeader();
  cg.setFileOrClassHeader(true);
  CodeGenerator::Context context = cg.getContext();
  bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
                       context == CodeGenerator::CppTypedParamsWrapperDecl);

  TypePtr paramType =
    typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
    Type::Variant : func->getParamType(sym->getParameterIndex());
  bool wrapper = typedWrapper ||
    context == CodeGenerator::CppFunctionWrapperImpl ||
    context == CodeGenerator::CppFunctionWrapperDecl;

  bool isCVarRef = false;
  const char *prefix = "";
  if (m_ref) {
    cg_printf("VRefParam");
    if (!wrapper) {
      prefix = "r";
    }
  } else if (wrapper ||
      (!variables->isLvalParam(m_name) &&
       !variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
       !variables->getAttribute(VariableTable::ContainsExtract))) {
    if (paramType->is(Type::KindOfVariant) ||
        paramType->is(Type::KindOfSome)) {
      cg_printf("CVarRef");
      isCVarRef = true;
    }
    else if (paramType->is(Type::KindOfArray))  cg_printf("CArrRef");
    else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
    else paramType->outputCPPDecl(cg, ar, getScope());
  } else {
    paramType->outputCPPDecl(cg, ar, getScope());
  }

  cg_printf(" %s%s%s",
            prefix, Option::VariablePrefix,
            CodeGenerator::FormatLabel(m_name).c_str());
  if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
    bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
      context == CodeGenerator::CppFunctionWrapperImpl ||
      context == CodeGenerator::CppImplementation ||
      (context == CodeGenerator::CppDeclaration && func->isInlined());
    if (comment) {
      cg_printf(" // ");
    }
    cg_printf(" = ");
    ConstantExpressionPtr con =
      dynamic_pointer_cast<ConstantExpression>(m_defaultValue);

    bool done = false;
    if (con && con->isNull()) {
      done = true;
      if (isCVarRef) {
        cg_printf("null_variant");
      } else if (paramType->is(Type::KindOfVariant) ||
                 paramType->is(Type::KindOfSome)) {
        cg_printf("null");
      } else if (paramType->is(Type::KindOfObject)) {
        cg_printf("Object()");
      } else if (paramType->is(Type::KindOfArray)) {
        cg_printf("Array()");
      } else if (paramType->is(Type::KindOfString)) {
        cg_printf("String()");
      } else {
        done = false;
      }
    }
    if (!done) {
      if (comment) {
        cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
      } else {
        cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
      }
      bool isScalar = m_defaultValue->isScalar();
      if (isCVarRef && isScalar) {
        ASSERT(!cg.hasScalarVariant());
        cg.setScalarVariant();
      }
      m_defaultValue->outputCPP(cg, ar);
      if (isCVarRef && isScalar) cg.clearScalarVariant();
      ASSERT(!cg.hasScalarVariant());
      cg.setContext(context);
    }
    if (comment) {
      cg_printf("\n");
    }
  }
  cg.setFileOrClassHeader(inHeader);
}
void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  FunctionScopePtr func = getFunctionScope();
  VariableTablePtr variables = func->getVariables();
  Symbol *sym = variables->getSymbol(m_name);
  assert(sym && sym->isParameter());

  CodeGenerator::Context context = cg.getContext();
  bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
                       context == CodeGenerator::CppTypedParamsWrapperDecl);

  TypePtr paramType =
    typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
    Type::Variant : func->getParamType(sym->getParameterIndex());

  bool isCVarRef = false;
  if (cg.getContext() == CodeGenerator::CppStaticMethodWrapper ||
      typedWrapper ||
      (!variables->isLvalParam(m_name) &&
       !variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
       !variables->getAttribute(VariableTable::ContainsExtract) &&
       !m_ref)) {
    if (paramType->is(Type::KindOfVariant) ||
        paramType->is(Type::KindOfSome)) {
      cg_printf("CVarRef");
      isCVarRef = true;
    }
    else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef");
    else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
    else paramType->outputCPPDecl(cg, ar, getScope());
  } else {
    paramType->outputCPPDecl(cg, ar, getScope());
  }

  cg_printf(" %s%s", Option::VariablePrefix, m_name.c_str());
  if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
    bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
      context == CodeGenerator::CppImplementation ||
      (context == CodeGenerator::CppDeclaration && func->isInlined());
    if (comment) {
      cg_printf(" // ");
    }
    cg_printf(" = ");
    ConstantExpressionPtr con =
      dynamic_pointer_cast<ConstantExpression>(m_defaultValue);
    if (isCVarRef && con && con->isNull()) {
      cg_printf("null_variant");
    } else {
      if (comment) {
        cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
      } else {
        cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
      }
      m_defaultValue->outputCPP(cg, ar);
      cg.setContext(context);
    }
    if (comment) {
      cg_printf("\n");
    }
  }
}
void MethodStatement::analyzeProgram(AnalysisResultPtr ar) {
  FunctionScopeRawPtr funcScope = getFunctionScope();

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

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    funcScope->setParamSpecs(ar);
    if (funcScope->isGenerator()) {
      MethodStatementRawPtr orig = getOrigGeneratorFunc();
      VariableTablePtr variables = funcScope->getVariables();

      Symbol *cont = variables->getSymbol(CONTINUATION_OBJECT_NAME);
      cont->setHidden();

      orig->getFunctionScope()->addUse(funcScope, BlockScope::UseKindClosure);
      orig->getFunctionScope()->setContainsBareThis(
        funcScope->containsBareThis(), funcScope->containsRefThis());
      orig->getFunctionScope()->setContainsThis(funcScope->containsThis());

      if (ExpressionListPtr params = orig->getParams()) {
        for (int i = 0; i < params->getCount(); ++i) {
          auto param = dynamic_pointer_cast<ParameterExpression>((*params)[i]);
          Symbol *gp = variables->addDeclaredSymbol(param->getName(), param);
          gp->setGeneratorParameter();
          if (param->isRef()) {
            gp->setRefGeneratorParameter();
            gp->setReferenced();
          }
        }
      }

      if (ClosureExpressionRawPtr closure = orig->getContainingClosure()) {
        if (ExpressionListPtr cvars = closure->getClosureVariables()) {
          for (int i = 0; i < cvars->getCount(); ++i) {
            auto param = dynamic_pointer_cast<ParameterExpression>((*cvars)[i]);
            Symbol *gp = variables->addDeclaredSymbol(
              param->getName(), ConstructPtr());
            gp->setGeneratorParameter();
            if (param->isRef()) {
              gp->setRefGeneratorParameter();
              gp->setReferenced();
            }
          }
        }
      }
    }
    if (funcScope->isSepExtension() ||
        Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) {
      funcScope->setDynamic();
    }
    // TODO: this may have to expand to a concept of "virtual" functions...
    if (m_method) {
      funcScope->disableInline();
      if (m_name.length() > 2 && m_name.substr(0,2) == "__") {
        bool magic = true;
        int paramCount = 0;
        if (m_name == "__destruct") {
          funcScope->setOverriding(Type::Variant);
        } else if (m_name == "__call") {
          funcScope->setOverriding(Type::Variant, Type::String, Type::Array);
          paramCount = 2;
        } else if (m_name == "__set") {
          funcScope->setOverriding(Type::Variant, Type::String, Type::Variant);
          paramCount = 2;
        } else if (m_name == "__get") {
          funcScope->setOverriding(Type::Variant, Type::String);
          paramCount = 1;
        } else if (m_name == "__isset") {
          funcScope->setOverriding(Type::Boolean, Type::String);
          paramCount = 1;
        } else if (m_name == "__unset") {
          funcScope->setOverriding(Type::Variant, Type::String);
          paramCount = 1;
        } else if (m_name == "__sleep") {
          funcScope->setOverriding(Type::Variant);
        } else if (m_name == "__wakeup") {
          funcScope->setOverriding(Type::Variant);
        } else if (m_name == "__set_state") {
          funcScope->setOverriding(Type::Variant, Type::Variant);
          paramCount = 1;
        } else if (m_name == "__tostring") {
          funcScope->setOverriding(Type::String);
        } else if (m_name == "__clone") {
          funcScope->setOverriding(Type::Variant);
        } else {
          paramCount = -1;
          if (m_name != "__construct") {
            magic = false;
          }
        }
        if (paramCount >= 0 && paramCount != funcScope->getMaxParamCount()) {
          Compiler::Error(Compiler::InvalidMagicMethod, shared_from_this());
          magic = false;
        }
        if (magic) funcScope->setMagicMethod();
      }
      // ArrayAccess methods
      else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") {
        if (m_name == "offsetexists") {
          funcScope->setOverriding(Type::Boolean, Type::Variant);
        } else if (m_name == "offsetget") {
          funcScope->setOverriding(Type::Variant, Type::Variant);
        } else if (m_name == "offsetset") {
          funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant);
        } else if (m_name == "offsetunset") {
          funcScope->setOverriding(Type::Variant, Type::Variant);
        }
      }
    }
  } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
    TypePtr ret = funcScope->getReturnType();
    if (ret && ret->isSpecificObject()) {
      FileScopePtr fs = getFileScope();
      if (fs) fs->addClassDependency(ar, ret->getName());
    }
    if (!getFunctionScope()->usesLSB()) {
      if (StatementPtr orig = getOrigGeneratorFunc()) {
        orig->getFunctionScope()->clearUsesLSB();
      }
    }
  }
}