solution with make-true

This commit is contained in:
Claudio Maggioni 2024-12-16 17:18:42 +01:00
parent 7dc37783d8
commit 32f106c61f
4 changed files with 91 additions and 2 deletions

View file

@ -81,6 +81,12 @@ object GenerativeFluentAssertionsDSL:
propertyNameExpr,
valueExpr
)
case '{
(${ typeProvider }: BePropertyTypeProvider[subjectType])
.applyDynamic($propertyNameExpr)($value)
.$asInstanceOf$[AssertionProperty]
} =>
'{} // placeholder
case _ =>
report.errorAndAbort(
"Invalid expression, must be a 'should be' or 'should have' assertion. ",

View file

@ -12,6 +12,10 @@ class DynamicShouldBeProperty extends AssertionProperty with Dynamic:
def applyDynamic(fieldName: String)(foo: Any*) = ???
end DynamicShouldBeProperty
class BePropertyTypeProvider[T](val subject: T) extends Selectable:
def applyDynamic(fieldName: String)(foo: Any*): AssertionProperty = ???
end BePropertyTypeProvider
/** The class that implements the syntactic aspect of the type provider. It
* extends Selectable and implements applyDynamic with arity 1, so that any
* object of this type can be invoked with an arbitrary method with 1 argument,
@ -32,6 +36,7 @@ end HavePropertyTypeProvider
sealed trait AssertionDSLVerb
case object be extends AssertionDSLVerb with Dynamic:
def selectDynamic(fieldName: String): AssertionProperty = ???
case object make extends AssertionDSLVerb
case object have extends AssertionDSLVerb
/** Implicit class to add 'should' assertions to a generic type T.
@ -51,6 +56,10 @@ extension [T](subject: T)
*/
def should(property: AssertionProperty) = ???
transparent inline def should(inline verbWord: make.type) = ${
ShouldBeTypeProvider.generateShouldBeTypeProvider[T]('subject)
}
/** Specifies the 'have' assertion.
*
* The method is a type provider: it generates, through a macro, a refinement

View file

@ -25,11 +25,18 @@ case class Box(label: String, weight: Mass, price: Money)
val box = Box("aBox", 30.kg, 10.CHF)
assertions:
// {
// val p: BePropertyTypeProvider[Person] = new BePropertyTypeProvider[Person](person)
// p.asInstanceOf[BePropertyTypeProvider[Person] {
// def adult: AssertionProperty
// }].adult
// }
/* be.property assertions */
// assert(person.adult, ...)
person should be.adult
person should make adult true
// assert(List().isEmpty, ...)
List().should(be.empty)
List() should be.empty
// assert(List(1,2,3).nonEmpty)
List(1, 2, 3) should be.nonEmpty

View file

@ -0,0 +1,67 @@
package ch.usi.si.msde.edsl.lecture10
import scala.annotation.tailrec
import scala.quoted.*
object ShouldBeTypeProvider:
def generateShouldBeTypeProvider[T](subject: Expr[T])(using Type[T])(using Quotes): Expr[Any] =
import quotes.reflect.*
val subjectTypeRepr = TypeRepr.of[T]
def refineTypeBySymbol(
currentTypeRepr: TypeRepr,
symbol: Symbol
): TypeRepr =
val methodType = MethodType(List("value"))(
_ => List(TypeRepr.of[true]),
_ => TypeRepr.of[AssertionProperty]
)
// val methodType = TypeRepr.of[AssertionProperty]
Refinement(currentTypeRepr, symbol.name, methodType)
@tailrec
def refineTypeBySymbols(
currentTypeRepr: TypeRepr,
fields: List[Symbol]
): TypeRepr =
fields match
// this is pattern matching on list - like head :: rest
case symbol :: symbols =>
refineTypeBySymbols(
refineTypeBySymbol(currentTypeRepr, symbol),
symbols
)
// empty list case
case Nil =>
currentTypeRepr
val booleanType = TypeRepr.of[Boolean]
val members = (subjectTypeRepr.typeSymbol.fieldMembers ++ subjectTypeRepr.typeSymbol.methodMembers)
.filter: fieldMember =>
subjectTypeRepr.memberType(fieldMember).widen <:< booleanType
val refinedType = refineTypeBySymbols(
TypeRepr.of[BePropertyTypeProvider[T]],
members
)
println(refinedType)
// This is the way to extract a (reflection) type to a
// type that can be used in some quoted code.
// it's the equivalent of .asExpr for expressions,
// but it's more complicated because in this case the
// exact type is unknown until compilation time.
refinedType.asType match
case '[tpe] => // tpe is the exact refined type
val res = '{
val p = BePropertyTypeProvider[T]($subject)
p.asInstanceOf[tpe]
}
println(res.show)
res
end ShouldBeTypeProvider