Skip to content

Commit d14de66

Browse files
committed
Add jaq support
Useful snippets and references: jaq -L . -n 'include "jqjq"; _builtins_src | lex' jaq -n -L . -rRs 'include "jqjq"; . | jqjq(["", "--run-tests"]; {})' < jqjq.test jaq -n -L . 'include "jqjq"; eval("1+2")' Disable TCO 01mf02/jaq#223 (comment)
1 parent f48258a commit d14de66

File tree

2 files changed

+62
-36
lines changed

2 files changed

+62
-36
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,7 @@ Note that the tests are meant to be used with jq 1.7.1.
242242
- [x] gojq
243243
- [x] jqjq
244244
- Used to work but runs out of memory on my laptop
245-
- [ ] jaq
246-
- Fails on missing destructing support
245+
- [x] jaq
247246
- [ ] xq
248247
- Fails on missing `debug`, maths, jqjq `lex` returns empty (regexp issues?)
249248
- [x] Bugs

jqjq.jq

+61-34
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ def lex:
153153
// _re("^\\)"; {rparen: ., string_stack: ($string_stack[0:-1])})
154154
// _re("^\\["; {lsquare: .})
155155
// _re("^\\]"; {rsquare: .})
156-
// _re("^{"; {lcurly: .})
157-
// _re("^}"; {rcurly: .})
156+
// _re("^\\{"; {lcurly: .})
157+
// _re("^\\}"; {rcurly: .})
158158
// _re("^\\.\\."; {dotdot: .})
159159
// _re("^\\."; {dot: .})
160160
// _re("^\\?"; {qmark: .})
@@ -173,7 +173,9 @@ def lex:
173173
[_lex];
174174

175175
def parse:
176-
def _consume(f): select(.[0] | f) | .[1:];
176+
# TODO: jaq null index
177+
# TODO: maybe a consume helper that returns first? ala [$rest, $v]?
178+
def _consume(f): select(length > 0 and (.[0] | f)) | .[1:];
177179
def _optional(f):
178180
( f
179181
// [., null]
@@ -200,7 +202,9 @@ def parse:
200202
# filter is used to disable operators, ex in keyval query
201203
def _op_prec_climb($p; filter):
202204
def _ops:
203-
if filter then false
205+
# TODO: jaq: nice way? don't even call _ops for null case?
206+
if . == null then false
207+
elif filter then false
204208
elif .pipe then {prec: 0, name: "|", assoc: "right"}
205209
# TODO: understand why jq has left associativity for "," but right seems to give correct parse tree
206210
elif .comma then {prec: 1, name: ",", assoc: "right"}
@@ -956,7 +960,9 @@ def parse:
956960

957961
# "abc \(123)"
958962
def _string_query:
959-
( .[0] as {$string_start}
963+
# TODO: jaq null index (consume checks length and outoput [value, rest]?)
964+
( select(length > 0)
965+
| .[0] as {$string_start}
960966
| _consume(.string_start)
961967
| _repeat(
962968
( select(length > 0 ) # make sure there is something
@@ -1060,7 +1066,7 @@ def parse:
10601066
]
10611067
);
10621068

1063-
( .# debug({_p: $type})
1069+
( . #debug({_p: $type, dot: .})
10641070
| if $type == "query" then
10651071
_op_prec_climb(0; false)
10661072
elif $type == "keyval_query" then
@@ -1267,8 +1273,12 @@ def func_defs_to_env($env):
12671273

12681274
def eval_ast($query; $path; $env; undefined_func):
12691275
def _e($query; $path; $env):
1270-
( .#| debug({c: ., $query, $path, $env})
1271-
| $query as
1276+
( . # debug({c: ., $query, $path, $env})
1277+
| ( $query
1278+
# TODO: jaq: destruct null index
1279+
| if .term == null then .term = {} end
1280+
| if .term.suffix_list == null then .term.suffix_list = [{}] end
1281+
) as
12721282
{ term:
12731283
{ type: $type
12741284
, suffix_list: [{$optional}]
@@ -1417,7 +1427,17 @@ def eval_ast($query; $path; $env; undefined_func):
14171427

14181428
# .name
14191429
def _index:
1420-
_e_index($query.term.index; $path; .; $query.term.suffix_list[0].optional);
1430+
_e_index(
1431+
$query.term.index;
1432+
$path;
1433+
.;
1434+
# TODO: jaq null index
1435+
( $query.term.suffix_list
1436+
| if . then .[0].optional
1437+
else false
1438+
end
1439+
)
1440+
);
14211441

14221442
def _func:
14231443
def _fromjson:
@@ -1454,8 +1474,9 @@ def eval_ast($query; $path; $env; undefined_func):
14541474
| $query.term.func as {$name, $args}
14551475
| func_name($name; $args) as $name
14561476
| $query_env[$name] as $e
1457-
| if $e | has("value") then [[null], $e.value]
1458-
elif $e.body then
1477+
# TODO: jaq null index and null has()
1478+
| if $e != null and ($e | has("value")) then [[null], $e.value]
1479+
elif $e != null and $e.body then
14591480
( ($e.args // []) as $func_args
14601481
| ($args // []) as $call_args
14611482
| ( $func_args
@@ -1519,10 +1540,10 @@ def eval_ast($query; $path; $env; undefined_func):
15191540
( a0 as $a0
15201541
| [[null], has($a0)]
15211542
)
1522-
elif $name == "delpaths/1" then
1523-
( a0 as $a0
1524-
| [[null], delpaths($a0)]
1525-
)
1543+
# elif $name == "delpaths/1" then
1544+
# ( a0 as $a0
1545+
# | [[null], delpaths($a0)]
1546+
# )
15261547
elif $name == "explode/0" then [[null], explode]
15271548
elif $name == "implode/0" then [[null], implode]
15281549
elif $name == "tonumber/0" then [[null], tonumber]
@@ -1539,19 +1560,20 @@ def eval_ast($query; $path; $env; undefined_func):
15391560
| error($a0)
15401561
)
15411562
elif $name == "halt_error/1" then [[null], halt_error(a0)]
1542-
elif $name == "getpath/1" then
1543-
( a0 as $a0
1544-
| [ $path+$a0
1545-
, getpath($a0)
1546-
]
1547-
)
1548-
elif $name == "setpath/2" then
1549-
( a0 as $a0
1550-
| a1 as $a1
1551-
| [ []
1552-
, setpath($a0; $a1)
1553-
]
1554-
)
1563+
# TODO: jaq: setpath/getpath missing
1564+
# elif $name == "getpath/1" then
1565+
# ( a0 as $a0
1566+
# | [ $path+$a0
1567+
# , getpath($a0)
1568+
# ]
1569+
# )
1570+
# elif $name == "setpath/2" then
1571+
# ( a0 as $a0
1572+
# | a1 as $a1
1573+
# | [ []
1574+
# , setpath($a0; $a1)
1575+
# ]
1576+
# )
15551577
elif $name == "path/1" then
15561578
( _e($args[0]; []; $query_env) as [$p, $_v]
15571579
# TODO: try/catch error
@@ -1903,7 +1925,7 @@ def eval_ast($query; $path; $env; undefined_func):
19031925
# .a.b?? case, just skip extra optional "?"
19041926
elif $suffix_list[0].optional then _f($suffix_list[1:])
19051927
else
1906-
( $suffix_list[1].optional as $opt
1928+
( ($suffix_list[1] // {}).optional as $opt # TOOO: jaq null index
19071929
| $suffix_list[if $opt then 2 else 1 end:] as $n
19081930
| _e_suffix($suffix_list[0]; $path; $input; $opt)
19091931
| _f($n)
@@ -2541,10 +2563,12 @@ def eval($expr; $globals; $builtins_env):
25412563
# TODO: does not work with jq yet because issue with bind patterns
25422564
# $ gojq -cn -L . 'include "jqjq"; {} | {a:1} | eval(".a") += 1'
25432565
# {"a":2}
2544-
| if $path | . == [] or . == [null] then $value
2545-
else getpath($path)
2546-
end
2547-
);
2566+
| $value
2567+
);
2568+
# | if $path | . == [] or . == [null] then $value
2569+
# else getpath($path)
2570+
# end
2571+
# );
25482572
def eval($expr):
25492573
eval($expr; {}; _builtins_env);
25502574

@@ -2924,7 +2948,10 @@ def jqjq($args; $env):
29242948
)
29252949
];
29262950
def _f:
2927-
def _to_unslurped: map(tojson) | join(",");
2951+
# TODO: jaq: [] | join("") -> null
2952+
# TODO: jaq: join works with more than strings
2953+
def _join($s): if . == [] then "" else join($s) end;
2954+
def _to_unslurped: map(tojson) | _join(",");
29282955
( _builtins_env as $builtins_env
29292956
| _from_jqtest[]
29302957
| . as $c

0 commit comments

Comments
 (0)