diff --git a/CHANGELOG.md b/CHANGELOG.md index 83da486..2b4f911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). 2. [For loops in RemesPath](/docs/RemesPath.md#for-loopsloop-variables-added-in-v60) 3. [`bool, s_csv` and `s_fa` vectorized arg functions](/docs/RemesPath.md#vectorized-functions) and [`randint` non-vectorized arg function](/docs/RemesPath.md#non-vectorized-functions) to RemesPath. 4. Make second argument of [`s_split` RemesPath function](/docs/RemesPath.md#vectorized-functions) optional; 1-argument variant splits on whitespace. +5. Right-click dropdown menu in [error form](/docs/README.md#error-form-and-status-bar), allowing export of errors to JSON or refreshing the form. +6. The parser is now much better at recovering when an object is missing its closing `'}'` or an array is missing its closing `']'`. ### Changed diff --git a/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs b/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs index d1eaa30..9e1233c 100644 --- a/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs +++ b/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs @@ -28,12 +28,17 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ErrorForm)); this.ErrorGrid = new System.Windows.Forms.DataGridView(); this.Severity = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Description = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Position = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.errorGridRightClickStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.refreshMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportToJsonMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.ErrorGrid)).BeginInit(); + this.errorGridRightClickStrip.SuspendLayout(); this.SuspendLayout(); // // ErrorGrid @@ -55,6 +60,7 @@ private void InitializeComponent() this.ErrorGrid.CellEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.ErrorGrid_CellEnter); this.ErrorGrid.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.ErrorGrid_CellEnter); this.ErrorGrid.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ErrorForm_KeyDown); + this.ErrorGrid.MouseClick += new System.Windows.Forms.MouseEventHandler(this.ErrorForm_RightClick); this.ErrorGrid.Resize += new System.EventHandler(this.ErrorGrid_Resize); // // Severity @@ -81,6 +87,29 @@ private void InitializeComponent() this.Position.ReadOnly = true; this.Position.Width = 75; // + // errorGridRightClickStrip + // + this.errorGridRightClickStrip.ImageScalingSize = new System.Drawing.Size(20, 20); + this.errorGridRightClickStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.refreshMenuItem, + this.exportToJsonMenuItem}); + this.errorGridRightClickStrip.Name = "errorGridRightClickStrip"; + this.errorGridRightClickStrip.Size = new System.Drawing.Size(252, 80); + // + // refreshMenuItem + // + this.refreshMenuItem.Name = "refreshMenuItem"; + this.refreshMenuItem.Size = new System.Drawing.Size(251, 24); + this.refreshMenuItem.Text = "Refresh with current errors"; + this.refreshMenuItem.Click += new System.EventHandler(this.RefreshMenuItem_Click); + // + // exportToJsonMenuItem + // + this.exportToJsonMenuItem.Name = "exportToJsonMenuItem"; + this.exportToJsonMenuItem.Size = new System.Drawing.Size(190, 24); + this.exportToJsonMenuItem.Text = "Export to JSON"; + this.exportToJsonMenuItem.Click += new System.EventHandler(this.ExportLintsToJsonMenuItem_Click); + // // ErrorForm // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); @@ -92,6 +121,7 @@ private void InitializeComponent() this.Text = "Syntax errors in JSON"; this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ErrorForm_KeyDown); ((System.ComponentModel.ISupportInitialize)(this.ErrorGrid)).EndInit(); + this.errorGridRightClickStrip.ResumeLayout(false); this.ResumeLayout(false); } @@ -101,5 +131,8 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn Description; private System.Windows.Forms.DataGridViewTextBoxColumn Position; private System.Windows.Forms.DataGridView ErrorGrid; + private System.Windows.Forms.ContextMenuStrip errorGridRightClickStrip; + private System.Windows.Forms.ToolStripMenuItem refreshMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportToJsonMenuItem; } } \ No newline at end of file diff --git a/JsonToolsNppPlugin/Forms/ErrorForm.cs b/JsonToolsNppPlugin/Forms/ErrorForm.cs index 1f3d0cc..e016592 100644 --- a/JsonToolsNppPlugin/Forms/ErrorForm.cs +++ b/JsonToolsNppPlugin/Forms/ErrorForm.cs @@ -11,6 +11,7 @@ using Kbg.NppPluginNET; using JSON_Tools.JSON_Tools; using JSON_Tools.Utils; +using System.Runtime; namespace JSON_Tools.Forms { @@ -137,6 +138,47 @@ private void ChangeSelectedRow(int oldIndex, int newIndex) HandleCellOrRowClick(newRow); // move to location of error } + /// + /// right-clicking the grid shows a drop-down where the user can choose to refresh the form or export the lints as JSON. + /// + private void ErrorForm_RightClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + errorGridRightClickStrip.Show(MousePosition); + } + } + + private void RefreshMenuItem_Click(object sender, EventArgs e) + { + Npp.notepad.HideDockingForm(this); + Main.OpenErrorForm(Npp.notepad.GetCurrentFilePath(), false); + } + + private void ExportLintsToJsonMenuItem_Click(object sender, EventArgs e) + { + int lintCount = lints == null ? 0 : lints.Count; + if (lintCount == 0) + { + MessageBox.Show($"No JSON syntax errors (at or below {Main.settings.logger_level} level) for {fname}", + "No JSON syntax errors for this file", + MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + var lintArrChildren = new List(); + foreach (JsonLint lint in lints) + { + var lintObj = lint.ToJson(); + lintArrChildren.Add(lintObj); + } + var lintArr = new JArray(0, lintArrChildren); + Main.PrettyPrintJsonInNewFile(lintArr); + } + + /// + /// hitting enter refreshes

+ /// hitting the first letter of any error description goes to that error description + ///
private void ErrorForm_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) diff --git a/JsonToolsNppPlugin/Forms/ErrorForm.resx b/JsonToolsNppPlugin/Forms/ErrorForm.resx index e627d24..d11fc5c 100644 --- a/JsonToolsNppPlugin/Forms/ErrorForm.resx +++ b/JsonToolsNppPlugin/Forms/ErrorForm.resx @@ -126,6 +126,18 @@ True + + True + + + True + + + True + + + 17, 17 + diff --git a/JsonToolsNppPlugin/JSONTools/JsonParser.cs b/JsonToolsNppPlugin/JSONTools/JsonParser.cs index 16d5c42..5ee574a 100644 --- a/JsonToolsNppPlugin/JSONTools/JsonParser.cs +++ b/JsonToolsNppPlugin/JSONTools/JsonParser.cs @@ -7,6 +7,7 @@ using System.Text; using System.Text.RegularExpressions; using JSON_Tools.Utils; +using static System.Windows.Forms.LinkLabel; namespace JSON_Tools.JSON_Tools { @@ -74,6 +75,19 @@ public static string CharDisplay(char c) default: return $"'{c}'"; } } + + /// + /// the object {"message": this.message, "position": this.pos, "severity": this.severity} + /// + public JNode ToJson() + { + return new JObject(0, new Dictionary + { + ["message"] = new JNode(message), + ["position"] = new JNode((long)pos), + ["severity"] = new JNode(severity.ToString()), + }); + } } /// @@ -762,9 +776,9 @@ public string ParseKey(string inp) public string ParseUnquotedKey(string inp) { var match = UNQUOTED_KEY_REGEX.Match(inp, ii); - if (!match.Success) + if (!match.Success || match.Index != ii) { - HandleError($"No valid unquoted key beginning at {ii}", inp, ii, ParserState.FATAL); + HandleError($"No valid unquoted key beginning at {ii}", inp, ii, ParserState.BAD); return null; } HandleError("Unquoted keys are only supported in JSON5", inp, ii, ParserState.JSON5); @@ -1120,7 +1134,17 @@ public JArray ParseArray(string inp, int recursionDepth) // a new array member of some sort alreadySeenComma = false; JNode newObj; + int iiBeforeParse = ii; + int utf8ExtraBeforeParse = utf8ExtraBytes; newObj = ParseSomething(inp, recursionDepth); + if (newObj.type == Dtype.STR && ii < inp.Length && inp[ii] == ':') + { + // maybe the user forgot the closing ']' of an array that's the child of an object. + HandleError("':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", inp, ii, ParserState.BAD); + ii = iiBeforeParse; + utf8ExtraBytes = utf8ExtraBeforeParse; + return arr; + } //if (includeExtraProperties) //{ // newObj.extras = new ExtraJNodeProperties(arr, ii, children.Count); @@ -1212,9 +1236,13 @@ public JObject ParseObject(string inp, int recursionDepth) return obj; } // a new key-value pair + int iiBeforeKey = ii; + int utf8ExtraBeforeKey = utf8ExtraBytes; string key = ParseKey(inp); if (fatal || key == null) { + // key could be null if there's a valid JSON there that is not a valid key + // this covers the possibility that the user forgot to close the object before this (presumed) key, and in fact it's meant to be a value in a parent array return obj; } if (ii >= inp.Length) @@ -1233,10 +1261,20 @@ public JObject ParseObject(string inp, int recursionDepth) { break; } - if (inp[ii] == ':') + char c = inp[ii]; + if (c == ':') { ii++; } + else if (c == ',' || c == ']') + { + // comma or ']' after key instead of value could mean that this is supposed to be a value in a parent array, + // so we'll try bailing out here and reinterpreting the key as such + HandleError($"Found '{c}' after key {childCount} when colon expected", inp, ii, ParserState.BAD); + ii = iiBeforeKey; + utf8ExtraBytes = utf8ExtraBeforeKey; + return obj; + } else HandleError($"No ':' between key {childCount} and value {childCount} of object", inp, ii, ParserState.BAD); } if (!ConsumeInsignificantChars(inp)) @@ -1376,7 +1414,7 @@ public JNode ParseSomething(string inp, int recursionDepth) inp, ii + 1, ParserState.FATAL); return new JNode(null, Dtype.NULL, startUtf8Pos); } - HandleError("Badly located character", inp, ii, ParserState.FATAL); + HandleError("Badly located character " + (ii >= inp.Length ? "\"\\x00\"" : JNode.StrToString(inp.Substring(ii, 1), true)), inp, ii, ParserState.FATAL); return new JNode(null, Dtype.NULL, startUtf8Pos); } diff --git a/JsonToolsNppPlugin/Main.cs b/JsonToolsNppPlugin/Main.cs index 4818902..052e0e9 100644 --- a/JsonToolsNppPlugin/Main.cs +++ b/JsonToolsNppPlugin/Main.cs @@ -1112,7 +1112,7 @@ private static void RestyleEverything() /// /// /// - private static void OpenErrorForm(string fname, bool wasAutoTriggered) + public static void OpenErrorForm(string fname, bool wasAutoTriggered) { bool wasVisible = errorForm != null && errorForm.Visible; if ((!TryGetInfoForFile(fname, out JsonFileInfo info) diff --git a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs index bc19eea..65a8b98 100644 --- a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs +++ b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("5.8.0.11")] -[assembly: AssemblyFileVersion("5.8.0.11")] +[assembly: AssemblyVersion("5.8.0.12")] +[assembly: AssemblyFileVersion("5.8.0.12")] diff --git a/JsonToolsNppPlugin/Tests/JsonParserTests.cs b/JsonToolsNppPlugin/Tests/JsonParserTests.cs index 4d50f72..b287164 100644 --- a/JsonToolsNppPlugin/Tests/JsonParserTests.cs +++ b/JsonToolsNppPlugin/Tests/JsonParserTests.cs @@ -769,11 +769,11 @@ public static bool TestLinter() new string[]{ "NaN is not part of the original JSON specification", "Infinity is not part of the original JSON specification", "Infinity is not part of the original JSON specification" }), - ("{'a\n':[1,2,},]", "{\"a\\n\": [1,2]}", new string[]{"Singlequoted strings are only allowed in JSON5", "Object key contains newline", "Tried to terminate an array with '}'", "Comma after last element of array", "Tried to terminate object with ']', Comma after last key-value pair of object" }), + ("{'a\n':[1,2,},]", "{\"a\\n\": [1,2]}", new string[]{"Singlequoted strings are only allowed in JSON5", "Object key contains newline", "Tried to terminate an array with '}'", "Comma after last element of array", "Tried to terminate object with ']'", "Comma after last key-value pair of object" }), ("[1, 2", "[1, 2]", new string[]{ "Unterminated array" }), ("{\"a\": 1", "{\"a\": 1}", new string[]{ "Unterminated object" }), ("{\"a\": [1, {\"b\": 2", "{\"a\": [1, {\"b\": 2}]}", new string[] { "Unterminated object", - "Unterminated array", + "Unterminated array", "Unterminated object" }), ("{", "{}", new string[] { "Unterminated object" }), ("[", "[]", new string[] { "Unterminated array" }), @@ -809,7 +809,7 @@ public static bool TestLinter() ("froeu", "null", new string[]{"Expected literal starting with 'f' to be false"}), ("Froeu", "null", new string[]{"Expected literal starting with 'F' to be False"}), ("nurnoe", "null",new string[]{"Expected literal starting with 'n' to be null or nan"}), - ("Hugre", "null", new string[]{"Badly located character"}), + ("Hugre", "null", new string[]{"Badly located character \"H\""}), ("[undefined, underpants]", "[null, null]", new string[]{ "undefined is not part of any JSON specification", @@ -914,6 +914,64 @@ public static bool TestLinter() }), ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFF", "null", new string[]{ "Hexadecimal numbers are only part of JSON5", "Hex number too large for a 64-bit signed integer type"}), ("-0xFFFFFFFFFFFFFFFFFFFFFFFFFFF", "null", new string[]{ "Hexadecimal numbers are only part of JSON5", "Hex number too large for a 64-bit signed integer type"}), + ("{\"a\": [[1, 2], [3, 4, \"b\": [5 , \"c\": [, \"d\": 6}", "{\"a\": [[1, 2], [3, 4]], \"b\": [5], \"c\": [], \"d\": 6}", + new string[]{ "':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", + "No comma between array members", + "':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", + "No comma after key-value pair 0 in object", + "':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", + "No comma after key-value pair 1 in object", + "Comma before first value in array", + "':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", + "No comma after key-value pair 2 in object"} + ), + ( "[{\"a\": 0, null" + // seeing the 2 where a key was expected triggers falling out of the object + ", {2" + // we fall out of the empty object upon seeing this invalid key + ", {,3" + // we fall out of the empty object upon seeing the comma + ", {\"b\": [4, 5," + + " {\"c\": 6, \"d\" ]}" + // seeing this ']' instead of a colon triggers falling out of the object, and reinterpreting the "d" as a member of the parent array + ", {\"e\": {" + + " \"f\": [null, \"g\": {" + // seeing the colon after "g" triggers falling out of the array, and reinterpreting the "g" as a key of the parent object + " \"h\": 7, \"i\"" + // seeing this comma instead of a colon triggers falling out of the object (and its parent object, and its grandparent object), and finally reinterpreting the "i" as a child of the great-grandparent array + ", \"j\"]", + "[{\"a\": 0}, null, {}, 2, {}, 3, {\"b\": [4, 5, {\"c\": 6}, \"d\"]}, {\"e\": {\"f\": [null], \"g\": {\"h\": 7}}}, \"i\", \"j\"]", + new string[]{ + "Unquoted keys are only supported in JSON5", + "Found ',' after key 1 when colon expected", + "No comma between array members", + "No valid unquoted key beginning at 17", + "No comma between array members", + "Comma before first value in object", + "No valid unquoted key beginning at 22", + "No comma between array members", + "Found ']' after key 1 when colon expected", + "No comma between array members", + "':' (key-value separator) where ',' between array members expected. Maybe you forgot to close the array?", + "No comma after key-value pair 0 in object", + "Found ',' after key 1 when colon expected", + "No comma after key-value pair 1 in object", + "Found ',' after key 2 when colon expected", + "No comma after key-value pair 0 in object", + "Found ',' after key 1 when colon expected", + "No comma between array members" + } + ), + ( + "[ \r\n" + + " {\"foo\": 1, \"bar\": [\"a\", \"b\"},\r\n" + // missing close ']' of array + " {\"foo\": 2, \"bar\": [\"c\", \"d\"]},\r\n" + // at the start of this object, the parser thinks it's parsing the last array + // however, when it tries to parse the '{' opening this object as a key, it fails, and falls back into the parent array + // once the parser has fallen through to the parent array, everything is fine. + " {\"foo\": 3, \"bar\": [\"e\", \"f\"]}\r\n" + // also fine + "]", + "[{\"foo\": 1, \"bar\": [\"a\", \"b\"]}, {\"foo\": 2, \"bar\": [\"c\", \"d\"]}, {\"foo\": 3, \"bar\": [\"e\", \"f\"]}]", + new string[] + { + "Tried to terminate an array with '}'", + "No valid unquoted key beginning at 43", + "No comma between array members" + } + ), }; int tests_failed = 0; @@ -929,7 +987,7 @@ public static bool TestLinter() continue; } JNode result = new JNode(); - string expected_lint_str = "[" + string.Join(", ", expected_lint) + "]"; + string expected_lint_str = "[" + string.Join(", ", expected_lint.Select(x => JNode.StrToString(x, true))) + "]"; string base_message = $"Expected JsonParser(LoggerLevel.STRICT).Parse({inp})\nto return\n{desired_out} and have lint {expected_lint_str}\n"; try { @@ -944,7 +1002,7 @@ public static bool TestLinter() lint_sb.Append('['); for (int jj = 0; jj < parser.lint.Count; jj++) { - lint_sb.Append(parser.lint[jj].message); + lint_sb.Append(JNode.StrToString(parser.lint[jj].message, true)); if (jj < parser.lint.Count - 1) lint_sb.Append(", "); } lint_sb.Append("]"); diff --git a/docs/README.md b/docs/README.md index 2d1954c..59d7027 100644 --- a/docs/README.md +++ b/docs/README.md @@ -100,7 +100,7 @@ Error reporting can be customized with the `logger_level` setting, which has 5 l * Python-style '#' comments * Python constants `None`, *`nan`, and `inf` (starting in [5.4.0](/CHANGELOG.md#540---2023-07-04))*. * missing commas between array members - * missing ']' or '}' at the ends of arrays and objects + * missing ']' or '}' at the ends of arrays and objects (supported for a long time, but *JsonTools got much better at this beginning in [v6.0](/CHANGELOG.md#600---unreleased-2023-mm-dd)*) * a bunch of other common syntax errors 6. __FATAL__: These errors always cause *immediate failure* of parsing. Examples include: * unquoted string literals other than `true`, `false`, `null`, `NaN`, `Infinity`, `None`, `True`, `False`, `nan`, `inf` and `undefined`. @@ -167,6 +167,8 @@ Clicking on or paging to a row in the error form with the arrow keys will move t Hitting `Enter` while in the form refreshes the form with the JSON in the current document. You can also seek the next syntax error with a description that starts with a letter by typing that letter while in the form. For example, typing `P` in the form might select the next `Python-style '#' comments are not part of any well-accepted JSON specification` error. +Beginning in [v6.0](/CHANGELOG.md#600---unreleased-2023-mm-dd), you can right-click on this form to gain the option of exporting all errors to JSON or refreshing the form. + In addition to this form, the document type status bar section will show how many errors were logged. ![Error form and description in status bar](/docs/error%20form%20and%20status%20bar%20section.PNG) @@ -654,7 +656,7 @@ Here's an example of what you get with successful request(s): The URLs of successful requests show up in the box on the right. I used the `View results in buffer` button at the bottom of the form to open the buffer and tree view shown here. -Of course, sometimes an API request will fail. You can click the [View errors button](#viewing-errors) to see any errors that happened. +Of course, sometimes an API request will fail. You can click the [View errors button](#error-form-and-status-bar) to see any errors that happened. ## Getting JSON from local directories ## diff --git a/most recent errors.txt b/most recent errors.txt index eeabd1a..6a785ab 100644 --- a/most recent errors.txt +++ b/most recent errors.txt @@ -1,4 +1,4 @@ -Test results for JsonTools v5.8.0.10 on Notepad++ 8.5.8 64bit +Test results for JsonTools v5.8.0.12 on Notepad++ 8.5.8 64bit NOTE: Ctrl-F (regular expressions *on*) for "Failed [1-9]\d*" to find all failed tests Tests failed: YAML dumper ========================= @@ -40,7 +40,7 @@ Testing JSON parser's linter ========================= Failed 0 tests. -Passed 57 tests. +Passed 60 tests. ========================= Testing JSON Lines parser ========================= @@ -202,33 +202,33 @@ Testing JsonParser performance Preview of json: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... -To convert JSON string of size 89556 into JNode took 3.399 +/- 1.483 ms over 32 trials -Load times (ms): 2, 3, 6, 5, 3, 1, 2, 3, 4, 2, 2, 5, 1, 1, 1, 2, 1, 1, 6, 2, 2, 3, 4, 4, 2, 3, 3, 1, 2, 5, 4, 5 +To convert JSON string of size 89556 into JNode took 2.762 +/- 1.319 ms over 32 trials +Load times (ms): 5, 2, 3, 5, 1, 2, 5, 1, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 4, 3, 4, 1, 1, 2, 4 ========================= Performance tests for RemesPath (float arithmetic) ========================= -Compiling query "@[@[:].a * @[:].t < @[:].e]" into took 2.598 +/- 15.789 microseconds over 40 trials -To run pre-compiled query "@[@[:].a * @[:].t < @[:].e]" on JNode from JSON of size 89556 into took 0.069 +/- 0.272 ms over 40 trials -Query times (ms): 0.067, 0.032, 0.024, 0.023, 0.023, 0.022, 0.023, 0.027, 0.024, 0.023, 0.023, 0.024, 0.023, 0.025, 1.769, 0.026, 0.024, 0.023, 0.023, 0.027, 0.023, 0.024, 0.042, 0.033, 0.032, 0.028, 0.023, 0.023, 0.023, 0.022, 0.022, 0.022, 0.022, 0.022, 0.022, 0.021, 0.022, 0.022, 0.022, 0.022 +Compiling query "@[@[:].a * @[:].t < @[:].e]" into took 2.618 +/- 15.946 microseconds over 40 trials +To run pre-compiled query "@[@[:].a * @[:].t < @[:].e]" on JNode from JSON of size 89556 into took 0.074 +/- 0.316 ms over 40 trials +Query times (ms): 0.076, 2.046, 0.025, 0.023, 0.023, 0.022, 0.022, 0.025, 0.022, 0.023, 0.022, 0.022, 0.022, 0.022, 0.021, 0.022, 0.021, 0.021, 0.021, 0.023, 0.021, 0.021, 0.021, 0.021, 0.021, 0.022, 0.022, 0.021, 0.021, 0.021, 0.021, 0.022, 0.021, 0.021, 0.021, 0.021, 0.021, 0.023, 0.028, 0.021 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= Performance tests for RemesPath (string operations) ========================= -Compiling query "@[@[:].z =~ `(?i)[a-z]{5}`]" into took 2.452 +/- 14.691 microseconds over 40 trials -To run pre-compiled query "@[@[:].z =~ `(?i)[a-z]{5}`]" on JNode from JSON of size 89556 into took 0.119 +/- 0.091 ms over 40 trials -Query times (ms): 0.15, 0.135, 0.103, 0.107, 0.103, 0.103, 0.103, 0.102, 0.102, 0.102, 0.102, 0.102, 0.684, 0.104, 0.103, 0.101, 0.102, 0.102, 0.102, 0.102, 0.103, 0.104, 0.102, 0.104, 0.102, 0.103, 0.102, 0.103, 0.102, 0.102, 0.102, 0.102, 0.103, 0.102, 0.103, 0.103, 0.102, 0.102, 0.104, 0.102 +Compiling query "@[@[:].z =~ `(?i)[a-z]{5}`]" into took 1.448 +/- 8.688 microseconds over 40 trials +To run pre-compiled query "@[@[:].z =~ `(?i)[a-z]{5}`]" on JNode from JSON of size 89556 into took 0.058 +/- 0.015 ms over 40 trials +Query times (ms): 0.113, 0.059, 0.111, 0.112, 0.068, 0.055, 0.056, 0.055, 0.053, 0.053, 0.054, 0.054, 0.052, 0.054, 0.053, 0.053, 0.054, 0.054, 0.053, 0.054, 0.056, 0.053, 0.053, 0.053, 0.053, 0.054, 0.053, 0.055, 0.053, 0.053, 0.052, 0.054, 0.053, 0.053, 0.052, 0.052, 0.053, 0.054, 0.052, 0.052 Preview of result: [{"A": "\n]o1VQ5t6g", "a": 4710024278, "b": 3268860721, "B": "g4Y7+ew^.v", "C": "NK nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" into took 9.315 +/- 56.379 microseconds over 40 trials +ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" into took 5.035 +/- 30.147 microseconds over 40 trials To run pre-compiled query "var qmask = @[:].q; var nmax_q = max(@[qmask].n); var nmax_notq = max(@[not qmask].n); -ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" on JNode from JSON of size 89556 into took 0.026 +/- 0.035 ms over 40 trials -Query times (ms): 0.102, 0.018, 0.017, 0.017, 0.016, 0.017, 0.053, 0.031, 0.016, 0.016, 0.042, 0.016, 0.016, 0.016, 0.016, 0.016, 0.227, 0.022, 0.017, 0.016, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.016, 0.017, 0.015, 0.016, 0.016, 0.016, 0.04, 0.016, 0.017, 0.016, 0.016, 0.016, 0.016 +ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" on JNode from JSON of size 89556 into took 0.018 +/- 0.008 ms over 40 trials +Query times (ms): 0.067, 0.019, 0.017, 0.016, 0.016, 0.017, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.024, 0.019, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.017, 0.016, 0.016, 0.017, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016 Preview of result: "when q=false, nmax= 9830935647.0" ... ========================= @@ -267,11 +267,11 @@ Performance tests for RemesPath (references to compile-time constant variables) Compiling query "var X = X; var onetwo = j`[1, 2]`; -@[:]->at(@, X)->at(@, onetwo)" into took 2.912 +/- 17.564 microseconds over 40 trials +@[:]->at(@, X)->at(@, onetwo)" into took 3.655 +/- 22.201 microseconds over 40 trials To run pre-compiled query "var X = X; var onetwo = j`[1, 2]`; -@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.015 +/- 0.007 ms over 40 trials -Query times (ms): 0.039, 0.026, 0.012, 0.013, 0.013, 0.013, 0.013, 0.012, 0.014, 0.013, 0.012, 0.012, 0.015, 0.028, 0.012, 0.012, 0.013, 0.04, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.013, 0.013, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.026 +/- 0.075 ms over 40 trials +Query times (ms): 0.042, 0.014, 0.023, 0.012, 0.013, 0.012, 0.493, 0.014, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.021, 0.013, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012 Preview of result: [[1695727848, 0.287562638736685], [2126430375, 0.00767794129708177], [5310550656, 0.380769772645687], [2519183283, 0.153176220930558], [6610062385, 0.662996225870666], [987168256, 0.924410189999928], [6615003609, 0.917112691225947], [4465232046, 0.684311931851536], [8654414565, 0.631485392105992], [ ... ========================= @@ -280,29 +280,29 @@ Performance tests for RemesPath (references to variables that are not compile-ti Compiling query "var X = @->`X`; var onetwo = @{1, 2}; -@[:]->at(@, X)->at(@, onetwo)" into took 4.392 +/- 26.502 microseconds over 40 trials +@[:]->at(@, X)->at(@, onetwo)" into took 3.185 +/- 19.298 microseconds over 40 trials To run pre-compiled query "var X = @->`X`; var onetwo = @{1, 2}; -@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.033 +/- 0.009 ms over 40 trials -Query times (ms): 0.087, 0.032, 0.032, 0.032, 0.032, 0.041, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032, 0.031, 0.032, 0.032 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.018 +/- 0.008 ms over 40 trials +Query times (ms): 0.059, 0.016, 0.017, 0.028, 0.017, 0.022, 0.017, 0.016, 0.017, 0.028, 0.016, 0.016, 0.044, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.017, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016 Preview of result: [[1695727848, 0.287562638736685], [2126430375, 0.00767794129708177], [5310550656, 0.380769772645687], [2519183283, 0.153176220930558], [6610062385, 0.662996225870666], [987168256, 0.924410189999928], [6615003609, 0.917112691225947], [4465232046, 0.684311931851536], [8654414565, 0.631485392105992], [ ... ========================= Performance tests for RemesPath (simple string mutations) ========================= -Compiling query "@[:].z = s_sub(@, g, B)" into took 2.455 +/- 14.739 microseconds over 40 trials -To run pre-compiled query "@[:].z = s_sub(@, g, B)" on JNode from JSON of size 89556 into took 0.102 +/- 0.479 ms over 40 trials -Query times (ms): 0.036, 0.034, 0.024, 0.024, 0.014, 0.036, 0.029, 0.025, 0.024, 0.034, 0.022, 0.025, 0.032, 0.025, 0.027, 0.021, 0.018, 0.02, 0.02, 0.026, 0.028, 0.032, 0.026, 0.026, 0.025, 0.03, 0.028, 3.095, 0.044, 0.017, 0.022, 0.029, 0.023, 0.013, 0.021, 0.022, 0.029, 0.029, 0.021, 0.018 +Compiling query "@[:].z = s_sub(@, g, B)" into took 3.812 +/- 23.409 microseconds over 40 trials +To run pre-compiled query "@[:].z = s_sub(@, g, B)" on JNode from JSON of size 89556 into took 0.015 +/- 0.005 ms over 40 trials +Query times (ms): 0.027, 0.012, 0.011, 0.016, 0.01, 0.009, 0.009, 0.011, 0.011, 0.01, 0.022, 0.019, 0.015, 0.02, 0.015, 0.017, 0.014, 0.022, 0.011, 0.01, 0.011, 0.025, 0.01, 0.01, 0.012, 0.011, 0.034, 0.014, 0.012, 0.011, 0.011, 0.016, 0.014, 0.013, 0.016, 0.014, 0.014, 0.015, 0.014, 0.017 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= Performance tests for RemesPath (simple number mutations) ========================= -Compiling query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" into took 3.658 +/- 22.008 microseconds over 40 trials -To run pre-compiled query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" on JNode from JSON of size 89556 into took 0.037 +/- 0.011 ms over 40 trials -Query times (ms): 0.053, 0.046, 0.069, 0.051, 0.04, 0.028, 0.028, 0.027, 0.054, 0.04, 0.038, 0.038, 0.046, 0.036, 0.035, 0.039, 0.038, 0.044, 0.038, 0.037, 0.037, 0.048, 0.038, 0.05, 0.03, 0.065, 0.024, 0.019, 0.021, 0.021, 0.021, 0.03, 0.041, 0.033, 0.03, 0.027, 0.03, 0.027, 0.028, 0.028 +Compiling query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" into took 2.8 +/- 16.878 microseconds over 40 trials +To run pre-compiled query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" on JNode from JSON of size 89556 into took 0.033 +/- 0.01 ms over 40 trials +Query times (ms): 0.044, 0.027, 0.024, 0.024, 0.042, 0.044, 0.036, 0.042, 0.032, 0.053, 0.04, 0.031, 0.038, 0.026, 0.024, 0.023, 0.035, 0.039, 0.04, 0.037, 0.038, 0.047, 0.052, 0.06, 0.037, 0.025, 0.022, 0.021, 0.022, 0.02, 0.021, 0.022, 0.022, 0.021, 0.02, 0.034, 0.031, 0.043, 0.025, 0.026 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= @@ -312,12 +312,12 @@ Performance tests for RemesPath (mutations with a for loop) Compiling query "var xhalf = @[:].x < 0.5; for lx = zip(@[:].l, xhalf); lx[0] = ifelse(lx[1], foo, bar); -end for;" into took 6.925 +/- 42.334 microseconds over 40 trials +end for;" into took 6.665 +/- 40.582 microseconds over 40 trials To run pre-compiled query "var xhalf = @[:].x < 0.5; for lx = zip(@[:].l, xhalf); lx[0] = ifelse(lx[1], foo, bar); -end for;" on JNode from JSON of size 89556 into took 0.039 +/- 0.013 ms over 40 trials -Query times (ms): 0.11, 0.062, 0.039, 0.041, 0.036, 0.044, 0.036, 0.036, 0.034, 0.038, 0.033, 0.034, 0.033, 0.035, 0.038, 0.034, 0.033, 0.032, 0.037, 0.034, 0.033, 0.032, 0.044, 0.035, 0.041, 0.037, 0.042, 0.038, 0.037, 0.036, 0.033, 0.039, 0.034, 0.033, 0.033, 0.039, 0.033, 0.033, 0.036, 0.04 +end for;" on JNode from JSON of size 89556 into took 0.052 +/- 0.021 ms over 40 trials +Query times (ms): 0.104, 0.08, 0.068, 0.091, 0.059, 0.041, 0.085, 0.06, 0.049, 0.037, 0.038, 0.037, 0.037, 0.037, 0.037, 0.037, 0.036, 0.037, 0.036, 0.063, 0.038, 0.036, 0.037, 0.039, 0.039, 0.061, 0.058, 0.043, 0.038, 0.037, 0.051, 0.059, 0.062, 0.044, 0.11, 0.067, 0.099, 0.034, 0.035, 0.037 Preview of result: [["bar", false], ["bar", false], ["foo", true], ["foo", true], ["foo", true], ["foo", true], ["foo", true], ["bar", false], ["bar", false], ["bar", false], ["foo", true], ["foo", true], ["bar", false], ["bar", false], ["foo", true], ["bar", false], ["bar", false], ["bar", false], ["foo", true], ["ba ... ========================= @@ -326,18 +326,18 @@ Testing performance of JSON compression and pretty-printing Preview of json: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... -To compress JNode from JSON string of 89556 took 4.63 +/- 1.207 ms over 64 trials (minimal whitespace, sort_keys=TRUE) -To compress JNode from JSON string of 89556 took 2.528 +/- 0.832 ms over 64 trials (minimal whitespace, sort_keys=FALSE) -To Google-style pretty-print JNode from JSON string of 89556 took 5.126 +/- 1.181 ms over 64 trials (sort_keys=true, indent=4) -To Whitesmith-style pretty-print JNode from JSON string of 89556 took 5.079 +/- 1.279 ms over 64 trials (sort_keys=true, indent=4) -To PPrint-style pretty-print JNode from JSON string of 89556 took 8.083 +/- 1.833 ms over 64 trials (sort_keys=true, indent=4) +To compress JNode from JSON string of 89556 took 4.056 +/- 0.303 ms over 64 trials (minimal whitespace, sort_keys=TRUE) +To compress JNode from JSON string of 89556 took 2.097 +/- 0.181 ms over 64 trials (minimal whitespace, sort_keys=FALSE) +To Google-style pretty-print JNode from JSON string of 89556 took 4.751 +/- 0.76 ms over 64 trials (sort_keys=true, indent=4) +To Whitesmith-style pretty-print JNode from JSON string of 89556 took 4.315 +/- 0.414 ms over 64 trials (sort_keys=true, indent=4) +To PPrint-style pretty-print JNode from JSON string of 89556 took 6.082 +/- 0.656 ms over 64 trials (sort_keys=true, indent=4) ========================= Testing performance of JsonSchemaValidator and random JSON creation ========================= -To create a random set of tweet JSON of size 168723 (15 tweets) based on the matching schema took 7.667 +/- 3.817 ms over 64 trials -To compile the tweet schema to a validation function took 0.36 +/- 0.625 ms over 64 trials -To validate tweet JSON of size 168723 (15 tweets) based on the compiled schema took 1.218 +/- 0.317 ms over 64 trials +To create a random set of tweet JSON of size 159731 (15 tweets) based on the matching schema took 7.16 +/- 3.45 ms over 64 trials +To compile the tweet schema to a validation function took 0.223 +/- 0.046 ms over 64 trials +To validate tweet JSON of size 159731 (15 tweets) based on the compiled schema took 1.099 +/- 0.268 ms over 64 trials ========================= Testing JSON grepper's API request tool =========================