Skip to content

Latest commit

 

History

History
755 lines (584 loc) · 13.1 KB

AST.adoc

File metadata and controls

755 lines (584 loc) · 13.1 KB

AST

TODO: Explain two types of representation (low-level and high-level API).

Program

The root node of the AST tree.

Node
{
  type: 'Program',
  body: [ ( SequentialList
          | AsyncCommand
          | AndOrList
          | Not
          | PipeSequence
          | Command )* ],
  comments: [ Comment* ]
}

CompoundList

Node
{
  type: 'CompoundList',
  cmds: [ ( SequentialList
          | AsyncCommand
          | AndOrList
          | Not
          | PipeSequence
          | Command )+ ]
}

SequentialList

Commands that are separated by a semicolon ; shall be executed sequentially. Read more…

Format
command1; command2 [; command3 ] ... [;]
Captures
Node
{
  type: 'SequentialList',
  cmds: [ ( AsyncCommand
          | AndOrList
          | Not
          | PipeSequence
          | Command )+ ]
}

AsyncCommand

If a command is terminated by the control operator &, the shell shall execute the command asynchronously in a subshell. Read more…

Format
command &
Captures
Node
{
  type: 'AsyncCommand',
  cmd: ( AndOrList
       | Not
       | PipeSequence
       | Command )
}

AndOrList

An AND-OR list is a sequence of one or more pipelines separated by the operators && and ||. They shall have equal precedence and shall be evaluated with left associativity. Read more…

Format
command1 && command2 [ || command3] ...
command1 || command2 [ && command3] ...

AndList

Captures
{
  ( OrList
  | Not
  | PipeSequence
  | Command ),
  (
    ( Not
    | PipeSequence
    | Command )
  )+
}
Node
{
  type: 'AndList',
  cmds: [ ( OrList
          | Not
          | PipeSequence
          | Command ),
          (
            ( Not
            | PipeSequence
            | Command )
          )+ ]
}

OrList

Captures
{
  ( AndList
  | Not
  | PipeSequence
  | Command ),
  (
    ( Not
    | PipeSequence
    | Command )
  )+
}
Node
{
  type: 'OrList',
  cmds: [ ( AndList
          | Not
          | PipeSequence
          | Command ),
          (
            ( Not
            | PipeSequence
            | Command )
          )+ ]
}

Not

Format
! command
Captures
Node
{
  type: 'Not',
  cmd: ( PipeSequence
       | Command )
}

PipeSequence

A pipeline is a sequence of one or more commands separated by the control operator |. For each command but the last, the shell shall connect the standard output of the command to the standard input of the next command as if by creating a pipe and passing the write end of the pipe as the standard output of the command and the read end of the pipe as the standard input of the next command. Read more…

Format
command1 | command2 [| command3 ] ...
Captures
{ Command+ }
Node
{
  type: 'PipeSequence',
  cmds: [ Command+ ]
}

Command

SimpleCommand

A “simple command” is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator. Read more…

Captures
{ { ( Redirect | Assignment )* }, Word | nil, { ( Redirect | Word )* } | nil }
  1. Redirections and assignments (prefix).

  2. Command name. If nil, then (1) is not empty and (3) is nil.

  3. Redirections and command arguments (suffix).

Nodes

TODO

Assignments

Format
[modifier] varname=value ...
Nodes
{
  type: 'Assignments',
  assignments: [ Assignment+ ],
  modifier: 'export' | 'local' | 'readonly' | null
}

CompoundCommand

BraceGroup

Execute compound-list in the current process environment. Read more…

Format
{ compound-list ; }
Captures
Node
{
  type: 'BraceGroup',
  body: CompoundList,
  redirs: [ Redirect* ]
}

Subshell

Execute compound-list in a subshell environment; see Shell Execution Environment. Read more…

Format
( compound-list )
Captures
{ CompoundList | nil, { Redirect* } }
Node
{
  type: 'Subshell',
  body: CompoundList | null,
  redirs: [ Redirect* ]
}

If

The if command shall execute a compound-list and use its exit status to determine whether to execute another compound-list. Read more…

Format
if compound-list
then
    compound-list
[elif compound-list
then
    compound-list] ...
[else
    compound-list]
fi
Captures
If         : { { IfClause, ElifClause*, ElseClause? }, { Redirect* } }
IfClause   : { CompoundList, CompoundList }
ElifClause : { CompoundList, CompoundList }
ElseClause : { CompoundList }
Node
{
  type: 'If',
  clauses: [ IfClause, ElifClause*, ElseClause? ],
  redirs: [ Redirect* ]
}
{
  type: 'IfClause',
  cond: CompoundList,
  body: CompoundList
}
{
  type: 'ElifClause',
  cond: CompoundList,
  body: CompoundList
}
{
  type: 'ElseClause',
  body: CompoundList
}

For

The for loop shall execute a sequence of commands for each member in a list of items. Read more…

Format
for name [ in [word ... ]]
do
    compound-list
done
Captures
{ Name, { Word* }, CompoundList, { Redirect* } }
  1. Variable name.

  2. List of items to loop over.

  3. Body of the for loop.

  4. Redirections.

Node
{
  type: 'For',
  var: Name,
  items: [ Word* ],
  body: CompoundList,
  redirs: [ Redirect* ]
}

Case

The conditional construct case shall execute the compound-list corresponding to the first one of several patterns (see Pattern Matching Notation) that is matched by the string resulting from the tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal of the given word. Read more…

Format
case word in
    [(] pattern1 ) compound-list ;;
    [[(] pattern[ | pattern] ... ) compound-list ;;] ...
    [[(] pattern[ | pattern] ... ) compound-list]
esac
Captures
Case     : { Word, { CaseItem* }, { Redirect* } }
CaseItem : { { Word+ }, CompoundList }
Node
{
  type: 'Case',
  var: Name,
  cases: [ CaseItem* ],
  redirs: [ Redirect* ]
}
{
  type: 'CaseItem',
  pattern: [ Word+ ],
  body: CompoundList
}

While

The while loop shall continuously execute one compound-list as long as another compound-list has a zero exit status. Read more…

Format
while compound-list-1
do
    compound-list-2
done
Captures
Node
{
  type: 'While',
  cond: CompoundList,
  body: CompoundList,
  redirs: [ Redirect* ]
}

Until

The until loop shall continuously execute one compound-list as long as another compound-list has a non-zero exit status. Read more…

Format
until compound-list-1
do
    compound-list-2
done
Captures
Node
{
  type: 'Until',
  cond: CompoundList,
  body: CompoundList,
  redirs: [ Redirect* ]
}

FunctionDef

A function is a user-defined name that is used as a simple command to call a compound command with new positional parameters. Read more…

Format
fname ( ) compound-command [io-redirect ...]
Captures
Node
{
  type: 'FunctionDef',
  name: Name,
  body: CompoundCommand,
  redirs: [ Redirect* ]
}

Redirect

Redirection is used to open and close files for the current shell execution environment (see Shell Execution Environment) or for any command. Read more…

RedirectFile

Format
[n]redir-file-op word
Captures
{ number | nil, redir-file-op, Word }
  1. File descriptor number (or nil if not specified).

  2. Operator.

  3. File path, or file descriptor number.

Node
{
  type: 'RedirectFile',
  fd: number | null,
  op: redir-file-op,
  file: Word
}
Terminals
redir-file-op: '<' | '<&' | '>' | '>|' | '>>' | '>&' | '<>'

RedirectHereDoc

The redirection operators << and <<- both allow redirection of subsequent lines read by the shell to the input of a command. The redirected lines are known as a “here-document”. Read more…

Format
[n] <<[-] word
    here-document
delimiter
Captures
{ number | nil, '<<' | '<<-', Word, HereDocContent (!), number }
  1. File descriptor number (or nil if not specified).

  2. Operator.

  3. The delimiter word.

  4. TODO

  5. ID of this here-document.

Nodes
{
  type: 'RedirectHereDoc',
  fd: number | null,
  op: '<<' | '<<-',
  delimiter: Word,
  content: Word
}

HereDocContent

Captures
{ { Word* }, number }
  1. File descriptor number (or nil if not specified).

  2. ID of this here-document.

Nodes
{
  type: 'HereDocContent',
  content: [ Word* ]
}

Assignment

Format
varname=[value]
Captures
{ Name, Word | nil }
  1. Variable name.

  2. Assigned value.

Nodes
{
  type: 'Assignment',
  name: Name,
  value: Word | null
}

Name

Captures
{ string }
Node
{
  type: 'Name',
  text: string
}

Word

Captures
{ ( string | Expansion )+ }
Node
{
  type: 'Word',
  content: [ ( string | Expansion )+ ]
}

Expansion

ParameterExpansion

See Parameter Expansion for more information.

Format
${[prefix-op] variable [infix-op [ word ]]}
Captures
{ prefix-op?, param-name, ( infix-op, string )? }
Node
{
  type: 'ParameterExpansion',
  op_pre: prefix-op | null,
  param: string,
  op_in: infix-op | null,
  word: string | null
}
Terminals
prefix-op: '#'
infix-op: ':-' | '-' | ':=' | '=' | ':?' | '?' | ':+' | '+' | '%%' | '%' | '##' | '#' | ':' | '//' | '/'

ArithmeticExpansion

Arithmetic expansion provides a mechanism for evaluating an arithmetic expression and substituting its value. Read more…

Format
$((expression))
Captures
{ string }
Node
{
  type: 'ArithmeticExpansion',
  text: string
}

CommandSubstitution

Command substitution allows the output of a command to be substituted in place of the command name itself. Read more…

Format
$(command)
Captures
Node
{
  type: 'CommandSubstitution',
  cmds: [ CompoundList* ]
}

CommandSubBackquote

Format
`command`
Captures
{ string }
Node
{
  type: 'CommandSubBackquote',
  text: string
}

Comment

Format
# foo bar <LF>
Captures
{ string }
Node
{
  type: 'Comment',
  text: string
}