feat: renamer maybe maybe maybe maybe

This commit is contained in:
Gleb Koval 2025-02-04 22:26:38 +00:00
parent 5f7a89b47f
commit 06c8a069fb
Signed by: cyclane
GPG Key ID: 15E168A8B332382C
5 changed files with 181 additions and 9 deletions

View File

@ -0,0 +1,8 @@
package wacc
enum Error {
case DuplicateDeclaration(ident: ast.Ident)
case UndefinedIdentifier(ident: ast.Ident)
case FunctionParamsMismatch(expected: Int, got: Int)
case TypeMismatch(expected: types.SemType, got: types.SemType)
}

View File

@ -1,5 +1,6 @@
package wacc package wacc
import scala.collection.mutable
import parsley.{Failure, Success} import parsley.{Failure, Success}
import scopt.OParser import scopt.OParser
import java.io.File import java.io.File
@ -32,8 +33,15 @@ val cliParser = {
def compile(contents: String): Int = { def compile(contents: String): Int = {
parser.parse(contents) match { parser.parse(contents) match {
case Success(ast) => case Success(ast) =>
// TODO: Do semantics things given errors: mutable.Builder[Error, List[Error]] = List.newBuilder
0 val names = renamer.rename(ast)
// given ctx: types.TypeCheckerCtx[List[Error]] =
// types.TypeCheckerCtx(names, errors)
// types.check(ast)
if (errors.result.nonEmpty) {
errors.result.foreach(println)
200
} else 0
case Failure(msg) => case Failure(msg) =>
println(msg) println(msg)
100 100

View File

@ -28,8 +28,10 @@ object ast {
object StrLiter extends ParserBridgePos1[String, StrLiter] object StrLiter extends ParserBridgePos1[String, StrLiter]
case class PairLiter()(pos: Position) extends Expr6 case class PairLiter()(pos: Position) extends Expr6
object PairLiter extends Expr6 with ParserBridgePos0[PairLiter] object PairLiter extends Expr6 with ParserBridgePos0[PairLiter]
case class Ident(v: String)(pos: Position) extends Expr6 with LValue case class Ident(v: String, var uid: Int = -1) extends Expr6 with LValue
object Ident extends ParserBridgePos1[String, Ident] object Ident extends ParserBridgePos1[String, Ident] {
def apply(x1: String): Ident = new Ident(x1)
}
case class ArrayElem(name: Ident, indices: NonEmptyList[Expr])(pos: Position) case class ArrayElem(name: Ident, indices: NonEmptyList[Expr])(pos: Position)
extends Expr6 extends Expr6
with LValue with LValue
@ -44,15 +46,18 @@ object ast {
sealed trait UnaryOp extends Expr { sealed trait UnaryOp extends Expr {
val x: Expr val x: Expr
} }
case class Negate(x: Expr6)(pos: Position) extends Expr6 with UnaryOp sealed trait UnaryOp extends Expr {
val x: Expr
}
case class Negate(x: Expr6)(pos: Position) extends Expr6 with UnaryOp with UnaryOp
object Negate extends ParserBridgePos1[Expr6, Negate] object Negate extends ParserBridgePos1[Expr6, Negate]
case class Not(x: Expr6)(pos: Position) extends Expr6 with UnaryOp case class Not(x: Expr6)(pos: Position) extends Expr6 with UnaryOp with UnaryOp
object Not extends ParserBridgePos1[Expr6, Not] object Not extends ParserBridgePos1[Expr6, Not]
case class Len(x: Expr6)(pos: Position) extends Expr6 with UnaryOp case class Len(x: Expr6)(pos: Position) extends Expr6 with UnaryOp with UnaryOp
object Len extends ParserBridgePos1[Expr6, Len] object Len extends ParserBridgePos1[Expr6, Len]
case class Ord(x: Expr6)(pos: Position) extends Expr6 with UnaryOp case class Ord(x: Expr6)(pos: Position) extends Expr6 with UnaryOp with UnaryOp
object Ord extends ParserBridgePos1[Expr6, Ord] object Ord extends ParserBridgePos1[Expr6, Ord]
case class Chr(x: Expr6)(pos: Position) extends Expr6 with UnaryOp case class Chr(x: Expr6)(pos: Position) extends Expr6 with UnaryOp with UnaryOp
object Chr extends ParserBridgePos1[Expr6, Chr] object Chr extends ParserBridgePos1[Expr6, Chr]
// Binary operators // Binary operators

119
src/main/wacc/renamer.scala Normal file
View File

@ -0,0 +1,119 @@
package wacc
import scala.collection.mutable
object renamer {
import ast._
import types._
private case class Scope(
current: mutable.Map[String, Ident],
parent: Map[String, Ident]
) {
def subscope: Scope =
Scope(mutable.Map.empty, Map.empty.withDefault(current.withDefault(parent)))
def add(semType: SemType, name: Ident)(using
globalNames: mutable.Map[Ident, SemType],
globalNumbering: mutable.Map[String, Int],
errors: mutable.Builder[Error, List[Error]]
) = {
if (current.contains(name.v)) {
errors += Error.DuplicateDeclaration(name)
} else {
val uid = globalNumbering.getOrElse(name.v, 0)
name.uid = uid
current(name.v) = name
globalNames(name) = semType
globalNumbering(name.v) = uid + 1
}
}
}
def rename(prog: Program)(using
errors: mutable.Builder[Error, List[Error]]
): Map[Ident, SemType] =
given globalNames: mutable.Map[Ident, SemType] = mutable.Map.empty
given globalNumbering: mutable.Map[String, Int] = mutable.Map.empty
rename(Scope(mutable.Map.empty, Map.empty))(prog)
globalNames.toMap
private def rename(scope: Scope)(
node: Program | FuncDecl | Ident | Stmt | LValue | RValue
)(using
globalNames: mutable.Map[Ident, SemType],
globalNumbering: mutable.Map[String, Int],
errors: mutable.Builder[Error, List[Error]]
): Unit = node match {
case Program(funcs, main) => {
funcs.foreach(rename(scope))
main.toList.foreach(rename(scope))
}
case FuncDecl(retType, name, params, body) => {
val functionScope = scope.subscope
val paramTypes = params.map { param =>
val paramType = SemType(param.paramType)
functionScope.add(paramType, param.name)
paramType
}
scope.add(KnownType.Func(SemType(retType), paramTypes), name)
body.toList.foreach(rename(functionScope))
}
case VarDecl(synType, name, value) => {
// Order matters here. Variable isn't declared until after the value is evaluated.
rename(scope)(value)
scope.add(SemType(synType), name)
}
case Assign(lhs, value) => {
rename(scope)(lhs)
rename(scope)(value)
}
case Read(lhs) => rename(scope)(lhs)
case Free(expr) => rename(scope)(expr)
case Return(expr) => rename(scope)(expr)
case Exit(expr) => rename(scope)(expr)
case Print(expr, _) => rename(scope)(expr)
case If(cond, thenStmt, elseStmt) => {
rename(scope)(cond)
thenStmt.toList.foreach(rename(scope.subscope))
elseStmt.toList.foreach(rename(scope.subscope))
}
case While(cond, body) => {
rename(scope)(cond)
body.toList.foreach(rename(scope.subscope))
}
case Block(body) => body.toList.foreach(rename(scope.subscope))
case NewPair(fst, snd) => {
rename(scope)(fst)
rename(scope)(snd)
}
case Call(name, args) => {
rename(scope)(name)
args.foreach(rename(scope))
}
case Fst(elem) => rename(scope)(elem)
case Snd(elem) => rename(scope)(elem)
case ArrayLiter(elems) => elems.foreach(rename(scope))
case ArrayElem(name, indices) => {
rename(scope)(name)
indices.toList.foreach(rename(scope))
}
case Parens(expr) => rename(scope)(expr)
case op: UnaryOp => rename(scope)(op.x)
case op: BinaryOp => {
rename(scope)(op.x)
rename(scope)(op.y)
}
case id: Ident => {
scope.current.withDefault(scope.parent).get(id.v) match {
case Some(Ident(_, uid)) => id.uid = uid
case None => {
errors += Error.UndefinedIdentifier(id)
scope.add(?, id)
}
}
}
case IntLiter(_) | BoolLiter(_) | CharLiter(_) | StrLiter(_) | PairLiter | Skip => ()
}
}

32
src/main/wacc/types.scala Normal file
View File

@ -0,0 +1,32 @@
package wacc
import scala.collection.mutable
object types {
import ast._
sealed trait SemType
case object ? extends SemType
enum KnownType extends SemType {
case Int
case Bool
case Char
case String
case Array(elem: SemType)
case Pair(left: SemType, right: SemType)
case Func(ret: SemType, params: List[SemType])
}
object SemType {
def apply(synType: Type | PairElemType): KnownType = synType match {
case IntType => KnownType.Int
case BoolType => KnownType.Bool
case CharType => KnownType.Char
case StringType => KnownType.String
case ArrayType(elemType, dimension) =>
(0 until dimension).foldLeft(SemType(elemType))((acc, _) => KnownType.Array(acc))
case PairType(fst, snd) => KnownType.Pair(SemType(fst), SemType(snd))
case UntypedPairType => KnownType.Pair(?, ?)
}
}
}