feat: renamer maybe maybe maybe maybe
This commit is contained in:
parent
e9ed197782
commit
3fbb90322f
8
src/main/wacc/Error.scala
Normal file
8
src/main/wacc/Error.scala
Normal 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)
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
119
src/main/wacc/renamer.scala
Normal 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
32
src/main/wacc/types.scala
Normal 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(?, ?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user