diff --git a/sjsonnet/src/sjsonnet/Format.scala b/sjsonnet/src/sjsonnet/Format.scala index 2f88e1a5..6bb7beca 100644 --- a/sjsonnet/src/sjsonnet/Format.scala +++ b/sjsonnet/src/sjsonnet/Format.scala @@ -1,5 +1,7 @@ package sjsonnet +import scala.util.control.NonFatal + /** * Minimal re-implementation of Python's `%` formatting logic, since Jsonnet's `%` formatter is * basically "do whatever python does", with a link to: @@ -273,7 +275,7 @@ object Format { } def format(s: String, values0: Val, pos: Position)(implicit evaluator: EvalScope): Val.Str = { - val parsed = parseFormatCached(s, evaluator.formatCache) + val parsed = parseFormatOrFail(pos)(parseFormatCached(s, evaluator.formatCache)) format(parsed, values0, pos) } @@ -558,9 +560,19 @@ object Format { def format(leading: String, chunks: scala.Seq[(FormatSpec, String)], values0: Val, pos: Position)( implicit evaluator: EvalScope): Val.Str = { - format(lowerParsedFormat((leading, chunks)), values0, pos) + val parsed = parseFormatOrFail(pos)(lowerParsedFormat((leading, chunks))) + format(parsed, values0, pos) } + private def parseFormatOrFail(pos: Position)(parse: => RuntimeFormat)(implicit + evaluator: EvalErrorScope): RuntimeFormat = + try parse + catch { + case e: Error => throw e + case NonFatal(e) => + Error.fail(e.getMessage, pos) + } + private def appendLeading(output: java.lang.StringBuilder, parsed: RuntimeFormat): Unit = { val source = parsed.source if (source != null) output.append(source, parsed.leadingStart, parsed.leadingEnd) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet b/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet new file mode 100644 index 00000000..ca3eeda2 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet @@ -0,0 +1 @@ +std.format("%z", [1]) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet.golden b/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet.golden new file mode 100644 index 00000000..41651169 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_invalid_conversion.jsonnet.golden @@ -0,0 +1,2 @@ +sjsonnet.Error: [std.format] Unrecognized conversion type: z + at [].(error.format_invalid_conversion.jsonnet:1:11) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet b/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet new file mode 100644 index 00000000..35947041 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet @@ -0,0 +1 @@ +"%z" % [1] diff --git a/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet.golden b/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet.golden new file mode 100644 index 00000000..b5c12b48 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_operator_invalid_conversion.jsonnet.golden @@ -0,0 +1 @@ +sjsonnet.Error: Unrecognized conversion type: z diff --git a/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet b/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet new file mode 100644 index 00000000..9564c8a6 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet @@ -0,0 +1 @@ +std.format("hello %", []) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet.golden b/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet.golden new file mode 100644 index 00000000..e9f434e3 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_truncated.jsonnet.golden @@ -0,0 +1,2 @@ +sjsonnet.Error: [std.format] Truncated format code at end of string + at [].(error.format_truncated.jsonnet:1:11) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet b/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet new file mode 100644 index 00000000..1e95db24 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet @@ -0,0 +1 @@ +std.format("%(key", { key: "value" }) diff --git a/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet.golden b/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet.golden new file mode 100644 index 00000000..7e86c2c2 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/error.format_unterminated_label.jsonnet.golden @@ -0,0 +1 @@ +sjsonnet.Error: [std.format] Unterminated ( in format spec diff --git a/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet b/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet new file mode 100644 index 00000000..943f0077 --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet @@ -0,0 +1,5 @@ +std.assertEqual(std.format("100%% done %s", ["yes"]), "100% done yes") && +std.assertEqual(std.format("%*s", [10, "hello"]), " hello") && +std.assertEqual(std.format("%.*f", [3, 3.14159]), "3.142") && +std.assertEqual(std.format("%#x", [255]), "0xff") && +true diff --git a/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet.golden b/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet.golden new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/sjsonnet/test/resources/new_test_suite/format_error_messages.jsonnet.golden @@ -0,0 +1 @@ +true