1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity average)
4 module dil.semantic.Scope;
5 
6 import dil.semantic.Symbol,
7        dil.semantic.Symbols;
8 import dil.lexer.Identifier;
9 import common;
10 
11 /// Models a hierarchy of environments.
12 class Scope
13 {
14   Scope parent; /// The surrounding scope, or null if this is the root scope.
15 
16   ScopeSymbol symbol; /// The current symbol with the symbol table.
17 
18   /// Constructs a Scope.
19   this(Scope parent, ScopeSymbol symbol)
20   {
21     this.parent = parent;
22     this.symbol = symbol;
23   }
24 
25   /// Finds a symbol in this scope.
26   /// Params:
27   ///   name = The name of the symbol.
28   Symbol lookup(Identifier* name)
29   {
30     return symbol.lookup(name);
31   }
32 
33   /// Searches for a symbol in this scope and all enclosing scopes.
34   /// Params:
35   ///   name = The name of the symbol.
36   Symbol search(Identifier* name)
37   {
38     Symbol symbol;
39     for (auto sc = this; sc; sc = sc.parent)
40     {
41       symbol = sc.lookup(name);
42       if (symbol !is null)
43         break;
44     }
45     return symbol;
46   }
47 
48   /// Searches for a symbol in this scope and all enclosing scopes.
49   /// Params:
50   ///   name = The name of the symbol.
51   ///   ignoreSymbol = The symbol that must be skipped.
52   Symbol search(Identifier* name, Symbol ignoreSymbol)
53   {
54     Symbol symbol;
55     for (auto sc = this; sc; sc = sc.parent)
56     {
57       symbol = sc.lookup(name);
58       if (symbol !is null && symbol !is ignoreSymbol)
59         break;
60     }
61     return symbol;
62   }
63 
64   /// Creates a new inner scope and returns that.
65   Scope enter(ScopeSymbol symbol)
66   {
67     return new Scope(this, symbol);
68   }
69 
70   /// Destroys this scope and returns the outer scope.
71   Scope exit()
72   {
73     auto sc = parent;
74     parent = null;
75     symbol = null;
76     return sc;
77   }
78 
79   /// Searches for a scope matching type sid.
80   Scope findScope(SYM sid)
81   {
82     auto s = this;
83     do
84       if (s.symbol.sid == sid)
85         break;
86     while ((s = s.parent) !is null);
87     return s;
88   }
89 
90   /// Searches for the enclosing Class scope.
91   Scope classScope()
92   {
93     return findScope(SYM.Class);
94   }
95 
96   /// Searches for the enclosing Module scope.
97   Scope moduleScope()
98   {
99     return findScope(SYM.Module);
100   }
101 }