1
1
mirror of https://github.com/wader/fq.git synced 2024-10-27 12:19:52 +03:00
fq/pkg/interp/init.jq
Mattias Wadman 1ddea1ada3 interp,format: Refactor registry usage and use function helpers
Move registry to interp and add support for functions and filesystems.
This will be used later for allow formats to add own functions and fq code.

Add gojqextra function helpers to have more comfortable API to add functions.
Takes care of argument type casting and JQValue:s and some more things.

Refactor interp package to use new function helper and registry. Probably
fixes a bunch of JQValue bugs and other type errors.

Refactor out some mpeg nal things to mpeg format.

Refactor interp jq code into display.q and init.jq.

Remove undocumented aes_ctr funciton, was a test. Hopefully will add more crypto things laster.
2022-07-16 19:24:13 +02:00

265 lines
7.7 KiB
Plaintext

include "internal";
include "options";
include "binary";
include "decode";
include "format_decode";
include "format_include";
include "format_func";
include "registry_files";
include "grep";
include "args";
include "eval";
include "query";
include "interp";
include "repl";
include "help";
include "funcs";
# optional user init
include "@config/init?";
# next valid input
def input:
def _input($opts; f):
( _input_filenames
| if length == 0 then error("break") end
| [.[0], .[1:]] as [$h, $t]
| _input_filenames($t)
| _input_filename(null) as $_
| ($h // "<stdin>") as $name
| $h
| try
# null input here means stdin
( open
| _input_filename($name) as $_
| .
)
catch
( . as $err
| _input_io_errors(. += {($name): $err}) as $_
| $err
| (_error_str([$name]) | printerrln)
, _input($opts; f)
)
| try f
catch
( . as $err
| _input_decode_errors(. += {($name): $err}) as $_
| [ $opts.decode_format
, if $err | _is_string then ": \($err)"
# TODO: if not string assume decode itself failed for now
else ": failed to decode (try -d FORMAT)"
end
] | join("")
| (_error_str([$name]) | printerrln)
, _input($opts; f)
)
);
def _input_string($opts):
( _input_strings_lines
| if . then
# we're already iterating lines
if length == 0 then error("break")
else
( [.[0], .[1:]] as [$h, $t]
| _input_strings_lines($t)
| $h
)
end
else
( [_repeat_break(_input($opts; tobytes | tostring))]
| . as $chunks
| if $opts.slurp then
# jq --raw-input combined with --slurp reads all inputs into a string
# make next input break
( _input_strings_lines([]) as $_
| $chunks
| join("")
)
else
# TODO: different line endings?
# jq strips last newline, "a\nb" and "a\nb\n" behaves the same
# also jq -R . <(echo -ne 'a\nb') <(echo c) produces "a" and "bc"
if ($chunks | length) > 0 then
( _input_strings_lines(
( $chunks
| join("")
| rtrimstr("\n")
| split("\n")
)
) as $_
| input
)
else error("break")
end
end
)
end
);
# TODO: don't rebuild options each time
( options as $opts
# this is a bit strange as jq for --raw-input can return one string
# instead of iterating lines
| if $opts.string_input then _input_string($opts)
else _input($opts; decode)
end
);
# iterate all valid inputs
def inputs: _repeat_break(input);
def input_filename: _input_filename;
# user expr error, report and continue
def _cli_eval_on_expr_error:
( if _is_object then
if .error | _eval_is_compile_error then .error | _eval_compile_error_tostring
elif .error then .error
end
else tostring
end
| . as $err
| _cli_last_expr_error($err) as $_
| (_error_str([input_filename // empty]) | printerrln)
);
# other expr error, other errors then cancel should not happen, report and halt
def _cli_eval_on_error:
if .error | _is_context_canceled_error then (null | halt_error(_exit_code_expr_error))
else halt_error(_exit_code_expr_error)
end;
# could not compile expr, report and halt
def _cli_eval_on_compile_error:
( .error
| _eval_compile_error_tostring
| halt_error(_exit_code_compile_error)
);
def _cli_repl_error($_):
_eval_error("compile"; "repl can only be used from interactive repl");
def _cli_slurp_error(_):
_eval_error("compile"; "slurp can only be used from interactive repl");
# _cli_eval halts on compile errors
def _cli_eval($expr; $opts):
eval(
$expr;
$opts + {
slurps: {
help: "_help_slurp",
repl: "_cli_repl_error",
slurp: "_cli_slurp_error"
},
catch_query: _query_func("_cli_eval_on_expr_error")
};
_cli_eval_on_error;
_cli_eval_on_compile_error
);
def _main:
def _map_argdecode:
map(
( . as $a
| .[1] |=
try (open | decode)
catch
( "--argdecode \($a[0]): \(.)"
| halt_error(_exit_code_args_error)
)
)
);
( . as {$version, $os, $arch, $args, args: [$arg0]}
# make sure we don't unintentionally use . to make things clearer
| null
| ( try _args_parse($args[1:]; _opt_cli_opts)
catch halt_error(_exit_code_args_error)
) as {parsed: $parsed_args, $rest}
# combine default fixed opt, parsed args and -o key=value opts
| _options_stack([
( ( _opt_build_default_fixed
+ $parsed_args
+ ($parsed_args.option | if . then _opt_cli_arg_to_options end)
)
| . + _opt_eval($rest)
)
]) as $_
| options as $opts
| if $opts.show_help then
( if ($opts.show_help | type) == "boolean" then
( ("banner", "", "usage", "", "example_usage", "", "args")
| if . != "" then _help($arg0; .) end
)
else _help($arg0; $opts.show_help)
end
| println
)
elif $opts.show_version then "\($version) (\($os) \($arch))" | println
elif
( $opts.filenames == [null] and
$opts.null_input == false and
($opts.repl | not) and
($opts.expr_file | not) and
stdin_tty.is_terminal and
stdout_tty.is_terminal
) then
( (_help($arg0; "usage") | printerrln)
, null | halt_error(_exit_code_args_error)
)
else
( # store some global state
( _include_paths($opts.include_path) as $_
| _input_filenames($opts.filenames) as $_
| _slurps(
( $opts.arg +
$opts.argjson +
$opts.raw_file +
($opts.argdecode | if . then _map_argdecode end)
| map({key: .[0], value: .[1]})
| from_entries
)
)
) as $_
| { filename: $opts.expr_eval_path
} as $eval_opts
# use _finally as display etc prints and outputs empty
| _finally(
if $opts.repl then
# TODO: share input_query but first have to figure out how to handle
# context/interrupts better as open will happen in a sub repl which
# context will be cancelled.
( def _inputs:
if $opts.null_input then null
elif $opts.string_input then inputs
elif $opts.slurp then [inputs]
else inputs
end;
[_inputs]
| map(_cli_eval($opts.expr; $eval_opts))
| _repl({})
)
else
( _cli_last_expr_error(null) as $_
| _display_default_opts as $default_opts
| _cli_eval(
$opts.expr;
( $eval_opts
| .input_query =
( if $opts.null_input then _query_null
# note that jq --slurp --raw-input (string_input) is special, will concat
# all files into one string instead of iterating lines
elif $opts.string_input then _query_func("inputs")
elif $opts.slurp then _query_func("inputs") | _query_array
else _query_func("inputs")
end
)
)
)
| display($default_opts)
)
end;
# finally
( if _input_io_errors then null | halt_error(_exit_code_input_io_error) end
| if _input_decode_errors then null | halt_error(_exit_code_input_decode_error) end
| if _cli_last_expr_error then null | halt_error(_exit_code_expr_error) end
)
)
)
end
);