(command.CommandList
  children: [
    (command.If
      arms: [
        (if_arm
          cond: [
            (command.Sentence
              child: 
                (command.DBracket
                  expr: 
                    (bool_expr.Binary
                      op_id: Id.BoolBinary_EqualTilde
                      left: {(DQ ($ Id.VSub_DollarName '$BASH_VERSION'))}
                      right: {(Id.Lit_Other '^') (3)}
                    )
                )
              terminator: (Token id:Id.Op_Semi val:';' span_id:18)
            )
          ]
          action: [
            (C {(echo)} {(SQ (Token id:Id.Lit_Chars val:'quinedb requires bash 4!' span_id:26))})
            (command.ControlFlow
              token: (Token id:Id.ControlFlow_Exit val:exit span_id:30)
              arg_word: {(1)}
            )
          ]
          spids: [4 20]
        )
      ]
    )
    (C {(declare)} {(-A)} {(db)})
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:db)
          op: assign_op.Equal
          rhs: {(sh_array_literal left:(Token id:Id.Op_LParen val:'(' span_id:45))}
          spids: [44]
        )
      ]
    )
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:PREAMBLE)
          op: assign_op.Equal
          rhs: 
            {
              (command_sub
                left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:51)
                command_list: 
                  (command.CommandList
                    children: [
                      (command.Simple
                        words: [{(cat)}]
                        redirects: [
                          (redir.HereDoc
                            op: (Token id:Id.Redir_DLess val:'<<' span_id:54)
                            fd: -1
                            here_begin: {(SQ (Token id:Id.Lit_Chars val:EOF span_id:56))}
                            here_end_span_id: 67
                            stdin_parts: [
                              ('#!/usr/bin/env bash\n')
                              ('\n')
                              ('if [[ "$BASH_VERSION" =~ ^3 ]]; then\n')
                              ("    echo 'quinedb requires bash 4!'\n")
                              ('    exit 1\n')
                              ('fi\n')
                              ('\n')
                              ('declare -A db\n')
                            ]
                          )
                        ]
                      )
                    ]
                  )
              )
            }
          spids: [50]
        )
      ]
    )
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:POSTAMBLE)
          op: assign_op.Equal
          rhs: 
            {
              (command_sub
                left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:72)
                command_list: 
                  (command.CommandList
                    children: [
                      (command.Simple
                        words: [{(cat)}]
                        redirects: [
                          (redir.HereDoc
                            op: (Token id:Id.Redir_DLess val:'<<' span_id:75)
                            fd: -1
                            here_begin: {(SQ (Token id:Id.Lit_Chars val:EOF span_id:77))}
                            here_end_span_id: 140
                            stdin_parts: [
                              ('pr_str () {\n')
                              ('    printf "%q" "$1"\n')
                              ('}\n')
                              ('\n')
                              ('case "$1" in\n')
                              ('    "get")\n')
                              ('        if [ ${db["$2"]+_} ]; then\n')
                              ('            v=${db["$2"]}\n')
                              ('            echo "$(pr_str "$v")" >&2\n')
                              ('        fi\n')
                              ('    ;;\n')
                              ('    "set")\n')
                              ('        db["$2"]="$3"\n')
                              ("        echo 'OK' >&2\n")
                              ('    ;;\n')
                              ('    "delete")\n')
                              ('        unset db["$2"]\n')
                              ("        echo 'OK' >&2\n")
                              ('    ;;\n')
                              ('    "keys")\n')
                              ('        for k in "${!db[@]}"; do echo "$(pr_str "$k")"; done >&2\n')
                              ('    ;;\n')
                              ('    *)\n')
                              (
'        echo "USAGE: quinedb [get k | set k v | delete k | keys]" >&2\n'
                              )
                              ('    ;;\n')
                              ('esac\n')
                              ('\n')
                              ('# print self\n')
                              ('\n')
                              ('print_db(){\n')
                              ('    echo "db=("\n')
                              ('    i=0\n')
                              ('    for k in "${!db[@]}"; do\n')
                              ('        escaped_keys[$i]=$(pr_str "$k")\n')
                              ('        i=$((i+1))\n')
                              ('    done\n')
                              ('\n')
                              ('    # sort the keys for deterministic printing\n')
                              (
"    IFS=$'\\n' sorted=($(for l in ${escaped_keys[@]}; do echo $l; done | sort))\n"
                              )
                              ('    unset IFS\n')
                              ('\n')
                              ('    for k in "${sorted[@]}"; do\n')
                              ('        unescaped=$(eval "echo $k")\n')
                              ('        v=${db["$unescaped"]}\n')
                              ('        echo "    [$k]=$(pr_str "$v")"\n')
                              ('    done\n')
                              ('    echo ")"\n')
                              ('}\n')
                              ('\n')
                              ('echo "$PREAMBLE"; echo\n')
                              ('print_db; echo\n')
                              ("echo 'PREAMBLE=$(cat <<'\\'EOF\\'\n")
                              ('echo "$PREAMBLE"\n')
                              ('echo EOF\n')
                              ('echo \\); echo\n')
                              ("echo 'POSTAMBLE=$(cat <<'\\'EOF\\'\n")
                              ('echo "$POSTAMBLE"\n')
                              ('echo EOF\n')
                              ('echo \\); echo\n')
                              ('echo "$POSTAMBLE"\n')
                            ]
                          )
                        ]
                      )
                    ]
                  )
              )
            }
          spids: [71]
        )
      ]
    )
    (command.ShFunction
      name: pr_str
      body: 
        (command.BraceGroup
          children: [(C {(printf)} {(DQ ('%q'))} {(DQ ($ Id.VSub_Number '$1'))})]
        )
    )
    (command.Case
      to_match: {(DQ ($ Id.VSub_Number '$1'))}
      arms: [
        (case_arm
          pat_list: [{(DQ (get))}]
          action: [
            (command.If
              arms: [
                (if_arm
                  cond: [
                    (command.Sentence
                      child: 
                        (C {(Id.Lit_LBracket '[')} 
                          {
                            (braced_var_sub
                              token: (Token id:Id.VSub_Name val:db span_id:185)
                              bracket_op: 
                                (bracket_op.ArrayIndex
                                  expr: (arith_expr.ArithWord w:{(DQ ($ Id.VSub_Number '$2'))})
                                )
                              suffix_op: (suffix_op.Unary op_id:Id.VTest_Plus arg_word:{(_)})
                            )
                          } {(Id.Lit_RBracket ']')}
                        )
                      terminator: (Token id:Id.Op_Semi val:';' span_id:196)
                    )
                  ]
                  action: [
                    (command.ShAssignment
                      pairs: [
                        (assign_pair
                          lhs: (sh_lhs_expr.Name name:v)
                          op: assign_op.Equal
                          rhs: 
                            {
                              (braced_var_sub
                                token: (Token id:Id.VSub_Name val:db span_id:203)
                                bracket_op: 
                                  (bracket_op.ArrayIndex
                                    expr: (arith_expr.ArithWord w:{(DQ ($ Id.VSub_Number '$2'))})
                                  )
                              )
                            }
                          spids: [201]
                        )
                      ]
                    )
                    (command.Simple
                      words: [
                        {(echo)}
                        {
                          (DQ 
                            (command_sub
                              left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:215)
                              command_list: 
                                (command.CommandList
                                  children: [(C {(pr_str)} {(DQ ($ Id.VSub_DollarName '$v'))})]
                                )
                            )
                          )
                        }
                      ]
                      redirects: [
                        (redir.Redir
                          op: (Token id:Id.Redir_GreatAnd val:'>&' span_id:224)
                          fd: -1
                          arg_word: {(2)}
                        )
                      ]
                    )
                  ]
                  spids: [180 198]
                )
              ]
            )
          ]
          spids: [174 177 231 -1]
        )
        (case_arm
          pat_list: [{(DQ (set))}]
          action: [
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: 
                    (sh_lhs_expr.IndexedName
                      name: db
                      index: (arith_expr.ArithWord w:{(DQ ($ Id.VSub_Number '$2'))})
                    )
                  op: assign_op.Equal
                  rhs: {(DQ ($ Id.VSub_Number '$3'))}
                  spids: [240]
                )
              ]
            )
            (command.Simple
              words: [{(echo)} {(SQ (Token id:Id.Lit_Chars val:OK span_id:257))}]
              redirects: [
                (redir.Redir
                  op: (Token id:Id.Redir_GreatAnd val:'>&' span_id:260)
                  fd: -1
                  arg_word: {(2)}
                )
              ]
            )
          ]
          spids: [234 237 264 -1]
        )
        (case_arm
          pat_list: [{(DQ (delete))}]
          action: [
            (C {(unset)} 
              {(Id.Lit_ArrayLhsOpen 'db[') (DQ ($ Id.VSub_Number '$2')) (Id.Lit_RBracket ']')}
            )
            (command.Simple
              words: [{(echo)} {(SQ (Token id:Id.Lit_Chars val:OK span_id:285))}]
              redirects: [
                (redir.Redir
                  op: (Token id:Id.Redir_GreatAnd val:'>&' span_id:288)
                  fd: -1
                  arg_word: {(2)}
                )
              ]
            )
          ]
          spids: [267 270 292 -1]
        )
        (case_arm
          pat_list: [{(DQ (keys))}]
          action: [
            (command.ForEach
              iter_name: k
              iter_words: [
                {
                  (DQ 
                    (braced_var_sub
                      token: (Token id:Id.VSub_Name val:db span_id:310)
                      prefix_op: (Id.VSub_Bang)
                      bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At)
                    )
                  )
                }
              ]
              do_arg_iter: F
              body: 
                (command.DoGroup
                  children: [
                    (command.Sentence
                      child: 
                        (C {(echo)} 
                          {
                            (DQ 
                              (command_sub
                                left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:323)
                                command_list: 
                                  (command.CommandList
                                    children: [(C {(pr_str)} {(DQ ($ Id.VSub_DollarName '$k'))})]
                                  )
                              )
                            )
                          }
                        )
                      terminator: (Token id:Id.Op_Semi val:';' span_id:331)
                    )
                  ]
                )
              redirects: [
                (redir.Redir
                  op: (Token id:Id.Redir_GreatAnd val:'>&' span_id:335)
                  fd: -1
                  arg_word: {(2)}
                )
              ]
            )
          ]
          spids: [295 298 339 -1]
        )
        (case_arm
          pat_list: [{(Id.Lit_Star '*')}]
          action: [
            (command.Simple
              words: [{(echo)} {(DQ ('USAGE: quinedb [get k | set k v | delete k | keys]'))}]
              redirects: [
                (redir.Redir
                  op: (Token id:Id.Redir_GreatAnd val:'>&' span_id:352)
                  fd: -1
                  arg_word: {(2)}
                )
              ]
            )
          ]
          spids: [342 343 356 -1]
        )
      ]
    )
    (command.ShFunction
      name: print_db
      body: 
        (command.BraceGroup
          children: [
            (C {(echo)} {(DQ ('db=('))})
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:i)
                  op: assign_op.Equal
                  rhs: {(0)}
                  spids: [378]
                )
              ]
            )
            (command.ForEach
              iter_name: k
              iter_words: [
                {
                  (DQ 
                    (braced_var_sub
                      token: (Token id:Id.VSub_Name val:db span_id:391)
                      prefix_op: (Id.VSub_Bang)
                      bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At)
                    )
                  )
                }
              ]
              do_arg_iter: F
              body: 
                (command.DoGroup
                  children: [
                    (command.ShAssignment
                      pairs: [
                        (assign_pair
                          lhs: 
                            (sh_lhs_expr.IndexedName
                              name: escaped_keys
                              index: (arith_expr.ArithWord w:{($ Id.VSub_DollarName '$i')})
                            )
                          op: assign_op.Equal
                          rhs: 
                            {
                              (command_sub
                                left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:405)
                                command_list: 
                                  (command.CommandList
                                    children: [(C {(pr_str)} {(DQ ($ Id.VSub_DollarName '$k'))})]
                                  )
                              )
                            }
                          spids: [402]
                        )
                      ]
                    )
                    (command.ShAssignment
                      pairs: [
                        (assign_pair
                          lhs: (sh_lhs_expr.Name name:i)
                          op: assign_op.Equal
                          rhs: 
                            {
                              (word_part.ArithSub
                                anode: 
                                  (arith_expr.Binary
                                    op_id: Id.Arith_Plus
                                    left: 
                                      (arith_expr.VarRef
                                        token: (Token id:Id.Lit_ArithVarLike val:i span_id:418)
                                      )
                                    right: (arith_expr.ArithWord w:{(Id.Lit_Digits 1)})
                                  )
                              )
                            }
                          spids: [416]
                        )
                      ]
                    )
                  ]
                )
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:IFS)
                  op: assign_op.Equal
                  rhs: 
                    {
                      (single_quoted
                        left: (Token id:Id.Left_SingleQuoteC val:"$'" span_id:434)
                        tokens: [(Token id:Id.Char_OneChar val:'\\n' span_id:435)]
                      )
                    }
                  spids: [433]
                )
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:sorted)
                  op: assign_op.Equal
                  rhs: 
                    {
                      (sh_array_literal
                        left: (Token id:Id.Op_LParen val:'(' span_id:439)
                        words: [
                          {
                            (command_sub
                              left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:440)
                              command_list: 
                                (command.CommandList
                                  children: [
                                    (command.Pipeline
                                      children: [
                                        (command.ForEach
                                          iter_name: l
                                          iter_words: [
                                            {
                                              (braced_var_sub
                                                token: 
                                                  (Token
                                                    id: Id.VSub_Name
                                                    val: escaped_keys
                                                    span_id: 448
                                                  )
                                                bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At)
                                              )
                                            }
                                          ]
                                          do_arg_iter: F
                                          body: 
                                            (command.DoGroup
                                              children: [
                                                (command.Sentence
                                                  child: (C {(echo)} {($ Id.VSub_DollarName '$l')})
                                                  terminator: 
                                                    (Token
                                                      id: Id.Op_Semi
                                                      val: ';'
                                                      span_id: 460
                                                    )
                                                )
                                              ]
                                            )
                                        )
                                        (C {(sort)})
                                      ]
                                      negated: F
                                    )
                                  ]
                                )
                            )
                          }
                        ]
                      )
                    }
                  spids: [438]
                )
              ]
            )
            (C {(unset)} {(IFS)})
            (command.ForEach
              iter_name: k
              iter_words: [
                {
                  (DQ 
                    (braced_var_sub
                      token: (Token id:Id.VSub_Name val:sorted span_id:485)
                      bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At)
                    )
                  )
                }
              ]
              do_arg_iter: F
              body: 
                (command.DoGroup
                  children: [
                    (command.ShAssignment
                      pairs: [
                        (assign_pair
                          lhs: (sh_lhs_expr.Name name:unescaped)
                          op: assign_op.Equal
                          rhs: 
                            {
                              (command_sub
                                left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:497)
                                command_list: 
                                  (command.CommandList
                                    children: [(C {(eval)} {(DQ ('echo ') ($ Id.VSub_DollarName '$k'))})]
                                  )
                              )
                            }
                          spids: [496]
                        )
                      ]
                    )
                    (command.ShAssignment
                      pairs: [
                        (assign_pair
                          lhs: (sh_lhs_expr.Name name:v)
                          op: assign_op.Equal
                          rhs: 
                            {
                              (braced_var_sub
                                token: (Token id:Id.VSub_Name val:db span_id:509)
                                bracket_op: 
                                  (bracket_op.ArrayIndex
                                    expr: 
                                      (arith_expr.ArithWord
                                        w: {(DQ ($ Id.VSub_DollarName '$unescaped'))}
                                      )
                                  )
                              )
                            }
                          spids: [507]
                        )
                      ]
                    )
                    (C {(echo)} 
                      {
                        (DQ ('    [') ($ Id.VSub_DollarName '$k') (']=') 
                          (command_sub
                            left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:524)
                            command_list: 
                              (command.CommandList
                                children: [(C {(pr_str)} {(DQ ($ Id.VSub_DollarName '$v'))})]
                              )
                          )
                        )
                      }
                    )
                  ]
                )
            )
            (C {(echo)} {(DQ (')'))})
          ]
        )
    )
    (command.CommandList
      children: [
        (command.Sentence
          child: (C {(echo)} {(DQ ($ Id.VSub_DollarName '$PREAMBLE'))})
          terminator: (Token id:Id.Op_Semi val:';' span_id:551)
        )
        (C {(echo)})
      ]
    )
    (command.CommandList
      children: [
        (command.Sentence
          child: (C {(print_db)})
          terminator: (Token id:Id.Op_Semi val:';' span_id:556)
        )
        (C {(echo)})
      ]
    )
    (C {(echo)} 
      {(SQ (Token id:Id.Lit_Chars val:'PREAMBLE=$(cat <<' span_id:563)) 
        (word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:"\\'" span_id:565)) (EOF) (word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:"\\'" span_id:567))
      }
    )
    (C {(echo)} {(DQ ($ Id.VSub_DollarName '$PREAMBLE'))})
    (C {(echo)} {(EOF)})
    (command.CommandList
      children: [
        (command.Sentence
          child: 
            (C {(echo)} 
              {(word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:'\\)' span_id:581))}
            )
          terminator: (Token id:Id.Op_Semi val:';' span_id:582)
        )
        (C {(echo)})
      ]
    )
    (C {(echo)} 
      {(SQ (Token id:Id.Lit_Chars val:'POSTAMBLE=$(cat <<' span_id:589)) 
        (word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:"\\'" span_id:591)) (EOF) (word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:"\\'" span_id:593))
      }
    )
    (C {(echo)} {(DQ ($ Id.VSub_DollarName '$POSTAMBLE'))})
    (C {(echo)} {(EOF)})
    (command.CommandList
      children: [
        (command.Sentence
          child: 
            (C {(echo)} 
              {(word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:'\\)' span_id:607))}
            )
          terminator: (Token id:Id.Op_Semi val:';' span_id:608)
        )
        (C {(echo)})
      ]
    )
    (C {(echo)} {(DQ ($ Id.VSub_DollarName '$POSTAMBLE'))})
  ]
)