On Wed, Nov 08, 2017 at 12:20:23PM +0800, Clark Wang wrote: [...] > It seems to me bash internally parses the `declare' command specially and > (logically) convert `declare -a arr=()' to two statements `declare -a arr' > and `arr=()'.
There is indeed special treatment for assignment builtins in the parser: dualbus@ubuntu:~/src/gnu/bash$ ack -H -C3 ASSIGNMENT_BUILTIN parse.y parse.y 5222- { 5223- struct builtin *b; 5224- b = builtin_address_internal (token, 0); 5225: if (b && (b->flags & ASSIGNMENT_BUILTIN)) 5226- parser_state |= PST_ASSIGNOK; 5227- else if (STREQ (token, "eval") || STREQ (token, "let")) 5228- parser_state |= PST_ASSIGNOK; > So does it make sense to move `declare' out of the SHELL BUILTIN COMMANDS > and put it in a separate section? Or at least explicitly state that > `declare' is special? But is it only `declare' that is special? According to: dualbus@ubuntu:~/src/gnu/bash$ ack -H ASSIGNMENT_BUILTIN builtins.h builtins.h 45:#define ASSIGNMENT_BUILTIN 0x10 /* This builtin takes assignment statements. */ A builtin is an assignment builtin if builtin->flags has the ASSIGNMENT_BUILTIN bit enabled. You can see which builtins are assignment builtins by looking at builtins/mkbuiltins.c: dualbus@ubuntu:~/src/gnu/bash$ ack -H -C3 'char \*assignment_builtins' builtins/mkbuiltins.c builtins/mkbuiltins.c 154-}; 155- 156-/* The builtin commands that take assignment statements as arguments. */ 157:char *assignment_builtins[] = 158-{ 159- "alias", "declare", "export", "local", "readonly", "typeset", 160- (char *)NULL Now, there's a slight complication. Loadable builtins are also subject to this special treatment. That is, you can define a new loadable builtin which is an assignment builtin. Which means that if you only document the 6 builtins above in the manual, the information will not be complete. I think the proper approach would be to mention in the manual that there are "assignment builtins", and that you can see the complete list with `enable -<something>' As a side note, this special treatment does lead to some weirdness around shadowing assignment builtins with functions, or using them with the `builtin' builtin: dualbus@ubuntu:~$ typeset -fp declare -bash: typeset: declare: not found dualbus@ubuntu:~$ declare a=() dualbus@ubuntu:~$ typeset -p a declare -a a=() dualbus@ubuntu:~$ builtin declare b=() -bash: syntax error near unexpected token `(' dualbus@ubuntu:~$ typeset -p b -bash: typeset: b: not found dualbus@ubuntu:~$ declare() { builtin declare "$@"; } dualbus@ubuntu:~$ declare b=() dualbus@ubuntu:~$ typeset -p b declare -a b=() dualbus@ubuntu:~$ declare() { echo nope "$@"; } dualbus@ubuntu:~$ declare c=() nope c dualbus@ubuntu:~$ typeset -p c declare -a c=()