mirror of
https://github.com/wader/fq.git
synced 2024-11-23 00:57:15 +03:00
824e51ec58
Rebase fq changes on latester gojq main. Most notable change visiable to users is that gojq now allows queries as object literal values. For example this now works: {a: 1+2+3} From upstream: 083fb39 refactor code using built-in min and max functions 470db58 bump up to Go 1.23, drop support for Go 1.20 0607aa5 bump up version to 0.12.16 0709341 update CHANGELOG.md for v0.12.16 1324e6e update dependencies 01355e9 improve parser to allow binary operators as object values a41a5f8 fix debug/1 function to be available only when debug/0 is defined f694c1b fix a benchmark test BenchmarkCompile f2559f6 remove private compare function 0cd3a66 improve compiler to abort with error if query is missing 422cc9d refactor stringify function declarations of query 1130c4e refactor program body, rename rules, remove empty actions in parser 8d7ccc9 add tests for immutability of arrays 375e90d remove useless receivers 1b5ce7f set correct offset for multibyte tokens 8874f53 fix tests of exp10 and atan2 failing on some platforms
293 lines
5.4 KiB
Plaintext
293 lines
5.4 KiB
Plaintext
# null
|
|
def _query_null:
|
|
{term: {type: "TermTypeNull"}};
|
|
|
|
# . -> (.)
|
|
def _query_query:
|
|
{ term:
|
|
{ type: "TermTypeQuery"
|
|
, query: .
|
|
}
|
|
};
|
|
|
|
# string
|
|
def _query_string($str):
|
|
{ term:
|
|
{ type: "TermTypeString"
|
|
, str: {str: $str}
|
|
}
|
|
};
|
|
|
|
# .
|
|
def _query_ident:
|
|
{term: {type: "TermTypeIdentity"}};
|
|
def _query_is_ident:
|
|
.term.type == "TermTypeIdentity";
|
|
|
|
# a($args...) -> b($args...)
|
|
def _query_func_rename(name):
|
|
.term.func.name = name;
|
|
# $name($args)
|
|
def _query_func($name; $args):
|
|
{ term:
|
|
{ type: "TermTypeFunc"
|
|
, func:
|
|
{ args: $args
|
|
, name: $name
|
|
}
|
|
}
|
|
};
|
|
def _query_func($name):
|
|
_query_func($name; null);
|
|
|
|
def _query_func_name:
|
|
.term.func.name;
|
|
def _query_func_args:
|
|
.term.func.args;
|
|
def _query_is_func:
|
|
.term.type == "TermTypeFunc";
|
|
def _query_is_func($name):
|
|
_query_is_func and _query_func_name == $name;
|
|
|
|
def _query_is_string:
|
|
.term.type == "TermTypeString";
|
|
def _query_string_str:
|
|
.term.str.str;
|
|
|
|
def _query_empty:
|
|
_query_func("empty");
|
|
|
|
# l | r
|
|
def _query_pipe(l; r):
|
|
{ op: "|"
|
|
, left: l
|
|
, right: r
|
|
};
|
|
|
|
# . -> [.]
|
|
def _query_array:
|
|
( . as $q
|
|
| { term:
|
|
{ type: "TermTypeArray"
|
|
, array: {}
|
|
}
|
|
}
|
|
| if $q then .term.array.query = $q end
|
|
);
|
|
|
|
# {} -> {}
|
|
def _query_object:
|
|
{ term:
|
|
{ object:
|
|
{ key_vals:
|
|
( to_entries
|
|
| map(
|
|
{ key: .key
|
|
, val: .value
|
|
}
|
|
)
|
|
)
|
|
}
|
|
, type: "TermTypeObject"
|
|
}
|
|
};
|
|
|
|
# l,r
|
|
def _query_comma(l; r):
|
|
{ left: l
|
|
, op: ","
|
|
, right: r
|
|
};
|
|
|
|
# [1,2,3] -> 1,2,3
|
|
# output each query in array
|
|
def _query_commas:
|
|
if length == 0 then _query_empty
|
|
else
|
|
reduce .[1:][] as $q (
|
|
.[0];
|
|
_query_comma(.; $q)
|
|
)
|
|
end;
|
|
|
|
# . -> .[]
|
|
def _query_iter:
|
|
.term.suffix_list = [{iter: true}];
|
|
|
|
# try b catch c
|
|
def _query_try(b; c):
|
|
{ term:
|
|
{ type: "TermTypeTry"
|
|
, try:
|
|
{ body: b
|
|
, catch: c
|
|
}
|
|
}
|
|
};
|
|
def _query_try(b):
|
|
_query_try(b; null);
|
|
|
|
# last query in pipeline
|
|
def _query_pipe_last:
|
|
if .term.suffix_list then
|
|
( .term.suffix_list[-1]
|
|
| if .bind.body then
|
|
( .bind.body
|
|
| _query_pipe_last
|
|
)
|
|
end
|
|
)
|
|
elif .op == "|" then
|
|
( .right
|
|
| _query_pipe_last
|
|
)
|
|
end;
|
|
|
|
def _query_transform_pipe_last(f):
|
|
def _f:
|
|
if .term.suffix_list then
|
|
.term.suffix_list[-1] |=
|
|
if .bind.body then
|
|
.bind.body |= _f
|
|
else f
|
|
end
|
|
elif .op == "|" then
|
|
.right |= _f
|
|
else f
|
|
end;
|
|
_f;
|
|
|
|
# last term, the right most
|
|
def _query_last:
|
|
if .term.suffix_list then
|
|
( .term.suffix_list[-1]
|
|
| if .bind.body then
|
|
( .bind.body
|
|
| _query_last
|
|
)
|
|
end
|
|
)
|
|
elif .op then
|
|
( .right
|
|
| _query_last
|
|
)
|
|
end;
|
|
|
|
# TODO: rename? what to call when need to transform suffix_list
|
|
def _query_transform_last(f):
|
|
def _f:
|
|
if .term.suffix_list then
|
|
( .
|
|
| if .term.suffix_list[-1].bind.body then
|
|
.term.suffix_list[-1].bind.body |= _f
|
|
else f
|
|
end
|
|
)
|
|
elif .op then
|
|
.right |= _f
|
|
else f
|
|
end;
|
|
_f;
|
|
|
|
def _query_completion_type:
|
|
( . as $q
|
|
| _query_last
|
|
| if .index.name then
|
|
{ query:
|
|
( $q
|
|
| _query_transform_last(
|
|
del(.term.suffix_list[-1])
|
|
)
|
|
)
|
|
, type: "index"
|
|
, prefix: .index.name
|
|
}
|
|
elif .term.index.name then
|
|
{ query:
|
|
( $q
|
|
| _query_transform_last(
|
|
_query_ident
|
|
)
|
|
)
|
|
, type: "index"
|
|
, prefix: .term.index.name
|
|
}
|
|
elif .term.func then
|
|
{ query:
|
|
( $q
|
|
| _query_transform_last(
|
|
_query_ident
|
|
)
|
|
)
|
|
, type:
|
|
( .term.func.name
|
|
| if startswith("$") then "var"
|
|
else "func"
|
|
end
|
|
)
|
|
, prefix: .term.func.name
|
|
}
|
|
else
|
|
null
|
|
end
|
|
);
|
|
|
|
# TODO: simplify
|
|
def _query_completion(f):
|
|
( . as $expr
|
|
# HACK: if ends with . or $, add a dummy prefix to make the query
|
|
# valid and then trim it later
|
|
| ( if (.[-1] | . == "." or . == "$") then "a"
|
|
else ""
|
|
end
|
|
) as $probesuffix
|
|
| ($expr + $probesuffix)
|
|
| try
|
|
( try _query_fromstring
|
|
catch .error
|
|
# move directives to new root query
|
|
| . as {$meta, $imports}
|
|
| del(.meta)
|
|
| del(.imports)
|
|
| _query_completion_type
|
|
| . as $c
|
|
| if . then
|
|
( .query |=
|
|
( _query_func("map"; [
|
|
_query_pipe(.; _query_try(_query_func($c | f)))
|
|
])
|
|
| _query_pipe(.; _query_func("add")
|
|
)
|
|
| .meta = $meta
|
|
| .imports = $imports
|
|
| _query_tostring
|
|
)
|
|
| .prefix |= rtrimstr($probesuffix)
|
|
|
|
)
|
|
else
|
|
{type: "none"}
|
|
end
|
|
)
|
|
catch {type: "error", name: "", error: .}
|
|
);
|
|
|
|
# query ast to ast of quey itself, used by query rewrite/slurp
|
|
def _query_toquery:
|
|
( tojson
|
|
| _query_fromstring
|
|
);
|
|
|
|
# query rewrite helper, takes care of from/to and directives
|
|
def _query_fromtostring(f):
|
|
( _query_fromstring
|
|
# save and move directives to possible new root query
|
|
| . as {$meta, $imports}
|
|
| del(.meta)
|
|
| del(.imports)
|
|
| f
|
|
| .meta = $meta
|
|
| .imports = $imports
|
|
| _query_tostring
|
|
);
|