(command.CommandList children: [ (command.If arms: [ (if_arm cond: [ (command.Sentence child: (command.DBracket expr: (bool_expr.BoolBinary op_id: BoolBinary_EqualTilde left: {(DQ ($ VSub_DollarName '$BASH_VERSION'))} right: {(Lit_Other '^') (3)} ) ) terminator: <Op_Semi ';'> ) ] action: [ (C {(echo)} {(SQ <'quinedb requires bash 4!'>)}) (command.ControlFlow token:<ControlFlow_Exit exit> arg_word:{(1)}) ] ) ] ) (command.Assignment keyword: Assign_Declare flags: [-A] pairs: [(assign_pair lhs:(lhs_expr.LhsName name:db) op:Equal)] ) (command.Assignment keyword: Assign_None pairs: [(assign_pair lhs:(lhs_expr.LhsName name:db) op:Equal rhs:{(word_part.ArrayLiteralPart)})] ) (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:PREAMBLE) op: Equal rhs: { (word_part.CommandSubPart command_list: (command.CommandList children: [ (command.SimpleCommand words: [{(cat)}] redirects: [ (redir.HereDoc op: <Redir_DLess '<<'> fd: 16777215 here_begin: {(SQ <EOF>)} 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') ] ) ] ) ] ) left_token: <Left_CommandSub '$('> ) } ) ] ) (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:POSTAMBLE) op: Equal rhs: { (word_part.CommandSubPart command_list: (command.CommandList children: [ (command.SimpleCommand words: [{(cat)}] redirects: [ (redir.HereDoc op: <Redir_DLess '<<'> fd: 16777215 here_begin: {(SQ <EOF>)} 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') ] ) ] ) ] ) left_token: <Left_CommandSub '$('> ) } ) ] ) (command.FuncDef name: pr_str body: (command.BraceGroup children:[(C {(printf)} {(DQ ('%q'))} {(DQ ($ VSub_Number '$1'))})]) ) (command.Case to_match: {(DQ ($ VSub_Number '$1'))} arms: [ (case_arm pat_list: [{(DQ (get))}] action: [ (command.If arms: [ (if_arm cond: [ (command.Sentence child: (C {(Lit_Other '[')} { (word_part.BracedVarSub token: <VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr: (arith_expr.ArithWord w:{(DQ ($ VSub_Number '$2'))}) ) suffix_op: (suffix_op.StringUnary op_id:VTest_Plus arg_word:{(_)}) ) } {(Lit_Other ']')} ) terminator: <Op_Semi ';'> ) ] action: [ (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:v) op: Equal rhs: { (word_part.BracedVarSub token: <VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr: (arith_expr.ArithWord w:{(DQ ($ VSub_Number '$2'))}) ) ) } ) ] ) (command.SimpleCommand words: [ {(echo)} { (DQ (word_part.CommandSubPart command_list: (command.CommandList children: [(C {(pr_str)} {(DQ ($ VSub_DollarName '$v'))})] ) left_token: <Left_CommandSub '$('> ) ) } ] redirects: [(redir.Redir op:<Redir_GreatAnd '>&'> fd:16777215 arg_word:{(2)})] ) ] ) ] ) ] ) (case_arm pat_list: [{(DQ (set))}] action: [ (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsIndexedName name: db index: (arith_expr.ArithWord w:{(DQ ($ VSub_Number '$2'))}) ) op: Equal rhs: {(DQ ($ VSub_Number '$3'))} ) ] ) (command.SimpleCommand words: [{(echo)} {(SQ <OK>)}] redirects: [(redir.Redir op:<Redir_GreatAnd '>&'> fd:16777215 arg_word:{(2)})] ) ] ) (case_arm pat_list: [{(DQ (delete))}] action: [ (C {(unset)} {(Lit_ArrayLhsOpen 'db[') (DQ ($ VSub_Number '$2')) (Lit_Other ']')}) (command.SimpleCommand words: [{(echo)} {(SQ <OK>)}] redirects: [(redir.Redir op:<Redir_GreatAnd '>&'> fd:16777215 arg_word:{(2)})] ) ] ) (case_arm pat_list: [{(DQ (keys))}] action: [ (command.ForEach iter_name: k iter_words: [ { (DQ (word_part.BracedVarSub token: <VSub_Name db> prefix_op: VSub_Bang bracket_op: (bracket_op.WholeArray op_id:Lit_At) ) ) } ] do_arg_iter: F body: (command.DoGroup children: [ (command.Sentence child: (C {(echo)} { (DQ (word_part.CommandSubPart command_list: (command.CommandList children: [(C {(pr_str)} {(DQ ($ VSub_DollarName '$k'))})] ) left_token: <Left_CommandSub '$('> ) ) } ) terminator: <Op_Semi ';'> ) ] ) redirects: [(redir.Redir op:<Redir_GreatAnd '>&'> fd:16777215 arg_word:{(2)})] ) ] ) (case_arm pat_list: [{(Lit_Other '*')}] action: [ (command.SimpleCommand words: [{(echo)} {(DQ ('USAGE: quinedb [get k | set k v | delete k | keys]'))}] redirects: [(redir.Redir op:<Redir_GreatAnd '>&'> fd:16777215 arg_word:{(2)})] ) ] ) ] ) (command.FuncDef name: print_db body: (command.BraceGroup children: [ (C {(echo)} {(DQ ('db=('))}) (command.Assignment keyword: Assign_None pairs: [(assign_pair lhs:(lhs_expr.LhsName name:i) op:Equal rhs:{(0)})] ) (command.ForEach iter_name: k iter_words: [ { (DQ (word_part.BracedVarSub token: <VSub_Name db> prefix_op: VSub_Bang bracket_op: (bracket_op.WholeArray op_id:Lit_At) ) ) } ] do_arg_iter: F body: (command.DoGroup children: [ (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsIndexedName name: escaped_keys index: (arith_expr.ArithWord w:{($ VSub_DollarName '$i')}) ) op: Equal rhs: { (word_part.CommandSubPart command_list: (command.CommandList children: [(C {(pr_str)} {(DQ ($ VSub_DollarName '$k'))})] ) left_token: <Left_CommandSub '$('> ) } ) ] ) (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:i) op: Equal rhs: { (word_part.ArithSubPart anode: (arith_expr.ArithBinary op_id: Arith_Plus left: (arith_expr.ArithVarRef token:<Lit_ArithVarLike i>) right: (arith_expr.ArithWord w:{(Lit_Digits 1)}) ) ) } ) ] ) ] ) ) (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:IFS) op: Equal rhs: { (word_part.SingleQuotedPart left: <Left_DollarSingleQuote "$'"> tokens: [<Char_OneChar '\\n'>] ) } ) (assign_pair lhs: (lhs_expr.LhsName name:sorted) op: Equal rhs: { (word_part.ArrayLiteralPart words: [ { (word_part.CommandSubPart command_list: (command.CommandList children: [ (command.Pipeline children: [ (command.ForEach iter_name: l iter_words: [ { (word_part.BracedVarSub token: <VSub_Name escaped_keys> bracket_op: (bracket_op.WholeArray op_id:Lit_At) ) } ] do_arg_iter: F body: (command.DoGroup children: [ (command.Sentence child: (C {(echo)} {($ VSub_DollarName '$l')}) terminator: <Op_Semi ';'> ) ] ) ) (C {(sort)}) ] negated: F ) ] ) left_token: <Left_CommandSub '$('> ) } ] ) } ) ] ) (C {(unset)} {(IFS)}) (command.ForEach iter_name: k iter_words: [ { (DQ (word_part.BracedVarSub token: <VSub_Name sorted> bracket_op: (bracket_op.WholeArray op_id:Lit_At) ) ) } ] do_arg_iter: F body: (command.DoGroup children: [ (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:unescaped) op: Equal rhs: { (word_part.CommandSubPart command_list: (command.CommandList children: [(C {(eval)} {(DQ ('echo ') ($ VSub_DollarName '$k'))})] ) left_token: <Left_CommandSub '$('> ) } ) ] ) (command.Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (lhs_expr.LhsName name:v) op: Equal rhs: { (word_part.BracedVarSub token: <VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr: (arith_expr.ArithWord w: {(DQ ($ VSub_DollarName '$unescaped'))} ) ) ) } ) ] ) (C {(echo)} { (DQ (' [') ($ VSub_DollarName '$k') (']=') (word_part.CommandSubPart command_list: (command.CommandList children: [(C {(pr_str)} {(DQ ($ VSub_DollarName '$v'))})] ) left_token: <Left_CommandSub '$('> ) ) } ) ] ) ) (C {(echo)} {(DQ (')'))}) ] ) ) (command.CommandList children: [ (command.Sentence child: (C {(echo)} {(DQ ($ VSub_DollarName '$PREAMBLE'))}) terminator: <Op_Semi ';'> ) (C {(echo)}) ] ) (command.CommandList children: [(command.Sentence child:(C {(print_db)}) terminator:<Op_Semi ';'>) (C {(echo)})] ) (C {(echo)} {(SQ <'PREAMBLE=$(cat <<'>) (word_part.EscapedLiteralPart token:<Lit_EscapedChar "\\'">) (EOF) (word_part.EscapedLiteralPart token:<Lit_EscapedChar "\\'">) } ) (C {(echo)} {(DQ ($ VSub_DollarName '$PREAMBLE'))}) (C {(echo)} {(EOF)}) (command.CommandList children: [ (command.Sentence child: (C {(echo)} {(word_part.EscapedLiteralPart token:<Lit_EscapedChar '\\)'>)}) terminator: <Op_Semi ';'> ) (C {(echo)}) ] ) (C {(echo)} {(SQ <'POSTAMBLE=$(cat <<'>) (word_part.EscapedLiteralPart token:<Lit_EscapedChar "\\'">) (EOF) (word_part.EscapedLiteralPart token:<Lit_EscapedChar "\\'">) } ) (C {(echo)} {(DQ ($ VSub_DollarName '$POSTAMBLE'))}) (C {(echo)} {(EOF)}) (command.CommandList children: [ (command.Sentence child: (C {(echo)} {(word_part.EscapedLiteralPart token:<Lit_EscapedChar '\\)'>)}) terminator: <Op_Semi ';'> ) (C {(echo)}) ] ) (C {(echo)} {(DQ ($ VSub_DollarName '$POSTAMBLE'))}) ] )