fix: separate variable and function in scope
This commit is contained in:
parent
06c8a069fb
commit
8c5b85b8c2
@ -2,7 +2,7 @@ package wacc
|
|||||||
|
|
||||||
enum Error {
|
enum Error {
|
||||||
case DuplicateDeclaration(ident: ast.Ident)
|
case DuplicateDeclaration(ident: ast.Ident)
|
||||||
case UndefinedIdentifier(ident: ast.Ident)
|
case UndefinedIdentifier(ident: ast.Ident, identType: renamer.IdentType)
|
||||||
case FunctionParamsMismatch(expected: Int, got: Int)
|
case FunctionParamsMismatch(expected: Int, got: Int)
|
||||||
case TypeMismatch(expected: types.SemType, got: types.SemType)
|
case TypeMismatch(expected: types.SemType, got: types.SemType)
|
||||||
}
|
}
|
||||||
|
@ -6,24 +6,29 @@ object renamer {
|
|||||||
import ast._
|
import ast._
|
||||||
import types._
|
import types._
|
||||||
|
|
||||||
|
enum IdentType {
|
||||||
|
case Func
|
||||||
|
case Var
|
||||||
|
}
|
||||||
|
|
||||||
private case class Scope(
|
private case class Scope(
|
||||||
current: mutable.Map[String, Ident],
|
current: mutable.Map[(String, IdentType), Ident],
|
||||||
parent: Map[String, Ident]
|
parent: Map[(String, IdentType), Ident]
|
||||||
) {
|
) {
|
||||||
def subscope: Scope =
|
def subscope: Scope =
|
||||||
Scope(mutable.Map.empty, Map.empty.withDefault(current.withDefault(parent)))
|
Scope(mutable.Map.empty, Map.empty.withDefault(current.withDefault(parent)))
|
||||||
|
|
||||||
def add(semType: SemType, name: Ident)(using
|
def add(semType: SemType, name: Ident, identType: IdentType)(using
|
||||||
globalNames: mutable.Map[Ident, SemType],
|
globalNames: mutable.Map[Ident, SemType],
|
||||||
globalNumbering: mutable.Map[String, Int],
|
globalNumbering: mutable.Map[String, Int],
|
||||||
errors: mutable.Builder[Error, List[Error]]
|
errors: mutable.Builder[Error, List[Error]]
|
||||||
) = {
|
) = {
|
||||||
if (current.contains(name.v)) {
|
if (current.contains((name.v, identType))) {
|
||||||
errors += Error.DuplicateDeclaration(name)
|
errors += Error.DuplicateDeclaration(name)
|
||||||
} else {
|
} else {
|
||||||
val uid = globalNumbering.getOrElse(name.v, 0)
|
val uid = globalNumbering.getOrElse(name.v, 0)
|
||||||
name.uid = uid
|
name.uid = uid
|
||||||
current(name.v) = name
|
current((name.v, identType)) = name
|
||||||
|
|
||||||
globalNames(name) = semType
|
globalNames(name) = semType
|
||||||
globalNumbering(name.v) = uid + 1
|
globalNumbering(name.v) = uid + 1
|
||||||
@ -54,16 +59,16 @@ object renamer {
|
|||||||
val functionScope = scope.subscope
|
val functionScope = scope.subscope
|
||||||
val paramTypes = params.map { param =>
|
val paramTypes = params.map { param =>
|
||||||
val paramType = SemType(param.paramType)
|
val paramType = SemType(param.paramType)
|
||||||
functionScope.add(paramType, param.name)
|
functionScope.add(paramType, param.name, IdentType.Var)
|
||||||
paramType
|
paramType
|
||||||
}
|
}
|
||||||
scope.add(KnownType.Func(SemType(retType), paramTypes), name)
|
scope.add(KnownType.Func(SemType(retType), paramTypes), name, IdentType.Func)
|
||||||
body.toList.foreach(rename(functionScope))
|
body.toList.foreach(rename(functionScope))
|
||||||
}
|
}
|
||||||
case VarDecl(synType, name, value) => {
|
case VarDecl(synType, name, value) => {
|
||||||
// Order matters here. Variable isn't declared until after the value is evaluated.
|
// Order matters here. Variable isn't declared until after the value is evaluated.
|
||||||
rename(scope)(value)
|
rename(scope)(value)
|
||||||
scope.add(SemType(synType), name)
|
scope.add(SemType(synType), name, IdentType.Var)
|
||||||
}
|
}
|
||||||
case Assign(lhs, value) => {
|
case Assign(lhs, value) => {
|
||||||
rename(scope)(lhs)
|
rename(scope)(lhs)
|
||||||
@ -89,7 +94,7 @@ object renamer {
|
|||||||
rename(scope)(snd)
|
rename(scope)(snd)
|
||||||
}
|
}
|
||||||
case Call(name, args) => {
|
case Call(name, args) => {
|
||||||
rename(scope)(name)
|
renameIdent(scope, name, IdentType.Func)
|
||||||
args.foreach(rename(scope))
|
args.foreach(rename(scope))
|
||||||
}
|
}
|
||||||
case Fst(elem) => rename(scope)(elem)
|
case Fst(elem) => rename(scope)(elem)
|
||||||
@ -105,15 +110,22 @@ object renamer {
|
|||||||
rename(scope)(op.x)
|
rename(scope)(op.x)
|
||||||
rename(scope)(op.y)
|
rename(scope)(op.y)
|
||||||
}
|
}
|
||||||
case id: Ident => {
|
// Default to variables. Only `call` uses IdentType.Func.
|
||||||
scope.current.withDefault(scope.parent).get(id.v) match {
|
case id: Ident => renameIdent(scope, id, IdentType.Var)
|
||||||
case Some(Ident(_, uid)) => id.uid = uid
|
|
||||||
case None => {
|
|
||||||
errors += Error.UndefinedIdentifier(id)
|
|
||||||
scope.add(?, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case IntLiter(_) | BoolLiter(_) | CharLiter(_) | StrLiter(_) | PairLiter | Skip => ()
|
case IntLiter(_) | BoolLiter(_) | CharLiter(_) | StrLiter(_) | PairLiter | Skip => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def renameIdent(scope: Scope, ident: Ident, identType: IdentType)(using
|
||||||
|
globalNames: mutable.Map[Ident, SemType],
|
||||||
|
globalNumbering: mutable.Map[String, Int],
|
||||||
|
errors: mutable.Builder[Error, List[Error]]
|
||||||
|
): Unit = {
|
||||||
|
scope.current.withDefault(scope.parent).get((ident.v, identType)) match {
|
||||||
|
case Some(Ident(_, uid)) => ident.uid = uid
|
||||||
|
case None => {
|
||||||
|
errors += Error.UndefinedIdentifier(ident, identType)
|
||||||
|
scope.add(?, ident, identType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package wacc
|
package wacc
|
||||||
|
|
||||||
import scala.collection.mutable
|
|
||||||
|
|
||||||
object types {
|
object types {
|
||||||
import ast._
|
import ast._
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user