(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'))}) ] )