Skip to content

Commit

Permalink
Parser layer for missing operations (#324) (#332)
Browse files Browse the repository at this point in the history
* add byteArrayToLong, decodePoint, xorOf parser tests;

* add SBoolean.toByte, SOption.map, SCollection.zip, zipWith, flatMap parser tests;

* add parser tests for new SBigInt, SNumeric, SGroupElement methods;

* add parser tests for HEADERS methods;

* add LogicalNot boolean unary op in parser;

* add Negation unary op for numeric type in parser;

* add BitInversion unary op in parser;

* add BinXor binary op in parser;
commented out tests for ^ bin op (used for exponentiate);

* add BitOp node;
add parser test for bitwise AND;

* make ^ to parse as method;

* add bit-shifted ops to the parser;

* add bit collections shift ops handling in parser;
add BitRotateLeft, BitRotateLeft handling in parser;

* rename parameters, add comments;

* update scala to 2.12.8 (sync with ergo);

* re-arrange op codes after rebase;

* assign | for bit OR for numeric types;

* fixed HEADERS parser test;

* merged BitRotateLeft and BitRotateRight into BitRotate and renamed params (removed TwoArgumentsOperation);

* generalize BitRotate into Rotate to use with collection of any type;

* generalize shifts to use with collection of any type;
  • Loading branch information
greenhat authored and ergomorphic committed Dec 19, 2018
1 parent ff8b162 commit e798c20
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 16 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ lazy val allConfigDependency = "compile->compile;test->test"

lazy val commonSettings = Seq(
organization := "org.scorexfoundation",
scalaVersion := "2.12.7",
scalaVersion := "2.12.8",
resolvers += Resolver.sonatypeRepo("public"),
licenses := Seq("CC0" -> url("https://creativecommons.org/publicdomain/zero/1.0/legalcode")),
homepage := Some(url("https://github.com/ScorexFoundation/sigmastate-interpreter")),
Expand Down
38 changes: 38 additions & 0 deletions src/main/scala/sigmastate/lang/SigmaBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ trait SigmaBuilder {
def mkBinOr(left: BoolValue, right: BoolValue): BoolValue
def mkBinAnd(left: BoolValue, right: BoolValue): BoolValue
def mkAtLeast(bound: Value[SInt.type], input: Value[SCollection[SSigmaProp.type]]): SigmaPropValue
def mkBinXor(left: BoolValue, right: BoolValue): BoolValue

def mkExponentiate(left: Value[SGroupElement.type],
right: Value[SBigInt.type]): Value[SGroupElement.type]
Expand Down Expand Up @@ -187,6 +188,16 @@ trait SigmaBuilder {
def mkPlusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type]
def mkMinusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type]

def mkLogicalNot(input: Value[SBoolean.type]): Value[SBoolean.type]

def mkNegation[T <: SNumericType](input: Value[T]): Value[T]
def mkBitInversion[T <: SNumericType](input: Value[T]): Value[T]
def mkBitOr[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitAnd[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitXor[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitShiftRight[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitShiftLeft[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]

def liftAny(v: Any): Nullable[SValue] = v match {
case arr: Array[Boolean] => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean))
case arr: Array[Byte] => Nullable(mkCollectionConstant[SByte.type](arr, SByte))
Expand Down Expand Up @@ -283,6 +294,8 @@ class StdSigmaBuilder extends SigmaBuilder {
override def mkAtLeast(bound: Value[SInt.type], input: Value[SCollection[SSigmaProp.type]]): SigmaPropValue =
AtLeast(bound, input)

override def mkBinXor(left: BoolValue, right: BoolValue): BoolValue = BinXor(left, right)

override def mkExponentiate(left: Value[SGroupElement.type], right: Value[SBigInt.type]): Value[SGroupElement.type] =
Exponentiate(left, right)

Expand Down Expand Up @@ -525,6 +538,31 @@ class StdSigmaBuilder extends SigmaBuilder {

override def mkMinusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type] =
ModQArithOp(left, right, OpCodes.MinusModQCode)

override def mkLogicalNot(input: Value[SBoolean.type]): Value[SBoolean.type] =
LogicalNot(input)

override def mkNegation[T <: SNumericType](input: Value[T]): Value[T] =
Negation(input)

override def mkBitInversion[T <: SNumericType](input: Value[T]): Value[T] =
BitInversion(input)

override def mkBitOr[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
BitOp(left, right, OpCodes.BitOrCode)

override def mkBitAnd[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
BitOp(left, right, OpCodes.BitAndCode)

override def mkBitXor[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
BitOp(left, right, OpCodes.BitXorCode)

override def mkBitShiftRight[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
BitOp(bits, shift, OpCodes.BitShiftRightCode)

override def mkBitShiftLeft[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
BitOp(bits, shift, OpCodes.BitShiftLeftCode)

}

trait TypeConstraintCheck {
Expand Down
9 changes: 6 additions & 3 deletions src/main/scala/sigmastate/lang/SigmaParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ object SigmaParser extends Exprs with Types with Core {
builder.mkConstant[SLong.type](-value, SLong)
case _ => error(s"cannot prefix $arg with op $opName")
}
case "!" => builder.mkLogicalNot(arg.asBoolValue)
case "-" => builder.mkNegation(arg.asNumValue)
case "~" => builder.mkBitInversion(arg.asNumValue)
case _ => error(s"Unknown prefix operation $opName for $arg")
}

val parseAsMethods = Set("*", "++", "||", "&&", "+")
val parseAsMethods = Set("*", "++", "||", "&&", "+", "^", "<<", ">>", ">>>")

def mkBinaryOp(l: Value[SType], opName: String, r: Value[SType]): Value[SType] = opName match {
case "==" => EQ(l, r)
Expand All @@ -66,8 +69,8 @@ object SigmaParser extends Exprs with Types with Core {
case "<=" => LE(l, r)
case "<" => LT(l, r)
case "-" => builder.mkMinus(l.asValue[SLong.type], r.asValue[SLong.type])
case "|" => builder.mkXor(l.asValue[SByteArray], r.asValue[SByteArray])
case "^" => builder.mkExponentiate(l.asValue[SGroupElement.type], r.asValue[SBigInt.type])
case "|" => builder.mkBitOr(l.asNumValue, r.asNumValue)
case "&" => builder.mkBitAnd(l.asNumValue, r.asNumValue)
case _ if parseAsMethods.contains(opName) =>
MethodCallLike(l, opName, IndexedSeq(r))
case "/" => builder.mkDivide(l.asValue[SLong.type], r.asValue[SLong.type])
Expand Down
22 changes: 21 additions & 1 deletion src/main/scala/sigmastate/serialization/OpCodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,25 @@ object OpCodes extends ValueCodes {

val DecodePointCode: OpCode = (LastConstantCode + 126).toByte

// reserved 127 - 143 (17)
val LogicalNotCode : OpCode = (LastConstantCode + 127).toByte
val NegationCode : OpCode = (LastConstantCode + 128).toByte
val BitInversionCode : OpCode = (LastConstantCode + 129).toByte
val BitOrCode : OpCode = (LastConstantCode + 130).toByte
val BitAndCode : OpCode = (LastConstantCode + 131).toByte

val BinXorCode : OpCode = (LastConstantCode + 132).toByte

val BitXorCode : OpCode = (LastConstantCode + 133).toByte
val BitShiftRightCode : OpCode = (LastConstantCode + 134).toByte
val BitShiftLeftCode : OpCode = (LastConstantCode + 135).toByte
val BitShiftRightZeroedCode : OpCode = (LastConstantCode + 136).toByte

val CollShiftRightCode : OpCode = (LastConstantCode + 137).toByte
val CollShiftLeftCode : OpCode = (LastConstantCode + 138).toByte
val CollShiftRightZeroedCode : OpCode = (LastConstantCode + 139).toByte

val CollRotateLeftCode : OpCode = (LastConstantCode + 140).toByte
val CollRotateRightCode : OpCode = (LastConstantCode + 141).toByte

// reserved 142 - 143 (2)
}
1 change: 0 additions & 1 deletion src/main/scala/sigmastate/sigmastate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,4 @@ package object sigmastate {

def MinusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type] =
mkMinusModQ(left, right)

}
37 changes: 37 additions & 0 deletions src/main/scala/sigmastate/trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,23 @@ object ArithOp {
}
}

case class Negation[T <: SNumericType](input: Value[T]) extends NotReadyValue[T] {
override val opCode: OpCode = OpCodes.NegationCode
override def tpe: T = input.tpe
override def opType: SFunc = SFunc(input.tpe, tpe)
}

case class BitInversion[T <: SNumericType](input: Value[T]) extends NotReadyValue[T] {
override val opCode: OpCode = OpCodes.BitInversionCode
override def tpe: T = input.tpe
override def opType: SFunc = SFunc(input.tpe, tpe)
}

case class BitOp[T <: SNumericType](left: Value[T], right: Value[T], opCode: OpCode)
extends TwoArgumentsOperation[T, T, T] with NotReadyValue[T] {
override def tpe: T = left.tpe
}

case class ModQ(input: Value[SBigInt.type])
extends NotReadyValue[SBigInt.type] {
override val opCode: OpCode = OpCodes.ModQCode
Expand Down Expand Up @@ -477,6 +494,21 @@ case class BinAnd(override val left: BoolValue, override val right: BoolValue)
override val opCode: OpCode = BinAndCode
}

case class BinXor(override val left: BoolValue, override val right: BoolValue)
extends Relation[SBoolean.type, SBoolean.type] {
override val opCode: OpCode = BinXorCode
}

/** Returns this collection shifted left/right by the specified number of elements,
* filling in the new right/left elements from left/right elements. The size of collection is preserved. */
case class Rotate[T <: SType](coll: Value[SCollection[T]],
shift: Value[SInt.type],
opCode: OpCode)
extends NotReadyValue[SCollection[T]] {
override def tpe: SCollection[T] = coll.tpe
override def opType = SFunc(Vector(coll.tpe, shift.tpe), tpe)
}

/**
* A tree node with three descendants
*/
Expand Down Expand Up @@ -545,3 +577,8 @@ case class If[T <: SType](condition: Value[SBoolean.type], trueBranch: Value[T],
object If {
val tT = STypeIdent("T")
}

case class LogicalNot(input: Value[SBoolean.type]) extends NotReadyValueBoolean {
override val opCode: OpCode = OpCodes.LogicalNotCode
override val opType = SFunc(Vector(SBoolean), SBoolean)
}
7 changes: 5 additions & 2 deletions src/test/scala/sigmastate/lang/SigmaBinderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with La
bind(env, "HEIGHT - 1") shouldBe mkMinus(Height, 1)
bind(env, "HEIGHT + 1") shouldBe plus(Height, 1)
bind(env, "INPUTS.size > 1") shouldBe GT(Select(Inputs, "size").asIntValue, 1)
bind(env, "arr1 | arr2") shouldBe Xor(Array[Byte](1, 2), Array[Byte](10, 20))
// todo: restore in https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324
// bind(env, "arr1 | arr2") shouldBe Xor(Array[Byte](1, 2), Array[Byte](10, 20))
bind(env, "arr1 ++ arr2") shouldBe MethodCallLike(Array[Byte](1, 2), "++", IndexedSeq(Array[Byte](10, 20))) // AppendBytes(Array[Byte](1, 2), Array[Byte](10,20))
bind(env, "col1 ++ col2") shouldBe
MethodCallLike(
ConcreteCollection(LongConstant(1), LongConstant(2)),
"++", IndexedSeq(ConcreteCollection(LongConstant(10), LongConstant(20))))
bind(env, "g1 ^ n1") shouldBe Exponentiate(g1, n1)
// todo should be g1.exp(n1)
// ( see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324 )
// bind(env, "g1 ^ n1") shouldBe Exponentiate(g1, n1)
bind(env, "g1 * g2") shouldBe MethodCallLike(g1, "*", IndexedSeq(g2))
}

Expand Down
Loading

0 comments on commit e798c20

Please sign in to comment.