(command.CommandList children: [ (command.If arms: [ (if_arm cond: (condition.Shell commands: [ (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: <Id.Op_Semi _> ) ] ) action: [ (C {<echo>} {(SQ <'quinedb requires bash 4!'>)}) (command.ControlFlow token:<Id.ControlFlow_Exit exit> 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:<Id.Op_LParen _>)} spids: [44] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:PREAMBLE) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Simple words: [{<cat>}] redirects: [ (redir op: <Id.Redir_DLess '<<'> loc: (redir_loc.Fd fd:0) arg: (redir_param.HereDoc 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'> ] ) ) ] do_fork: T ) ) } spids: [50] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:POSTAMBLE) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Simple words: [{<cat>}] redirects: [ (redir op: <Id.Redir_DLess '<<'> loc: (redir_loc.Fd fd:0) arg: (redir_param.HereDoc 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'> ] ) ) ] do_fork: T ) ) } spids: [71] ) ] ) (command.ShFunction name: pr_str body: (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: (condition.Shell commands: [ (command.Sentence child: (C {<Id.Lit_LBracket '['>} { (braced_var_sub token: <Id.VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr: {(DQ ($ Id.VSub_Number '$2'))} ) suffix_op: (suffix_op.Unary tok:<Id.VTest_Plus '+'> arg_word:{<_>}) ) } {<Id.Lit_RBracket ']'>} ) terminator: <Id.Op_Semi _> ) ] ) action: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:v) op: assign_op.Equal rhs: { (braced_var_sub token: <Id.VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr:{(DQ ($ Id.VSub_Number '$2'))}) ) } spids: [201] ) ] ) (command.Simple words: [ {<echo>} { (DQ (command_sub left_token: <Id.Left_DollarParen '$('> child: (C {<pr_str>} {(DQ ($ Id.VSub_DollarName '$v'))}) ) ) } ] redirects: [(redir op:<Id.Redir_GreatAnd '>&'> loc:(redir_loc.Fd fd:1) arg:{<2>})] do_fork: T ) ] 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:{(DQ ($ Id.VSub_Number '$2'))}) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_Number '$3'))} spids: [240] ) ] ) (command.Simple words: [{<echo>} {(SQ <OK>)}] redirects: [(redir op:<Id.Redir_GreatAnd '>&'> loc:(redir_loc.Fd fd:1) arg:{<2>})] do_fork: T ) ] 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 <OK>)}] redirects: [(redir op:<Id.Redir_GreatAnd '>&'> loc:(redir_loc.Fd fd:1) arg:{<2>})] do_fork: T ) ] spids: [267 270 292 -1] ) (case_arm pat_list: [{(DQ <keys>)}] action: [ (command.ForEach iter_name: k iter_words: [ { (DQ (braced_var_sub token: <Id.VSub_Name db> 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: <Id.Left_DollarParen '$('> child: (C {<pr_str>} {(DQ ($ Id.VSub_DollarName '$k'))}) ) ) } ) terminator: <Id.Op_Semi _> ) ] ) redirects: [(redir op:<Id.Redir_GreatAnd '>&'> loc:(redir_loc.Fd fd:1) arg:{<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 op:<Id.Redir_GreatAnd '>&'> loc:(redir_loc.Fd fd:1) arg:{<2>})] do_fork: T ) ] spids: [342 343 356 -1] ) ] ) (command.ShFunction name: print_db body: (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: <Id.VSub_Name db> 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: {($ Id.VSub_DollarName '$i')} ) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (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: <Id.Lit_ArithVarLike i> right: {<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: <Id.Left_DollarSingleQuote '$\''> tokens: [<Id.Char_OneChar '\\n'>] multiline: F ) } spids: [433] ) (assign_pair lhs: (sh_lhs_expr.Name name:sorted) op: assign_op.Equal rhs: { (sh_array_literal left: <Id.Op_LParen _> words: [ { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [ (command.ForEach iter_name: l iter_words: [ { (braced_var_sub token: <Id.VSub_Name escaped_keys> 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: <Id.Op_Semi _> ) ] ) ) (C {<sort>}) ] negated: F ) ) } ] ) } spids: [438] ) ] ) (C {<unset>} {<IFS>}) (command.ForEach iter_name: k iter_words: [ { (DQ (braced_var_sub token: <Id.VSub_Name sorted> 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: <Id.Left_DollarParen '$('> child: (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: <Id.VSub_Name db> bracket_op: (bracket_op.ArrayIndex expr: {(DQ ($ Id.VSub_DollarName '$unescaped'))} ) ) } spids: [507] ) ] ) (C {<echo>} { (DQ <' ['> ($ Id.VSub_DollarName '$k') <']='> (command_sub left_token: <Id.Left_DollarParen '$('> child: (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: <Id.Op_Semi _> ) (C {<echo>}) ] ) (command.CommandList children: [(command.Sentence child:(C {<print_db>}) terminator:<Id.Op_Semi _>) (C {<echo>})] ) (C {<echo>} {(SQ <'PREAMBLE=$(cat <<'>) (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\\''>) <EOF> (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\\''>) } ) (C {<echo>} {(DQ ($ Id.VSub_DollarName '$PREAMBLE'))}) (C {<echo>} {<EOF>}) (command.CommandList children: [ (command.Sentence child: (C {<echo>} {(word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\)'>)}) terminator: <Id.Op_Semi _> ) (C {<echo>}) ] ) (C {<echo>} {(SQ <'POSTAMBLE=$(cat <<'>) (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\\''>) <EOF> (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\\''>) } ) (C {<echo>} {(DQ ($ Id.VSub_DollarName '$POSTAMBLE'))}) (C {<echo>} {<EOF>}) (command.CommandList children: [ (command.Sentence child: (C {<echo>} {(word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\)'>)}) terminator: <Id.Op_Semi _> ) (C {<echo>}) ] ) (C {<echo>} {(DQ ($ Id.VSub_DollarName '$POSTAMBLE'))}) ] )