Skip to content

Commit 4ca5e73

Browse files
authored
Merge pull request #1055 from novamon/i1039
I1039 Finishes executeFromSelfReg
2 parents e0cc6e5 + 762e2f2 commit 4ca5e73

File tree

10 files changed

+304
-8
lines changed

10 files changed

+304
-8
lines changed

data/shared/src/main/scala/sigma/SigmaDataReflection.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,18 @@ object SigmaDataReflection {
645645
)
646646
)
647647

648+
registerClassEntry(classOf[DeserializeRegister[_]],
649+
constructors = Array(
650+
mkConstructor(Array(classOf[RegisterId], classOf[SType], classOf[SOption[_]])) { args =>
651+
new DeserializeRegister[SType](
652+
args(0).asInstanceOf[RegisterId],
653+
args(1).asInstanceOf[SType],
654+
args(2).asInstanceOf[Option[Value[SType]]]
655+
)
656+
}
657+
)
658+
)
659+
648660
registerClassEntry(classOf[LongToByteArray],
649661
constructors = Array(
650662
mkConstructor(Array(classOf[Value[_]])) { args =>

data/shared/src/main/scala/sigma/ast/Operations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ object Operations {
190190
}
191191

192192
object DeserializeRegisterInfo extends InfoObject {
193-
private val func = predefinedOps.funcs("executeFromSelfReg")
193+
private val func = predefinedOps.funcs("executeFromSelfRegWithDefault")
194194
val idArg: ArgInfo = func.argInfo("id")
195195
val defaultArg: ArgInfo = func.argInfo("default")
196196
val argInfos: Seq[ArgInfo] = Array(idArg, defaultArg)

data/shared/src/main/scala/sigma/ast/SigmaPredef.scala

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ package sigma.ast
22

33
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
44
import org.ergoplatform.{ErgoAddressEncoder, P2PKAddress}
5+
import org.ergoplatform.ErgoBox.RegisterId
56
import scorex.util.encode.{Base16, Base58, Base64}
7+
import sigma.data._
8+
import sigma.{Colls}
69
import sigma.ast.SCollection.{SByteArray, SIntArray}
710
import sigma.ast.SOption.SIntOption
811
import sigma.ast.SigmaPropConstant
912
import sigma.ast.syntax._
1013
import sigma.data.Nullable
14+
import sigma.data.RType.asType
15+
import sigma.Evaluation.stypeToRType
16+
import scala.reflect.ClassTag
1117
import sigma.exceptions.InvalidArguments
1218
import sigma.serialization.CoreByteWriter.ArgInfo
1319
import sigma.serialization.ValueSerializer
@@ -383,25 +389,63 @@ object SigmaPredef {
383389
Seq(ArgInfo("id", "identifier of the context variable")))
384390
)
385391

386-
val ExecuteFromSelfRegFunc = PredefinedFunc("executeFromSelfReg",
392+
val ExecuteFromSelfRegWithDefaultFunc = PredefinedFunc("executeFromSelfRegWithDefault",
387393
Lambda(
388394
Seq(paramT),
389-
Array("id" -> SByte, "default" -> SOption(tT)),
395+
Array("id" -> SInt, "default" -> tT),
390396
tT, None
391397
),
392-
PredefFuncInfo(undefined),
398+
PredefFuncInfo(
399+
{ case (Ident(_, SFunc(_, rtpe, _)), Seq(id: Constant[SNumericType]@unchecked, default)) =>
400+
val idx: Int = SInt.downcast((id.value.asInstanceOf[AnyVal]))
401+
if (idx < 0 || idx >= org.ergoplatform.ErgoBox.allRegisters.length) {
402+
default.v
403+
} else {
404+
val r: RegisterId = org.ergoplatform.ErgoBox.registerByIndex(idx)
405+
val d = Some(default.asValue[rtpe.type])
406+
mkDeserializeRegister[rtpe.type](r, rtpe, d)
407+
}
408+
}),
393409
OperationInfo(DeserializeRegister,
394410
"""Extracts SELF register as \lst{Coll[Byte]}, deserializes it to script
395411
| and then executes this script in the current context.
396412
| The original \lst{Coll[Byte]} of the script is available as \lst{SELF.getReg[Coll[Byte]](id)}.
397413
| Type parameter \lst{T} result type of the deserialized script.
398414
| Throws an exception if the actual script type doesn't conform to \lst{T}.
399-
| Returns a result of the script execution in the current context
415+
| Returns a result of the script execution in the current context or the default value
416+
| provided when the specified register is unavailable
400417
""".stripMargin,
401418
Seq(ArgInfo("id", "identifier of the register"),
402419
ArgInfo("default", "optional default value, if register is not available")))
403420
)
404421

422+
val ExecuteFromSelfRegFunc = PredefinedFunc("executeFromSelfReg",
423+
Lambda(
424+
Seq(paramT),
425+
Array("id" -> SInt),
426+
tT, None
427+
),
428+
PredefFuncInfo(
429+
{ case (Ident(_, SFunc(_, rtpe, _)), Seq(id: Constant[SNumericType]@unchecked)) =>
430+
val idx: Int = SInt.downcast((id.value.asInstanceOf[AnyVal]))
431+
if (idx < 0 || idx >= org.ergoplatform.ErgoBox.allRegisters.length) {
432+
throw new InvalidArguments(s"Invalid register specified $id")
433+
}
434+
435+
val r: RegisterId = org.ergoplatform.ErgoBox.registerByIndex(idx)
436+
mkDeserializeRegister[rtpe.type](r, rtpe, None)
437+
}),
438+
OperationInfo(DeserializeRegister,
439+
"""Extracts SELF register as \lst{Coll[Byte]}, deserializes it to script
440+
| and then executes this script in the current context.
441+
| The original \lst{Coll[Byte]} of the script is available as \lst{SELF.getReg[Coll[Byte]](id)}.
442+
| Type parameter \lst{T} result type of the deserialized script.
443+
| Throws an exception if the actual script type doesn't conform to \lst{T}.
444+
| Returns a result of the script execution in the current context
445+
""".stripMargin,
446+
Seq(ArgInfo("id", "identifier of the register")))
447+
)
448+
405449
val globalFuncs: Map[String, PredefinedFunc] = Seq(
406450
AllOfFunc,
407451
AnyOfFunc,
@@ -429,6 +473,7 @@ object SigmaPredef {
429473
AvlTreeFunc,
430474
SubstConstantsFunc,
431475
ExecuteFromVarFunc,
476+
ExecuteFromSelfRegWithDefaultFunc,
432477
ExecuteFromSelfRegFunc
433478
).map(f => f.name -> f).toMap
434479

data/shared/src/main/scala/sigma/ast/transformers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ object DeserializeContext extends ValueCompanion {
548548
}
549549

550550
/** Extract register of SELF box as Coll[Byte], deserialize it into Value and inline into executing script.
551-
* NOTE: it only applicable to SELF box
551+
* NOTE: it's only applicable to SELF box
552552
*/
553553
case class DeserializeRegister[V <: SType](reg: RegisterId, tpe: V, default: Option[Value[V]] = None) extends Deserialize[V] {
554554
override def companion = DeserializeRegister

docs/LangSpec.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,55 @@ def PK(input: String): SigmaProp
10171017
*/
10181018
def deserialize[T](string: String): T
10191019

1020+
/**
1021+
*
1022+
* Extracts, deserializes and executes a script contained in the context variable specified
1023+
* by id. Returns the result of the script execution in the current context.
1024+
* Throws an exception if the result type of the execution doesn't conform to the return
1025+
* type specified.
1026+
*
1027+
* @param id context variable holding the serialized script to execute
1028+
* @tparam T expected type of the variable and return type.
1029+
* @return result of the executed script
1030+
* @throws InvalidType exception when the result type of the execution value is
1031+
* different from T.
1032+
*/
1033+
def executeFromVar[T](id: Byte): T
1034+
1035+
/**
1036+
*
1037+
* Extracts, deserializes and executes a script contained in the SELF register
1038+
* indicated by id. Returns the result of the script execution in the current context
1039+
* An exception is thrown if the result type of the execution doesn't conform to the
1040+
* return type specified and if an invalid register is specified.
1041+
*
1042+
* @param id register id holding the serialized script to execute
1043+
* @tparam T expected type of the register and return type.
1044+
* @return result of the executed script or default value
1045+
* @throws InterpreterException when a script reduces to false
1046+
* @throws InvalidType exception when the result type of the execution value is
1047+
* different from T.
1048+
*/
1049+
def executeFromSelfReg[T](id: Int): T
1050+
1051+
/**
1052+
*
1053+
* Extracts, deserializes and executes a script contained in the SELF register
1054+
* indicated by id. Returns the result of the script execution in the current context
1055+
* or default value, if the register is unavailable. An exception is thrown if the result
1056+
* type of the execution doesn't conform to the return type specified and if an invalid
1057+
* register is specified.
1058+
*
1059+
* @param id register id holding the serialized script to execute
1060+
* @param default value returned if the register is unavailable
1061+
* @tparam T expected type of the register and return type.
1062+
* @return result of the executed script or default value
1063+
* @throws InterpreterException when a script reduces to false
1064+
* @throws InvalidType exception when the result type of the execution value is
1065+
* different from T.
1066+
*/
1067+
def executeFromSelfRegWithDefault[T](id: Int, default: T): T
1068+
10201069
/**
10211070
* Transforms serialized bytes of ErgoTree with segregated constants by
10221071
* replacing constants at given positions with new values. This operation allow

sc/shared/src/main/scala/sigma/compiler/ir/Base.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package sigma.compiler.ir
22

33
import debox.{cfor, Buffer => DBuffer}
44
import sigma.compiler.ir.core.MutableLazy
5-
import sigma.ast.{DeserializeContext, SType}
5+
import sigma.ast.{DeserializeContext, DeserializeRegister, SType}
66
import sigma.data.{AVHashMap, Nullable, RType}
77
import sigma.data.OverloadHack.Overloaded1
88
import sigma.reflection.RConstructor
@@ -211,6 +211,13 @@ abstract class Base { thisIR: IRContext =>
211211
override def resultType: Elem[V#WrappedType] = e
212212
}
213213

214+
/**
215+
* Def done in order to carry on DeserializeRegister through stages of compilation intact
216+
*/
217+
case class DeserializeRegisterDef[V <: SType](d: DeserializeRegister[V], e: Elem[V#WrappedType]) extends Def[V#WrappedType] {
218+
override def resultType: Elem[V#WrappedType] = e
219+
}
220+
214221
/** Base class for virtualized instances of type companions.
215222
* Each virtualized entity type (trait or class) may have virtualized companion class. */
216223
abstract class CompanionDef[T] extends Def[T] {

sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import sigma.{SigmaException, ast}
1717
import sigmastate.interpreter.Interpreter.ScriptEnv
1818

1919
import scala.collection.mutable.ArrayBuffer
20+
import scala.language.{existentials,implicitConversions}
2021

2122
/** Perform translation of typed expression given by [[Value]] to a graph in IRContext.
2223
* Which be than be translated to [[ErgoTree]] by using [[TreeBuilding]].
@@ -553,6 +554,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
553554
val e = stypeToElem(d.tpe)
554555
DeserializeContextDef(d, e)
555556

557+
case d: DeserializeRegister[T] =>
558+
val e = stypeToElem(d.tpe)
559+
DeserializeRegisterDef[T](d, e)
560+
556561
case ValUse(valId, _) =>
557562
env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env"))
558563

sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ trait TreeBuilding extends Base { IR: IRContext =>
192192
case Def(DeserializeContextDef(d, _)) =>
193193
d
194194

195+
case Def(DeserializeRegisterDef(d, _)) =>
196+
d
197+
195198
case Def(IsContextProperty(v)) => v
196199
case s if s == sigmaDslBuilder => Global
197200

sc/shared/src/test/scala/sigmastate/lang/SigmaTyperTest.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,14 @@ class SigmaTyperTest extends AnyPropSpec
563563
typecheck(env, "executeFromVar[Boolean](1)") shouldBe SBoolean
564564
}
565565

566+
property("executeFromSelfRegWithDefault") {
567+
typecheck(env, "executeFromSelfRegWithDefault[Boolean](4, getVar[Boolean](1).get)") shouldBe SBoolean
568+
569+
an[TyperException] should be thrownBy {
570+
typecheck(env, "executeFromSelfRegWithDefault[Boolean](4, getVar[Int](1).get)")
571+
}
572+
}
573+
566574
property("LogicalNot") {
567575
typecheck(env, "!true") shouldBe SBoolean
568576
typefail(env, "!getVar[SigmaProp](1).get", 1, 2)

0 commit comments

Comments
 (0)