From ce35ff374ad7dfc282e7b5295df23498674cbf3f Mon Sep 17 00:00:00 2001 From: He-Pin Date: Fri, 6 Mar 2026 13:24:44 +0800 Subject: [PATCH] chore: Make aggressive optimization default --- sjsonnet/src/sjsonnet/Expr.scala | 103 +- .../src/sjsonnet/ScopedExprTransform.scala | 2 +- sjsonnet/src/sjsonnet/Settings.scala | 9 +- sjsonnet/src/sjsonnet/StaticOptimizer.scala | 49 +- sjsonnet/src/sjsonnet/Val.scala | 16 +- .../AggressiveStaticOptimizationTests.scala | 225 ++-- .../test/src/sjsonnet/CustomValTests.scala | 2 +- .../test/src/sjsonnet/EvaluatorTests.scala | 1058 ++++------------- sjsonnet/test/src/sjsonnet/TestUtils.scala | 8 +- 9 files changed, 384 insertions(+), 1088 deletions(-) diff --git a/sjsonnet/src/sjsonnet/Expr.scala b/sjsonnet/src/sjsonnet/Expr.scala index e0710ccf..16d5da0d 100644 --- a/sjsonnet/src/sjsonnet/Expr.scala +++ b/sjsonnet/src/sjsonnet/Expr.scala @@ -12,7 +12,17 @@ import scala.collection.immutable.IntMap * into the file that is later used to provide error messages. */ trait Expr { - def pos: Position + + /** + * Source position of this expression, used for error messages. + * + * This is a `var` (not `val` or `def`) so that [[StaticOptimizer]] can update positions in-place + * when it replaces an expression with a sub-expression (e.g. branch elimination: + * `IfElse(pos, true, thenExpr, _)` → `thenExpr` with `thenExpr.pos = pos`). Without mutable + * `pos`, the optimizer would need to wrap the result in a `LocalExpr` just to carry the original + * position, adding unnecessary AST nodes. Do not change this to `val` or `def`. + */ + var pos: Position private[sjsonnet] def tag: Byte = ExprTags.UNTAGGED /** The name of this expression type to be shown in error messages */ @@ -60,26 +70,26 @@ object Expr { if (a == null) "null" else a.mkString("[", ", ", "]") } - final case class Self(pos: Position) extends Expr { + final case class Self(var pos: Position) extends Expr { final override private[sjsonnet] def tag = ExprTags.Self } - final case class Super(pos: Position) extends Expr { + final case class Super(var pos: Position) extends Expr { final override private[sjsonnet] def tag = ExprTags.Super } - final case class $(pos: Position) extends Expr { + final case class $(var pos: Position) extends Expr { final override private[sjsonnet] def tag = ExprTags.`$` } - final case class Id(pos: Position, name: String) extends Expr { + final case class Id(var pos: Position, name: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.Id override def exprErrorString: String = s"${super.exprErrorString} $name" } - final case class ValidId(pos: Position, name: String, nameIdx: Int) extends Expr { + final case class ValidId(var pos: Position, name: String, nameIdx: Int) extends Expr { final override private[sjsonnet] def tag = ExprTags.ValidId override def exprErrorString: String = s"${super.exprErrorString} $name" } - final case class Arr(pos: Position, value: Array[Expr]) extends Expr { + final case class Arr(var pos: Position, value: Array[Expr]) extends Expr { final override private[sjsonnet] def tag = ExprTags.Arr override def toString: String = s"Arr($pos, ${arrStr(value)})" } @@ -101,7 +111,7 @@ object Expr { case object Unhide extends Visibility } final case class Field( - pos: Position, + var pos: Position, fieldName: FieldName, plus: Boolean, // see https://jsonnet.org/ref/language.html#nested-field-inheritance args: Params, @@ -120,7 +130,7 @@ object Expr { override def toString: String = s"Params(${arrStr(names)}, ${arrStr(defaultExprs)})" } - final case class UnaryOp(pos: Position, op: Int, value: Expr) extends Expr { + final case class UnaryOp(var pos: Position, op: Int, value: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.UnaryOp override def exprErrorString: String = s"${super.exprErrorString} ${UnaryOp.name(op)}" } @@ -132,13 +142,13 @@ object Expr { private val names = IntMap(OP_! -> "!", OP_- -> "-", OP_~ -> "~", OP_+ -> "+") def name(op: Int): String = names.getOrElse(op, "") } - final case class And(pos: Position, lhs: Expr, rhs: Expr) extends Expr { + final case class And(var pos: Position, lhs: Expr, rhs: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.And } - final case class Or(pos: Position, lhs: Expr, rhs: Expr) extends Expr { + final case class Or(var pos: Position, lhs: Expr, rhs: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.Or } - final case class BinaryOp(pos: Position, lhs: Expr, op: Int, rhs: Expr) extends Expr { + final case class BinaryOp(var pos: Position, lhs: Expr, op: Int, rhs: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.BinaryOp override def exprErrorString: String = s"${super.exprErrorString} ${BinaryOp.name(op)}" } @@ -185,11 +195,12 @@ object Expr { ) def name(op: Int): String = names.getOrElse(op, "") } - final case class AssertExpr(pos: Position, asserted: Member.AssertStmt, returned: Expr) + final case class AssertExpr(var pos: Position, asserted: Member.AssertStmt, returned: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.AssertExpr } - final case class LocalExpr(pos: Position, bindings: Array[Bind], returned: Expr) extends Expr { + final case class LocalExpr(var pos: Position, bindings: Array[Bind], returned: Expr) + extends Expr { final override private[sjsonnet] def tag = ExprTags.LocalExpr override def toString: String = s"LocalExpr($pos, ${arrStr(bindings)}, $returned)" override def equals(o: Any): Boolean = o match { @@ -202,21 +213,21 @@ object Expr { } } - final case class Bind(pos: Position, name: String, args: Params, rhs: Expr) extends Member - final case class Import(pos: Position, value: String) extends Expr { + final case class Bind(var pos: Position, name: String, args: Params, rhs: Expr) extends Member + final case class Import(var pos: Position, value: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.Import } - final case class ImportStr(pos: Position, value: String) extends Expr { + final case class ImportStr(var pos: Position, value: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.ImportStr } - final case class ImportBin(pos: Position, value: String) extends Expr { + final case class ImportBin(var pos: Position, value: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.ImportBin } - final case class Error(pos: Position, value: Expr) extends Expr { + final case class Error(var pos: Position, value: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.Error } final case class Apply( - pos: Position, + var pos: Position, value: Expr, args: Array[Expr], namedNames: Array[String], @@ -225,23 +236,23 @@ object Expr { final override private[sjsonnet] def tag = ExprTags.Apply override def exprErrorString: String = Expr.callTargetName(value) } - final case class Apply0(pos: Position, value: Expr, tailstrict: Boolean) + final case class Apply0(var pos: Position, value: Expr, tailstrict: Boolean) extends TailstrictableExpr { final override private[sjsonnet] def tag = ExprTags.Apply0 override def exprErrorString: String = Expr.callTargetName(value) } - final case class Apply1(pos: Position, value: Expr, a1: Expr, tailstrict: Boolean) + final case class Apply1(var pos: Position, value: Expr, a1: Expr, tailstrict: Boolean) extends TailstrictableExpr { final override private[sjsonnet] def tag = ExprTags.Apply1 override def exprErrorString: String = Expr.callTargetName(value) } - final case class Apply2(pos: Position, value: Expr, a1: Expr, a2: Expr, tailstrict: Boolean) + final case class Apply2(var pos: Position, value: Expr, a1: Expr, a2: Expr, tailstrict: Boolean) extends TailstrictableExpr { final override private[sjsonnet] def tag = ExprTags.Apply2 override def exprErrorString: String = Expr.callTargetName(value) } final case class Apply3( - pos: Position, + var pos: Position, value: Expr, a1: Expr, a2: Expr, @@ -252,7 +263,7 @@ object Expr { override def exprErrorString: String = Expr.callTargetName(value) } final case class ApplyBuiltin( - pos: Position, + var pos: Position, func: Val.Builtin, argExprs: Array[Expr], tailstrict: Boolean) @@ -260,18 +271,22 @@ object Expr { final override private[sjsonnet] def tag = ExprTags.ApplyBuiltin override def exprErrorString: String = func.qualifiedName } - final case class ApplyBuiltin0(pos: Position, func: Val.Builtin0, tailstrict: Boolean) + final case class ApplyBuiltin0(var pos: Position, func: Val.Builtin0, tailstrict: Boolean) extends TailstrictableExpr { final override private[sjsonnet] def tag = ExprTags.ApplyBuiltin0 override def exprErrorString: String = func.qualifiedName } - final case class ApplyBuiltin1(pos: Position, func: Val.Builtin1, a1: Expr, tailstrict: Boolean) + final case class ApplyBuiltin1( + var pos: Position, + func: Val.Builtin1, + a1: Expr, + tailstrict: Boolean) extends TailstrictableExpr { final override private[sjsonnet] def tag = ExprTags.ApplyBuiltin1 override def exprErrorString: String = func.qualifiedName } final case class ApplyBuiltin2( - pos: Position, + var pos: Position, func: Val.Builtin2, a1: Expr, a2: Expr, @@ -281,7 +296,7 @@ object Expr { override def exprErrorString: String = func.qualifiedName } final case class ApplyBuiltin3( - pos: Position, + var pos: Position, func: Val.Builtin3, a1: Expr, a2: Expr, @@ -292,7 +307,7 @@ object Expr { override def exprErrorString: String = func.qualifiedName } final case class ApplyBuiltin4( - pos: Position, + var pos: Position, func: Val.Builtin4, a1: Expr, a2: Expr, @@ -303,25 +318,25 @@ object Expr { override private[sjsonnet] def tag = ExprTags.ApplyBuiltin4 override def exprErrorString: String = func.qualifiedName } - final case class Select(pos: Position, value: Expr, name: String) extends Expr { + final case class Select(var pos: Position, value: Expr, name: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.Select override def exprErrorString: String = s"${super.exprErrorString} $name" } - final case class SelectSuper(pos: Position, selfIdx: Int, name: String) extends Expr { + final case class SelectSuper(var pos: Position, selfIdx: Int, name: String) extends Expr { final override private[sjsonnet] def tag = ExprTags.SelectSuper override def exprErrorString: String = s"${super.exprErrorString} $name" } - final case class InSuper(pos: Position, value: Expr, selfIdx: Int) extends Expr { + final case class InSuper(var pos: Position, value: Expr, selfIdx: Int) extends Expr { final override private[sjsonnet] def tag = ExprTags.InSuper } - final case class Lookup(pos: Position, value: Expr, index: Expr) extends Expr { + final case class Lookup(var pos: Position, value: Expr, index: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.Lookup } - final case class LookupSuper(pos: Position, selfIdx: Int, index: Expr) extends Expr { + final case class LookupSuper(var pos: Position, selfIdx: Int, index: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.LookupSuper } final case class Slice( - pos: Position, + var pos: Position, value: Expr, start: Option[Expr], end: Option[Expr], @@ -329,30 +344,30 @@ object Expr { extends Expr { final override private[sjsonnet] def tag = ExprTags.Slice } - final case class Function(pos: Position, params: Params, body: Expr) extends Expr { + final case class Function(var pos: Position, params: Params, body: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.Function } - final case class IfElse(pos: Position, cond: Expr, `then`: Expr, `else`: Expr) extends Expr { + final case class IfElse(var pos: Position, cond: Expr, `then`: Expr, `else`: Expr) extends Expr { final override private[sjsonnet] def tag = ExprTags.IfElse } sealed trait CompSpec extends Expr - final case class IfSpec(pos: Position, cond: Expr) extends CompSpec - final case class ForSpec(pos: Position, name: String, cond: Expr) extends CompSpec + final case class IfSpec(var pos: Position, cond: Expr) extends CompSpec + final case class ForSpec(var pos: Position, name: String, cond: Expr) extends CompSpec - final case class Comp(pos: Position, value: Expr, first: ForSpec, rest: Array[CompSpec]) + final case class Comp(var pos: Position, value: Expr, first: ForSpec, rest: Array[CompSpec]) extends Expr { final override private[sjsonnet] def tag = ExprTags.Comp override def exprErrorString: String = "array comprehension" } - final case class ObjExtend(pos: Position, base: Expr, ext: ObjBody) extends Expr { + final case class ObjExtend(var pos: Position, base: Expr, ext: ObjBody) extends Expr { final override private[sjsonnet] def tag = ExprTags.ObjExtend } trait ObjBody extends Expr object ObjBody { final case class MemberList( - pos: Position, + var pos: Position, binds: Array[Bind], fields: Array[Member.Field], asserts: Array[Member.AssertStmt]) @@ -362,7 +377,7 @@ object Expr { s"MemberList($pos, ${arrStr(binds)}, ${arrStr(fields)}, ${arrStr(asserts)})" } final case class ObjComp( - pos: Position, + var pos: Position, preLocals: Array[Bind], key: Expr, value: Expr, diff --git a/sjsonnet/src/sjsonnet/ScopedExprTransform.scala b/sjsonnet/src/sjsonnet/ScopedExprTransform.scala index da84f1e1..c7d58bde 100644 --- a/sjsonnet/src/sjsonnet/ScopedExprTransform.scala +++ b/sjsonnet/src/sjsonnet/ScopedExprTransform.scala @@ -13,7 +13,7 @@ class ScopedExprTransform extends ExprTransform { // Marker for Exprs in the scope that should not be used because they need to be evaluated in a different scope val dynamicExpr: Expr = new Expr { - def pos: Position = ???; override def toString = "dynamicExpr" + var pos: Position = null; override def toString = "dynamicExpr" } def transform(e: Expr): Expr = e match { diff --git a/sjsonnet/src/sjsonnet/Settings.scala b/sjsonnet/src/sjsonnet/Settings.scala index 9afd92b7..afc086a0 100644 --- a/sjsonnet/src/sjsonnet/Settings.scala +++ b/sjsonnet/src/sjsonnet/Settings.scala @@ -13,14 +13,7 @@ final case class Settings( brokenAssertionLogic: Boolean = false, maxMaterializeDepth: Int = 1000, materializeRecursiveDepthLimit: Int = 128, - maxStack: Int = 500, - /** - * Enable aggressive static optimizations in the optimization phase, including: constant folding - * for arithmetic, comparison, bitwise, and shift operators; branch elimination for if-else with - * constant conditions; short-circuit elimination for And/Or with constant lhs. These reduce AST - * node count, benefiting long-running Jsonnet programs. - */ - aggressiveStaticOptimization: Boolean = false + maxStack: Int = 500 ) object Settings { diff --git a/sjsonnet/src/sjsonnet/StaticOptimizer.scala b/sjsonnet/src/sjsonnet/StaticOptimizer.scala index e6efd570..1ed8ad77 100644 --- a/sjsonnet/src/sjsonnet/StaticOptimizer.scala +++ b/sjsonnet/src/sjsonnet/StaticOptimizer.scala @@ -9,8 +9,7 @@ import ScopedExprTransform.* * StaticOptimizer performs necessary transformations for the evaluator (assigning ValScope indices) * plus additional optimizations (post-order) and static checking (pre-order). * - * When `aggressiveStaticOptimization` is enabled, the optimizer additionally performs during the - * optimization phase: + * The optimizer performs: * - Constant folding for arithmetic (+, -, *, /, %), comparison (<, >, <=, >=, ==, !=), bitwise * (&, ^, |), shift (<<, >>), and unary (!, -, ~, +) operators. * - Branch elimination for if-else with constant conditions. @@ -32,8 +31,6 @@ class StaticOptimizer( extends ScopedExprTransform { def optimize(e: Expr): Expr = transform(e) - private val aggressiveOptimization = ev.settings.aggressiveStaticOptimization - override def transform(_e: Expr): Expr = super.transform(check(_e)) match { case a: Apply => transformApply(a) @@ -104,18 +101,8 @@ class StaticOptimizer( if (binds == null && asserts == null && allFieldsStaticAndUniquelyNamed) Val.staticObject(pos, fields, internedStaticFieldSets, internedStrings) else m - // Aggressive optimizations: constant folding, branch elimination, short-circuit elimination. // These reduce AST node count at parse time, benefiting long-running Jsonnet programs. - case e => if (aggressiveOptimization) tryAggressiveOptimize(e) else e - } - - /** - * Aggressive static optimizations that benefit long-running programs by reducing AST size. - * Includes: branch elimination, short-circuit elimination, constant folding for arithmetic, - * comparison, bitwise, and shift operators. - */ - private def tryAggressiveOptimize(e: Expr): Expr = e match { // Constant folding: BinaryOp with two constant operands (most common case first) case e @ BinaryOp(pos, lhs: Val, op, rhs: Val) => tryFoldBinaryOp(pos, lhs, op, rhs, e) @@ -123,9 +110,11 @@ class StaticOptimizer( case e @ UnaryOp(pos, op, v: Val) => tryFoldUnaryOp(pos, op, v, e) // Branch elimination: constant condition in if-else - case IfElse(_, _: Val.True, thenExpr, _) => thenExpr + case IfElse(pos, _: Val.True, thenExpr, _) => + thenExpr.pos = pos; thenExpr case IfElse(pos, _: Val.False, _, elseExpr) => - if (elseExpr == null) Val.Null(pos) else elseExpr + if (elseExpr == null) Val.Null(pos) + else { elseExpr.pos = pos; elseExpr } // Short-circuit elimination for And/Or with constant lhs. // @@ -135,12 +124,11 @@ class StaticOptimizer( // into just `rhs` without the Bool guard, we silently remove that runtime type check, // causing programs like `true && "hello"` to return "hello" instead of erroring. // See: Evaluator.visitAnd / Evaluator.visitOr for the authoritative runtime semantics. - case And(_, _: Val.True, rhs: Val.Bool) => rhs - case And(pos, _: Val.False, _) => Val.False(pos) - case Or(pos, _: Val.True, _) => Val.True(pos) - case Or(_, _: Val.False, rhs: Val.Bool) => rhs - - case _ => e + case And(pos, _: Val.True, rhs: Val.Bool) => rhs.pos = pos; rhs + case And(pos, _: Val.False, _) => Val.False(pos) + case Or(pos, _: Val.True, _) => Val.True(pos) + case Or(pos, _: Val.False, rhs: Val.Bool) => rhs.pos = pos; rhs + case e => e } private object ValidSuper { @@ -400,25 +388,20 @@ class StaticOptimizer( } case BinaryOp.OP_& => (lhs, rhs) match { - case (Val.Num(_, _), Val.Num(_, _)) => - Val.Num( - pos, - (lhs.asInstanceOf[Val.Num].asSafeLong & rhs - .asInstanceOf[Val.Num] - .asSafeLong).toDouble - ) + case (l: Val.Num, r: Val.Num) => + Val.Num(pos, (l.asSafeLong & r.asSafeLong).toDouble) case _ => fallback } case BinaryOp.OP_^ => (lhs, rhs) match { - case (Val.Num(_, _), Val.Num(_, _)) => - Val.Num(pos, (lhs.asLong ^ rhs.asLong).toDouble) + case (l: Val.Num, r: Val.Num) => + Val.Num(pos, (l.asSafeLong ^ r.asSafeLong).toDouble) case _ => fallback } case BinaryOp.OP_| => (lhs, rhs) match { - case (Val.Num(_, _), Val.Num(_, _)) => - Val.Num(pos, (lhs.asLong | rhs.asLong).toDouble) + case (l: Val.Num, r: Val.Num) => + Val.Num(pos, (l.asSafeLong | r.asSafeLong).toDouble) case _ => fallback } case _ => fallback diff --git a/sjsonnet/src/sjsonnet/Val.scala b/sjsonnet/src/sjsonnet/Val.scala index 4aaf39ec..491f593c 100644 --- a/sjsonnet/src/sjsonnet/Val.scala +++ b/sjsonnet/src/sjsonnet/Val.scala @@ -84,20 +84,20 @@ object Val { def bool(pos: Position, b: Boolean): Bool = if (b) True(pos) else False(pos) - final case class True(pos: Position) extends Bool { + final case class True(var pos: Position) extends Bool { def prettyName = "boolean" } - final case class False(pos: Position) extends Bool { + final case class False(var pos: Position) extends Bool { def prettyName = "boolean" } - final case class Null(pos: Position) extends Literal { + final case class Null(var pos: Position) extends Literal { def prettyName = "null" } - final case class Str(pos: Position, str: String) extends Literal { + final case class Str(var pos: Position, str: String) extends Literal { def prettyName = "string" override def asString: String = str } - final case class Num(pos: Position, private val num: Double) extends Literal { + final case class Num(var pos: Position, private val num: Double) extends Literal { if (num.isInfinite) { Error.fail("overflow") } @@ -137,7 +137,7 @@ object Val { } } - final case class Arr(pos: Position, private val arr: Array[? <: Eval]) extends Literal { + final case class Arr(var pos: Position, private val arr: Array[? <: Eval]) extends Literal { def prettyName = "array" override def asArr: Arr = this @@ -254,7 +254,7 @@ object Val { * objects, it is dynamically computed only if the object has a `super` */ final class Obj( - val pos: Position, + var pos: Position, private var value0: util.LinkedHashMap[String, Obj.Member], private val static: Boolean, private val triggerAsserts: (Val.Obj, Val.Obj) => Unit, @@ -649,7 +649,7 @@ object Val { ) } - abstract class Func(val pos: Position, val defSiteValScope: ValScope, val params: Params) + abstract class Func(var pos: Position, val defSiteValScope: ValScope, val params: Params) extends Val with Expr { final override private[sjsonnet] def tag = ExprTags.`Val.Func` diff --git a/sjsonnet/test/src/sjsonnet/AggressiveStaticOptimizationTests.scala b/sjsonnet/test/src/sjsonnet/AggressiveStaticOptimizationTests.scala index 37b72e92..6acc9365 100644 --- a/sjsonnet/test/src/sjsonnet/AggressiveStaticOptimizationTests.scala +++ b/sjsonnet/test/src/sjsonnet/AggressiveStaticOptimizationTests.scala @@ -4,28 +4,16 @@ import utest._ import TestUtils.{eval, evalErr} /** - * Tests for `aggressiveStaticOptimization = true`. + * Tests for aggressive static optimizations in [[StaticOptimizer.tryAggressiveOptimize]]. * - * Covers every optimization branch in [[StaticOptimizer.tryAggressiveOptimize]], which runs during - * the optimization phase (not parse time): + * Covers every optimization branch: * - Constant folding: arithmetic (+, -, *, /, %), comparison (<, >, <=, >=, ==, !=), bitwise (&, * ^, |), shift (<<, >>), unary (!, -, ~, +), string/array concatenation. * - Branch elimination: if-else with constant condition. * - Short-circuit elimination: And/Or with constant lhs. - * - * Each case is verified to produce the same result as without the optimization, confirming that the - * optimization is semantics-preserving. */ object AggressiveStaticOptimizationTests extends TestSuite { - /** Shorthand: evaluate with aggressiveStaticOptimization enabled. */ - def evalOpt(s: String): ujson.Value = - eval(s, aggressiveStaticOptimization = true) - - /** Shorthand: evaluate and expect an error with aggressiveStaticOptimization enabled. */ - def evalErrOpt(s: String): String = - evalErr(s, aggressiveStaticOptimization = true) - def tests: Tests = Tests { // ------------------------------------------------------------------------- @@ -33,32 +21,32 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("constantFolding") { test("addNumbers") { - evalOpt("1 + 2") ==> ujson.Num(3) - evalOpt("1.5 + 2.5") ==> ujson.Num(4) + eval("1 + 2") ==> ujson.Num(3) + eval("1.5 + 2.5") ==> ujson.Num(4) } test("subtractNumbers") { - evalOpt("10 - 3") ==> ujson.Num(7) - evalOpt("0 - 5") ==> ujson.Num(-5) + eval("10 - 3") ==> ujson.Num(7) + eval("0 - 5") ==> ujson.Num(-5) } test("multiplyNumbers") { - evalOpt("3 * 4") ==> ujson.Num(12) - evalOpt("2.5 * 2") ==> ujson.Num(5) + eval("3 * 4") ==> ujson.Num(12) + eval("2.5 * 2") ==> ujson.Num(5) } test("divideNumbers") { - evalOpt("10 / 4") ==> ujson.Num(2.5) - evalOpt("9 / 3") ==> ujson.Num(3) + eval("10 / 4") ==> ujson.Num(2.5) + eval("9 / 3") ==> ujson.Num(3) } test("moduloNumbers") { - evalOpt("10 % 3") ==> ujson.Num(1) - evalOpt("7 % 7") ==> ujson.Num(0) + eval("10 % 3") ==> ujson.Num(1) + eval("7 % 7") ==> ujson.Num(0) } test("addStrings") { - evalOpt(""" "hello" + " world" """) ==> ujson.Str("hello world") - evalOpt(""" "foo" + "bar" """) ==> ujson.Str("foobar") + eval(""" "hello" + " world" """) ==> ujson.Str("hello world") + eval(""" "foo" + "bar" """) ==> ujson.Str("foobar") } test("addArrays") { - evalOpt("[1, 2] + [3, 4]") ==> ujson.Arr(1, 2, 3, 4) - evalOpt("[] + [1]") ==> ujson.Arr(1) + eval("[1, 2] + [3, 4]") ==> ujson.Arr(1, 2, 3, 4) + eval("[] + [1]") ==> ujson.Arr(1) } } @@ -67,19 +55,19 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("unaryConstantFolding") { test("logicalNot") { - evalOpt("!true") ==> ujson.False - evalOpt("!false") ==> ujson.True + eval("!true") ==> ujson.False + eval("!false") ==> ujson.True } test("negateNumber") { - evalOpt("-5") ==> ujson.Num(-5) - evalOpt("-(-3)") ==> ujson.Num(3) + eval("-5") ==> ujson.Num(-5) + eval("-(-3)") ==> ujson.Num(3) } test("bitwiseNot") { - evalOpt("~0") ==> ujson.Num(-1) - evalOpt("~(-1)") ==> ujson.Num(0) + eval("~0") ==> ujson.Num(-1) + eval("~(-1)") ==> ujson.Num(0) } test("unaryPlus") { - evalOpt("+7") ==> ujson.Num(7) + eval("+7") ==> ujson.Num(7) } } @@ -88,55 +76,55 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("comparisonConstantFolding") { test("lessThan") { - evalOpt("1 < 2") ==> ujson.True - evalOpt("2 < 1") ==> ujson.False - evalOpt("1 < 1") ==> ujson.False + eval("1 < 2") ==> ujson.True + eval("2 < 1") ==> ujson.False + eval("1 < 1") ==> ujson.False } test("greaterThan") { - evalOpt("2 > 1") ==> ujson.True - evalOpt("1 > 2") ==> ujson.False - evalOpt("1 > 1") ==> ujson.False + eval("2 > 1") ==> ujson.True + eval("1 > 2") ==> ujson.False + eval("1 > 1") ==> ujson.False } test("lessThanOrEqual") { - evalOpt("1 <= 1") ==> ujson.True - evalOpt("1 <= 2") ==> ujson.True - evalOpt("2 <= 1") ==> ujson.False + eval("1 <= 1") ==> ujson.True + eval("1 <= 2") ==> ujson.True + eval("2 <= 1") ==> ujson.False } test("greaterThanOrEqual") { - evalOpt("1 >= 1") ==> ujson.True - evalOpt("2 >= 1") ==> ujson.True - evalOpt("1 >= 2") ==> ujson.False + eval("1 >= 1") ==> ujson.True + eval("2 >= 1") ==> ujson.True + eval("1 >= 2") ==> ujson.False } test("equalNumbers") { - evalOpt("1 == 1") ==> ujson.True - evalOpt("1 == 2") ==> ujson.False + eval("1 == 1") ==> ujson.True + eval("1 == 2") ==> ujson.False } test("notEqualNumbers") { - evalOpt("1 != 2") ==> ujson.True - evalOpt("1 != 1") ==> ujson.False + eval("1 != 2") ==> ujson.True + eval("1 != 1") ==> ujson.False } test("equalStrings") { - evalOpt(""" "abc" == "abc" """) ==> ujson.True - evalOpt(""" "abc" == "def" """) ==> ujson.False + eval(""" "abc" == "abc" """) ==> ujson.True + eval(""" "abc" == "def" """) ==> ujson.False } test("notEqualStrings") { - evalOpt(""" "abc" != "def" """) ==> ujson.True - evalOpt(""" "abc" != "abc" """) ==> ujson.False + eval(""" "abc" != "def" """) ==> ujson.True + eval(""" "abc" != "abc" """) ==> ujson.False } test("equalBooleans") { - evalOpt("true == true") ==> ujson.True - evalOpt("false == false") ==> ujson.True - evalOpt("true == false") ==> ujson.False + eval("true == true") ==> ujson.True + eval("false == false") ==> ujson.True + eval("true == false") ==> ujson.False } test("equalNull") { - evalOpt("null == null") ==> ujson.True - evalOpt("null != null") ==> ujson.False + eval("null == null") ==> ujson.True + eval("null != null") ==> ujson.False } test("stringComparison") { - evalOpt(""" "abc" < "abd" """) ==> ujson.True - evalOpt(""" "b" > "a" """) ==> ujson.True - evalOpt(""" "abc" <= "abc" """) ==> ujson.True - evalOpt(""" "abc" >= "abc" """) ==> ujson.True + eval(""" "abc" < "abd" """) ==> ujson.True + eval(""" "b" > "a" """) ==> ujson.True + eval(""" "abc" <= "abc" """) ==> ujson.True + eval(""" "abc" >= "abc" """) ==> ujson.True } } @@ -145,24 +133,24 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("bitwiseConstantFolding") { test("bitwiseAnd") { - evalOpt("12 & 10") ==> ujson.Num(8) - evalOpt("0 & 255") ==> ujson.Num(0) + eval("12 & 10") ==> ujson.Num(8) + eval("0 & 255") ==> ujson.Num(0) } test("bitwiseXor") { - evalOpt("12 ^ 10") ==> ujson.Num(6) - evalOpt("0 ^ 0") ==> ujson.Num(0) + eval("12 ^ 10") ==> ujson.Num(6) + eval("0 ^ 0") ==> ujson.Num(0) } test("bitwiseOr") { - evalOpt("12 | 10") ==> ujson.Num(14) - evalOpt("0 | 0") ==> ujson.Num(0) + eval("12 | 10") ==> ujson.Num(14) + eval("0 | 0") ==> ujson.Num(0) } test("shiftLeft") { - evalOpt("1 << 3") ==> ujson.Num(8) - evalOpt("3 << 2") ==> ujson.Num(12) + eval("1 << 3") ==> ujson.Num(8) + eval("3 << 2") ==> ujson.Num(12) } test("shiftRight") { - evalOpt("8 >> 2") ==> ujson.Num(2) - evalOpt("16 >> 4") ==> ujson.Num(1) + eval("8 >> 2") ==> ujson.Num(2) + eval("16 >> 4") ==> ujson.Num(1) } } @@ -171,19 +159,19 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("branchElimination") { test("trueConditionSelectsThenBranch") { - evalOpt("if true then 42 else 0") ==> ujson.Num(42) - evalOpt("if true then 'yes' else 'no'") ==> ujson.Str("yes") + eval("if true then 42 else 0") ==> ujson.Num(42) + eval("if true then 'yes' else 'no'") ==> ujson.Str("yes") } test("falseConditionSelectsElseBranch") { - evalOpt("if false then 42 else 0") ==> ujson.Num(0) - evalOpt("if false then 'yes' else 'no'") ==> ujson.Str("no") + eval("if false then 42 else 0") ==> ujson.Num(0) + eval("if false then 'yes' else 'no'") ==> ujson.Str("no") } test("falseConditionWithNoElseYieldsNull") { // `if false then expr` with no else branch should yield null - evalOpt("if false then 42") ==> ujson.Null + eval("if false then 42") ==> ujson.Null } test("nestedBranchElimination") { - evalOpt("if true then (if false then 1 else 2) else 3") ==> ujson.Num(2) + eval("if true then (if false then 1 else 2) else 3") ==> ujson.Num(2) } } @@ -192,69 +180,26 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("shortCircuitElimination") { test("trueAndTrue") { - evalOpt("true && true") ==> ujson.True + eval("true && true") ==> ujson.True } test("trueAndFalse") { - evalOpt("true && false") ==> ujson.False + eval("true && false") ==> ujson.False } test("falseAndAnything") { // false && rhs should short-circuit to false regardless of rhs - evalOpt("false && true") ==> ujson.False - evalOpt("false && false") ==> ujson.False + eval("false && true") ==> ujson.False + eval("false && false") ==> ujson.False } test("trueOrAnything") { // true || rhs should short-circuit to true regardless of rhs - evalOpt("true || false") ==> ujson.True - evalOpt("true || true") ==> ujson.True + eval("true || false") ==> ujson.True + eval("true || true") ==> ujson.True } test("falseOrTrue") { - evalOpt("false || true") ==> ujson.True + eval("false || true") ==> ujson.True } test("falseOrFalse") { - evalOpt("false || false") ==> ujson.False - } - } - - // ------------------------------------------------------------------------- - // Semantics-preserving: results must match the non-optimized evaluator - // ------------------------------------------------------------------------- - test("semanticsMatch") { - val expressions = Seq( - "1 + 2", - "10 - 3", - "3 * 4", - "10 / 4", - "10 % 3", - "!true", - "!false", - "-5", - "~0", - "+7", - "1 < 2", - "2 > 1", - "1 <= 1", - "2 >= 1", - "1 == 1", - "1 != 2", - "12 & 10", - "12 ^ 10", - "12 | 10", - "1 << 3", - "8 >> 2", - "if true then 1 else 0", - "if false then 1 else 0", - "if false then 1", - "true && true", - "true && false", - "false && true", - "true || false", - "false || true", - "false || false" - ) - for (expr <- expressions) { - val withOpt = eval(expr, aggressiveStaticOptimization = true) - val withoutOpt = eval(expr, aggressiveStaticOptimization = false) - withOpt ==> withoutOpt + eval("false || false") ==> ujson.False } } @@ -263,9 +208,9 @@ object AggressiveStaticOptimizationTests extends TestSuite { // ------------------------------------------------------------------------- test("nonConstantOperandsNotFolded") { // Variables are not statically known values; the optimizer must not fold these. - evalOpt("local x = 3; local y = 4; x + y") ==> ujson.Num(7) - evalOpt("local b = true; if b then 1 else 0") ==> ujson.Num(1) - evalOpt("local b = false; b || true") ==> ujson.True + eval("local x = 3; local y = 4; x + y") ==> ujson.Num(7) + eval("local b = true; if b then 1 else 0") ==> ujson.Num(1) + eval("local b = false; b || true") ==> ujson.True } // ------------------------------------------------------------------------- @@ -275,33 +220,33 @@ object AggressiveStaticOptimizationTests extends TestSuite { test("divisionByZeroNotFolded") { // Division by zero: the optimizer must NOT fold `1 / 0` into a value; // it should fall back to the runtime error path. - val err = evalErrOpt("1 / 0") + val err = evalErr("1 / 0") assert(err.contains("sjsonnet.Error")) } test("negativeShiftNotFolded") { // Negative shift amounts must not be constant-folded; runtime error expected. - val err = evalErrOpt("1 << -1") + val err = evalErr("1 << -1") assert(err.contains("sjsonnet.Error")) } test("andWithNonBoolRhsStillErrors") { // `true && "hello"` must still error: the optimizer only short-circuits when // rhs is a Val.Bool. If rhs is not a Bool, the BinaryOp is left intact and // the runtime type-check fires. - val err = evalErrOpt(""" true && "hello" """) + val err = evalErr(""" true && "hello" """) assert(err.contains("binary operator &&")) } test("orWithNonBoolRhsStillErrors") { - val err = evalErrOpt(""" false || "hello" """) + val err = evalErr(""" false || "hello" """) assert(err.contains("binary operator ||")) } } // ------------------------------------------------------------------------- - // Interaction with other settings: aggressiveStaticOptimization + useNewEvaluator + // Interaction with useNewEvaluator // ------------------------------------------------------------------------- test("withNewEvaluator") { def evalBoth(s: String): ujson.Value = - eval(s, aggressiveStaticOptimization = true, useNewEvaluator = true) + eval(s, useNewEvaluator = true) evalBoth("1 + 2") ==> ujson.Num(3) evalBoth("if true then 'yes' else 'no'") ==> ujson.Str("yes") diff --git a/sjsonnet/test/src/sjsonnet/CustomValTests.scala b/sjsonnet/test/src/sjsonnet/CustomValTests.scala index d89ef290..9b920a5d 100644 --- a/sjsonnet/test/src/sjsonnet/CustomValTests.scala +++ b/sjsonnet/test/src/sjsonnet/CustomValTests.scala @@ -4,7 +4,7 @@ import upickle.core.Visitor import utest._ object CustomValTests extends TestSuite { - private final case class ImportantString(pos: Position, str: String, importance: Int) + private final case class ImportantString(var pos: Position, str: String, importance: Int) extends Val.Literal with Materializer.Materializable { override def prettyName: String = "Important string" diff --git a/sjsonnet/test/src/sjsonnet/EvaluatorTests.scala b/sjsonnet/test/src/sjsonnet/EvaluatorTests.scala index 87666fd8..88347900 100644 --- a/sjsonnet/test/src/sjsonnet/EvaluatorTests.scala +++ b/sjsonnet/test/src/sjsonnet/EvaluatorTests.scala @@ -4,377 +4,160 @@ import utest._ import TestUtils.{eval, evalErr} object EvaluatorTests extends TestSuite { - def allTests(useNewEvaluator: Boolean, aggressiveOpt: Boolean): Tests = Tests { + def allTests(useNewEvaluator: Boolean): Tests = Tests { test("arithmetic") { - eval( - "1 + 2 + 3", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(6) - eval( - "1 + 2 * 3", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(7) - eval( - "-1 + 2 * 3", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(5) - eval( - "6 - 3 + 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(5) + eval("1 + 2 + 3", useNewEvaluator = useNewEvaluator) ==> ujson.Num(6) + eval("1 + 2 * 3", useNewEvaluator = useNewEvaluator) ==> ujson.Num(7) + eval("-1 + 2 * 3", useNewEvaluator = useNewEvaluator) ==> ujson.Num(5) + eval("6 - 3 + 2", useNewEvaluator = useNewEvaluator) ==> ujson.Num(5) } test("objects") { - eval( - "{x: 1}.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) + eval("{x: 1}.x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) } test("arrays") { - eval( - "[1, [2, 3], 4][1][0]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(2) - eval( - "([1, 2, 3] + [4, 5, 6])[3]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(4) - evalErr( - "[][0]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("[1, [2, 3], 4][1][0]", useNewEvaluator = useNewEvaluator) ==> ujson.Num(2) + eval("([1, 2, 3] + [4, 5, 6])[3]", useNewEvaluator = useNewEvaluator) ==> ujson.Num(4) + evalErr("[][0]", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: array bounds error: array is empty |at [].(:1:3)""".stripMargin - eval( - "std.slice(std.range(1,4), 0, null, 2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("std.slice(std.range(1,4), 0, null, 2)", useNewEvaluator = useNewEvaluator) ==> ujson .Arr(1, 3) - eval( - "std.slice(std.range(1,4), null, null, 2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("std.slice(std.range(1,4), null, null, 2)", useNewEvaluator = useNewEvaluator) ==> ujson .Arr(1, 3) eval( "std.slice(std.range(1,4), null, null, null)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Arr(1, 2, 3, 4) eval(""" |std.slice("jsonnet", -3, null, null) |""".stripMargin) ==> ujson.Str("net") - eval( - "std.range(1,4)[0::2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Arr(1, 3) - eval( - "std.range(1,4)[0:null:2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Arr(1, 3) - eval( - "std.range(1,4)[null:null:2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Arr(1, 3) - eval( - "std.range(1,4)[null:null:null]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Arr( + eval("std.range(1,4)[0::2]", useNewEvaluator = useNewEvaluator) ==> ujson.Arr(1, 3) + eval("std.range(1,4)[0:null:2]", useNewEvaluator = useNewEvaluator) ==> ujson.Arr(1, 3) + eval("std.range(1,4)[null:null:2]", useNewEvaluator = useNewEvaluator) ==> ujson.Arr(1, 3) + eval("std.range(1,4)[null:null:null]", useNewEvaluator = useNewEvaluator) ==> ujson.Arr( 1, 2, 3, 4 ) - eval( - "std.range(1,4)[::2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Arr(1, 3) + eval("std.range(1,4)[::2]", useNewEvaluator = useNewEvaluator) ==> ujson.Arr(1, 3) } test("functions") { - eval( - "(function(x) x)(1)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "function() 1", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "function(a=1) a", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "(function(x, y = x + 1) y)(x = 10)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num( + eval("(function(x) x)(1)", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("function() 1", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("function(a=1) a", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("(function(x, y = x + 1) y)(x = 10)", useNewEvaluator = useNewEvaluator) ==> ujson.Num( 11 ) - eval( - "local f(x) = function() true; f(42)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.True + eval("local f(x) = function() true; f(42)", useNewEvaluator = useNewEvaluator) ==> ujson.True eval( "local f(x) = function() true; f(42) == true", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.False eval( "local f(x) = function() true; f(42)() == true", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.True assert( - evalErr( - "{foo: function() true}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).startsWith( + evalErr("{foo: function() true}", useNewEvaluator = useNewEvaluator).startsWith( "sjsonnet.Error: Couldn't manifest function with params" ) ) - eval( - "{foo: (function() true)()}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj { + eval("{foo: (function() true)()}", useNewEvaluator = useNewEvaluator) ==> ujson.Obj { "foo" -> ujson.True } } test("members") { - eval( - "{local x = 1, x: x}['x']", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "{local x(y) = y + '1', x: x('2')}['x']", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("{local x = 1, x: x}['x']", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("{local x(y) = y + '1', x: x('2')}['x']", useNewEvaluator = useNewEvaluator) ==> ujson .Str("21") - eval( - "{local x(y) = y + '1', x: x(y='2')}['x']", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("{local x(y) = y + '1', x: x(y='2')}['x']", useNewEvaluator = useNewEvaluator) ==> ujson .Str("21") - eval( - "{local x(y='2') = y + '1', x: x()}['x']", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("{local x(y='2') = y + '1', x: x()}['x']", useNewEvaluator = useNewEvaluator) ==> ujson .Str("21") eval( """{[{local x = $.y + "lol", y: x, z: "1"}.z]: 2}["1"]""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(2) - eval( - "{local x = 1, y: { z: x }}.y.z", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) + eval("{local x = 1, y: { z: x }}.y.z", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) } test("extends") { - eval( - "(function(a) a.x + a.y)({x: 1}{y: 2})", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("(function(a) a.x + a.y)({x: 1}{y: 2})", useNewEvaluator = useNewEvaluator) ==> ujson .Num(3) eval( "(function(a) a.x + a.y)({x: 1}{x: 2, y: 3})", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(5) - eval( - "({x: 1}{x+: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(3) - eval( - "({x+: 1}{x: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(2) - eval( - "({x+: 1}{x+: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(3) - eval( - "({x+: 1} + {x+: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(3) + eval("({x: 1}{x+: 2}).x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(3) + eval("({x+: 1}{x: 2}).x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(2) + eval("({x+: 1}{x+: 2}).x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(3) + eval("({x+: 1} + {x+: 2}).x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(3) eval( "(function(a, b) a + b)({x+: 1}, {x+: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(3) - eval( - """({a: [1]} + {a+: "1"}).a""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("[1]1") - eval( - """({a: 1} + {a+: "1"}).a""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("11") - eval( - """({a: "1"} + {a+: 1}).a""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("11") + eval("""({a: [1]} + {a+: "1"}).a""", useNewEvaluator = useNewEvaluator) ==> ujson.Str("[1]1") + eval("""({a: 1} + {a+: "1"}).a""", useNewEvaluator = useNewEvaluator) ==> ujson.Str("11") + eval("""({a: "1"} + {a+: 1}).a""", useNewEvaluator = useNewEvaluator) ==> ujson.Str("11") } test("ifElse") { - eval( - "if true then 1 else 0", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "if 2 > 1 then 1 else 0", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "if false then 1 else 0", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(0) - eval( - "if 1 > 2 then 1 else 0", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(0) + eval("if true then 1 else 0", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("if 2 > 1 then 1 else 0", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("if false then 1 else 0", useNewEvaluator = useNewEvaluator) ==> ujson.Num(0) + eval("if 1 > 2 then 1 else 0", useNewEvaluator = useNewEvaluator) ==> ujson.Num(0) } test("self") { - eval( - "{x: 1, y: $.x + 10}.y", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(11) - eval( - "{x: 1, y: self.x}.y", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(1) - eval( - "{x: 1, y: {x: 2, z: $.x + 10}}.y.z", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num( + eval("{x: 1, y: $.x + 10}.y", useNewEvaluator = useNewEvaluator) ==> ujson.Num(11) + eval("{x: 1, y: self.x}.y", useNewEvaluator = useNewEvaluator) ==> ujson.Num(1) + eval("{x: 1, y: {x: 2, z: $.x + 10}}.y.z", useNewEvaluator = useNewEvaluator) ==> ujson.Num( 11 ) - eval( - "{x: 1, y: {x: 2, z: self.x + 10}}.y.z", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("{x: 1, y: {x: 2, z: self.x + 10}}.y.z", useNewEvaluator = useNewEvaluator) ==> ujson .Num(12) - eval( - "{x: 1, y: {x: 0, y: self.x}.y}.y", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(0) - eval( - """{x: 1, y: "x" in self}.y""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.True - eval( - """{x: 1, y: "z" in self}.y""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.False - eval( - """{y: "y" in self}.y""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.True + eval("{x: 1, y: {x: 0, y: self.x}.y}.y", useNewEvaluator = useNewEvaluator) ==> ujson.Num(0) + eval("""{x: 1, y: "x" in self}.y""", useNewEvaluator = useNewEvaluator) ==> ujson.True + eval("""{x: 1, y: "z" in self}.y""", useNewEvaluator = useNewEvaluator) ==> ujson.False + eval("""{y: "y" in self}.y""", useNewEvaluator = useNewEvaluator) ==> ujson.True } test("topLevel") { - eval( - "local p(n='A') = {w: 'H'+n}; {p: p()}.p.w", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("local p(n='A') = {w: 'H'+n}; {p: p()}.p.w", useNewEvaluator = useNewEvaluator) ==> ujson .Str("HA") } test("lazy") { - eval( - "[{x: $.y, y: $.x}.x, 2][1]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(2) + eval("[{x: $.y, y: $.x}.x, 2][1]", useNewEvaluator = useNewEvaluator) ==> ujson.Num(2) eval( "{x: $.y, y: $.x, local z(z0) = [3], w: z($.x)}.w[0]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(3) eval( "(function(a=[1, b[1]], b=[a[0], 2]) [a, b])()[0][1]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(2) } test("comprehensions") { - eval( - "[x + 1 for x in [1, 2, 3]][2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(4) - eval( - "[x + 1, for x in [1, 2, 3]][2]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(4) + eval("[x + 1 for x in [1, 2, 3]][2]", useNewEvaluator = useNewEvaluator) ==> ujson.Num(4) + eval("[x + 1, for x in [1, 2, 3]][2]", useNewEvaluator = useNewEvaluator) ==> ujson.Num(4) eval( "[x + y for x in [1, 2, 3] for y in [4, 5, 6] if x + y != 7][3]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(8) eval( """{[""+x]: x * x for x in [1, 2, 3]}["3"]""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(9) eval( """{local y = $["2"], [x]: if x == "1" then y else 0, for x in ["1", "2"]}["1"]""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(0) // References between locals in an object comprehension: eval( """{local a = 1, local b = a + 1, [k]: b + 1 for k in ["x"]}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("x" -> ujson.Num(3)) // Locals which reference variables from the comprehension: eval( """{local x2 = k*2, [std.toString(k)]: x2 for k in [1]}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("1" -> ujson.Num(2)) // Regression test for https://github.com/databricks/sjsonnet/issues/357 // self references in object comprehension locals are properly rebound during inheritance: @@ -397,8 +180,7 @@ object EvaluatorTests extends TestSuite { |} |+ lib.foo() |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("foo" -> ujson.Obj("foo" -> "foo")) // Regression test for a related bug involving local references to `super`: eval( @@ -414,8 +196,7 @@ object EvaluatorTests extends TestSuite { |{ x: 2 } |+ lib.foo() |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("x" -> ujson.Num(3)) // Yet another related bug involving super references _not_ in locals: eval( @@ -430,15 +211,10 @@ object EvaluatorTests extends TestSuite { |{ x: 2 } |+ lib.foo() |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("x" -> ujson.Num(3)) // Regression test for a bug in handling of non-string field names: - evalErr( - "{[k]: k for k in [1]}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("{[k]: k for k in [1]}", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: [object comprehension] Field name must be string or null, not number |at [].(:1:1)""".stripMargin // Basic function support: @@ -450,8 +226,7 @@ object EvaluatorTests extends TestSuite { |}; |funcs.f1(10) |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(20) // Functions which use locals from the comprehension: eval( @@ -463,277 +238,181 @@ object EvaluatorTests extends TestSuite { |}; |funcs.f1(10) |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(20) } test("super") { test("implicit") { - eval( - "({ x: 1, y: self.x } + { x: 2 }).y", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num( + eval("({ x: 1, y: self.x } + { x: 2 }).y", useNewEvaluator = useNewEvaluator) ==> ujson.Num( 2 ) eval( "({ local x = $.y, y: 1, z: x} + { y: 2 }).z", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(2) eval( "({ local x = self.y, y: 1, z: x} + { y: 2 }).z", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(2) eval( "local A = {x: 1, local outer = self, y: A{z: outer}}; A.y.z.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( "{local x = self, y: 1, z: {a: x, y: 2}}.z.a.y", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( "local A = {x: 1, local outer = self, y: A{x: outer.x}}; A.y.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( "local A = {x: 1, local outer = self, y: A{x: outer.x + 1}}; A.y.y.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(3) - eval( - """("a" in ({a: 1}{b: 2}))""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.True + eval("""("a" in ({a: 1}{b: 2}))""", useNewEvaluator = useNewEvaluator) ==> ujson.True } test("explicit") { - eval( - "{ x: 1, y: self.x } + { x: 2, y: super.y + 1}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{ x: 1, y: self.x } + { x: 2, y: super.y + 1}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{ "x": 2, "y": 3 }""") eval( "{ x: 1 } + { x: 2, y: super.x } + { x: 3, z: super.x }", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.read("""{ "x": 3, "y": 1, "z": 2 }""") eval( """({a: 1} + {b: 2} + {c: ["a" in super, "b" in super]}).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Arr(true, true) - eval( - """{a: ["a" in super, "b" in super]}.a""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("""{a: ["a" in super, "b" in super]}.a""", useNewEvaluator = useNewEvaluator) ==> ujson .Arr(false, false) - eval( - """(({a: 1}{b: 2}){c: super.a}).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num( + eval("""(({a: 1}{b: 2}){c: super.a}).c""", useNewEvaluator = useNewEvaluator) ==> ujson.Num( 1 ) - eval( - """(({a: 1}{b: 2}){c: super.b}).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num( + eval("""(({a: 1}{b: 2}){c: super.b}).c""", useNewEvaluator = useNewEvaluator) ==> ujson.Num( 2 ) eval( """(({a: 1}{b: 2, f: super.a}){c: super.f}).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) val ex = assertThrows[Exception] { - eval( - """(({a: 1}{b: 2, f: super.b}){c: super.f}).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("""(({a: 1}{b: 2, f: super.b}){c: super.f}).c""", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("Field does not exist: b")) eval( """(({a: 1}{b: 2}) + ({c: super.b}{d: super.a})).c""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(2) eval( """(({a: 1}{b: 2}) + ({c: super.b}{d: super.a})).d""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( """local x = {a: 1}; local y = {b: super.a}; x + y""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.read("""{"a": 1, "b": 1}""") eval( """local x = { a: 1, b: { c: 2 }}; x { a: super.a * 10, b:: { c: super.b.c * 10 } }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("a" -> ujson.Num(10)) evalErr( """local x = { a: 1, b: { c: 2 }}; x { a: super.a * 10, b:: { c: super.b.c * 10 } }.b""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> """sjsonnet.Error: Attempt to use `super` when there is no super class |at [].(:1:7)""".stripMargin } } test("hidden") { - eval( - "{i::1 }", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i::1 }", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{}""") - eval( - "{i:: 1} + {i: 2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i:: 1} + {i: 2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{}""") - eval( - "{i: 1} + {i:: 2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i: 1} + {i:: 2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{}""") - eval( - "{i:: 1} + {i:: 2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i:: 1} + {i:: 2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{}""") - eval( - "{i:::1} + {i::2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i:::1} + {i::2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{}""") - eval( - "{i::1} + {i:::2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i::1} + {i:::2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{"i": 2}""") - eval( - "{i:1} + {i:::2}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("{i:1} + {i:::2}", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{"i": 2}""") - eval( - "local M = {x+: self.i, i :: 1}; { x: 1 } + M", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + eval("local M = {x+: self.i, i :: 1}; { x: 1 } + M", useNewEvaluator = useNewEvaluator) ==> ujson.read("""{ "x": 2 }""") - eval( - """("%(hello)s" % {hello::"world"})""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("""("%(hello)s" % {hello::"world"})""", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "world" ) eval( """("%(hello)s" % {hello::"world", bad:: error "lol"})""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str("world") } test("evaluator2") { eval( """{local x = 1, [x]: x, for x in ["foo"]}.foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( """{[x]: x, local x = 1, for x in ["foo"]}.foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( """local foo = ["foo"]; {local foo = 1, [x]: x, for x in foo}.foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str("foo") eval( """local foo = ["foo"]; {[x]: x, local foo = 2, for x in foo}.foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str("foo") eval( """{ [x + ""]: if x == 1 then 1 else x + $["1"] for x in [1, 2, 3] }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.read("""{ "1": 1, "2": 3, "3": 4 }""") eval( """local x = "baz"; { local x = "bar", [x]: x for x in ["foo"] }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.read("""{ "foo": "bar" }""") eval( """{ [x + ""]: x + foo, local foo = 3 for x in [1, 2, 3] }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.read("""{ "1": 4, "2": 5, "3": 6 }""") eval( """{local y = x, ["foo"]: y, for x in ["foo"]}.foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str("foo") } test("shadowing") { - eval( - "local x = 1; local x = 2; x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(2) - eval( - "local x = 1; x + local x = 2; x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(3) + eval("local x = 1; local x = 2; x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(2) + eval("local x = 1; x + local x = 2; x", useNewEvaluator = useNewEvaluator) ==> ujson.Num(3) eval( """local str1 = ||| | text @@ -745,40 +424,18 @@ object EvaluatorTests extends TestSuite { | |(str1 == "\\n\n") |""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.True } test("stdLib") { - eval( - "std.pow(2, 3)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(8) - eval( - "std.pow(x=2, n=3)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(8) - eval( - "std.pow(n=3, x=2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(8) - eval( - "({a:: 1} + {a+:::2}).a", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(3) - eval( - "(std.prune({a:: 1}) + {a+:::2}).a", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Num(2) + eval("std.pow(2, 3)", useNewEvaluator = useNewEvaluator) ==> ujson.Num(8) + eval("std.pow(x=2, n=3)", useNewEvaluator = useNewEvaluator) ==> ujson.Num(8) + eval("std.pow(n=3, x=2)", useNewEvaluator = useNewEvaluator) ==> ujson.Num(8) + eval("({a:: 1} + {a+:::2}).a", useNewEvaluator = useNewEvaluator) ==> ujson.Num(3) + eval("(std.prune({a:: 1}) + {a+:::2}).a", useNewEvaluator = useNewEvaluator) ==> ujson.Num(2) eval( "std.toString(std.mapWithIndex(function(idx, elem) elem, [2,1,0]))", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str("[2, 1, 0]") } test("unboundParam") { @@ -794,8 +451,7 @@ object EvaluatorTests extends TestSuite { |params.y | """.stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) } @@ -813,8 +469,7 @@ object EvaluatorTests extends TestSuite { | person2: Person('Bob', hello=123), |} """.stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) } @@ -822,32 +477,16 @@ object EvaluatorTests extends TestSuite { } test("unknownVariable") { - evalErr( - "x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("x", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.StaticError: Unknown variable: x |at [].(:1:1)""".stripMargin - evalErr( - "self.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("self.x", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.StaticError: Can't use self outside of an object |at [].(:1:1)""".stripMargin - evalErr( - "$.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("$.x", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.StaticError: Can't use $ outside of an object |at [].(:1:1)""".stripMargin - evalErr( - "super.x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("super.x", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.StaticError: Can't use super outside of an object |at [].(:1:1)""".stripMargin } @@ -862,8 +501,7 @@ object EvaluatorTests extends TestSuite { | person2: Person(name='Bob'), |}.person2.welcome """.stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) res ==> ujson.Str("Hello Bob!") @@ -872,17 +510,12 @@ object EvaluatorTests extends TestSuite { test("equalDollar") { eval( "local f(x) = x; {hello: 123, world: f(x=$.hello)}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("hello" -> 123, "world" -> 123) } test("stdSubstr") { - eval( - "std.substr('cookie', 6, 2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("") + eval("std.substr('cookie', 6, 2)", useNewEvaluator = useNewEvaluator) ==> ujson.Str("") } test("manifestIni") { eval( @@ -890,281 +523,126 @@ object EvaluatorTests extends TestSuite { | main: { a: "1", b: 2, c: true, d: null, e: [1, {"2": 2}, [3]], f: {"hello": "world"} }, | sections: {} |})""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Str( "a = 1\nb = 2\nc = true\nd = null\ne = 1\ne = {\"2\": 2}\ne = [3]\nf = {\"hello\": \"world\"}\n" ) } test("format") { - eval( - "\"%s\" % \"world\"", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("world") - eval( - "\"%s\" % [\"world\"]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("world") - eval( - "\"%s %s\" % [\"hello\", \"world\"]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("\"%s\" % \"world\"", useNewEvaluator = useNewEvaluator) ==> ujson.Str("world") + eval("\"%s\" % [\"world\"]", useNewEvaluator = useNewEvaluator) ==> ujson.Str("world") + eval("\"%s %s\" % [\"hello\", \"world\"]", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "hello world" ) - eval( - "\"%(hello)s\" % {hello: \"world\"}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("\"%(hello)s\" % {hello: \"world\"}", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "world" ) - eval( - "\"%()s %()s!\" % [\"Hello\", \"World\"]", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("\"%()s %()s!\" % [\"Hello\", \"World\"]", useNewEvaluator = useNewEvaluator) ==> ujson .Str("Hello World!") } test("binaryOps") { val ex = assertThrows[Exception]( - eval( - "1 && 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("1 && 2", useNewEvaluator = useNewEvaluator) ) assert(ex.getMessage.contains("binary operator && does not operate on numbers.")) val ex2 = assertThrows[Exception]( - eval( - "1 || 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("1 || 2", useNewEvaluator = useNewEvaluator) ) assert(ex2.getMessage.contains("binary operator || does not operate on numbers.")) } test("stdToString") { - eval( - """std.toString({k: "v"})""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("""std.toString({k: "v"})""", useNewEvaluator = useNewEvaluator) ==> ujson.Str( """{"k": "v"}""" ) } test("floatFormatRegression") { - eval( - "'%.4f' % 0.01", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("0.0100") - eval( - "'%05d' % 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("00002") - eval( - "'%000d' % 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("2") - eval( - "'%000d' % 2.123", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("2") - eval( - "'%5d' % 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str(" 2") - eval( - "'%5f' % 2", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("2.000000") - - eval( - "'%10d' % 2.123", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str(" 2") - eval( - "'%+5.5f' % 123.456", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("+123.45600") - eval( - "'%+5.5f' % -123.456", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("-123.45600") - eval( - "'% 5.5f' % -123.456", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("-123.45600") - eval( - "'%--+5.5f' % -123.456", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("-123.45600") - eval( - "'%#-0- + 5.5f' % -123.456", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("'%.4f' % 0.01", useNewEvaluator = useNewEvaluator) ==> ujson.Str("0.0100") + eval("'%05d' % 2", useNewEvaluator = useNewEvaluator) ==> ujson.Str("00002") + eval("'%000d' % 2", useNewEvaluator = useNewEvaluator) ==> ujson.Str("2") + eval("'%000d' % 2.123", useNewEvaluator = useNewEvaluator) ==> ujson.Str("2") + eval("'%5d' % 2", useNewEvaluator = useNewEvaluator) ==> ujson.Str(" 2") + eval("'%5f' % 2", useNewEvaluator = useNewEvaluator) ==> ujson.Str("2.000000") + + eval("'%10d' % 2.123", useNewEvaluator = useNewEvaluator) ==> ujson.Str(" 2") + eval("'%+5.5f' % 123.456", useNewEvaluator = useNewEvaluator) ==> ujson.Str("+123.45600") + eval("'%+5.5f' % -123.456", useNewEvaluator = useNewEvaluator) ==> ujson.Str("-123.45600") + eval("'% 5.5f' % -123.456", useNewEvaluator = useNewEvaluator) ==> ujson.Str("-123.45600") + eval("'%--+5.5f' % -123.456", useNewEvaluator = useNewEvaluator) ==> ujson.Str("-123.45600") + eval("'%#-0- + 5.5f' % -123.456", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "-123.45600" ) } test("formatIntegerOverflow") { // %d, %o, %x should not overflow to Long.MAX_VALUE for large doubles - eval( - "'%d' % 1e19", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("10000000000000000000") - eval( - "'%d' % 1e20", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("'%d' % 1e19", useNewEvaluator = useNewEvaluator) ==> ujson.Str("10000000000000000000") + eval("'%d' % 1e20", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "100000000000000000000" ) - eval( - "'%d' % -1e19", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("'%d' % -1e19", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "-10000000000000000000" ) - eval( - "'%o' % 1e19", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str( + eval("'%o' % 1e19", useNewEvaluator = useNewEvaluator) ==> ujson.Str( "1053071060221172000000" ) - eval( - "'%x' % 1e19", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("8ac7230489e80000") + eval("'%x' % 1e19", useNewEvaluator = useNewEvaluator) ==> ujson.Str("8ac7230489e80000") // Sign should be determined from the truncated integer, not the original double: // -0.3 truncates to 0, so no minus sign should appear. - eval( - "'%5.3d' % -0.3", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str(" 000") - eval( - "'%d' % -0.9", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Str("0") + eval("'%5.3d' % -0.3", useNewEvaluator = useNewEvaluator) ==> ujson.Str(" 000") + eval("'%d' % -0.9", useNewEvaluator = useNewEvaluator) ==> ujson.Str("0") } test("strict") { - eval( - "({ a: 1 } { b: 2 }).a", - strict = false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("({ a: 1 } { b: 2 }).a", strict = false, useNewEvaluator = useNewEvaluator) ==> ujson .Num(1) - evalErr( - "({ a: 1 } { b: 2 }).a", - strict = true, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("({ a: 1 } { b: 2 }).a", strict = true, useNewEvaluator = useNewEvaluator) ==> """sjsonnet.StaticError: Adjacent object literals not allowed in strict mode - Use '+' to concatenate objects |at [].(:1:11)""".stripMargin eval( "local x = { c: 3 }; (x { a: 1 } { b: 2 }).a", strict = false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) eval( "local x = { c: 3 }; (x { a: 1 }).a", strict = true, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1) evalErr( "local x = { c: 3 }; ({ a: 1 } { b: 2 }).a", strict = true, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> """sjsonnet.StaticError: Adjacent object literals not allowed in strict mode - Use '+' to concatenate objects |at [].(:1:31)""".stripMargin } test("objectDeclaration") { - eval( - "{ ['foo']: x for x in []}", - false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj() - eval( - "{ ['foo']: x for x in [1]}", - false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj( + eval("{ ['foo']: x for x in []}", false, useNewEvaluator = useNewEvaluator) ==> ujson.Obj() + eval("{ ['foo']: x for x in [1]}", false, useNewEvaluator = useNewEvaluator) ==> ujson.Obj( "foo" -> 1 ) - eval( - "{ ['foo']+: x for x in []}", - false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj() - eval( - "{ ['foo']+: x for x in [1]}", - false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj( + eval("{ ['foo']+: x for x in []}", false, useNewEvaluator = useNewEvaluator) ==> ujson.Obj() + eval("{ ['foo']+: x for x in [1]}", false, useNewEvaluator = useNewEvaluator) ==> ujson.Obj( "foo" -> 1 ) eval( "{ ['foo']+: [x] for x in [1]} + { ['foo']+: [x] for x in [2]}", false, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Obj("foo" -> ujson.Arr(1, 2)) } test("givenNoDuplicateFieldsInListComprehension1_expectSuccess") { - eval( - """{ ["bar"]: x for x in [-876.89]}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj( + eval("""{ ["bar"]: x for x in [-876.89]}""", useNewEvaluator = useNewEvaluator) ==> ujson.Obj( "bar" -> -876.89 ) } test("givenNoDuplicateFieldsInListComprehension2_expectSuccess") { - eval( - """{ ["bar_" + x]: x for x in [5,12]}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson + eval("""{ ["bar_" + x]: x for x in [5,12]}""", useNewEvaluator = useNewEvaluator) ==> ujson .Obj("bar_5" -> 5, "bar_12" -> 12) } test("givenDuplicateFieldsInListComprehension_expectFailure") { - evalErr( - """{ [x]: x for x in ["A", "A"]}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + evalErr("""{ [x]: x for x in ["A", "A"]}""", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: [object comprehension] Duplicate key A in evaluated object comprehension. |at [].(:1:1)""".stripMargin } @@ -1173,23 +651,14 @@ object EvaluatorTests extends TestSuite { """local y = { a: "A" }; |local z = { a: "A" }; |{ [x.a]: x for x in [y, z]}""".stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> """sjsonnet.Error: [object comprehension] Duplicate key A in evaluated object comprehension. |at [].(:1:7)""".stripMargin } test("functionEqualsNull") { - eval( - """local f(x)=null; f == null""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.False - eval( - """local f=null; f == null""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.True + eval("""local f(x)=null; f == null""", useNewEvaluator = useNewEvaluator) ==> ujson.False + eval("""local f=null; f == null""", useNewEvaluator = useNewEvaluator) ==> ujson.True } test("dynamicDuplicateFields") { @@ -1198,52 +667,34 @@ object EvaluatorTests extends TestSuite { // duplicate field names is dynamically computed via a field name expression. // Cases where StaticOptimizer replaces the dynamic field names with fixed ones: - test - (evalErr( - """{ ["k"]: 1, ["k"]: 2 }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + test - (evalErr("""{ ["k"]: 1, ["k"]: 2 }""", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: Duplicate key k in evaluated object. |at [].(:1:1)""".stripMargin) - test - (evalErr( - """{ k: 1, ["k"]: 2 }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + test - (evalErr("""{ k: 1, ["k"]: 2 }""", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: Duplicate key k in evaluated object. |at [].(:1:1)""".stripMargin) - test - (evalErr( - """{ ["k"]: 1, k: 2 }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + test - (evalErr("""{ ["k"]: 1, k: 2 }""", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: Duplicate key k in evaluated object. |at [].(:1:1)""".stripMargin) // Test that lazy evaluation is preserved - duplicate fields should only error when accessed test - (eval( """{x: { ["k"]: 1, ["k"]: 2 }, y:1 }.y""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(1)) // But accessing the problematic field should still error test - (evalErr( """{x: { ["k"]: 1, ["k"]: 2 }, y:1 }.x""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> """sjsonnet.Error: Duplicate key k in evaluated object. |at [].(:1:34)""".stripMargin) // Non-StaticOptimizable case: - test - (evalErr( - """{ k: 1, ["k" + ""]: 2 }""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> + test - (evalErr("""{ k: 1, ["k" + ""]: 2 }""", useNewEvaluator = useNewEvaluator) ==> """sjsonnet.Error: Duplicate key k in evaluated object. |at [].(:1:1)""".stripMargin) } @@ -1252,14 +703,9 @@ object EvaluatorTests extends TestSuite { for (keyword <- Parser.keywords) { eval( s"""local ${keyword}Foo = 123; ${keyword}Foo""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) ==> ujson.Num(123) - eval( - s"""{${keyword}Foo: 123}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) ==> ujson.Obj( + eval(s"""{${keyword}Foo: 123}""", useNewEvaluator = useNewEvaluator) ==> ujson.Obj( s"${keyword}Foo" -> ujson.Num(123) ) } @@ -1267,18 +713,10 @@ object EvaluatorTests extends TestSuite { test("errorNonString") { assert( - evalErr( - """error {a: "b"}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains("""{"a": "b"}""") + evalErr("""error {a: "b"}""", useNewEvaluator = useNewEvaluator).contains("""{"a": "b"}""") ) assert( - evalErr( - """assert 1 == 2 : { a: "b"}; 1""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""assert 1 == 2 : { a: "b"}; 1""", useNewEvaluator = useNewEvaluator).contains( """{"a": "b"}""" ) ) @@ -1286,57 +724,33 @@ object EvaluatorTests extends TestSuite { test("assertInheritance") { test - assert( - evalErr( - """{ } + {assert false}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""{ } + {assert false}""", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) test - assert( - evalErr( - """{assert false} + {}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""{assert false} + {}""", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) test - assert( - evalErr( - """{assert false} + {} + {}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""{assert false} + {} + {}""", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) test - assert( - evalErr( - """{} + {assert false} + {}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""{} + {assert false} + {}""", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) test - assert( - evalErr( - """{} + {} + {assert false}""", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("""{} + {} + {assert false}""", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) // Both own and inherited assertions are evaluated: test - assert( - evalErr( - "{assert false} + {assert true}", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("{assert false} + {assert true}", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) @@ -1344,20 +758,12 @@ object EvaluatorTests extends TestSuite { // assertions plus any inherited assertions, even if the accessed member happens // to be a constant. test - assert( - evalErr( - "({assert false} + {x: 2}).x", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("({assert false} + {x: 2}).x", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) test - assert( - evalErr( - "({assert false} + {f(x): x}).f(1)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains( + evalErr("({assert false} + {f(x): x}).f(1)", useNewEvaluator = useNewEvaluator).contains( "sjsonnet.Error: Assertion failed" ) ) @@ -1367,11 +773,8 @@ object EvaluatorTests extends TestSuite { |{ a: template { flag: true, }, b: template { flag: false, } } |""".stripMargin assert( - evalErr( - problematicStrictInheritedAssertionsSnippet, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ).contains("sjsonnet.Error: Assertion failed") + evalErr(problematicStrictInheritedAssertionsSnippet, useNewEvaluator = useNewEvaluator) + .contains("sjsonnet.Error: Assertion failed") ) } } @@ -1380,8 +783,7 @@ object EvaluatorTests extends TestSuite { evalErr( """{ } + {assert false}""", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1390,8 +792,7 @@ object EvaluatorTests extends TestSuite { evalErr( """{assert false} + {}""", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1400,8 +801,7 @@ object EvaluatorTests extends TestSuite { evalErr( """{assert false} + {} + {}""", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1410,8 +810,7 @@ object EvaluatorTests extends TestSuite { evalErr( """{} + {assert false} + {}""", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1420,8 +819,7 @@ object EvaluatorTests extends TestSuite { evalErr( """{} + {} + {assert false}""", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1430,8 +828,7 @@ object EvaluatorTests extends TestSuite { evalErr( "({assert false} + {f(x): x}).f(1)", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains( "sjsonnet.Error: Assertion failed" ) @@ -1445,8 +842,7 @@ object EvaluatorTests extends TestSuite { evalErr( problematicStrictInheritedAssertionsSnippet, useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ).contains("sjsonnet.Error: Assertion failed") ) } @@ -1456,14 +852,12 @@ object EvaluatorTests extends TestSuite { eval( "{assert false} + {assert true}", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ) ==> ujson.Obj() eval( "({assert false} + {x: 2}).x", useNewEvaluator = useNewEvaluator, - brokenAssertionLogic = true, - aggressiveStaticOptimization = aggressiveOpt + brokenAssertionLogic = true ) ==> ujson.Num(2) } } @@ -1474,11 +868,7 @@ object EvaluatorTests extends TestSuite { // Too many args test("tooManyArgs") { val ex = assertThrows[Exception] { - eval( - "std.length([1], [2])", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("std.length([1], [2])", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("Too many args, has")) } @@ -1486,11 +876,7 @@ object EvaluatorTests extends TestSuite { // Parameter not bound in call (missing required arg) test("missingRequiredArg") { val ex = assertThrows[Exception] { - eval( - "std.substr('hello')", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("std.substr('hello')", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("parameter")) assert(ex.getMessage.contains("not bound in call")) @@ -1499,11 +885,7 @@ object EvaluatorTests extends TestSuite { // Function has no parameter (invalid named arg) test("invalidNamedArg") { val ex = assertThrows[Exception] { - eval( - "std.length(x=[1], noSuchParam=2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("std.length(x=[1], noSuchParam=2)", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("has no parameter noSuchParam")) } @@ -1511,11 +893,7 @@ object EvaluatorTests extends TestSuite { // Binding parameter a second time test("duplicateArg") { val ex = assertThrows[Exception] { - eval( - "std.pow(2, x=3)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("std.pow(2, x=3)", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("binding parameter a second time: x in function pow")) } @@ -1527,8 +905,7 @@ object EvaluatorTests extends TestSuite { """local myFunc(x, y) = x + y; |myFunc("a") """.stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) } assert(ex.getMessage.contains("parameter y not bound in call")) @@ -1541,8 +918,7 @@ object EvaluatorTests extends TestSuite { """local add(x, y) = x + y; |add(1, 2, 3) """.stripMargin, - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt + useNewEvaluator = useNewEvaluator ) } assert(ex.getMessage.contains("Too many args, has 2 parameter(s)")) @@ -1551,11 +927,7 @@ object EvaluatorTests extends TestSuite { // Anonymous function should NOT include function name in error message test("anonymousFunctionNoFunctionName") { val ex = assertThrows[Exception] { - eval( - "(function(x, y) x + y)('a')", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("(function(x, y) x + y)('a')", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("parameter y not bound in call")) } @@ -1563,11 +935,7 @@ object EvaluatorTests extends TestSuite { // Anonymous function: too many args should NOT include function name test("anonymousFunctionTooManyArgs") { val ex = assertThrows[Exception] { - eval( - "(function(x) x)(1, 2)", - useNewEvaluator = useNewEvaluator, - aggressiveStaticOptimization = aggressiveOpt - ) + eval("(function(x) x)(1, 2)", useNewEvaluator = useNewEvaluator) } assert(ex.getMessage.contains("Too many args, has 1 parameter(s)")) } @@ -1608,8 +976,6 @@ object EvaluatorTests extends TestSuite { } def tests: Tests = - allTests(useNewEvaluator = false, aggressiveOpt = false).prefix("Evaluator") ++ - allTests(useNewEvaluator = true, aggressiveOpt = false).prefix("NewEvaluator") ++ - allTests(useNewEvaluator = false, aggressiveOpt = true).prefix("AggressiveOpt") ++ - allTests(useNewEvaluator = true, aggressiveOpt = true).prefix("NewEvaluator+AggressiveOpt") + allTests(useNewEvaluator = false).prefix("Evaluator") ++ + allTests(useNewEvaluator = true).prefix("NewEvaluator") } diff --git a/sjsonnet/test/src/sjsonnet/TestUtils.scala b/sjsonnet/test/src/sjsonnet/TestUtils.scala index a6dcbb65..4122c018 100644 --- a/sjsonnet/test/src/sjsonnet/TestUtils.scala +++ b/sjsonnet/test/src/sjsonnet/TestUtils.scala @@ -10,7 +10,6 @@ object TestUtils { useNewEvaluator: Boolean = false, brokenAssertionLogic: Boolean = false, maxStack: Int = 500, - aggressiveStaticOptimization: Boolean = false, std: sjsonnet.stdlib.StdLibModule = sjsonnet.stdlib.StdLibModule.Default) : Either[String, Value] = { new Interpreter( @@ -25,8 +24,7 @@ object TestUtils { throwErrorForInvalidSets = true, useNewEvaluator = useNewEvaluator, brokenAssertionLogic = brokenAssertionLogic, - maxStack = maxStack, - aggressiveStaticOptimization = aggressiveStaticOptimization + maxStack = maxStack ), std = std.module ).interpret(s, DummyPath("(memory)")) @@ -39,7 +37,6 @@ object TestUtils { useNewEvaluator: Boolean = false, brokenAssertionLogic: Boolean = false, maxStack: Int = 500, - aggressiveStaticOptimization: Boolean = false, std: sjsonnet.stdlib.StdLibModule = sjsonnet.stdlib.StdLibModule.Default): Value = { eval0( s, @@ -48,7 +45,6 @@ object TestUtils { useNewEvaluator, brokenAssertionLogic, maxStack, - aggressiveStaticOptimization, std ) match { case Right(x) => x @@ -63,7 +59,6 @@ object TestUtils { useNewEvaluator: Boolean = false, brokenAssertionLogic: Boolean = false, maxStack: Int = 500, - aggressiveStaticOptimization: Boolean = false, std: sjsonnet.stdlib.StdLibModule = sjsonnet.stdlib.StdLibModule.Default): String = { eval0( s, @@ -72,7 +67,6 @@ object TestUtils { useNewEvaluator, brokenAssertionLogic, maxStack, - aggressiveStaticOptimization, std ) match { case Left(err) =>