63 lines
1.7 KiB
JavaScript
63 lines
1.7 KiB
JavaScript
module.exports = grammar({
|
|
name: 'nixshell',
|
|
|
|
rules: {
|
|
// TODO: allow trailing whitespace on any line
|
|
source_file: $ => seq($.first_line, repeat($.next_line)),
|
|
|
|
first_line: $ => seq($._shebang_open, $._opt_ws, optional(seq($._env, $._ws)), $._nix_shell),
|
|
next_line: $ => seq($._newline, choice(
|
|
$.annotation_line,
|
|
repeat(/./),
|
|
)),
|
|
annotation_line: $ => seq($._shebang_open, $._opt_ws, $._nix_shell, optional($.nix_shell_args)),
|
|
|
|
// nix acts as if it actually just `exec`'s whichever line contains `#! nix-shell` in the style of `sh`'s `exec`.
|
|
// so arguments can be quoted, invoke subshells, interpolate environment variables, etc.
|
|
// the full scope cannot be covered, but the minimal scope here gets 99% of use cases.
|
|
nix_shell_args: $ => repeat1(seq($._ws, $._nix_shell_arg)),
|
|
_nix_shell_arg: $ => choice(
|
|
seq('-i', $._opt_ws, $.interpreter),
|
|
$.sh_arg,
|
|
),
|
|
interpreter: $ => $.sh_arg,
|
|
sh_arg: $ => choice(
|
|
$._sh_lit,
|
|
$._sh_quote1,
|
|
$._sh_quote2,
|
|
),
|
|
_sh_lit: $ => repeat1(choice(
|
|
/[^ \\]/,
|
|
seq('\\', /./),
|
|
)),
|
|
_sh_quote1: $ => seq(
|
|
'\'',
|
|
repeat(choice(
|
|
/[^'\\]/,
|
|
seq('\\', /./),
|
|
)),
|
|
'\'',
|
|
),
|
|
_sh_quote2: $ => seq(
|
|
'"',
|
|
repeat(choice(
|
|
/[^"\\]/,
|
|
seq('\\', /./),
|
|
)),
|
|
'"',
|
|
),
|
|
|
|
_shebang_open: $ => '#!',
|
|
// TODO: env accepts flags like `-v` or `--unset=NAME` or `VAR=VALUE` before `nix-shell`,
|
|
_env: $ => choice(
|
|
'/usr/bin/env',
|
|
'/bin/env',
|
|
'env',
|
|
),
|
|
_nix_shell: $ => 'nix-shell',
|
|
_ws: $ => / +/,
|
|
_opt_ws: $ => / */,
|
|
_newline: $ => '\n',
|
|
}
|
|
});
|