void FunctionCall::checkParamTypeCodeErrors(AnalysisResultPtr ar) { if (!m_funcScope || m_arrayParams) return; for (int i = 0, n = m_funcScope->getMaxParamCount(); i < n; ++i) { TypePtr specType = m_funcScope->getParamTypeSpec(i); if (!specType) continue; const char *fmt = 0; string ptype; if (!m_params || m_params->getCount() <= i) { if (i >= m_funcScope->getMinParamCount()) break; fmt = "parameter %d of %s() requires %s, none given"; } else { ExpressionPtr param = (*m_params)[i]; if (!Type::Inferred(ar, param->getType(), specType)) { fmt = "parameter %d of %s() requires %s, called with %s"; } ptype = param->getType()->toString(); } if (fmt) { string msg; string_printf (msg, fmt, i + 1, escapeStringForCPP(m_funcScope->getOriginalName()).c_str(), specType->toString().c_str(), ptype.c_str()); Compiler::Error(Compiler::BadArgumentType, shared_from_this(), msg); } } }
ExpressionPtr buildPtrOfFunction(const ExpressionPtr& funExpr) { assert_true(funExpr->getType().isa<FunctionTypePtr>()) << "Trying to build a ptr of a non-function type:\n" << dumpColor(funExpr) << "\nType: " << dumpColor(funExpr->getType()); IRBuilder builder(funExpr->getNodeManager()); auto& pExt = funExpr->getNodeManager().getLangExtension<PointerExtension>(); return builder.callExpr(pExt.getPtrOfFunction(), funExpr); }
void FunctionCall::analyzeProgram(AnalysisResultPtr ar) { if (m_class) m_class->analyzeProgram(ar); if (m_nameExp) m_nameExp->analyzeProgram(ar); if (m_params) m_params->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_funcScope && !m_arrayParams) { for (int i = 0, n = m_funcScope->getMaxParamCount(); i < n; ++i) { if (TypePtr specType = m_funcScope->getParamTypeSpec(i)) { const char *fmt = 0; string ptype; if (!m_params || m_params->getCount() <= i) { if (i >= m_funcScope->getMinParamCount()) break; fmt = "parameter %d of %s() requires %s, none given"; } else { ExpressionPtr param = (*m_params)[i]; if (!Type::Inferred(ar, param->getType(), specType)) { fmt = "parameter %d of %s() requires %s, called with %s"; } ptype = param->getType()->toString(); } if (fmt) { string msg; Util::string_printf (msg, fmt, i + 1, Util::escapeStringForCPP(m_funcScope->getOriginalName()).c_str(), specType->toString().c_str(), ptype.c_str()); Compiler::Error(Compiler::BadArgumentType, shared_from_this(), msg); } } } } } }
/* * Changes the type of the field of a struct */ void updateStruct(const ExpressionPtr& structure, TypePtr& type, const ExpressionPtr& identifier) { NodeManager& mgr = structure->getNodeManager(); IRBuilder builder(mgr); TypePtr baseType = structure->getType(); RefTypePtr refTy = baseType.isa<RefTypePtr>(); StructTypePtr kst = refTy ? refTy->getElementType().as<StructTypePtr>() : structure->getType().as<StructTypePtr>(); std::string name = identifier->toString(); NamedTypePtr oldType = kst->getNamedTypeEntryOf(name); NamedTypePtr newType = builder.namedType(name, refTy ? builder.refType(type) : type); TypePtr newStructType = transform::replaceAll(mgr, baseType, oldType, newType).as<TypePtr>(); type = newStructType; }
ExpressionPtr buildPtrFromIntegral(const ExpressionPtr& intExpr, const TypePtr& ptrType) { assert_pred1(intExpr->getNodeManager().getLangBasic().isInt, intExpr->getType()) << "Trying to build ptr from non-integral."; assert_pred1(isPointer, ptrType) << "Trying to build non-ptr-type from integral."; IRBuilder builder(intExpr->getNodeManager()); auto& pExt = intExpr->getNodeManager().getLangExtension<PointerExtension>(); return builder.callExpr(pExt.getPtrFromIntegral(), intExpr, builder.getTypeLiteral(ptrType)); }
ExpressionPtr buildPtrSubscript(const ExpressionPtr& ptrExpr, const ExpressionPtr& subscriptExpr) { assert_pred1(isPointer, ptrExpr) << "Trying to build a ptr subscript from non-ptr."; assert_pred1(ptrExpr->getNodeManager().getLangBasic().isInt, subscriptExpr->getType()) << "Trying to build a ptr subscript with non-integral subscript."; IRBuilder builder(ptrExpr->getNodeManager()); auto& pExt = ptrExpr->getNodeManager().getLangExtension<PointerExtension>(); return builder.callExpr(pExt.getPtrSubscript(), ptrExpr, subscriptExpr); }
TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { if (m_vars) { assert(m_values && m_values->getCount() == m_vars->getCount()); // containing function's variable table (not closure function's) VariableTablePtr variables = getScope()->getVariables(); // closure function's variable table VariableTablePtr cvariables = m_func->getFunctionScope()->getVariables(); // force all reference use vars into variant for this function scope for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); if (param->isRef()) { variables->forceVariant(ar, name, VariableTable::AnyVars); } } // infer the types of the values m_values->inferAndCheck(ar, Type::Some, false); // coerce the types inferred from m_values into m_vars for (int i = 0; i < m_vars->getCount(); i++) { ExpressionPtr value = (*m_values)[i]; ParameterExpressionPtr var = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); assert(!var->getExpectedType()); assert(!var->getImplementedType()); if (var->isRef()) { var->setActualType(Type::Variant); } else { TypePtr origVarType(var->getActualType() ? var->getActualType() : Type::Some); var->setActualType(Type::Coerce(ar, origVarType, value->getType())); } } { // this lock isn't technically needed for thread-safety, since // the dependencies are all set up. however, the lock assertions // will fail if we don't acquire it. GET_LOCK(m_func->getFunctionScope()); // bootstrap the closure function's variable table with // the types from m_vars for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); cvariables->addParamLike(name, param->getType(), ar, shared_from_this(), getScope()->isFirstPass()); } } } return s_ClosureType; }
ExpressionPtr Expression::replaceValue(ExpressionPtr rep) { if (hasContext(Expression::RefValue) && isRefable(true) && !rep->isRefable(true)) { /* An assignment isRefable, but the rhs may not be. Need this to prevent "bad pass by reference" errors. */ ExpressionListPtr el(new ExpressionList(getScope(), getRange(), ExpressionList::ListKindWrapped)); el->addElement(rep); rep->clearContext(AssignmentRHS); rep = el; } if (rep->is(KindOfSimpleVariable) && !is(KindOfSimpleVariable)) { static_pointer_cast<SimpleVariable>(rep)->setAlwaysStash(); } rep->copyContext(m_context & ~(DeadStore|AccessContext)); if (TypePtr t1 = getType()) { if (TypePtr t2 = rep->getType()) { if (!Type::SameType(t1, t2)) { rep->setExpectedType(t1); } } } if (rep->getScope() != getScope()) { rep->resetScope(getScope()); } return rep; }
ExpressionPtr buildPtrFromArray(const ExpressionPtr& arrExpr) { assert_pred1(isReference, arrExpr) << "Trying to buildPtrFromArray from non-ref."; assert_pred1(isArray, core::analysis::getReferencedType(arrExpr->getType())) << "Trying to buildPtrFromArray from non-array."; IRBuilder builder(arrExpr->getNodeManager()); auto& pExt = arrExpr->getNodeManager().getLangExtension<PointerExtension>(); return builder.callExpr(pExt.getPtrFromArray(), arrExpr); }
ExpressionPtr buildPtrReinterpret(const ExpressionPtr& ptrExpr, const TypePtr& newElementType) { assert_pred1(core::lang::isPointer, ptrExpr) << "Trying to build a ptr reinterpret from non-ptr."; PointerType srcTy(ptrExpr->getType()); // early exit if there is nothing to do if(srcTy.getElementType() == newElementType) return ptrExpr; // otherwise, build reinterpret IRBuilder builder(ptrExpr->getNodeManager()); auto& pExt = ptrExpr->getNodeManager().getLangExtension<PointerExtension>(); return builder.callExpr(pExt.getPtrReinterpret(), ptrExpr, builder.getTypeLiteral(newElementType)); }
ExpressionPtr buildPtrCast(const ExpressionPtr& ptrExpr, bool newConst, bool newVolatile) { assert_pred1(core::lang::isPointer, ptrExpr) << "Trying to build a ptr cast from non-ptr."; PointerType srcTy(ptrExpr->getType()); // early exit if there is nothing to do if(srcTy.isConst() == newConst && srcTy.isVolatile() == newVolatile) return ptrExpr; // otherwise, build cast IRBuilder builder(ptrExpr->getNodeManager()); auto& pExt = ptrExpr->getNodeManager().getLangExtension<PointerExtension>(); auto& bmExt = ptrExpr->getNodeManager().getLangExtension<BooleanMarkerExtension>(); return builder.callExpr(pExt.getPtrCast(), ptrExpr, bmExt.getMarkerTypeLiteral(newConst), bmExt.getMarkerTypeLiteral(newVolatile)); }
void QOpExpression::wrapBoolean(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp) { TypePtr t(exp->getType()); ASSERT(t); bool wrap = false; if (!t->is(Type::KindOfBoolean)) { wrap = true; cg_printf("toBoolean("); } exp->outputCPP(cg, ar); if (wrap) cg_printf(")"); }
ExpressionPtr buildPtrOperation(BasicGenerator::Operator op, const ExpressionPtr& ptrExpr) { assert_true(isReference(ptrExpr) && isPointer(core::analysis::getReferencedType(ptrExpr->getType()))) << "Trying to build a unary pointer operation with non-ref<ptr>."; IRBuilder builder(ptrExpr->getNodeManager()); auto& pExt = ptrExpr->getNodeManager().getLangExtension<PointerExtension>(); switch(op) { case BasicGenerator::Operator::PostInc: return builder.callExpr(pExt.getPtrPostInc(), ptrExpr); case BasicGenerator::Operator::PostDec: return builder.callExpr(pExt.getPtrPostDec(), ptrExpr); case BasicGenerator::Operator::PreInc: return builder.callExpr(pExt.getPtrPreInc(), ptrExpr); case BasicGenerator::Operator::PreDec: return builder.callExpr(pExt.getPtrPreDec(), ptrExpr); default: break; } assert_fail() << "Unsupported unary pointer operation " << op; return ExpressionPtr(); }
bool Expression::CheckNeededRHS(ExpressionPtr value) { bool needed = true; always_assert(value); while (value->is(KindOfAssignmentExpression)) { value = dynamic_pointer_cast<AssignmentExpression>(value)->getValue(); } if (value->isScalar()) { needed = false; } else { TypePtr type = value->getType(); if (type && (type->is(Type::KindOfSome) || type->is(Type::KindOfAny))) { type = value->getActualType(); } if (type && type->isNoObjectInvolved()) needed = false; } return needed; }
void RefDict::updateParams() { ControlFlowGraph *g = m_am.graph(); ControlBlock *b = g->getDfBlock(1); BitOps::Bits *refbv = b->getRow(DataFlow::PRefIn); BitOps::Bits *objbv = b->getRow(DataFlow::PObjIn); for (int i = size(); i--; ) { if (ExpressionPtr e = get(i)) { always_assert(e->is(Expression::KindOfSimpleVariable)); always_assert(((unsigned int)i) == e->getCanonID()); Symbol *sym = static_pointer_cast<SimpleVariable>(e)->getSymbol(); if (sym && (sym->isParameter() || sym->isClosureVar())) { TypePtr paramType; bool isRef; if (sym->isParameter()) { ExpressionListPtr methodParams = m_method_stmt->getParams(); ExpressionPtr paramExprPtr = (*methodParams)[sym->getParameterIndex()]; paramType = paramExprPtr->getType(); isRef = m_method_stmt->isRef(sym->getParameterIndex()); } else { assert(sym->isClosureVar()); // can only assume it is a Variant for now paramType = Type::Variant; isRef = sym->isRefClosureVar(); } if (first_pass) { if (isRef || sym->isCallTimeRef()) { BitOps::set_bit(i, refbv, true); } } else { if (paramType) { if (!paramType->isNoObjectInvolved()) { BitOps::set_bit(i, objbv, true); } } else { // no type information, so we must assume it holds an object BitOps::set_bit(i, objbv, true); } } } } } }
ExpressionPtr Function::execute (vector<ExpressionPtr> * params) { symbol::Table * table = symbol::Table::getInstance (); table->enterFunBlock (shared_from_this ()); _ret.push_back (NullExpression ()); if (_params != NULL) { if (params == NULL || (params->size () != _params->size ())) { cout << "[!] Invalid parameters" << endl; throw -1; } for (int i = 0; i < params->size (); i++) { ParamPtr param = _params->at (i); ExpressionPtr value = params->at (i); cout << "param : "; value->print (cout); cout << endl; if (value->getType ()->value != param->getType ()->value) { cout << "[!] Invalid param type !" << endl; throw -1; } table->addSymbol (new symbol::Symbol (param->getVarId ()->getName (), value), param->getPos ()); } } else { if (params != NULL) { cout << "[!] Invalid parameter." << endl; throw -1; } } /* We interpret the content function while we don't meet a return statement */ vector<InstructionPtr> * vec_inst = _content->getContent (); int i = 0; int vec_size = vec_inst->size (); while (i < vec_size && _ret.back () == NULL) { (*vec_inst)[i]->interpret (); i++; } table->exitFunBlock (); ExpressionPtr ret = _ret.back (); _ret.pop_back (); return ret; }
static bool checkCopyElision(FunctionScopePtr func, ExpressionPtr exp) { if (!exp->getType()->is(Type::KindOfVariant) || func->isRefReturn()) { return false; } TypePtr imp = exp->getImplementedType(); if (!imp) imp = exp->getActualType(); if (!imp || !imp->is(Type::KindOfVariant)) return false; if (func->getNRVOFix() && exp->is(Expression::KindOfSimpleVariable)) { return true; } if (FunctionCallPtr fc = dynamic_pointer_cast<FunctionCall>(exp)) { FunctionScopePtr fs = fc->getFuncScope(); if (!fs || fs->isRefReturn()) { return true; } } return false; }
ExpressionPtr KernelReplacer::handleArgument(const TypePtr& argTy, const TypePtr& memberTy, const ExpressionPtr& tupleMemberAccess, StatementList& body) { NodeManager& mgr = argTy->getNodeManager(); IRBuilder builder(mgr); const core::lang::BasicGenerator& gen = builder.getLangBasic(); ExpressionPtr argument; // check for local memory arguments if(*memberTy == *gen.getUInt8()) { argument = tupleMemberAccess; } else { argument = builder.callExpr(gen.getArrayRefElem1D(), tupleMemberAccess, builder.castExpr(gen.getUInt8(), builder.intLit(0))); TypePtr refArtTy = builder.refType(argTy); if(!types::isSubTypeOf(argument->getType(), refArtTy)) {// e.g. argument of kernel is an ocl vector type argument = builder.callExpr(refArtTy, gen.getRefReinterpret(), argument, builder.getTypeLiteral(argTy)); } argument = utils::tryDeref(argument); } return argument; }
static void outputStringExpr(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp, bool asLitStr) { if (asLitStr && exp->isLiteralString()) { const std::string &s = exp->getLiteralString(); char *enc = string_cplus_escape(s.c_str(), s.size()); cg_printf("\"%s\", %d", enc, s.size()); free(enc); return; } bool close = false; if ((exp->hasContext(Expression::LValue) && (!exp->getActualType()->is(Type::KindOfString) || (exp->getImplementedType() && !exp->getImplementedType()->is(Type::KindOfString)))) || !exp->getType()->is(Type::KindOfString)) { cg_printf("toString("); close = true; } exp->outputCPP(cg, ar); if (close) cg_printf(")"); }
void SemanticAnalyzer::visitValueBinding(const ValueBindingPtr& node) { PatternPtr name = node->getName(); //tuple was already exploded in declaration analyzer if(name->getNodeType() == NodeType::Tuple) { validateTupleTypeDeclaration(node); } if (name->getNodeType() != NodeType::Identifier) return; if(node->getOwner()->isReadOnly() && !node->getInitializer() && ctx->currentType == nullptr) { error(node, Errors::E_LET_REQUIRES_INITIALIZER); return; } //handle type inference for temporary variable if(node->isTemporary() && node->getInitializer()) { //temporary variable always has an initializer TypePtr initializerType; TypePtr declaredType = node->getType(); SCOPED_SET(ctx->contextualType, declaredType); node->getInitializer()->accept(this); initializerType = node->getInitializer()->getType(); assert(initializerType != nullptr); if(declaredType) { //it has both type definition and initializer, then we need to check if the initializer expression matches the type annotation if(!initializerType->canAssignTo(declaredType)) { error(node, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initializerType->toString(), declaredType->toString()); return; } } else { node->setType(initializerType); } } //add implicitly constructor for Optional IdentifierPtr id = static_pointer_cast<Identifier>(node->getName()); SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypePtr declaredType = node->getType() ? node->getType() : lookupType(node->getDeclaredType()); SCOPED_SET(ctx->contextualType, declaredType); if(!declaredType && !node->getInitializer()) { error(node, Errors::E_TYPE_ANNOTATION_MISSING_IN_PATTERN); return; } SymbolPtr sym = currentScope->lookup(id->getIdentifier()); assert(sym != nullptr); SymbolPlaceHolderPtr placeholder = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym); assert(placeholder != nullptr); if(declaredType) { placeholder->setType(declaredType); } ExpressionPtr initializer = node->getInitializer(); if(initializer) { placeholder->setFlags(SymbolFlagInitializing, true); ExpressionPtr initializer = transformExpression(declaredType, node->getInitializer()); node->setInitializer(initializer); TypePtr actualType = initializer->getType(); assert(actualType != nullptr); if(declaredType) { if(!Type::equals(actualType, declaredType) && !canConvertTo(initializer, declaredType)) { error(initializer, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, actualType->toString(), declaredType->toString()); return; } } if(!declaredType) placeholder->setType(actualType); } assert(placeholder->getType() != nullptr); placeholder->setFlags(SymbolFlagInitializing, false); //optional type always considered initialized, compiler will make it has a default value nil TypePtr symbolType = sym->getType(); GlobalScope* global = symbolRegistry->getGlobalScope(); if(initializer || global->isOptional(symbolType) || global->isImplicitlyUnwrappedOptional(symbolType)) markInitialized(placeholder); if (initializer) placeholder->setFlags(SymbolFlagHasInitializer, true); if(node->isTemporary()) { placeholder->setFlags(SymbolFlagTemporary, true); markInitialized(placeholder); } if(!node->isTemporary()) { //check access control level DeclarationType decl = ctx->currentType ? DeclarationTypeProperty : DeclarationTypeVariable; declarationAnalyzer->verifyAccessLevel(node->getOwner(), placeholder->getType(), decl, ComponentTypeType); } if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol) { error(node, Errors::E_PROTOCOL_VAR_MUST_BE_COMPUTED_PROPERTY_1); } }
void DeclarationAnalyzer::visitEnum(const EnumDefPtr& node) { TypeBuilderPtr type = static_pointer_cast<TypeBuilder>(defineType(node)); SCOPED_SET(ctx->currentType, type); GlobalScope* global = symbolRegistry->getGlobalScope(); SymbolScope* local = symbolRegistry->getCurrentScope(); //check if it's raw value enum bool isRawValues = false; if(node->numParents() > 0) { TypePtr firstParent = lookupType(node->getParent(0)); if(firstParent) { Type::Category category = firstParent->getCategory(); isRawValues = category == Type::Struct || category == Type::Enum || category == Type::Aggregate || category == Type::Class; if(isRawValues) type->setParentType(firstParent); } } //initialize enum's cases if(isRawValues) { if(!node->numCases()) { error(node, Errors::E_ENUM_WITH_NO_CASES_CANNOT_DECLARE_A_RAW_TYPE); return; } //Add RawRepresentable protocol if it's not implemented if(!type->canAssignTo(global->RawRepresentable())) { makeRawRepresentable(type, global); } TypePtr rawType = type->getParentType(); assert(rawType != nullptr); bool integerConvertible = rawType->canAssignTo(global->IntegerLiteralConvertible()); for(auto c : node->getCases()) { if(!c.value && !integerConvertible) { //Enum cases require explicit raw values when the raw type is not integer literal convertible error(node, Errors::E_ENUM_CASES_REQUIRE_EXPLICIT_RAW_VALUES_WHEN_THE_RAW_TYPE_IS_NOT_INTEGER_LITERAL_CONVERTIBLE); return; } if(c.value) { if(dynamic_pointer_cast<TupleType>(c.value)) { error(node, Errors::E_ENUM_WITH_RAW_TYPE_CANNOT_HAVE_CASES_WITH_ARGUMENTS); return; } ExpressionPtr initializer = dynamic_pointer_cast<Expression>(c.value); assert(initializer != nullptr); if(!isLiteralExpression(initializer)) { error(node, Errors::E_RAW_VALUE_FOR_ENUM_CASE_MUST_BE_LITERAL); return; } SCOPED_SET(ctx->contextualType, rawType); initializer->accept(semanticAnalyzer); TypePtr caseType = initializer->getType(); assert(caseType != nullptr); if(!caseType->canAssignTo(rawType)) { error(node, Errors::E_A_IS_NOT_CONVERTIBLE_TO_B_2, caseType->toString(), rawType->toString()); return; } } type->addEnumCase(c.name, global->Void()); //register it to scope local->addSymbol(SymbolPlaceHolderPtr(new SymbolPlaceHolder(c.name, type, SymbolPlaceHolder::R_PARAMETER, SymbolFlagReadable | SymbolFlagMember | SymbolFlagStatic | SymbolFlagInitialized))); } } else { //it's an associated-values enum for(auto c : node->getCases()) { TypePtr associatedType = global->Void(); if(c.value) { TypeNodePtr typeNode = dynamic_pointer_cast<TypeNode>(c.value); if(!typeNode) { error(node, Errors::E_ENUM_CASE_CANNOT_HAVE_A_RAW_VALUE_IF_THE_ENUM_DOES_NOT_HAVE_A_RAW_TYPE); return; } assert(typeNode != nullptr); associatedType = lookupType(typeNode); } type->addEnumCase(c.name, associatedType); if(associatedType == global->Void()) local->addSymbol(SymbolPlaceHolderPtr(new SymbolPlaceHolder(c.name, type, SymbolPlaceHolder::R_PARAMETER, SymbolFlagReadable | SymbolFlagMember | SymbolFlagStatic | SymbolFlagInitialized))); } } //check member declaration of enum { SCOPED_SET(ctx->flags, (ctx->flags & (~SemanticContext::FLAG_PROCESS_IMPLEMENTATION)) | SemanticContext::FLAG_PROCESS_DECLARATION); for (const DeclarationPtr &decl : *node) { bool isStatic = decl->hasModifier(DeclarationModifiers::Class) || decl->hasModifier(DeclarationModifiers::Static); if (!isStatic && (decl->getNodeType() == NodeType::ValueBindings)) { error(node, Errors::E_ENUMS_MAY_NOT_CONTAIN_STORED_PROPERTIES); continue; } decl->accept(semanticAnalyzer); } //add a default initializer for raw value enum if(isRawValues) { vector<Parameter> params = {Parameter(L"rawValue", false, type->getParentType())}; TypePtr initType = Type::newFunction(params, global->Void(), false, nullptr); initType->setFlags(SymbolFlagAllocatingInit, true); static_pointer_cast<TypeBuilder>(initType)->setDeclaringType(type); initType->setFlags(SymbolFlagInit | SymbolFlagFailableInitializer | SymbolFlagMember | SymbolFlagAllocatingInit); FunctionSymbolPtr init(new FunctionSymbol(L"init", initType, FunctionRoleInit, nullptr)); declarationFinished(init->getName(), init, nullptr); } } if(type->getParentType() != nullptr) verifyAccessLevel(node, type->getParentType(), D_ENUM, C_RAW_TYPE); validateDeclarationModifiers(node); visitImplementation(node); }
NegateExpr::NegateExpr(ExpressionPtr expr) { m_expr = expr; setType(expr->getType()); }
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_kind == ListKindParam && !m_arrayElements) { return Expression::preOutputCPP(cg, ar, state|StashKidVars); } unsigned n = m_exps.size(); bool inExpression = cg.inExpression(); if (!inExpression && (state & FixOrder)) { return true; } cg.setInExpression(false); bool ret = false; if (m_arrayElements) { /* * would like to do: * ret = Expression::preOutputCPP(cg, ar, state); * but icc has problems with the generated code. */ ret = hasEffect(); } else if (n > 1 && m_kind == ListKindLeft) { ret = true; } else { for (unsigned int i = 0; i < n; i++) { if (m_exps[i]->preOutputCPP(cg, ar, 0)) { ret = true; break; } } } if (!inExpression) return ret; cg.setInExpression(true); if (!ret) { if (state & FixOrder) { preOutputStash(cg, ar, state); return true; } return false; } cg.wrapExpressionBegin(); if (m_arrayElements) { setCPPTemp(genCPPTemp(cg, ar)); outputCPPInternal(cg, ar, true, true); } else { unsigned ix = m_kind == ListKindLeft ? 0 : n - 1; for (unsigned int i = 0; i < n; i++) { ExpressionPtr e = m_exps[i]; e->preOutputCPP(cg, ar, i == ix ? state : 0); if (i != ix) { if (e->outputCPPUnneeded(cg, ar)) { cg_printf(";\n"); } e->setCPPTemp("/**/"); } else if (e->hasCPPTemp() && Type::SameType(e->getType(), getType())) { setCPPTemp(e->cppTemp()); } else if (!i && n > 1) { e->Expression::preOutputStash(cg, ar, state | FixOrder); if (!(state & FixOrder)) { cg_printf("id(%s);\n", e->cppTemp().c_str()); } setCPPTemp(e->cppTemp()); } } } return true; }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if (num <= MAX_CONCAT_ARGS) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': if (!first->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = first->hasCPPTemp() ? first->getType() : first->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_SL: case T_SR: ASSERT(first->getType()->is(Type::KindOfInt64)); first->outputCPP(cg, ar); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': if (!second->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = second->hasCPPTemp() ? second->getType() : second->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_INSTANCEOF: { if (second->isScalar()) { ScalarExpressionPtr scalar = dynamic_pointer_cast<ScalarExpression>(second); bool notQuoted = scalar && !scalar->isQuoted(); std::string s = second->getLiteralString(); if (s == "static" && notQuoted) { cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())"); } else if (s != "") { if (s == "self" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls) { s = cls->getOriginalName(); } } else if (s == "parent" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls && !cls->getParent().empty()) { s = cls->getParent(); } } cg_printString(s, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
ExpressionPtr buildPtrOperation(BasicGenerator::Operator op, const ExpressionPtr& lhs, const ExpressionPtr& rhs) { auto& basic = lhs->getNodeManager().getLangBasic(); auto& pExt = lhs->getNodeManager().getLangExtension<PointerExtension>(); IRBuilder builder(lhs->getNodeManager()); auto assertPtr = [&](const ExpressionPtr& exp) { assert_pred1(isPointer, exp) << "Trying to build a ptr operation from non-ptr:" << "\n lhs: " << *lhs << "\n - of type: " << *lhs->getType() << "\n rhs: " << *rhs << "\n - of type: " << *rhs->getType() << "\n op: " << op; }; auto assertInt = [&](const ExpressionPtr& exp) { assert_pred1(basic.isInt, exp->getType()) << "Trying to build a ptr add/sub with non-int" << "\n lhs: " << *lhs << "\n - of type: " << *lhs->getType() << "\n rhs: " << *rhs << "\n - of type: " << *rhs->getType() << "\n op: " << op; }; auto buildInt8Cast = [&](const ExpressionPtr& exp) { if(!core::types::isSubTypeOf(exp->getType(), basic.getInt8())) { return builder.numericCast(exp, basic.getInt8()); } return exp; }; // arithmetic operations switch(op) { case BasicGenerator::Operator::Add: { if(!isPointer(lhs)) { assertPtr(rhs); assertInt(lhs); return builder.callExpr(pExt.getPtrAdd(), rhs, buildInt8Cast(lhs)); } assertPtr(lhs); assertInt(rhs); return builder.callExpr(pExt.getPtrAdd(), lhs, buildInt8Cast(rhs)); } case BasicGenerator::Operator::Sub: { // minus is only supported with ptr on the lhs assertPtr(lhs); if(!isPointer(rhs)) { assertInt(rhs); return builder.callExpr(pExt.getPtrSub(), lhs, buildInt8Cast(rhs)); } else { return builder.callExpr(pExt.getPtrDiff(), lhs, rhs); } } default: break; } // comparison operations assertPtr(lhs); assertPtr(rhs); switch(op) { case BasicGenerator::Operator::Eq: return builder.callExpr(pExt.getPtrEqual(), lhs, rhs); case BasicGenerator::Operator::Ne: return builder.callExpr(pExt.getPtrNotEqual(), lhs, rhs); case BasicGenerator::Operator::Le: return builder.callExpr(pExt.getPtrLessEqual(), lhs, rhs); case BasicGenerator::Operator::Lt: return builder.callExpr(pExt.getPtrLessThan(), lhs, rhs); case BasicGenerator::Operator::Ge: return builder.callExpr(pExt.getPtrGreaterEqual(), lhs, rhs); case BasicGenerator::Operator::Gt: return builder.callExpr(pExt.getPtrGreaterThan(), lhs, rhs); default: break; } assert_fail() << "Unsupported binary pointer operation " << op; return ExpressionPtr(); }
DataPath DataPath::element(const ExpressionPtr& element) const { auto& mgr = path.getNodeManager(); auto& ext = mgr.getLangExtension<lang::DatapathExtension>(); assert_true(mgr.getLangBasic().isSignedInt(element->getType())) << "Index has to be a signed integer!"; return DataPath(IRBuilder(mgr).callExpr(ext.getDataPathElement(), path, element)); }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if ((num <= MAX_CONCAT_ARGS || (Option::GenConcat && cg.getOutput() != CodeGenerator::SystemCPP))) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = first->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); first->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_SL: case T_SR: cg_printf("toInt64("); first->outputCPP(cg, ar); cg_printf(")"); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = second->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); second->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_INSTANCEOF: { if (second->isScalar()) { std::string s = second->getLiteralString(); std::string sLower = Util::toLower(s); if (sLower != "") { cg_printString(sLower, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }