Skip to content

Commit

Permalink
Add regression tests
Browse files Browse the repository at this point in the history
with prototype of places macro
  • Loading branch information
nicolasstucki committed Jun 2, 2022
1 parent 040d141 commit a4bab18
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
3 changes: 3 additions & 0 deletions tests/run-macros/places-proto.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
2
List(3, 2, 4)
A(3, 2, 4)
49 changes: 49 additions & 0 deletions tests/run-macros/places-proto/Macros_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import scala.quoted.*

object Places:
def withPlace[T: Type, R: Type](expr: Expr[T])(body: Quotes ?=> Place[T] => Expr[R])(using Quotes): Expr[R] = {
// TODO: support applyDynamic/updateDynamic?
import quotes.reflect.*
expr match
case '{ $expr: T } =>
expr.asTerm match
case placeVar: Ident if placeVar.symbol.flags.is(Flags.Mutable) =>
body(
new Place[T]:
def set(x: Expr[T]): Expr[Unit] = Assign(placeVar, x.asTerm).asExprOf[Unit]
def get: Expr[T] = expr
)
case Apply(placeApply @ Select(placeTerm, "apply"), List(indexTerm)) =>
def updateWithCorrectSignature(sym: Symbol): Boolean =
true // TODO check signature
val updateSym = placeTerm.symbol.methodMember("update")
.find(updateWithCorrectSignature)
.getOrElse(report.errorAndAbort("Cannot assign to " + expr, expr))
val placeUpdate = placeTerm.select(updateSym)
indexTerm.asExpr match
case '{ $indexExpr: idx } =>
'{
val index: idx = $indexExpr
${
val boundIndex = '{index}.asTerm
val place = new Place[T]:
def set(x: Expr[T]): Expr[Unit] = placeUpdate.appliedTo(boundIndex, x.asTerm).asExprOf[Unit]
def get: Expr[T] = placeApply.appliedTo(boundIndex).asExprOf[T]
body(place)
}
}
case tree =>
throw new MatchError(tree.show(using Printer.TreeStructure))
}


trait Place[T]:
def set(x: Expr[T]): Expr[Unit]
def get: Expr[T]

end Places

inline def increment(inline x: Int): Unit = ${ incrementExpr('x) } // TODO generalize to Numeric types

private def incrementExpr(x: Expr[Int])(using Quotes): Expr[Unit] =
Places.withPlace(x) { place => place.set('{ ${place.get} + 1 }) }
24 changes: 24 additions & 0 deletions tests/run-macros/places-proto/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

@main def Test: Unit =
var x = 1
increment(x)
println(x)

val arr = Array(1, 2, 3)
increment(arr(0))
increment(arr(0))
increment(arr(2))
println(arr.toList)

val a = new A
increment(a(0))
increment(a(0))
increment(a(2))
println(a)


class A:
private var x = Array(1, 2, 3)
def apply(i: Int): Int = x(i)
def update(i: Int, value: Int): Unit = { x(i) = value }
override def toString(): String = s"A(${x.mkString(", ")})"

0 comments on commit a4bab18

Please sign in to comment.