Bash.Tokenizer (Bash v0.6.0)

Copy Markdown View Source

Lexer for Bash syntax.

Produces a stream of tokens with position information for the parser to consume. Handles quoting, escapes, and nested structures (command substitution, etc.) correctly.

Token Types

Tokens are tuples of {type, value, line, column} or {type, line, column} for valueless tokens like operators.

Word tokens

  • {:word, parts, line, col} - A word with parts (literals, variables, etc.)
  • {:assignment_word, name, value_parts, line, col} - VAR=value

Operators

  • {:pipe, line, col} - |
  • {:and_if, line, col} - &&
  • {:or_if, line, col} - ||
  • {:background, line, col} - &
  • {:semi, line, col} - ;
  • {:dsemi, line, col} - ;;
  • {:semi_and, line, col} - ;&
  • {:dsemi_and, line, col} - ;;&
  • {:newline, line, col} - \n
  • {:lparen, line, col} - (
  • {:rparen, line, col} - )
  • {:lbrace, line, col} - {
  • {:rbrace, line, col} - }

Redirections

  • {:less, fd, line, col} - <
  • {:greater, fd, line, col} - >
  • {:dgreater, fd, line, col} - >>
  • {:lessand, fd, line, col} - <&
  • {:greaterand, fd, line, col} - >&
  • {:lessgreat, fd, line, col} - <>
  • {:dless, fd, line, col} - << (heredoc)
  • {:dlessdash, fd, line, col} - <<- (heredoc with tab stripping)
  • {:tless, fd, line, col} - <<< (herestring)
  • {:andgreat, line, col} - &>
  • {:anddgreat, line, col} - &>>
  • {:brace_fd, varname, line, col} - {VAR} before redirect operator

Reserved words (context-dependent)

  • {:if, line, col}
  • {:then, line, col}
  • {:else, line, col}
  • {:elif, line, col}
  • {:fi, line, col}
  • {:case, line, col}
  • {:esac, line, col}
  • {:for, line, col}
  • {:while, line, col}
  • {:until, line, col}
  • {:do, line, col}
  • {:done, line, col}
  • {:in, line, col}
  • {:function, line, col}
  • {:bang, line, col} - !

Test constructs

  • {:lbracket, line, col} - [
  • {:rbracket, line, col} - ]
  • {:dlbracket, line, col} - [[
  • {:drbracket, line, col} - ]]

Arithmetic

  • {:arith_command, content, line, col} - ((...)) arithmetic command with raw content

Special

  • {:eof, line, col} - End of input
  • {:comment, text, line, col} - # comment

Summary

Functions

Tokenize a Bash script into a list of tokens.

Types

brace_spec()

@type brace_spec() :: %{
  type: :list | :range,
  items: [[word_part()]] | nil,
  range_start: String.t() | nil,
  range_end: String.t() | nil,
  step: integer() | nil,
  zero_pad: non_neg_integer() | nil
}

heredoc_pending()

@type heredoc_pending() :: %{
  delimiter: String.t(),
  strip_tabs: boolean(),
  expand: boolean(),
  start_line: pos_integer(),
  start_col: pos_integer()
}

position()

@type position() :: {line :: pos_integer(), column :: pos_integer()}

state()

@type state() :: %{
  input: String.t(),
  pos: non_neg_integer(),
  line: pos_integer(),
  column: pos_integer(),
  in_test_expr: boolean(),
  after_regex_op: boolean(),
  pending_heredocs: [heredoc_pending()]
}

token()

@type token() ::
  {:word, [word_part()], pos_integer(), pos_integer()}
  | {:assignment_word, String.t(), [word_part()], pos_integer(), pos_integer()}
  | {:append_word, String.t(), [word_part()], pos_integer(), pos_integer()}
  | {:arith_command, String.t(), pos_integer(), pos_integer()}
  | {atom(), pos_integer(), pos_integer()}
  | {atom(), non_neg_integer(), pos_integer(), pos_integer()}
  | {:comment, String.t(), pos_integer(), pos_integer()}

word_part()

@type word_part() ::
  {:literal, String.t()}
  | {:single_quoted, String.t()}
  | {:double_quoted, [word_part()]}
  | {:variable, String.t()}
  | {:variable_braced, String.t(), keyword()}
  | {:command_subst, [token()]}
  | {:process_subst_in, [token()]}
  | {:process_subst_out, [token()]}
  | {:arith_expand, String.t()}
  | {:backtick, String.t()}
  | {:brace_expand, brace_spec()}

Functions

tokenize(input)

@spec tokenize(String.t()) ::
  {:ok, [token()]} | {:error, String.t(), pos_integer(), pos_integer()}

Tokenize a Bash script into a list of tokens.

Returns {:ok, tokens} or {:error, reason, line, column}.