...(compound_word parts: [ (Token id: Id.Lit_Chars col: 0 length: 2 span_id: 0 line: (SourceLine line_num:1 content:'hi\'\n' src:(source.MainFile path:hi)) tval: hi ) (single_quoted left: (Token id: Id.Left_SingleQuote col: 2 length: 1 span_id: 1 line: (SourceLine line_num:1 content:'hi\'\n' src:(source.MainFile path:hi)) tval: '\'' ) tokens: [ (Token id: Id.Lit_Chars col: 3 length: 1 span_id: 2 line: (SourceLine line_num:1 content:'hi\'\n' src:(source.MainFile path:hi)) tval: '\n' ) (Token id: Id.Lit_Chars col: 0 length: 13 span_id: 3 line: (SourceLine line_num: 2 content: 'single quoted\'"double\n' src: (source.MainFile path:hi) ) tval: 'single quoted' ) ] right: (Token id: Id.Right_SingleQuote col: 13 length: 1 span_id: 4 line: (SourceLine line_num: 2 content: 'single quoted\'"double\n' src: (source.MainFile path:hi) ) tval: '\'' ) ) (double_quoted left: (Token id: Id.Left_DoubleQuote col: 14 length: 1 span_id: 5 line: (SourceLine line_num: 2 content: 'single quoted\'"double\n' src: (source.MainFile path:hi) ) tval: '"' ) parts: [ (Token id: Id.Lit_Chars col: 15 length: 7 span_id: 6 line: (SourceLine line_num: 2 content: 'single quoted\'"double\n' src: (source.MainFile path:hi) ) tval: 'double\n' ) (Token id: Id.Lit_Chars col: 0 length: 7 span_id: 7 line: (SourceLine line_num:3 content:'quoted\n' src:(source.MainFile path:hi)) tval: 'quoted\n' ) ] right: (Token id: Id.Right_DoubleQuote col: 0 length: 1 span_id: 8 line: (SourceLine line_num:4 content:'"there\n' src:(source.MainFile path:hi)) tval: '"' ) ) (Token id: Id.Lit_Chars col: 1 length: 5 span_id: 9 line: (SourceLine line_num:4 content:'"there\n' src:(source.MainFile path:hi)) tval: there ) ] ) s = '\'\nsingle quoted\'"double\nquoted\n"' s = "'\nsingle quoted'" s = 'hi' (compound_word parts: [ (Token id: Id.Lit_VarLike col: 4 length: 4 span_id: 3 line: (SourceLine line_num:1 content:'ls; foo=42' src:(source.MainFile path:'')) tval: 'foo=' ) (Token id: Id.Lit_Chars col: 8 length: 2 span_id: 4 line: (SourceLine line_num:1 content:'ls; foo=42' src:(source.MainFile path:'')) tval: 42 ) ] ) (compound_word parts: [ (Token id: Id.Lit_VarLike col: 4 length: 5 span_id: 9 line: (SourceLine line_num:1 content:'ls; foo+=X' src:(source.MainFile path:'')) tval: 'foo+=' ) (Token id: Id.Lit_Chars col: 9 length: 1 span_id: 10 line: (SourceLine line_num:1 content:'ls; foo+=X' src:(source.MainFile path:'')) tval: X ) ] ) ('\n---', '${array[0]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${array[5+5]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.ArrayIndex expr: (arith_expr.Binary .... op_id: Id.Arith_Plus left: {} right: {} ) ) right: ) }('\n---', '${array[@]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) }('\n---', '${array[*]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.WholeArray op_id:Id.Arith_Star) right: ) }('\n---', '${#}') {(${ Id.VSub_Pound '#')}('\n---', '${!}') {(${ Id.VSub_Bang '!')}('\n---', '${?}') {(${ Id.VSub_QMark '?')}('\n---', '${var}') {(${ Id.VSub_Name var)}('\n---', '${15}') {(${ Id.VSub_Number 15)}('\n---', '${#var}') { (braced_var_sub left: token: var_name: var prefix_op: right: ) }('\n---', '${!ref}') { (braced_var_sub left: token: var_name: ref prefix_op: right: ) }('\n---', '${##}') { (braced_var_sub left: token: var_name: '#' prefix_op: right: ) }('\n---', '${array[0]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${array[@]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) }('\n---', '${#array[0]}') { (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${!array[0]}') { (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${var#prefix}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${!var#prefix}') { (braced_var_sub left: token: var_name: var prefix_op: suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${#var#prefix}') Got expected ParseError: ('\n---', '${##2}') Got expected ParseError: --MULTI ('\n---', '${undef:-') Got expected ParseError: ('\n---', '${undef:-$') Got expected ParseError: ('\n---', '${undef:-$F') Got expected ParseError: ('\n---', '${x@') Got expected ParseError: ('\n---', '${x@Q') Got expected ParseError: ('\n---', '${x%') Got expected ParseError: ('\n---', '${x/') Got expected ParseError: ('\n---', '${x/a/') Got expected ParseError: ('\n---', '${x/a/b') Got expected ParseError: ('\n---', '${x:') Got expected ParseError: ('\n---', '--foo=$func()') {<--foo> args: (ArgList left: positional:[] named:[] right:) ) }('\n---', '$func()trailer') { (word_part.FuncCall name: args: (ArgList left: positional:[] named:[] right:) ) }('\n---', '--foo=$func()trailer') {<--foo> args: (ArgList left: positional:[] named:[] right:) ) }('\n---', '${#@}') { (braced_var_sub left: token: var_name: '@' prefix_op: right: ) }('\n---', '${#11}') { (braced_var_sub left: token: var_name: 11 prefix_op: right: ) }('\n---', '${#str}') { (braced_var_sub left: token: var_name: str prefix_op: right: ) }('\n---', '${#array[0]}') { (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${#array["key"]}') { (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.ArrayIndex expr:{(DQ )}) right: ) }('\n---', '@words') {(word_part.Splice name: var_name:words)}('\n---', '.@words') {<.> }('\n---', '.@words.') {<.> <.>}('\n---', '@words[') Got expected ParseError: ('\n---', '@words.') Got expected ParseError: ('\n---', '@func()') { (word_part.FuncCall name: args: (ArgList left: positional:[] named:[] right:) ) }('\n---', '$(echo @func())') { (command_sub left_token: child: (C {} { (word_part.FuncCall name: args: (ArgList left: positional:[] named:[] right:) ) } ) right: ) }('\n---', '$(($(echo @func())))') { (word_part.ArithSub anode: { (command_sub left_token: child: (C {} { (word_part.FuncCall name: args: (ArgList left: positional: [] named: [] right: ) ) } ) right: ) } ) }('\n---', '@func().') Got expected ParseError: { ch:'$')}\$ 0 (Token id: Id.Lit_EscapedChar col: 0 length: 2 span_id: 0 line: (SourceLine line_num:1 content:'\\$' src:(source.MainFile path:word_parse_test.py)) tval: '\\$' ) {(SQ )}'' 0 (Token id: Id.Left_SingleQuote col: 0 length: 1 span_id: 0 line: (SourceLine line_num:1 content:'\'\'' src:(source.MainFile path:word_parse_test.py)) tval: '\'' ) {(SQ )}'sq' 0 (Token id: Id.Left_SingleQuote col: 0 length: 1 span_id: 0 line: (SourceLine line_num:1 content:'\'sq\'' src:(source.MainFile path:word_parse_test.py)) tval: '\'' ) {(DQ )}"" 0 (Token id: Id.Left_DoubleQuote col: 0 length: 1 span_id: 0 line: (SourceLine line_num:1 content:'""' src:(source.MainFile path:word_parse_te.st.py)) tval: '"' ) {(DQ )}"dq" 0 (Token id: Id.Left_DoubleQuote col: 0 length: 1 span_id: 0 line: (SourceLine line_num:1 content:'"dq"' src:(source.MainFile path:word_parse_test.py)) tval: '"' ) { (command_sub left_token: child: (C {} {} {}) right: ) }$(echo command sub) 0 (Token id: Id.Left_DollarParen col: 0 length: 2 span_id: 0 line: (SourceLine line_num: 1 content: '$(echo command sub)' src: (source.MainFile path:word_parse_test.py) ) tval: '$(' ) { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }$(( 1 + 2 )) 0 (Token id: Id.Left_DollarDParen col: 0 length: 3 span_id: 0 line: (SourceLine line_num:1 content:'$(( 1 + 2 ))' src:(source.MainFile path:word_parse_test.py)) tval: '$((' ) {}~user 0 (Token id: Id.Lit_TildeLike col: 0 length: 5 span_id: 0 line: (SourceLine line_num:1 content:'~user' src:(source.MainFile path:word_parse_test.py)) tval: '~user' ) { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }${var#} 0 (Token id: Id.Left_DollarBrace col: 0 length: 2 span_id: 0 line: (SourceLine line_num:1 content:'${var#}' src:(source.MainFile path:word_parse_test.py)) tval: '${' ) ('\n---', '${var/pat/replace}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {} replace_mode: Id.Undefined_Tok slash_tok: ) right: ) }('\n---', '${var//pat/replace}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {} replace_mode: Id.Lit_Slash slash_tok: ) right: ) }('\n---', '${var/%pat/replace}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {} replace_mode: Id.Lit_Percent slash_tok: ) right: ) }('\n---', '${var/#pat/replace}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {} replace_mode: Id.Lit_Pound slash_tok: ) right: ) }('\n---', '${var/pat}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: (rhs_word.Empty) replace_mode: Id.Undefined_Tok slash_tok: ) right: ) }('\n---', '${var//pat}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: (rhs_word.Empty) replace_mode: Id.Lit_Slash slash_tok: ) right: ) }('\n---', '${var/pat//}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {} replace_mode: Id.Undefined_Tok slash_tok: ) right: ) }('\n---', '${var/pat///}') { (braced_var_sub left: t..oken: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: { } replace_mode: Id.Undefined_Tok slash_tok: ) right: ) }('\n---', '${var/pat/"//"}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {(DQ <'//'>)} replace_mode: Id.Undefined_Tok slash_tok: ) right: ) }('\n---', '${var////\\\\/}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.PatSub pat: {} replace: {(word_part.EscapedLiteral token: ch:'\\') } replace_mode: Id.Lit_Slash slash_tok: ) right: ) }--- ls "foo" () {}{(DQ )}--- $(( 1 + 2 )) () { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }--- $(echo $(( 1 )) ) () { (command_sub left_token: child: (C {} {(word_part.ArithSub anode:{})}) right: ) }--- echo ${#array[@]} b () {}{ (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) }{}--- echo $(( ${#array[@]} )) () {}{ (word_part.ArithSub anode: { (braced_var_sub left: token: var_name: array prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ) }--- echo ${@%suffix} () {}{ (braced_var_sub left: token: var_name: '@' suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }--- ${@} () {(${ Id.VSub_At '@')}--- echo ${var,,} () {}{ (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }--- echo ${var,,?} () {}{ (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }--- ${\ foo} () {(${ Id.VSub_Name foo)}--- ${foo\ } () {(${ Id.VSub_Name foo)}--- ${foo#\ yo} () { (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }--- "${foo#\ yo}" () { (DQ (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) }--- 1 + 2 () {}{}--- a + b () {}{}--- $a * $b () {($ Id.VSub_DollarName a)}{($ Id.VSub_DollarName b)}--- ${a} * ${b} () {(${ Id.VSub_Name a)}{(${ Id.VSub_Name b)}--- $(echo 1) * $(echo 2) () {(command_sub left_token: child:(C {} {<1>}) right:)}{(command_sub left_token: child:(C {} {<2>}) right:)}--- `echo 1` + 2 () { (command_sub left_token: child: (C {} {<1>}) right: ) }{}--- $((1 + 2)) * $((3 + 4)) () { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }{ (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }--- 'single quoted' () {(SQ <'single quoted'>)}--- "${a}" + "${b}" () {(DQ (${ Id.VSub_Name a))}{(DQ (${ Id.VSub_Name b))}--- $# + $$ () {($ Id.VSub_Pound '#')}{($ Id.VSub_Dollar '$')}--- $(( x[0] < 5 )) () { (word_part.ArithSub anode: (arith_expr.Binary op_id: Id.Arith_Less left: (arith_expr.Binary op_id: Id.Arith_LBracket left: ($ Id.Lit_ArithVarLike x) right: {} ) right: {} ) ) }--- $(( ++i )) () { (word_part.ArithSub anode: (arith_expr.UnaryAssign op_id:Id.Arith_DPlus child:($ Id.Lit_ArithVarLike i)) ) }--- $(( i++ )) () { (word_part.ArithSub anode: (arith_expr.UnaryAssign op_id:Id.Node_PostDPlus child:($ Id.Lit_ArithVarLike i)) ) }--- $(( x -= 1)) () { (word_part.ArithSub anode: (arith_expr.BinaryAssign op_id: Id.Arith_MinusEqual left: ($ Id.Lit_ArithVarLike x) right: {} ) ) }--- $(( x |= 1)) () { (word_part.ArithSub anode: (arith_expr.BinaryAssign op_id: Id.Arith_PipeEqual left: ($ Id.Lit_ArithVarLike x) right: {} ) ) }--- $(( x[0] = 1 )) () { (word_part.ArithSub anode: (arith_expr.BinaryAssign op_id: Id.Arith_Equal left: (arith_expr.Binary op_id: Id.Arith_LBracket left: ($ Id.Lit_ArithVarLike x) right: {} ) right: {} ) ) }--- $(( 1 | 0 )) () { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Pipe left:{} right:{}) ) }--- $((0x$size)) () {(word_part.ArithSub anode:{ ($ Id.VSub_DollarName size)})}('\n---', '$(( (1+2) ))') { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }('\n---', '$(( (1+2) ))') { (word_part.ArithSub anode: (arith_expr.Binary op_id:Id.Arith_Plus left:{} right:{}) ) }('\n---', '${foo:0}') { (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Slice begin:{}) right: ) }('\n---', '${foo:0:1}') { (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Slice begin:{} length:{}) right: ) }('\n---', '${foo:1+2:2+3}') { (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Slice begin: (arith_expr.Binary op_id: Id.Arith_Plus left: {} right: {} ) length: (arith_expr.Binary op_id: Id.Arith_Plus left: {} right....... ---------------------------------------------------------------------- Ran 24 tests in 0.112s OK : {} ) ) right: ) }('\n---', '${foo::1}') { (braced_var_sub left: token: var_name: foo suffix_op: (suffix_op.Slice length:{}) right: ) }('\n---', '${var:-default]}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{<'default]'>}) right: ) }('\n---', '~/git/oilshell/oil') { <'/git/oilshell/oil'>}('\n---', '~andy/git/oilshell/oil') { <'/git/oilshell/oil'>}('\n---', '~andy_c/git/oilshell/oil') { <'/git/oilshell/oil'>}('\n---', '~andy.c/git/oilshell/oil') { <'/git/oilshell/oil'>}('\n---', '~andy-c/git/oilshell/oil') { <'/git/oilshell/oil'>}('\n---', '~andy-c:git/oilshell/oil') { <'git/oilshell/oil'>}('\n---', '${var#}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${var#prefix}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${var##}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${var##prefix}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${var%suffix}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${var%%suffix}') { (braced_var_sub left: token: var_name: var suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) }('\n---', '${name}') {(${ Id.VSub_Name name)}('\n---', '${name[0]}') { (braced_var_sub left: token: var_name: name bracket_op: (bracket_op.ArrayIndex expr:{}) right: ) }('\n---', '${array[@]}') { (braced_var_sub left: token: var_name: array bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) }