Spicy
scope-lookup.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 //
3 // Functionality factored out from scope.h to avoid header loops.
4 
5 #pragma once
6 
7 #include <optional>
8 #include <utility>
9 
10 #include <hilti/ast/declarations/type.h>
11 #include <hilti/ast/id.h>
12 #include <hilti/ast/module.h>
13 #include <hilti/ast/node-ref.h>
14 #include <hilti/ast/type.h>
15 #include <hilti/base/visitor-types.h>
16 
17 namespace hilti::scope {
18 
19 namespace detail {
21 std::pair<bool, Result<std::pair<NodeRef, ID>>> lookupID(const ID& id, const Node& n);
22 } // namespace detail
23 
35 template<typename D>
36 Result<std::pair<NodeRef, ID>> lookupID(const ID& id, const visitor::Position<Node&>& p, const std::string_view& what) {
37  if ( ! id )
38  logger().internalError("lookupID() called with empty ID");
39 
40  for ( auto i = p.path.rbegin(); i != p.path.rend(); ++i ) {
41  auto [stop, resolved] = detail::lookupID(id, **i);
42 
43  if ( resolved ) {
44  if ( auto d = (*resolved).first->tryAs<D>() ) {
45  if ( ! resolved->second.namespace_() ) {
46  // If it's from module's scope, qualify the ID.
47  if ( auto m = (*i)->tryAs<Module>() )
48  return std::make_pair(resolved->first, ID(m->id(), resolved->second));
49  }
50 
51  else
52  return std::move(resolved);
53  }
54  else
55  return result::Error(util::fmt("ID '%s' does not resolve to a %s (but to a %s)", id, what,
56  (*resolved).first->as<Declaration>().displayName()));
57  }
58 
59  if ( stop )
60  // Pass back error.
61  return std::move(resolved);
62 
63  // If the type has the NoInheritScope flag, we skip everything else
64  // in remainder of the path except for the top-level module, to which
65  // we then jump directly. One exception: If the type is part of a
66  // type declaration, we need to check the declaration's scope still
67  // as well; that's the "if" clause below allowing to go one further
68  // step up, and the "else" clause then stopping during the next
69  // round.
70  bool skip_to_module = false;
71 
72  if ( auto t = (*i)->tryAs<Type>(); t && t->hasFlag(type::Flag::NoInheritScope) ) {
73  if ( auto x = i; ++x != p.path.rend() && (*x)->tryAs<declaration::Type>() )
74  // Ignore, we'll cover this in next round in the case below.
75  continue;
76 
77  skip_to_module = true;
78  }
79  else if ( auto t = (*i)->tryAs<declaration::Type>(); t && t->type().hasFlag(type::Flag::NoInheritScope) )
80  skip_to_module = true;
81 
82  if ( skip_to_module ) {
83  // Advance to module scope directly.
84  while ( ++i != p.path.rend() ) {
85  if ( (*i)->isA<Module>() )
86  break;
87  }
88  --i; // for-loop will increase
89  }
90  }
91 
92  return result::Error(util::fmt("unknown ID '%s'", id));
93 }
94 
95 } // namespace hilti::scope
Definition: scope-lookup.h:17