Skip to content

Commit

Permalink
add support for explicit casting. Fixes #101
Browse files Browse the repository at this point in the history
  • Loading branch information
rachitnigam committed May 2, 2019
1 parent 74b50df commit 0cf88a4
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/main/scala/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ private class FuseParser extends RegexParsers with PackratParsers {
braces(repsep(recLiteralField, ";")) ^^ { case fs => ERecLiteral(fs.toMap) }
}

lazy val exprCast: P[Expr] = parens(expr ~ "as" ~ atyp) ^^ { case e ~ _ ~ t => ECast(e, t)}

lazy val simpleAtom: P[Expr] = positioned {
eaa |
recLiteral |
Expand All @@ -50,6 +52,7 @@ private class FuseParser extends RegexParsers with PackratParsers {
boolean ^^ { case b => EBool(b) } |
iden ~ parens(repsep(expr, ",")) ^^ { case f ~ args => EApp(f, args) } |
iden ^^ { case id => EVar(id) } |
exprCast |
parens(expr)
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/RewriteView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ object RewriteView {

private def rewriteExpr(e: Expr): State[Env, Expr] = e match {
case EVar(_) | EInt(_, _) | EFloat(_) | EBool(_) | _:ERecAccess => State.unit(e)
case ec@ECast(e, _) => for {
en <- rewriteExpr(e)
} yield ec.copy(e = en)
case eb@EBinop(_, e1, e2) => for {
e1n <- rewriteExpr(e1)
e2n <- rewriteExpr(e2)
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/Subtyping.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,12 @@ object Subtyping {
Some(TSizedInt(max(bitsNeeded(ti1.maxVal), bitsNeeded(ti2.maxVal))))
case (t1, t2) => if (t1 == t2) Some(t1) else None
}

def safeCast(originalType: Type, castType: Type) = (originalType, castType) match {
case (t1:IntType, t2:TSizedInt) => isSubtype(t1, t2)
case (_:TFloat, _:TSizedInt) => false
case (_:IntType, _:TFloat) => true
case (_:TFloat, _:TFloat) => true
case _ => false
}
}
1 change: 1 addition & 0 deletions src/main/scala/Syntax.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ object Syntax {
case class ERecLiteral(fields: Map[Id, Expr]) extends Expr
case class EApp(func: Id, args: List[Expr]) extends Expr
case class EVar(id: Id) extends Expr
case class ECast(e: Expr, castType: Type) extends Expr

case class CRange(iter: Id, s: Int, e: Int, u: Int) extends Positional {
def idxType: TIndex = {
Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/TypeCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Subtyping._
import TypeEnv._
import TypeEnvImplementation._
import Utils.RichOption
import Logger.PositionalLoggable

/**
* Type checker implementation for Fuse. Apart from normal typechecking, such as
Expand Down Expand Up @@ -175,6 +176,15 @@ object TypeChecker {
case EInt(v, _) => TStaticInt(v) -> env
case EBool(_) => TBool() -> env
case ERecLiteral(_) => throw RecLiteralNotInBinder(expr.pos)
case ECast(e, castType) => {
val (typ, nEnv) = checkE(e)
if (safeCast(typ, castType) == false) {
scribe.warn {
(s"Casting expression of type $typ to $castType which might not be safe", expr)
}
}
castType -> nEnv
}
case EVar(id) => {
// Add type information to variable
id.typ = Some(env(id));
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/backends/CppLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ object Cpp {
}

implicit def emitExpr(e: Expr): Doc = e match {
case ECast(e, typ) => parens(emitType(typ)) <> emitExpr(e)
case EApp(fn, args) => fn <> parens(hsep(args.map(emitExpr), comma))
case EInt(v, base) => value(emitBaseInt(v, base))
case EFloat(f) => value(f)
Expand Down
8 changes: 8 additions & 0 deletions src/test/scala/ParsingPositive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,12 @@ class ParsingTests extends org.scalatest.FunSuite {
""" )
}

test("casting") {
parseAst("""
let x = (y as bit<32>)
""" )
parseAst("""
let x = (y as float)
""" )
}
}
17 changes: 17 additions & 0 deletions src/test/scala/TypeCheckerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1219,4 +1219,21 @@ class TypeCheckerSpec extends FunSpec {
}
}
}

describe("Explicit casting") {
it("safe to cast integer types to float") {
typeCheck("""
decl x: float;
decl y: bit<32>;
(y as float) + x;
""" )
}
it("warning when casting float to bit type") {
typeCheck("""
decl x: float;
decl y: bit<32>;
(x as bit<32>) + y
""" )
}
}
}

0 comments on commit 0cf88a4

Please sign in to comment.