Skip to content

Commit

Permalink
functions as args to functions in RemesPath
Browse files Browse the repository at this point in the history
1. max_by, min_by, sort_by, and s_sub functions in RemesPath
    now all can be called with functions as arguments. See docs.
2. bool() function in RemesPath (shorthand for `not not x`)
3. ifelse() function in RemesPath uses truthiness.
  • Loading branch information
molsonkiko committed Nov 26, 2023
1 parent 90d5f69 commit e612b27
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 201 deletions.
10 changes: 5 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### To Be Changed

- __IMPROVE REGEX-REPLACE, REGEX SEARCH FUNCTIONS IN REMESPATH__
- __MAKE FIRST CLASS FUNCTIONS A THING IN REMESPATH__
- __ADD ABILITY TO REGEX SEARCH DOCUMENT UNPARSED DOCUMENT (USING REMESPATH)__
- If there's a validation error inside of an `anyOf` list of schemas (i.e. JSON doesn't validate under *any* of the schemas), the error message is rather uninformative, and says only "the JSON didn't validate under any of the schemas", but not *why* it didn't validate.
- *(Note to future devs)*: Resist the temptation to fool around with the StringBuilder initial capacity for the ToString method of `Dtype.STR` JNodes. I tried, and it doesn't help performance.
Expand All @@ -40,14 +38,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- this problem only seems to appear after the user has opened a docking form, and maybe not even every time
- bug with calling arg functions on projections - seems like object projections are treated as arrays when calling arg functions on them in some cases?
- issue with treeview closing when a file with a treeview is moved from one view to another
- `loop()` function used in `s_sub` callbacks is not thread-safe. This doesn't matter right now because RemesPath is single-threaded, but it could matter in the future.

## [5.9.0] - (UNRELEASED) 2023-MM-DD
## [6.0.0] - (UNRELEASED) 2023-MM-DD

### Added

1. Option to customize which [toolbar icons](/docs/README.md#toolbar-icons) are displayed, and their order.
2. [For loops in RemesPath](/docs/RemesPath.md#for-loopsloop-variables-added-in-v59)
3. [`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.
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.

### Fixed
Expand Down
21 changes: 7 additions & 14 deletions JsonToolsNppPlugin/JSONTools/JNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Collections.Generic; // for dictionary, list
using System.Globalization;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -47,7 +46,8 @@ public enum Dtype : ushort
/// </summary>
DATETIME = 2048,
/// <summary>
/// a JNode has this type if and only if it is CurJson
/// NO JNODES ACTUALLY HAVE THE FUNCTION TYPE.<br></br>
/// It is used in RemesPath to distinguish CurJson from non-CurJson
/// </summary>
FUNCTION = 4096,
/********* COMPOSITE TYPES *********/
Expand Down Expand Up @@ -1631,7 +1631,7 @@ public class CurJson : JNode
public Func<JNode, JNode> function;
public override bool CanOperate => true;

public CurJson(Dtype type, Func<JNode, JNode> function) : base(null, type /*| Dtype.FUNCTION*/, 0)
public CurJson(Dtype type, Func<JNode, JNode> function) : base(null, type, 0)
{
this.function = function;
}
Expand All @@ -1640,7 +1640,7 @@ public CurJson(Dtype type, Func<JNode, JNode> function) : base(null, type /*| Dt
/// A CurJson node that simply stands in for the current json itself (represented by @)
/// Its function is the identity function.
/// </summary>
public CurJson() : base(null, Dtype.UNKNOWN /*| Dtype.FUNCTION*/, 0)
public CurJson() : base(null, Dtype.UNKNOWN, 0)
{
function = Identity;
}
Expand Down Expand Up @@ -1899,18 +1899,11 @@ public bool TryGetValue(int tokenIndex, string varname, out JNode val)
}

/// <summary>
/// set varReferenced to the first variable name referenced at any index in tokens &gt;= startIndex and &lt; endIndex, and return true<br></br>
/// if no variable names referenced in that range of indices, varReferenced = null and return false
/// return true if and only if a variable is referenced at any index ii in tokens such that ii &gt;= startIndex and ii &lt; endIndex
/// </summary>
public bool TryGetFirstVariableNameReferencedInRange(int startIndex, int endIndex, out string varReferenced)
public bool AnyVariableReferencedInRange(int startIndex, int endIndex)
{
varReferenced = null;
for (int ii = startIndex; ii < endIndex; ii++)
{
if (tokenIndicesOfVariableReferences.TryGetValue(ii, out varReferenced))
return true;
}
return false;
return tokenIndicesOfVariableReferences.Keys.Any(x => x >= startIndex && x < endIndex);
}

/// <summary>
Expand Down
25 changes: 14 additions & 11 deletions JsonToolsNppPlugin/JSONTools/RemesPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -910,10 +910,13 @@ private JNode ApplyArgFunction(ArgFunctionWithArgs func)
JNode x = func.args[0];
bool other_callables = false;
List<JNode> other_args = new List<JNode>(func.args.Count - 1);
bool[] argsCanBeFunctions = new bool[func.args.Count - 1]; // for each othe_args index, whether that arg can be a function
bool firstArgCanBeFunction = (func.function.TypeOptions(0) & Dtype.FUNCTION) != 0;
for (int ii = 0; ii < func.args.Count - 1; ii++)
{
JNode arg = func.args[ii + 1];
if (arg is CurJson) { other_callables = true; }
argsCanBeFunctions[ii] = (func.function.TypeOptions(ii + 1) & Dtype.FUNCTION) != 0;
other_args.Add(arg);
}
Dtype out_type = func.function.OutputType(x);
Expand All @@ -929,11 +932,11 @@ private JNode ApplyArgFunction(ArgFunctionWithArgs func)
// x is a function of the current JSON, as is at least one other argument
JNode arg_outfunc(JNode inp)
{
var itbl = xcur.function(inp);
var itbl = firstArgCanBeFunction ? xcur : xcur.function(inp);
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
if (itbl is JObject otbl)
{
Expand Down Expand Up @@ -973,7 +976,7 @@ JNode arg_outfunc(JNode inp)
JNode arg_outfunc(JNode inp)
{

var itbl = xcur.function(inp);
var itbl = firstArgCanBeFunction ? xcur : xcur.function(inp);
if (itbl is JObject otbl)
{
var dic = new Dictionary<string, JNode>(otbl.Length);
Expand Down Expand Up @@ -1013,7 +1016,7 @@ JNode arg_outfunc(JNode inp)
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
foreach (KeyValuePair<string, JNode> xkv in xobj.children)
{
Expand All @@ -1034,7 +1037,7 @@ JNode arg_outfunc(JNode inp)
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
foreach (JNode val in xarr.children)
{
Expand All @@ -1053,7 +1056,7 @@ JNode arg_outfunc(JNode inp)
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
all_args[0] = x;
return func.function.Call(all_args);
Expand All @@ -1080,9 +1083,9 @@ JNode arg_outfunc(JNode inp)
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
all_args[0] = xcur.function(inp);
all_args[0] = firstArgCanBeFunction ? xcur : xcur.function(inp);
return func.function.Call(all_args);
}
return new CurJson(out_type, arg_outfunc);
Expand All @@ -1096,7 +1099,7 @@ JNode arg_outfunc(JNode inp)
}
JNode arg_outfunc(JNode inp)
{
all_args[0] = xcur.function(inp);
all_args[0] = firstArgCanBeFunction ? xcur : xcur.function(inp);
return func.function.Call(all_args);
}
return new CurJson(out_type, arg_outfunc);
Expand All @@ -1111,7 +1114,7 @@ JNode arg_outfunc(JNode inp)
for (int ii = 0; ii < other_args.Count; ii++)
{
JNode other_arg = other_args[ii];
all_args[ii + 1] = other_arg is CurJson cjoa ? cjoa.function(inp) : other_arg;
all_args[ii + 1] = (other_arg is CurJson cjoa && !argsCanBeFunctions[ii]) ? cjoa.function(inp) : other_arg;
}
all_args[0] = x;
return func.function.Call(all_args);
Expand Down Expand Up @@ -1826,7 +1829,7 @@ JNode idx_func(JNode inp)
}
// if a variable is referenced in the indexers (e.g., "var x = @; range(10)[:]->at(x, @ % len(x))",
// we also need to wait until runtime to evaluate the indexers
if (context.TryGetFirstVariableNameReferencedInRange(indStartEndPos, pos, out _))
if (context.AnyVariableReferencedInRange(indStartEndPos, pos))
{
JNode idx_func_var_ref(JNode _)
{
Expand Down
Loading

0 comments on commit e612b27

Please sign in to comment.