{"id":96590,"date":"2025-02-08T17:49:45","date_gmt":"2025-02-08T14:19:45","guid":{"rendered":"https:\/\/nabfollower.com\/blog\/tsonnet-5-json-%da%86%d8%a7%d9%be-%d8%b2%db%8c%d8%a8%d8%a7\/"},"modified":"2025-02-08T17:49:45","modified_gmt":"2025-02-08T14:19:45","slug":"tsonnet-5-json-%da%86%d8%a7%d9%be-%d8%b2%db%8c%d8%a8%d8%a7","status":"publish","type":"post","link":"https:\/\/nabfollower.com\/blog\/tsonnet-5-json-%da%86%d8%a7%d9%be-%d8%b2%db%8c%d8%a8%d8%a7\/","title":{"rendered":"Tsonnet #5 &#8211; JSON \u0686\u0627\u067e \u0632\u06cc\u0628\u0627"},"content":{"rendered":"<div data-article-id=\"2266121\" id=\"article-body\">\n<p>\u0628\u0647 \u0633\u0631\u06cc TSONNET \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f!<\/p>\n<p>\u062f\u0631 \u067e\u0633\u062a \u0642\u0628\u0644\u06cc \u060c \u0645\u0627 \u0627\u0646\u0648\u0627\u0639 \u0639\u062f\u062f\u06cc \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0627\u0635\u0644\u0627\u062d \u06a9\u0631\u062f\u06cc\u0645:<\/p>\n<p>\u0627\u0645\u0631\u0648\u0632 \u060c \u0645\u0646 \u0645\u06cc \u062e\u0648\u0627\u0647\u0645 \u0628\u0627 \u0644\u0627\u06cc\u0647 \u0627\u0631\u0627\u0626\u0647 \u0645\u0642\u0627\u0628\u0644\u0647 \u06a9\u0646\u0645: \u0686\u0627\u067e \u06a9\u0646\u0646\u062f\u0647 \u062e\u0631\u0648\u062c\u06cc JSON.<\/p>\n<p>\u062f\u0631 <code>print<\/code> \u0639\u0645\u0644\u06a9\u0631\u062f \u062f\u0631 \u0648\u0627\u0642\u0639 \u0686\u0627\u067e &#8220;JSON&#8221; \u0646\u06cc\u0633\u062a \u060c \u0641\u0642\u0637 \u0628\u0627\u0632\u0646\u0645\u0627\u06cc\u06cc \u0647\u0627\u06cc \u0627\u0631\u0632\u0634 \u062e\u0627\u0645.<\/p>\n<p>Yojson \u06cc\u06a9 \u0627\u0646\u062a\u062e\u0627\u0628 \u0628\u0633\u06cc\u0627\u0631 \u0631\u0627\u06cc\u062c \u0628\u0631\u0627\u06cc \u062a\u062c\u0632\u06cc\u0647 JSON \u062f\u0631 OCAML \u0627\u0633\u062a. <\/p>\n<p>\u0628\u06cc\u0627\u06cc\u06cc\u062f \u0622\u0646 \u0631\u0627 \u0628\u0627 OPAM \u0646\u0635\u0628 \u06a9\u0646\u06cc\u0645:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nv\">$ <\/span>opam <span class=\"nb\">install <\/span>yojson\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0648 \u0622\u0646 \u0631\u0627 \u0628\u0647 \u0648\u0627\u0628\u0633\u062a\u06af\u06cc \u0647\u0627\u06cc \u0645\u0627 \u062f\u0631 \u067e\u0631\u0648\u0698\u0647 Dune \u0627\u0636\u0627\u0641\u0647 \u06a9\u0646\u06cc\u062f:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">Diff-Git A\/Dune-Project B\/Dune-Project INDEX 383BBEF..775351B 100644\n<\/span><span class=\"gd\">--- A\/Dune Project\n<\/span><span class=\"gi\">+++ b\/dune-project\n<\/span><span class=\"p\">-33\u060c7 +33\u060c9<\/span>\n   (bisect_ppx (\u0648: \u0628\u0627 \u0622\u0632\u0645\u0648\u0646\n<span class=\"gd\">- (> = 2.8.3))))\n<\/span><span class=\"gi\">+ (> = 2.8.3))) + (yojson + (> = 2.2.2))\n<\/span>  (\u0628\u0631\u0686\u0633\u0628 \u0647\u0627 (\u06a9\u0627\u0645\u067e\u0627\u06cc\u0644\u0631 \u0645\u062a\u0631\u062c\u0645 JSONNET)))\n<span class=\"gh\">Diff -git a\/tsonnet.opam b\/tsonnet.opam \u0634\u0627\u062e\u0635 31C792C..16783C3 100644\n<\/span><span class=\"gd\">--- a\/tsonnet.opam\n<\/span><span class=\"gi\">+++ b\/tsonnet.opam\n<\/span><span class=\"p\">-15\u060c6 +15\u060c7<\/span> \u0628\u0633\u062a\u06af\u06cc \u062f\u0627\u0631\u062f: [\n   \"menhir\" {= \"20240715\"}\n   \"alcotest\" {with-test &amp; &gt;= \"1.8.0\"}\n   \"bisect_ppx\" {with-test &amp; &gt;= \"2.8.3\"}\n<span class=\"gi\">+  \"yojson\" {&gt;= \"2.2.2\"}\n<\/span>   \"odoc\" {with-doc}\n ]\n \u0633\u0627\u062e\u062a: [\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>Enter fullscreen mode<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>Exit fullscreen mode<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>The opam file is automatically updated by dune.<\/p>\n<p>Before using the library, we need to specify that the lib config will depend on yojson:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">diff --git a\/lib\/dune b\/lib\/dune\nindex 3452131..05c4dc3 100644\n<\/span><span class=\"gd\">--- a\/lib\/dune\n<\/span><span class=\"gi\">+++ b\/lib\/dune\n<\/span><span class=\"p\">@@ -1,7 +1,8 @@<\/span>\n (library\n  (name tsonnet)\n  (instrumentation\n<span class=\"gd\">-  (backend bisect_ppx)))\n<\/span><span class=\"gi\">+  (backend bisect_ppx))\n+ (libraries yojson))\n<\/span><span class=\"err\">\n<\/span> (menhir\n  (modules parser))\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>Enter fullscreen mode<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>Exit fullscreen mode<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>To get rid of the printfs, we need a way of converting a <code>expr<\/code> to JSON.<\/p>\n<p>Let&#8217;s encapsulate the expression conversion in a new module, dedicated to transforming expressions into JSON representation:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">diff --git a\/lib\/json.ml b\/lib\/json.ml\n<\/span><span class=\"p\">new file mode 100644\n<\/span><span class=\"gh\">index 0000000..886d2bd\n<\/span><span class=\"gd\">--- \/dev\/null\n<\/span><span class=\"gi\">+++ b\/lib\/json.ml\n<\/span><span class=\"p\">@@ -0,0 +1,17 @@<\/span>\n<span class=\"gi\">+open Ast\n+\n+let rec expr_to_yojson : (expr -&gt; Yojson.t) = function\n+  | Number n -&gt;\n+    (match n with\n+    | Int i -&gt; `Int i\n+    | Float f -&gt; `Float f)\n+  | Null -&gt; `Null\n+  | Bool b -&gt; `Bool b\n+  | String s -&gt; `String s\n+  | Array values -&gt; `List (List.map expr_to_yojson values)\n+  | Object attrs -&gt;\n+    let eval' = fun (k, v) -&gt; (k, expr_to_yojson v)\n+    in `Assoc (List.map eval' attrs)\n+  | _ -&gt; failwith \"value type not representable as JSON\"\n+\n+let expr_to_string expr = Yojson.pretty_to_string (expr_to_yojson expr)\n<\/span><\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>Enter fullscreen mode<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>Exit fullscreen mode<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>The new <code>Json<\/code> module will implement two functions. The function <code>expr_to_yojson<\/code> basically maps our <code>expr<\/code> types to <code>Yojson.t<\/code>. The function <code>expr_to_string<\/code> will use the previous function to convert from <code>Yojson.t<\/code> to <code>string<\/code>.<\/p>\n<p>If eventually we decide to change the way we want to render JSON, like using a more performant library, for example, we refactor this module and there&#8217;s no need to update anywhere else &#8212; maybe the tests.<\/p>\n<p>With that, we can remove our messy hand-written print function:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">diff --git a\/lib\/tsonnet.ml b\/lib\/tsonnet.ml\nindex 832b56c..a528488 100644\n<\/span><span class=\"gd\">--- a\/lib\/tsonnet.ml\n<\/span><span class=\"gi\">+++ b\/lib\/tsonnet.ml\n<\/span><span class=\"p\">@@ -6,24 +6,6 @@<\/span> let parse (s: string) : expr =\n   let ast = Parser.prog Lexer.read lexbuf in\n   ast\n<span class=\"err\">\n<\/span><span class=\"gd\">-let rec print = function\n-  | Number n -&gt;\n-    (match n with\n-    | Int i -&gt; Printf.sprintf \"%d\" i\n-    | Float f -&gt; Printf.sprintf \"%f\" f)\n-  | Null -&gt; Printf.sprintf \"null\"\n-  | Bool b -&gt; Printf.sprintf \"%b\" b\n-  | String s -&gt; Printf.sprintf \"\\\"%s\\\"\" s\n-  | Array values -&gt; Printf.sprintf \"[%s]\"(string.concat\" \u060c \"(\u0644\u06cc\u0633\u062a. \u0645\u0642\u0627\u062f\u06cc\u0631 \u0686\u0627\u067e\u06cc)) - | \u0634\u06cc\u0621 \u0634\u06cc -> - \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f print_key_val = \u062a\u0627\u0628\u0639 - | (k \u060c v) -> printf.sprintf\" \\ \"\u066a s \\\": \u066a s \" k (print v) - in - printf.sprintf \"{\u066a s}\" ( - string.concat \"\u060c\" (list.map print_key_val \u062c\u0627\u0630\u0628\u0647) -) - | _ -> failwith \"\u0627\u062c\u0631\u0627 \u0646\u0634\u062f\u0647\" -\n<\/span> \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u062a\u0641\u0633\u06cc\u0631_BIN_OP (OP: BIN_OP) (N1: \u0634\u0645\u0627\u0631\u0647) (N2: \u0634\u0645\u0627\u0631\u0647): Expr = Match OP \u060c N1 \u060c N2 \u0628\u0627 | \u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u060c (int a) \u060c (int b) -> \u0634\u0645\u0627\u0631\u0647 (int (a + b))\n<span class=\"p\">-52\u060c7 +34\u060c7<\/span> \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u062a\u0641\u0633\u06cc\u0631 (e: expr): expr = | (\u0634\u0645\u0627\u0631\u0647 V1) \u060c (\u0634\u0645\u0627\u0631\u0647 V2) -> \u062a\u0641\u0633\u06cc\u0631_BIN_OP OP V1 V2 | _ -> FailWith \"\u0639\u0645\u0644\u06cc\u0627\u062a \u0628\u0627\u06cc\u0646\u0631\u06cc \u0646\u0627\u0645\u0639\u062a\u0628\u0631\"\n<span class=\"err\">\n<\/span><span class=\"gd\">-let Run (S: String): expr =\n<\/span><span class=\"gi\">+\u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u0627\u062c\u0631\u0627 \u0634\u0648\u062f (s: string) =\n<\/span>   \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f AST = \u062a\u062c\u0632\u06cc\u0647 \u062f\u0631 let let letuated_ast = \u062a\u0641\u0633\u06cc\u0631 AST \u062f\u0631\n<span class=\"gd\">- \u0627\u0631\u0632\u06cc\u0627\u0628\u06cc_\u0633\u062a\n<\/span><span class=\"gi\">+ json.expr_to_string \u0627\u0631\u0632\u06cc\u0627\u0628\u06cc_ast\n<\/span><\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0645\u0627\u0698\u0648\u0644 \u06a9\u062a\u0627\u0628\u062e\u0627\u0646\u0647 Tsonnet \u0628\u0633\u06cc\u0627\u0631 \u062a\u0645\u06cc\u0632 \u062a\u0631 \u0628\u0647 \u0646\u0638\u0631 \u0645\u06cc \u0631\u0633\u062f!<\/p>\n<p>\u0647\u0645\u0627\u0646\u0637\u0648\u0631 \u06a9\u0647 \u0645\u0627 \u062f\u0631 \u062d\u0627\u0644 \u0633\u0627\u062e\u062a\u0646 <code>run<\/code> \u0639\u0645\u0644\u06a9\u0631\u062f \u0628\u0627\u0632\u06af\u0634\u062a a <code>string<\/code>\u060c \u0645\u0627 \u0628\u0627\u06cc\u062f \u0628\u0647 \u0631\u0648\u0632 \u06a9\u0646\u06cc\u0645 <code>main.ml<\/code> \u0628\u0631 \u0627\u06cc\u0646 \u0627\u0633\u0627\u0633:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">diff --git a\/bin\/main.ml b\/bin\/main.ml\nindex 78e9bb8..723b106 100644\n<\/span><span class=\"gd\">--- a\/bin\/main.ml\n<\/span><span class=\"gi\">+++ b\/bin\/main.ml\n<\/span><span class=\"p\">@@ -7,8 +7,8 @@<\/span> let run_parser filename =\n   let input_channel = open_in filename in\n   let content = really_input_string input_channel (in_channel_length input_channel) in\n   close_in input_channel;\n<span class=\"gd\">-  let expr = Tsonnet.run content in\n-  print_endline (Tsonnet.print expr)\n<\/span><span class=\"gi\">+  let result = Tsonnet.run content in\n+  print_endline result\n<\/span><span class=\"err\">\n<\/span> let () =\n   Arg.parse spec_list anonymous_fun usage_msg;\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0648 \u062a\u0633\u062a \u0647\u0627\u06cc CRAM \u0646\u06cc\u0632 \u0628\u0627\u06cc\u062f \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u0645\u0646\u0639\u06a9\u0633 \u06a9\u0646\u0646\u062f:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight diff\"><code><span class=\"gh\">diff --git a\/bin\/usage.t b\/bin\/usage.t\nindex a8fc82f..b488efe 100644\n<\/span><span class=\"gd\">--- a\/bin\/usage.t\n<\/span><span class=\"gi\">+++ b\/bin\/usage.t\n<\/span><span class=\"p\">@@ -7,7 +7,14 @@<\/span> Using the Tsonnet program:\n   \"Hello, world!\"\n<span class=\"err\">\n<\/span>   $ tsonnet ..\/samples\/literals\/object.jsonnet\n<span class=\"gd\">-  {\"int_attr\": 1, \"float_attr\": 4.200000, \"string_attr\": \"Hello, world!\", \"null_attr\": null, \"array_attr\": [1, false, {}], \"obj_attr\": {\"a\": true, \"b\": false, \"c\": {\"d\": [42]}}}\n<\/span><span class=\"gi\">+  {\n+    \"int_attr\": 1,\n+    \"float_attr\": 4.2,\n+    \"string_attr\": \"Hello, world!\",\n+    \"null_attr\": null,\n+    \"array_attr\": [ 1, false, {} ],\n+    \"obj_attr\": { \"a\": true, \"b\": false, \"c\": { \"d\": [ 42 ] } }\n+  }\n<\/span><span class=\"err\">\n<\/span>   $ tsonnet ..\/samples\/binary_operations.jsonnet\n<span class=\"gd\">-  44.700000\n<\/span><span class=\"gi\">+  44.7 \n<\/span><\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u06cc\u06a9\u06cc \u0627\u0632 \u062a\u0631\u0641\u0646\u062f\u0647\u0627\u06cc\u06cc \u06a9\u0647 \u0632\u0646\u062f\u06af\u06cc \u0645\u0627 \u0631\u0627 \u0628\u0633\u06cc\u0627\u0631 \u0622\u0633\u0627\u0646 \u0645\u06cc \u06a9\u0646\u062f \u0627\u06cc\u0646 \u0648\u0627\u0642\u0639\u06cc\u062a \u0627\u0633\u062a \u06a9\u0647 Dune \u0648\u06cc\u0698\u06af\u06cc \u0627\u06cc \u0628\u0647 \u0646\u0627\u0645 \u062f\u0627\u0631\u062f <code>promote<\/code>\u0628\u0634\u0631<\/p>\n<p>\u0686\u0647 \u06a9\u0627\u0631\u06cc \u0627\u0646\u062c\u0627\u0645 \u0645\u06cc \u062f\u0647\u062f\u061f \u0627\u06af\u0631 \u062a\u0633\u062a \u0647\u0627 \u0627\u062c\u0631\u0627 \u0634\u0648\u0646\u062f \u0648 \u062e\u0631\u0648\u062c\u06cc \u0635\u062d\u06cc\u062d \u0628\u0627\u0634\u062f \u060c \u0627\u0645\u0627 \u062a\u0641\u0627\u0648\u062a \u0645\u062a\u0646\u0627\u0642\u0636 \u0627\u0633\u062a \u060c \u0634\u0645\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0622\u0646 \u0631\u0627 \u062a\u0631\u0648\u06cc\u062c \u06a9\u0646\u06cc\u062f \u060c \u0628\u0647 \u0627\u06cc\u0646 \u0645\u0639\u0646\u06cc \u06a9\u0647 \u062a\u0641\u0627\u0648\u062a \u0622\u0646 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0634\u0645\u0627 \u0628\u0627 \u06cc\u06a9 \u062f\u0633\u062a\u0648\u0631 \u0648\u0627\u062d\u062f \u0627\u0639\u0645\u0627\u0644 \u0645\u06cc \u06a9\u0646\u062f:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nv\">$ <\/span>dune runtest <span class=\"nt\">--auto-promote<\/span>\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u062f\u0633\u062a\u0648\u0631 \u0628\u0627\u0644\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0647\u0627 \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0627\u062c\u0631\u0627 \u0645\u06cc \u06a9\u0646\u062f \u0648 \u062a\u0641\u0627\u0648\u062a \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u062f\u0631 \u067e\u0631\u0648\u0646\u062f\u0647 \u0647\u0627\u06cc \u0645\u0631\u0628\u0648\u0637\u0647 \u0627\u0639\u0645\u0627\u0644 \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<p>\u0627\u06cc\u0646 \u0641\u0648\u0642 \u0627\u0644\u0639\u0627\u062f\u0647 \u0645\u0641\u06cc\u062f \u0627\u0633\u062a! \u0645\u0646 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0647 \u062c\u0632\u0626\u06cc\u0627\u062a \u0646\u0645\u06cc \u067e\u0631\u062f\u0627\u0632\u0645 \u060c \u0627\u0645\u0627 \u0648\u0627\u0642\u0639\u0627\u064b \u062a\u0648\u0635\u06cc\u0647 \u0645\u06cc \u06a9\u0646\u0645 \u0645\u0633\u062a\u0646\u062f\u0627\u062a \u0645\u062a\u0641\u0627\u0648\u062a \u0648 \u062a\u0628\u0644\u06cc\u063a\u06cc \u0631\u0627 \u0628\u062e\u0648\u0627\u0646\u06cc\u062f. <\/p>\n<p>\u0645\u0631\u0627\u0642\u0628 \u0628\u0627\u0634\u06cc\u062f \u060c \u0627\u06cc\u0646 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0634\u0645\u0627 \u0631\u0627 \u062f\u0631 \u0628\u0631\u0627\u0628\u0631 \u0627\u0628\u0632\u0627\u0631 \u0633\u0627\u062e\u062a\u0645\u0627\u0646 \u0641\u0639\u0644\u06cc \u062e\u0648\u062f \u0646\u0627\u0631\u0627\u062d\u062a \u06a9\u0646\u062f &#8211; \u0628\u0627 \u0627\u062d\u062a\u06cc\u0627\u0637. \u0648\u0627\u0642\u0639\u0627\u064b \u062c\u0627\u062f\u0648 \u0645\u06cc \u0634\u0648\u062f! \ud83d\ude1c<\/p>\n<p>\u0627\u06cc\u0646 \u0627\u062d\u0633\u0627\u0633 \u0628\u0647\u062a\u0631 \u0627\u0633\u062a \u06a9\u0647 \u06cc\u06a9 \u062e\u0631\u0648\u062c\u06cc \u0632\u06cc\u0628\u0627 \u0686\u0627\u067e \u0634\u062f\u0647 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u060c \u0627\u06cc\u0646\u0637\u0648\u0631 \u0646\u06cc\u0633\u062a\u061f!<\/p>\n<hr\/>\n<p>\u0628\u0627 \u062a\u0634\u06a9\u0631 \u0627\u0632 \u0634\u0645\u0627 \u0628\u0631\u0627\u06cc \u062e\u0648\u0627\u0646\u062f\u0646 \u0628\u06cc\u062a \u0634\u0627\u06cc\u062f \u0639\u0627\u0642\u0644\u0627\u0646\u0647! \u0628\u0631\u0627\u06cc \u062f\u0631\u06cc\u0627\u0641\u062a \u067e\u0633\u062a \u0647\u0627\u06cc \u062c\u062f\u06cc\u062f \u062f\u0631\u0628\u0627\u0631\u0647 TSONNET \u0645\u0634\u062a\u0631\u06a9 \u0634\u0648\u06cc\u062f.<\/p>\n<p>\u0639\u06a9\u0633 \u062a\u0648\u0633\u0637 \u067e\u06cc\u062a \u06af\u0648\u062f\u0641\u0631\u06cc \u062f\u0631 Unsplash<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u0628\u0647 \u0633\u0631\u06cc TSONNET \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f! \u062f\u0631 \u067e\u0633\u062a \u0642\u0628\u0644\u06cc \u060c \u0645\u0627 \u0627\u0646\u0648\u0627\u0639 \u0639\u062f\u062f\u06cc \u0631\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u0627\u0635\u0644\u0627\u062d \u06a9\u0631\u062f\u06cc\u0645: \u0627\u0645\u0631\u0648\u0632 \u060c \u0645\u0646 \u0645\u06cc \u062e\u0648\u0627\u0647\u0645 \u0628\u0627 \u0644\u0627\u06cc\u0647 \u0627\u0631\u0627\u0626\u0647 \u0645\u0642\u0627\u0628\u0644\u0647 \u06a9\u0646\u0645: \u0686\u0627\u067e \u06a9\u0646\u0646\u062f\u0647 \u062e\u0631\u0648\u062c\u06cc JSON. \u062f\u0631 print \u0639\u0645\u0644\u06a9\u0631\u062f \u062f\u0631 \u0648\u0627\u0642\u0639 \u0686\u0627\u067e &#8220;JSON&#8221; \u0646\u06cc\u0633\u062a \u060c \u0641\u0642\u0637 \u0628\u0627\u0632\u0646\u0645\u0627\u06cc\u06cc \u0647\u0627\u06cc \u0627\u0631\u0632\u0634 \u062e\u0627\u0645. Yojson \u06cc\u06a9 \u0627\u0646\u062a\u062e\u0627\u0628 \u0628\u0633\u06cc\u0627\u0631 \u0631\u0627\u06cc\u062c \u0628\u0631\u0627\u06cc \u062a\u062c\u0632\u06cc\u0647 JSON \u062f\u0631 OCAML \u0627\u0633\u062a. &hellip;<\/p>\n","protected":false},"author":2,"featured_media":96591,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/media2.dev.to\/dynamic\/image\/width=1000,height=500,fit=cover,gravity=auto,format=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2lw1g6tcndzumx5l0pp.jpg","fifu_image_alt":"","footnotes":""},"categories":[339],"tags":[],"class_list":["post-96590","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/96590","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/comments?post=96590"}],"version-history":[{"count":0,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/96590\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media\/96591"}],"wp:attachment":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media?parent=96590"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/categories?post=96590"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/tags?post=96590"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}