fix: separate variable and function in scope

This commit is contained in:
Gleb Koval 2025-02-05 05:12:32 +00:00 committed by Barf-Vader
parent 3fbb90322f
commit 30cf42ee3a
3 changed files with 31 additions and 21 deletions

View File

@ -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)
} }

View File

@ -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)
}
}
}
} }

View File

@ -1,7 +1,5 @@
package wacc package wacc
import scala.collection.mutable
object types { object types {
import ast._ import ast._