//throw on error static ResolutionResult checkImport(const PackageManager& pm, const ParseResultPtr& pr, const std::string& pkgName, const CustomTypeExprNode* tnode, const std::string& type) { PackagePtr pkg = pm.package(pkgName); NodePtr node = pkg->getExport(type); TypeKind kind; if (node) { switch (node->type()) { case NodeType_InterfaceDecl: kind = TypeKind_Interface; break; case NodeType_EnumDecl: kind = TypeKind_Enum; break; case NodeType_StructDecl: kind = TypeKind_Struct; break; default: pr->addDiag(Diagnostic(DiagnosticType_Error, "'" + type + "' in package '" + pkgName + "' is not a type", tnode->loc())); throw std::runtime_error("Not a type"); break; } return ResolutionResult(pkgName, type, kind); } pr->addDiag(Diagnostic(DiagnosticType_Error, "Can't find '" + type + "' in package '" + pkgName + "'", tnode->loc())); throw std::runtime_error("Can't find import"); }
//public interface ParseResultPtr parse(const FileReaderPtr& file) { ParseResultPtr ret = newParseResult(); ret->filename = file->filename(); if (!file->isOpen()) { ret->addDiag(Diagnostic(DiagnosticType_Error, "Can't open file '" + file->filename() + "'")); return ret; } Parser p(file); return p.result(); }
/** 1 / Check for missing or multiple package declaration * 2 / Check that the directory path and package name match * 3 / register the content of the file to the package */ bool PackageManager::addFileToPackage(const std::string& absfile, const FileReaderPtr& file, ParseResultPtr& pr) { // 1 NodePtrVector result; result = findNode(pr->ast, NodeType_Package); if (result.size() == 0) { pr->addDiag(Diagnostic(DiagnosticType_Error, "missing package declaration", Location(file->filename()))); return false; } if (result.size() > 1) { for (unsigned i = 1; i < result.size(); ++i) { pr->addDiag(Diagnostic(DiagnosticType_Error, "extra package declaration", result.at(i)->loc())); } pr->addDiag(Diagnostic(DiagnosticType_Info, "previous declared here", result.at(0)->loc())); return false; } std::string pkgname = extractPackageName(result.at(0)); // 2 qi::Path pf(file->filename()); StringVector leafs = splitPkgName(pkgname); qi::Path dirname; qi::Path cur = pf.parent().absolute(); for (unsigned i = 0; i < leafs.size(); ++i) { dirname = qi::Path(cur.filename()) / dirname; cur = cur.parent(); if (cur.isEmpty()) break; } qi::Path p = pf.parent().absolute(); for (int i = leafs.size() - 1; i >= 0; --i) { std::string par = p.filename(); if (par != leafs.at(i)) { pr->addDiag(Diagnostic(DiagnosticType_Error, "package name '" + pkgname + "' do not match parent directory name '" + (std::string)dirname + "'", result.at(0)->loc())); return false; } p = p.parent(); } std::string pkgpath = p.absolute().str(); addInclude(pkgpath); addPackage(pkgname); pr->package = pkgname; package(pkgname)->setContent(absfile, pr); return true; }
//throw on error ResolutionResult PackageManager::resolveImport(const ParseResultPtr& pr, const PackagePtr& pkg, const CustomTypeExprNode* tnode) { const std::string type = tnode->value; qiLogVerbose() << "Resolving: " << type << " from package: " << pkg->_name; const auto lastDot = type.find_last_of('.'); const std::string pkgName = (lastDot == std::string::npos) ? "" : type.substr(0, lastDot); const auto valueBegins = pkgName.empty() ? 0 : (pkgName.size() + 1); std::string value = type.substr(valueBegins); //package name provided if (!pkgName.empty() && pkgName != type) return checkImport(*this, pr, pkgName, tnode, value); value = type; //no package name. find the package name NodePtr exportnode = pkg->getExport(type); if (exportnode) return checkImport(*this, pr, pkg->_name, tnode, type); ASTMap::const_iterator it; for (it = pkg->_imports.begin(); it != pkg->_imports.end(); ++it) { const NodePtrVector& v = it->second; for (unsigned i = 0; i < v.size(); ++i) { ImportNode* inode = static_cast<ImportNode*>(v.at(i).get()); switch (inode->importType) { case ImportType_All: { return checkImport(*this, pr, inode->name, tnode, type); } case ImportType_List: { StringVector::iterator it = std::find(inode->imports.begin(), inode->imports.end(), type); if (it != inode->imports.end()) { return checkImport(*this, pr, inode->name, tnode, type); } break; } case ImportType_Package: break; } } } pr->addDiag(Diagnostic(DiagnosticType_Error, "cant resolve id '" + type + "' from package '" + pkg->_name + "'", tnode->loc())); throw std::runtime_error("cant resolve id"); }