colis-anr / morbig

A static parser for POSIX Shell
Other
192 stars 8 forks source link

alias expansion should apply only to the command word of a simple command #17

Closed treinen closed 6 years ago

treinen commented 6 years ago

The Posix standard says:

... resulting word that is identified to be the command name word of a simple command shall be examined to determine whether it is an unquoted, valid alias name ...

In my understanding (which may be wrong) this means that only a WORD which is obtained through this sub-derivation

simple_command -> cmd_name -> WORD

or maybe as the first WORD in

simple_command -> cmd_name cmd_suffix -> WORD cmd_suffix

can be candidate for alias substitution. How these can be found before applying any grammar rules, as the standard requires, escapes me but that is a different matter.

For instance, the following shell script

alias show=echo show show

should print "show", and "not "echo" . Dash does this right, but when you look at the json produced by morbig you see that it has in fact replaced both occurrences of "show".

The same error occurs on toplevel-unalias.sh in the tests/good directory: If you look at the json produced by morbig you see that the unalias has not been executed. The reason for this is that the first alias has also replaced the argument of the succeeding unalias, making it ineffective.

treinen commented 6 years ago

As I understand the standard, only command words of simple comands shall be candidates for alias substitution. That is, in my opinion, in a script like this

alias foreach=for foreach x in a b c; do ....; done

the foreach should not be replaced as it is part of a complex command, not a simple command. OTOH, dash does make this replacment. Maybe the explanation is that the alias substitution shall happen before applying any grammatical rules?

Niols commented 6 years ago

How can we know that it is indeed a complex command? Do you think that the alias substitution should happen after the promotion from word to reserved word?

yurug commented 6 years ago

This issue seems fixed to me by the following implementation of alias_substitution.

(** [alias_substitution aliases checkpoint word] substitutes an
    alias by its definition if word is not a reserved word and
    if the parsing context is about to reduce a [cmd_name]. *)
let alias_substitution aliases checkpoint word =
    if about_to_reduce_cmd_name checkpoint then (
      if not (Keyword.is_reserved_word word) then
        substitute aliases word
      else
        word
    ) else word