Skip to content

Commit 37d4902

Browse files
committed
update namer and typer to match the new testcases
1 parent a7382c7 commit 37d4902

File tree

11 files changed

+232
-120
lines changed

11 files changed

+232
-120
lines changed

src/main/scala/decaf/annot/Flag.scala

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/main/scala/decaf/annot/Scope.scala

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package decaf.annot
22

3+
import decaf.parsing.Pos
4+
35
import 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+
*/
79101
class 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:

src/main/scala/decaf/annot/Symbol.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ sealed trait Symbol extends Annot {
2424

2525
def str: String
2626

27+
var domain: Scope = _
28+
2729
override def toString: String = s"(${ pos.line },${ pos.column }) -> " + str
2830
}
2931

@@ -76,7 +78,8 @@ class MethodSymbol(tree: SyntaxTree.MethodDef, val typ: FunType, val scope: Form
7678

7779
override def pos: Pos = tree.pos
7880

79-
override def str: String = (if (isStatic) "static " else "") + s"function $name : " + typ.toString
81+
override def str: String =
82+
(if (tree.modifiers.isEmpty) "" else s"${ tree.modifiers } ") + s"function $name : " + typ.toString
8083

8184
scope.owner = this
8285

src/main/scala/decaf/annot/Type.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ sealed trait Type extends Annot {
3535
def isVoidType: Boolean = false
3636

3737
def isBaseType: Boolean = false
38+
39+
def isFuncType: Boolean = false
3840
}
3941

4042
class BaseType extends Type {
@@ -92,7 +94,7 @@ case class ClassType(name: String, parent: Option[ClassType] = None) extends Typ
9294

9395
override def isClassType: Boolean = true
9496

95-
override def toString: String = s"class : $name"
97+
override def toString: String = s"class $name"
9698
}
9799

98100
case class ArrayType(elemType: Type) extends Type {
@@ -106,7 +108,14 @@ case class ArrayType(elemType: Type) extends Type {
106108
case _ => false
107109
}
108110

109-
override def toString: String = s"$elemType[]"
111+
override def toString: String = {
112+
if (elemType.isFuncType) {
113+
// NOTE: [] has higher priority than functions, so we must add extra parenthesis, e.g.
114+
// `(int => int)[]` means an array of functions from integers to integers, but
115+
// `int => int[]` means a function from integers to integer arrays
116+
s"($elemType)[]"
117+
} else s"$elemType[]"
118+
}
110119
}
111120

112121
case class FunType(params: List[Type], ret: Type) extends Type {
@@ -124,13 +133,15 @@ case class FunType(params: List[Type], ret: Type) extends Type {
124133
case _ => false
125134
}
126135

136+
override def isFuncType: Boolean = true
137+
127138
override def toString: String = {
128139
val ps = params match {
129140
case Nil => "()"
130141
case t :: Nil => t.toString
131142
case ts => s"(${ ts.mkString(", ") })"
132143
}
133-
s"$ps -> $ret"
144+
s"$ps => $ret"
134145
}
135146
}
136147

src/main/scala/decaf/parsing/Parser.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ class Parser extends Phase[InputStream, Tree]("parser") {
171171
if (ctx.expr == null) theVar
172172
else {
173173
val init = ctx.expr.accept(ExprVisitor)
174-
val ret = LocalVarDef(theVar.typeLit, theVar.id, Some(init)).setPos(theVar.pos)
175-
ret.assignPos = getPos(ctx.ASSIGN.getSymbol)
174+
val ret = LocalVarDef(theVar.typeLit, theVar.id, Some(init), getPos(ctx.ASSIGN.getSymbol)).setPos(theVar.pos)
176175
ret
177176
}
178177
}

src/main/scala/decaf/printing/PrettyScope.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ object PrettyScope {
1010
case s: GlobalScope =>
1111
printer.writeln("GLOBAL SCOPE:")
1212
printer.withIndent {
13-
s.values.foreach { symbol => printer.writeln(symbol.toString) }
13+
if (s.isEmpty) printer.writeln("<empty>")
14+
else s.values.foreach { symbol => printer.writeln(symbol.toString) }
1415
s.values.foreach { symbol => pretty(symbol.scope) }
1516
}
1617
case s: ClassScope =>
1718
printer.writeln(s"CLASS SCOPE OF '${ s.owner.name }':")
1819
printer.withIndent {
19-
s.values.foreach { symbol => printer.writeln(symbol.toString) }
20+
if (s.isEmpty) printer.writeln("<empty>")
21+
else s.values.foreach { symbol => printer.writeln(symbol.toString) }
2022
s.values.foreach {
2123
case m: MethodSymbol => pretty(m.scope)
2224
case _ => // do not print
@@ -25,13 +27,15 @@ object PrettyScope {
2527
case s: FormalScope =>
2628
printer.writeln(s"FORMAL SCOPE OF '${ s.owner.name }':")
2729
printer.withIndent {
28-
s.values.foreach { symbol => printer.writeln(symbol.toString) }
30+
if (s.isEmpty) printer.writeln("<empty>")
31+
else s.values.foreach { symbol => printer.writeln(symbol.toString) }
2932
pretty(s.nestedScope)
3033
}
3134
case s: LocalScope =>
3235
printer.writeln(s"LOCAL SCOPE:")
3336
printer.withIndent {
34-
s.values.foreach { symbol => printer.writeln(symbol.toString) }
37+
if (s.isEmpty) printer.writeln("<empty>")
38+
else s.values.foreach { symbol => printer.writeln(symbol.toString) }
3539
s.nestedScopes.foreach(pretty)
3640
}
3741
}

src/main/scala/decaf/tree/TreeNode.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ object TreeNode {
183183
class Modifiers(val code: Int = 0, val pos: Pos = NoPos) {
184184
def isStatic: Boolean = (code & 1) == 1
185185

186+
def isEmpty: Boolean = code == 0
187+
186188
private lazy val flags = if (isStatic) List("STATIC") else Nil
187189

188190
override def toString: String = flags.mkString(" ")

src/main/scala/decaf/tree/TreeTmpl.scala

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,30 +160,31 @@ trait TreeTmpl {
160160
* }}}
161161
* Initialization is not supported.
162162
*/
163-
case class LocalVarDef(typeLit: TypeLit, id: Id, init: Option[Expr] = None)(implicit val annot: LocalVarAnnot)
163+
case class LocalVarDef(typeLit: TypeLit, id: Id, init: Option[Expr] = None, assignPos: Pos = NoPos)
164+
(implicit val annot: LocalVarAnnot)
164165
extends Stmt with Var with Annotated[LocalVarAnnot] {
165166
type TypeLitType = TypeLit
166167

167-
var assignPos: Pos = NoPos
168+
override def productArity: Int = 3
168169
}
169170

170-
/**
171-
* Normal control flow statements.
172-
*
173-
* They should have the same type of annotation in a specialized tree.
174-
*/
175-
trait ControlFlowStmt extends Stmt with Annotated[StmtAnnot]
176-
177171
/**
178172
* Statement block:
179173
* {{{
180174
* { <stmt1> <stmt2> ... }
181175
* }}}
182176
*/
183-
case class Block(stmts: List[Stmt] = Nil)(implicit val annot: StmtAnnot) extends ControlFlowStmt {
177+
case class Block(stmts: List[Stmt] = Nil)(implicit val annot: BlockAnnot) extends Stmt with Annotated[BlockAnnot] {
184178
override def isEmpty: Boolean = stmts.isEmpty
185179
}
186180

181+
/**
182+
* Normal control flow statements.
183+
*
184+
* They should have the same type of annotation in a specialized tree.
185+
*/
186+
trait ControlFlowStmt extends Stmt with Annotated[StmtAnnot]
187+
187188
/**
188189
* Assignment:
189190
* {{{
@@ -414,4 +415,5 @@ trait TreeTmpl {
414415
* Cast the given object `obj` into class type `to`.
415416
*/
416417
case class ClassCast(obj: Expr, to: ClassRef)(implicit val annot: ExprAnnot) extends Expr
418+
417419
}

src/main/scala/decaf/tree/TypedTree.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object TypedTree extends TreeTmpl {
1818
type LocalVarAnnot = LocalVarSymbol
1919
type MethodAnnot = MethodSymbol
2020
type TypeLitAnnot = Type
21-
type StmtAnnot = Flag
21+
type StmtAnnot = SyntaxTree.No
2222
type BlockAnnot = LocalScope
2323
type ExprAnnot = Type
2424

0 commit comments

Comments
 (0)