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  for ( auto i = p.path.rbegin(); i != p.path.rend(); ++i ) {
38  auto [stop, resolved] = detail::lookupID(id, **i);
39 
40  if ( resolved ) {
41  if ( auto d = (*resolved).first->tryAs<D>() ) {
42  if ( ! resolved->second.namespace_() ) {
43  // If it's from module's scope, qualify the ID.
44  if ( auto m = (*i)->tryAs<Module>() )
45  return std::make_pair(resolved->first, ID(m->id(), resolved->second));
46  }
47 
48  else
49  return std::move(resolved);
50  }
51  else
52  return result::Error(util::fmt("ID '%s' does not resolve to a %s (but to a %s)", id, what,
53  (*resolved).first->as<Declaration>().displayName()));
54  }
55 
56  if ( stop )
57  // Pass back error.
58  return std::move(resolved);
59 
60  // If the type has the NoInheritScope flag, we skip everything else
61  // in remainder of the path except for the top-level module, to which
62  // we then jump directly. One exception: If the type is part of a
63  // type declaration, we need to check the declaration's scope still
64  // as well; that's the "if" clause below allowing to go one further
65  // step up, and the "else" clause then stopping during the next
66  // round.
67  bool skip_to_module = false;
68 
69  if ( auto t = (*i)->tryAs<Type>(); t && t->hasFlag(type::Flag::NoInheritScope) ) {
70  if ( auto x = i; ++x != p.path.rend() && (*x)->tryAs<declaration::Type>() )
71  // Ignore, we'll cover this in next round in the case below.
72  continue;
73 
74  skip_to_module = true;
75  }
76  else if ( auto t = (*i)->tryAs<declaration::Type>(); t && t->type().hasFlag(type::Flag::NoInheritScope) )
77  skip_to_module = true;
78 
79  if ( skip_to_module ) {
80  // Advance to module scope directly.
81  while ( ++i != p.path.rend() ) {
82  if ( (*i)->isA<Module>() )
83  break;
84  }
85  --i; // for-loop will increase
86  }
87  }
88 
89  return result::Error(util::fmt("unknown ID '%s'", id));
90 }
91 
92 } // namespace hilti::scope
Definition: scope-lookup.h:17