Type * TypeResolver::resolveBaseType(TypeSpecifier *spec) { switch (spec->resolver()) { case TOK_LABEL: case TOK_NAME: return resolveNameToType(spec->proxy()); case TOK_DEFINED: return spec->getResolvedBase(); case TOK_FUNCTION: { FunctionSignature *sig = spec->signature(); if (!sig->isResolved()) resolveTypesInSignature(sig); return FunctionType::New(sig); } default: // Other cases should have been handled during name resolution. assert(false); return nullptr; } }
Type * NameResolver::resolveBase(TypeSpecifier &spec) { switch (spec.resolver()) { // These are the most common cases - either a primitive type or a signature // containing primitive types. In some cases we could have already resolved // the type even earlier, for example, the parser does this for certain = // builtin tags. case TOK_VOID: return cc_.types()->getVoid(); case TOK_IMPLICIT_INT: return cc_.types()->getImplicitInt(); case TOK_INT: return cc_.types()->getPrimitive(PrimitiveType::Int32); case TOK_BOOL: return cc_.types()->getPrimitive(PrimitiveType::Bool); case TOK_CHAR: return cc_.types()->getPrimitive(PrimitiveType::Char); case TOK_FLOAT: return cc_.types()->getPrimitive(PrimitiveType::Float); case TOK_DEFINED: return spec.getResolvedBase(); case TOK_FUNCTION: { FunctionSignature *sig = spec.signature(); if (!sig->isResolved()) return nullptr; return FunctionType::New(sig); } case TOK_LABEL: case TOK_NAME: { NameProxy *proxy = spec.proxy(); Symbol *sym = proxy->sym(); if (!sym) { // This can happen if we use a type before it's been defined. We wait // until type resolution to try again. return nullptr; } TypeSymbol *ts = sym->asType(); if (!ts) { cc_.report(proxy->loc(), rmsg::not_a_type) << sym->name(); return nullptr; } // If we resolved a TypeSymbol, we must have allocated a Type object // (even if it's incomplete). assert(ts->type()); return ts->type(); } default: return nullptr; } }
FunctionCall FunctionCall::deserialize(const Message& message) { FunctionSignature signature = FunctionSignature::deserialize(message); // Count trailing null bytes size_t bytesRead = sizeof(int) * (signature.numArgs() + 1); bytesRead += signature.name.size() + 1; std::string msgCopy = message.message; msgCopy.erase(0, bytesRead); return FunctionCall(std::move(signature), msgCopy); }
FunctionSignature * NameResolver::HandleFunctionSignature(const TypeExpr &te, ParameterList *params, bool canResolveEagerly) { FunctionSignature *sig = new (pool_) FunctionSignature(te, params); if (te.resolved() && canResolveEagerly) { #if defined(DEBUG) for (size_t i = 0; i < params->length(); i++) assert(params->at(i)->sym()->type()); #endif sig->setResolved(); } return sig; }
bool sp::AreFunctionTypesEqual(FunctionType *a, FunctionType *b) { FunctionSignature *af = a->signature(); FunctionSignature *bf = b->signature(); if (!AreTypesEquivalent(af->returnType().resolved(), bf->returnType().resolved(), Qualifiers::None)) { return false; } ParameterList *ap = af->parameters(); ParameterList *bp = bf->parameters(); if (ap->length() != bp->length()) return false; for (size_t i = 0; i < ap->length(); i++) { VarDecl *arga = ap->at(i); VarDecl *argb = bp->at(i); if (!AreTypesEquivalent(arga->te().resolved(), argb->te().resolved(), Qualifiers::None)) { return false; } } return true; }
void SemanticAnalysis::visitCallExpr(CallExpr *node) { // :TODO: we must verify that the callee is an implemented scripted func. Expression *callee = visitForRValue(node->callee()); if (!callee) return; if (!callee->type()->isFunction()) { cc_.report(node->loc(), rmsg::callee_is_not_a_function) << callee->type(); return; } node->setCallee(callee); FunctionSignature *sig = callee->type()->toFunction()->signature(); checkCall(sig, node->arguments()); Type *returnType = sig->returnType().resolved(); node->setOutput(returnType, VK::rvalue); // We mark calls as always having side effects. node->setHasSideEffects(); }
void NameResolver::OnLeaveFunctionDecl(FunctionStatement *node) { FunctionSignature *sig = node->signature(); // For compatibility with SP1, we change implicit-int return values to // implicit-void when there is no return value, so we can error when the // return value is used. We differentiate this from "void" so the following // transitional case does not error: // // forward void OnThing1(); // OnThing1() {} TypeExpr &rt = sig->returnType(); if (((rt.resolved() && rt.resolved()->isImplicitInt()) || (rt.spec() && rt.spec()->resolver() == TOK_IMPLICIT_INT)) && !(node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) && !encountered_return_value_) { rt.setResolved(cc_.types()->getImplicitVoid()); } if (!sig->isResolved()) tr_.addPending(node); }
foreach (const ArgumentGroup &group, convention()->argumentGroups()) { bool groupIsFull = true; foreach (const Argument &argument, group.arguments()) { bool argumentIsUsed = false; foreach (const MemoryLocation &memoryLocation, argument.locations()) { if (isRealArgument(memoryLocation)) { signature.addArgument(memoryLocation); argumentIsUsed = true; } } if (!argumentIsUsed) { groupIsFull = false; break; } } if (groupIsFull) { considerStack = true; } }
int Client::connectToServer(const FunctionSignature& signature) const { int binderSocket = connectTo(binderHost, binderPort); if (binderSocket < 0) { return binderSocket; } Connection binderConnection(binderSocket); // Send a request for the server address binderConnection.send(Message::Type::ADDRESS, signature.serialize()); // Read the response for the server address Message message; if (binderConnection.read(&message) < 0 || message.type != Message::Type::ADDRESS) { binderConnection.close(); return -1; } binderConnection.close(); // Okay, now we have the message with the server address auto serverAddress = ServerAddress::deserialize(message); return connectTo(serverAddress.hostname, serverAddress.port); }
FunctionSignature GenericDescriptorAnalyzer::getFunctionSignature() const { FunctionSignature signature; struct Counts { std::size_t defs; std::size_t uses; Counts(): defs(0), uses(0) {} }; /* * Estimate the memory locations of arguments. */ boost::unordered_map<MemoryLocation, Counts> argVotes; std::size_t callsCount = callAnalyzers_.size(); std::size_t functionsCount = 0; foreach (GenericCallAnalyzer *callAnalyzer, callAnalyzers_) { foreach (const MemoryLocation &memoryLocation, callAnalyzer->argumentLocations()) { ++argVotes[memoryLocation].defs; } }
bool FunctionSignature::operator==(const FunctionSignature &other) const { return name() == other.name() && isArityValid(other.maximumArguments()) && isArityValid(other.minimumArguments()); }