Skip to content

Commit

Permalink
SFunc support in SigmaPrint, LSV6 test
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Sep 2, 2024
1 parent 57b792e commit 410f136
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 32 deletions.
2 changes: 0 additions & 2 deletions core/shared/src/main/scala/sigma/ast/TypeCodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ object TypeCodes {
/** SFunc type */
val FuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte

// val LastFuncType : TypeCode = TypeCode @@ 255.toByte

/** We use optimized encoding of constant values to save space in serialization.
* Since Box registers are stored as Constant nodes we save 1 byte for each register.
* This is due to convention that Value.opCode falling in [1..LastDataType] region is a constant.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ object SigmaPPrint extends PPrinter {
s"SOption[${typeName(ot.elemType)}]"
case _: STuple =>
"STuple"
case _: SFunc =>
s"SFunc"
case _ =>
sys.error(s"Cannot get typeName($tpe)")
}
Expand Down
24 changes: 0 additions & 24 deletions sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9827,30 +9827,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite =>
}
}

property("higher order lambdas") {
val f = existingFeature(
{ (xs: Coll[Int]) =>
val inc = { (x: Int) => x + 1 }

def apply(in: (Int => Int, Int)) = in._1(in._2)

xs.map { (x: Int) => apply((inc, x)) }
},
"""{(xs: Coll[Int]) =>
| val inc = { (x: Int) => x + 1 }
| def apply(in: (Int => Int, Int)) = in._1(in._2)
| xs.map { (x: Int) => apply((inc, x)) }
| }
|""".stripMargin
)

// TODO v6.0: Add support of SFunc in TypeSerializer (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/847)
assertExceptionThrown(
f.verifyCase(Coll[Int](), Expected(Success(Coll[Int]()), 0)),
exceptionLike[MatchError]("(SInt$) => SInt$ (of class sigma.ast.SFunc)")
)
}

override protected def afterAll(): Unit = {
printDebug(CErgoTreeEvaluator.DefaultProfiler.generateReport)
printDebug("==========================================================")
Expand Down
72 changes: 72 additions & 0 deletions sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import sigma.ast.syntax.TrueSigmaProp
import sigma.ast._
import sigma.data.{CBigInt, ExactNumeric}
import sigma.eval.{CostDetails, SigmaDsl, TracedCost}
import sigma.serialization.ValueCodes.OpCode
import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps}
import sigmastate.exceptions.MethodNotFound
import sigmastate.utils.Helpers
Expand Down Expand Up @@ -463,4 +464,75 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
tree.root shouldBe t2.root
}

property("higher order lambdas") {
val f = newFeature[Coll[Int], Coll[Int]](
{ (xs: Coll[Int]) =>
val inc = { (x: Int) => x + 1 }

def apply(in: (Int => Int, Int)) = in._1(in._2)

xs.map { (x: Int) => apply((inc, x)) }
},
"""{(xs: Coll[Int]) =>
| val inc = { (x: Int) => x + 1 }
| def apply(in: (Int => Int, Int)) = in._1(in._2)
| xs.map { (x: Int) => apply((inc, x)) }
| }
|""".stripMargin,
FuncValue(
Array((1, SCollectionType(SInt))),
MapCollection(
ValUse(1, SCollectionType(SInt)),
FuncValue(
Array((3, SInt)),
Apply(
FuncValue(
Array((5, SPair(SFunc(Array(SInt), SInt, List()), SInt))),
Apply(
SelectField.typed[Value[SFunc]](
ValUse(5, SPair(SFunc(Array(SInt), SInt, List()), SInt)),
1.toByte
),
Array(
SelectField.typed[Value[SInt.type]](
ValUse(5, SPair(SFunc(Array(SInt), SInt, List()), SInt)),
2.toByte
)
)
)
),
Array(
Tuple(
Vector(
FuncValue(
Array((5, SInt)),
ArithOp(ValUse(5, SInt), IntConstant(1), OpCode @@ (-102.toByte))
),
ValUse(3, SInt)
)
)
)
)
)
)
),
sinceVersion = VersionContext.V6SoftForkVersion
)

verifyCases(
Seq(
Coll(1, 2) -> Expected(
Success(Coll(2, 3)),
cost = 1793,
expectedDetails = CostDetails.ZeroCost
)
),
f,
preGeneratedSamples = Some(Seq(
Coll(Int.MinValue, Int.MaxValue - 1),
Coll(0, 1, 2, 3, 100, 1000)
))
)
}

}
29 changes: 23 additions & 6 deletions sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class SigmaDslTesting extends AnyPropSpec
s"""Should succeed with the same value or fail with the same exception, but was:
|First result: $b1
|Second result: $b2
|Input: $x
|Root cause: $cause
|""".stripMargin)
}
Expand Down Expand Up @@ -715,11 +716,17 @@ class SigmaDslTesting extends AnyPropSpec
override def checkEquality(input: A, logInputOutput: Boolean = false): Try[(B, CostDetails)] = {
// check the old implementation against Scala semantic function
var oldRes: Try[(B, CostDetails)] = null
if (ergoTreeVersionInTests < VersionContext.JitActivationVersion)
oldRes = VersionContext.withVersions(activatedVersionInTests, ergoTreeVersionInTests) {
try checkEq(scalaFunc)(oldF)(input)
catch {
case e: TestFailedException => throw e
case e: TestFailedException =>
if(activatedVersionInTests < changedInVersion) {
throw e
} else {
// old ergoscript may succeed in new version while old scalafunc may fail,
// see e.g. "Option.getOrElse with lazy default" test
Failure(e)
}
case t: Throwable =>
Failure(t)
}
Expand Down Expand Up @@ -872,10 +879,14 @@ class SigmaDslTesting extends AnyPropSpec
extends Feature[A, B] {

override def isSupportedIn(vc: VersionContext): Boolean =
vc.activatedVersion >= sinceVersion && vc.ergoTreeVersion >= sinceVersion
vc.activatedVersion >= sinceVersion

override def scalaFunc: A => B = { x =>
sys.error(s"Semantic Scala function is not defined for old implementation: $this")
if (isSupportedIn(VersionContext.current)) {
scalaFuncNew(x)
} else {
sys.error(s"Semantic Scala function is not defined for old implementation: $this")
}
}
implicit val cs = compilerSettingsInTests

Expand Down Expand Up @@ -925,8 +936,14 @@ class SigmaDslTesting extends AnyPropSpec
printTestCases: Boolean,
failOnTestVectors: Boolean): Unit = {
val funcRes = checkEquality(input, printTestCases)
funcRes.isFailure shouldBe true
Try(scalaFunc(input)) shouldBe expected.value
if(!isSupportedIn(VersionContext.current)) {
funcRes.isFailure shouldBe true
}
if(isSupportedIn(VersionContext.current)) {
Try(scalaFunc(input)) shouldBe expected.value
} else {
Try(scalaFunc(input)).isFailure shouldBe true
}
}
}

Expand Down

0 comments on commit 410f136

Please sign in to comment.