diff --git a/sjsonnet/src/sjsonnet/Std.scala b/sjsonnet/src/sjsonnet/Std.scala index 6860b9cf..8f8f0197 100644 --- a/sjsonnet/src/sjsonnet/Std.scala +++ b/sjsonnet/src/sjsonnet/Std.scala @@ -524,6 +524,37 @@ class Std { new Val.Arr(pos, out.result()) } } + + private object FlattenDeepArrays extends Val.Builtin1("flattenDeepArray", "value") { + def evalRhs(value: Val, ev: EvalScope, pos: Position): Val = { + val out = new mutable.ArrayBuilder.ofRef[Lazy] + val q = new java.util.ArrayDeque[Lazy]() + value.asArr.asLazyArray.foreach(q.add) + while (!q.isEmpty) { + q.removeFirst().force match { + case v: Val.Arr => v.asLazyArray.reverseIterator.foreach(q.push) + case x => out += x + } + } + new Val.Arr(pos, out.result()) + } + } + + private object DeepJoin extends Val.Builtin1("deepJoin", "arr") { + def evalRhs(value: Val, ev: EvalScope, pos: Position): Val = { + val out = new StringWriter() + val q = new java.util.ArrayDeque[Lazy]() + q.add(value) + while (!q.isEmpty) { + q.removeFirst().force match { + case v: Val.Arr => v.asLazyArray.reverseIterator.foreach(q.push) + case s: Val.Str => out.write(s.value) + } + } + Val.Str(pos, out.toString) + } + } + private object Reverse extends Val.Builtin1("reverse", "arrs") { def evalRhs(arrs: Val, ev: EvalScope, pos: Position): Val = { new Val.Arr(pos, arrs.asArr.asLazyArray.reverse) @@ -862,6 +893,9 @@ class Std { builtin("floor", "x"){ (pos, ev, x: Double) => math.floor(x) }, + builtin("round", "x") { (pos, ev, x: Double) => + math.round(x) + }, builtin("ceil", "x"){ (pos, ev, x: Double) => math.ceil(x) }, @@ -877,7 +911,18 @@ class Std { builtin("tan", "x"){ (pos, ev, x: Double) => math.tan(x) }, - + builtin("isEven", "x"){ (_, _, x: Double) => + math.round(x) % 2 == 0 + }, + builtin("isInteger", "x"){ (_, _, x: Double) => + math.round(x).toDouble == x + }, + builtin("isOdd", "x"){ (_, _, x: Double) => + math.round(x) % 2 != 0 + }, + builtin("isDecimal", "x"){ (_, _, x: Double) => + math.round(x).toDouble != x + }, builtin("asin", "x"){ (pos, ev, x: Double) => math.asin(x) }, @@ -1013,6 +1058,8 @@ class Std { }, builtin(FlattenArrays), + builtin(FlattenDeepArrays), + builtin(DeepJoin), builtin(Reverse), builtin("manifestIni", "v"){ (pos, ev, v: Val) => @@ -1041,6 +1088,21 @@ class Std { BaseRenderer.escape(out, str, unicode = true) out.toString }, + + builtin("escapeStringXML", "str"){ (_, _, str: String) => + val out = new StringWriter() + for (c <- str) { + c match { + case '<' => out.write("<") + case '>' => out.write(">") + case '&' => out.write("&") + case '"' => out.write(""") + case '\'' => out.write("'") + case _ => out.write(c) + } + } + out.toString + }, builtin("escapeStringBash", "str"){ (pos, ev, str: String) => "'" + str.replace("'", """'"'"'""") + "'" }, @@ -1363,6 +1425,9 @@ class Std { }, builtin(MinArray), builtin(MaxArray), + builtin("primitiveEquals", "x", "y") { (_, ev, x: Val, y: Val) => + x.isInstanceOf[y.type] && ev.compare(x, y) == 0 + } ) private def toSetArrOrString(args: Array[Val], idx: Int, pos: Position, ev: EvalScope) = { diff --git a/sjsonnet/test/resources/test_suite/stdlib.jsonnet b/sjsonnet/test/resources/test_suite/stdlib.jsonnet index 25e18f87..5a83b762 100644 --- a/sjsonnet/test/resources/test_suite/stdlib.jsonnet +++ b/sjsonnet/test/resources/test_suite/stdlib.jsonnet @@ -313,10 +313,10 @@ std.assertEqual(std.lines(['a', null, 'b']), 'a\nb\n') && std.assertEqual(std.flattenArrays([[1, 2, 3], [4, 5, 6], []]), [1, 2, 3, 4, 5, 6]) && -//std.assertEqual(std.flattenDeepArray([]), []) && -//std.assertEqual(std.flattenDeepArray([1, 2, 3]), [1, 2, 3]) && -//std.assertEqual(std.flattenDeepArray([1, [2, 3]]), [1, 2, 3]) && -//std.assertEqual(std.flattenDeepArray([[1], [2, 3], [[null]]]), [1, 2, 3, null]) && +std.assertEqual(std.flattenDeepArray([]), []) && +std.assertEqual(std.flattenDeepArray([1, 2, 3]), [1, 2, 3]) && +std.assertEqual(std.flattenDeepArray([1, [2, 3]]), [1, 2, 3]) && +std.assertEqual(std.flattenDeepArray([[1], [2, 3], [[null]]]), [1, 2, 3, null]) && std.assertEqual( std.manifestIni({ @@ -356,11 +356,11 @@ std.assertEqual(std.escapeStringJson('he"llo'), '"he\\"llo"') && std.assertEqual(std.escapeStringJson('he"llo'), '"he\\"llo"') && std.assertEqual(std.escapeStringBash("he\"l'lo"), "'he\"l'\"'\"'lo'") && std.assertEqual(std.escapeStringDollars('The path is ${PATH}.'), 'The path is $${PATH}.') && -//std.assertEqual(std.escapeStringXML('2 < 3'), '2 < 3') && -//std.assertEqual(std.escapeStringXML('3 > 2'), '3 > 2') && -//std.assertEqual(std.escapeStringXML('"foo"'), '"foo"') && -//std.assertEqual(std.escapeStringXML("don't believe the hype"), 'don't believe the hype') && -//std.assertEqual(std.escapeStringXML('PB&J'), 'PB&J') && +std.assertEqual(std.escapeStringXML('2 < 3'), '2 < 3') && +std.assertEqual(std.escapeStringXML('3 > 2'), '3 > 2') && +std.assertEqual(std.escapeStringXML('"foo"'), '"foo"') && +std.assertEqual(std.escapeStringXML("don't believe the hype"), 'don't believe the hype') && +std.assertEqual(std.escapeStringXML('PB&J'), 'PB&J') && std.assertEqual(std.escapeStringJson('!~'), '"!~"') && std.assertEqual(std.manifestPython({ @@ -1520,8 +1520,8 @@ std.assertEqual(std.type(std.parseYaml('id: "12345"').id), 'string') && std.assertEqual(std.asciiUpper('!@#$%&*()asdfghFGHJKL09876 '), '!@#$%&*()ASDFGHFGHJKL09876 ') && std.assertEqual(std.asciiLower('!@#$%&*()asdfghFGHJKL09876 '), '!@#$%&*()asdfghfghjkl09876 ') && -//std.assertEqual(std.deepJoin(['a', ['b', 'c', [[], 'd', ['e'], 'f', 'g'], [], []], 'h']), -// 'abcdefgh') && +std.assertEqual(std.deepJoin(['a', ['b', 'c', [[], 'd', ['e'], 'f', 'g'], [], []], 'h']), + 'abcdefgh') && std.assertEqual(std.findSubstr('', 'a'), []) && std.assertEqual(std.findSubstr('aa', ''), []) && @@ -1581,8 +1581,8 @@ std.assertEqual(std.xor(true, true), false) && std.assertEqual(std.xnor(true, false), false) && std.assertEqual(std.xnor(true, true), true) && -//std.assertEqual(std.round(1.2), 1) && -//std.assertEqual(std.round(1.5), 2) && +std.assertEqual(std.round(1.2), 1) && +std.assertEqual(std.round(1.5), 2) && std.assertEqual(std.isEmpty(''), true) && std.assertEqual(std.isEmpty('non-empty string'), false) && @@ -1593,14 +1593,14 @@ std.assertEqual(std.contains([1, 2, 3], 'foo'), false) && std.assertEqual(std.equalsIgnoreCase('foo', 'FOO'), true) && std.assertEqual(std.equalsIgnoreCase('foo', 'bar'), false) && -//std.assertEqual(std.isEven(10), true) && -//std.assertEqual(std.isEven(5), false) && -//std.assertEqual(std.isOdd(5), true) && -//std.assertEqual(std.isOdd(10), false) && -//std.assertEqual(std.isInteger(1), true) && -//std.assertEqual(std.isInteger(1.1), false) && -//std.assertEqual(std.isDecimal(1.1), true) && -//std.assertEqual(std.isDecimal(1), false) && +std.assertEqual(std.isEven(10), true) && +std.assertEqual(std.isEven(5), false) && +std.assertEqual(std.isOdd(5), true) && +std.assertEqual(std.isOdd(10), false) && +std.assertEqual(std.isInteger(1), true) && +std.assertEqual(std.isInteger(1.1), false) && +std.assertEqual(std.isDecimal(1.1), true) && +std.assertEqual(std.isDecimal(1), false) && std.assertEqual(std.remove([1, 2, 3], 2), [1, 3]) && std.assertEqual(std.removeAt([1, 2, 3], 1), [1, 3]) && diff --git a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet index b72790cb..e26198cc 100644 --- a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet +++ b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet @@ -313,10 +313,10 @@ std.assertEqual(std.lines(['a', null, 'b']), 'a\nb\n') && std.assertEqual(std.flattenArrays([[1, 2, 3], [4, 5, 6], []]), [1, 2, 3, 4, 5, 6]) && -//std.assertEqual(std.flattenDeepArray([]), []) && -//std.assertEqual(std.flattenDeepArray([1, 2, 3]), [1, 2, 3]) && -//std.assertEqual(std.flattenDeepArray([1, [2, 3]]), [1, 2, 3]) && -//std.assertEqual(std.flattenDeepArray([[1], [2, 3], [[null]]]), [1, 2, 3, null]) && +std.assertEqual(std.flattenDeepArray([]), []) && +std.assertEqual(std.flattenDeepArray([1, 2, 3]), [1, 2, 3]) && +std.assertEqual(std.flattenDeepArray([1, [2, 3]]), [1, 2, 3]) && +std.assertEqual(std.flattenDeepArray([[1], [2, 3], [[null]]]), [1, 2, 3, null]) && std.assertEqual( std.manifestIni({ @@ -356,11 +356,11 @@ std.assertEqual(std.escapeStringJson('he"llo'), '"he\\"llo"') && std.assertEqual(std.escapeStringJson('he"llo'), '"he\\"llo"') && std.assertEqual(std.escapeStringBash("he\"l'lo"), "'he\"l'\"'\"'lo'") && std.assertEqual(std.escapeStringDollars('The path is ${PATH}.'), 'The path is $${PATH}.') && -//std.assertEqual(std.escapeStringXML('2 < 3'), '2 < 3') && -//std.assertEqual(std.escapeStringXML('3 > 2'), '3 > 2') && -//std.assertEqual(std.escapeStringXML('"foo"'), '"foo"') && -//std.assertEqual(std.escapeStringXML("don't believe the hype"), 'don't believe the hype') && -//std.assertEqual(std.escapeStringXML('PB&J'), 'PB&J') && +std.assertEqual(std.escapeStringXML('2 < 3'), '2 < 3') && +std.assertEqual(std.escapeStringXML('3 > 2'), '3 > 2') && +std.assertEqual(std.escapeStringXML('"foo"'), '"foo"') && +std.assertEqual(std.escapeStringXML("don't believe the hype"), 'don't believe the hype') && +std.assertEqual(std.escapeStringXML('PB&J'), 'PB&J') && std.assertEqual(std.escapeStringJson('!~'), '"!~"') && std.assertEqual(std.manifestPython({ @@ -1518,8 +1518,8 @@ std.assertEqual(std.parseJson('{"a": {"b": ["c", 42]}}'), { a: { b: ['c', 42] } std.assertEqual(std.asciiUpper('!@#$%&*()asdfghFGHJKL09876 '), '!@#$%&*()ASDFGHFGHJKL09876 ') && std.assertEqual(std.asciiLower('!@#$%&*()asdfghFGHJKL09876 '), '!@#$%&*()asdfghfghjkl09876 ') && -//std.assertEqual(std.deepJoin(['a', ['b', 'c', [[], 'd', ['e'], 'f', 'g'], [], []], 'h']), -// 'abcdefgh') && +std.assertEqual(std.deepJoin(['a', ['b', 'c', [[], 'd', ['e'], 'f', 'g'], [], []], 'h']), + 'abcdefgh') && std.assertEqual(std.findSubstr('', 'a'), []) && std.assertEqual(std.findSubstr('aa', ''), []) && @@ -1579,8 +1579,8 @@ std.assertEqual(std.xor(true, true), false) && std.assertEqual(std.xnor(true, false), false) && std.assertEqual(std.xnor(true, true), true) && -//std.assertEqual(std.round(1.2), 1) && -//std.assertEqual(std.round(1.5), 2) && +std.assertEqual(std.round(1.2), 1) && +std.assertEqual(std.round(1.5), 2) && std.assertEqual(std.isEmpty(''), true) && std.assertEqual(std.isEmpty('non-empty string'), false) && @@ -1591,14 +1591,14 @@ std.assertEqual(std.contains([1, 2, 3], 'foo'), false) && std.assertEqual(std.equalsIgnoreCase('foo', 'FOO'), true) && std.assertEqual(std.equalsIgnoreCase('foo', 'bar'), false) && -//std.assertEqual(std.isEven(10), true) && -//std.assertEqual(std.isEven(5), false) && -//std.assertEqual(std.isOdd(5), true) && -//std.assertEqual(std.isOdd(10), false) && -//std.assertEqual(std.isInteger(1), true) && -//std.assertEqual(std.isInteger(1.1), false) && -//std.assertEqual(std.isDecimal(1.1), true) && -//std.assertEqual(std.isDecimal(1), false) && +std.assertEqual(std.isEven(10), true) && +std.assertEqual(std.isEven(5), false) && +std.assertEqual(std.isOdd(5), true) && +std.assertEqual(std.isOdd(10), false) && +std.assertEqual(std.isInteger(1), true) && +std.assertEqual(std.isInteger(1.1), false) && +std.assertEqual(std.isDecimal(1.1), true) && +std.assertEqual(std.isDecimal(1), false) && std.assertEqual(std.remove([1, 2, 3], 2), [1, 3]) && std.assertEqual(std.removeAt([1, 2, 3], 1), [1, 3]) &&