11package decaf .annot
22
3+ import decaf .parsing .Pos
4+
35import scala .collection .mutable
46
57/**
@@ -15,6 +17,8 @@ sealed trait Scope extends Annot {
1517
1618 var owner : Owner = _
1719
20+ def isEmpty : Boolean = symbols.isEmpty
21+
1822 def values : List [Item ] = symbols.values.toList.sortBy(_.pos)
1923
2024 def flatMap [T <: Item ](p : Item => Option [T ]): List [T ] = symbols.values.flatMap(p).toList
@@ -33,6 +37,7 @@ sealed trait Scope extends Annot {
3337
3438 def declare (symbol : Item ): Unit = {
3539 symbols(symbol.name) = symbol
40+ symbol.domain = this
3641 }
3742
3843 def isLocalOrFormal : Boolean = false
@@ -76,6 +81,23 @@ class LocalScope extends Scope {
7681 val nestedScopes : mutable.ArrayBuffer [LocalScope ] = new mutable.ArrayBuffer [LocalScope ]
7782}
7883
84+ /**
85+ * A symbol table, which is organized as a stack of scopes, maintained by {@link decaf.frontend.typecheck.Namer}.
86+ * A typical full scope stack looks like the following:
87+ * {{{
88+ * LocalScope --- stack top (current scope)
89+ * ... --- many nested local scopes
90+ * LocalScope
91+ * FormalScope
92+ * ClassScope
93+ * ... --- many parent class scopes
94+ * ClassScope
95+ * GlobalScope --- stack bottom
96+ * }}}
97+ * Make sure the global scope is always at the bottom, and NO class scope appears in neither formal nor local scope.
98+ *
99+ * @see Scope
100+ */
79101class ScopeContext private (global : GlobalScope , private val scopes : List [Scope ], val currentScope : Scope ,
80102 val currentClass : ClassSymbol , val currentMethod : MethodSymbol ) {
81103
@@ -91,34 +113,46 @@ class ScopeContext private(global: GlobalScope, private val scopes: List[Scope],
91113 }
92114
93115 /**
94- * Find a symbol by key. Search in all possible scopes while the predicate `p ` holds, and returns the innermost
95- * result.
116+ * Find a symbol by key. Search in all possible scopes while the predicate `cond ` holds, and the found symbols
117+ * satisfies `p`. Returns the innermost result.
96118 *
97119 * @param key the key
98- * @param p the predicate over the currently seeing scope
120+ * @param cond the predicate over the currently seeing scope
121+ * @param p the predicate over the suspect symbol
99122 * @param scopes all remaining scopes to be searched
100123 * @return innermost found symbol (if any)
101124 */
102125 @ scala.annotation.tailrec
103- private def findWhile (key : String , p : Scope => Boolean , scopes : List [Scope ] = scopes :+ global): Option [Symbol ] =
126+ private def findWhile (key : String , cond : Scope => Boolean = _ => true , p : Symbol => Boolean = _ => true ,
127+ scopes : List [Scope ] = scopes :+ global): Option [Symbol ] =
104128 scopes match {
105- case Nil => if ( ! p(global)) None else global.find(key)
129+ case Nil => None
106130 case s :: ss =>
107- if (! p (s)) None
131+ if (! cond (s)) None
108132 else s.find(key) match {
109- case Some (symbol) => Some (symbol)
110- case None => findWhile(key, p, ss)
133+ case Some (symbol) if p(symbol) => Some (symbol)
134+ case _ => findWhile(key, cond , p, ss)
111135 }
112136 }
113137
114138 /**
115139 * Lookup a symbol by key. By saying "lookup", the user expects that the symbol is found.
116140 * In this way, we will always search in all possible scopes and returns the innermost result.
117141 *
118- * @param key the key
142+ * @param key symbol's name
119143 * @return innermost found symbol (if any)
120144 */
121- def lookup (key : String ): Option [Symbol ] = findWhile(key, _ => true )
145+ def lookup (key : String ): Option [Symbol ] = findWhile(key)
146+
147+ /**
148+ * Same with {@link #lookup} but we restrict the symbol's position to be before the given `pos`.
149+ *
150+ * @param key symbol's name
151+ * @param pos position
152+ * @return innermost found symbol before `pos` (if any)
153+ */
154+ def lookupBefore (key : String , pos : Pos ): Option [Symbol ] = findWhile(key, _ => true ,
155+ s => ! (s.domain.isLocalOrFormal && s.pos >= pos))
122156
123157 /**
124158 * Find if `key` conflicts with some already defined symbol. Rules:
0 commit comments