*** Running test-parse-osh --- (command.CommandList children: [ (command.Simple words: [{} {<-s>} {} {}] redirects: [] more_env: [] do_fork: T ) (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left: words: [ {($ Id.VSub_DollarName myglobal)} { (SingleQuoted left: tokens: [ ] right: ) } { (BracedVarSub left: token: var_name: z suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) } ] ) ) (command.Simple words: [{<'spec/bin/argv.py'>} {}] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [ {} { token: var_name: myarray prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ] redirects: [] more_env: [] do_fork: T ) (command.Simple words:[{}] redirects:[] more_env:[] do_fork:T) (command.Simple words: [ {} {} {} {(SQ <'1 2'>)} { (BracedVarSub left: token: var_name: myglobal suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) } ] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [{<'spec/bin/argv.py'>} {}] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [ {} { token: var_name: myarray prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ] redirects: [] more_env: [] do_fork: T ) (command.Simple words:[{}] redirects:[] more_env:[] do_fork:T) (command.ForEach keyword: iter_names: [item] iterable: (for_iter.Words words: [ { (DQ (BracedVarSub left: token: var_name: myarray bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] ) body: (command.DoGroup left: children: [ (command.Simple words: [{} {(DQ <' '> ($ Id.VSub_DollarName item))}] redirects: [] more_env: [] do_fork: T ) ] right: ) redirects: [] ) ] ) --- (command.CommandList children: [ (command.ShFunction name: argv body: (BraceGroup left: children: [ (command.Sentence child: (command.Simple words: [{<'spec/bin/argv.py'>} {(DQ ($ Id.VSub_At '@'))}] redirects: [] more_env: [] do_fork: T ) terminator: ) ] redirects: [] right: ) ) (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left: token: var_name: regex bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] ) body: (command.DoGroup left: children: [ (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.IndexedName left: name: flags index: { (BracedVarSub left: token: var_name: flags prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ) op: assign_op.Equal rhs: {(DQ <'--regex='> ($ Id.VSub_DollarName r))} spids: [76] ) ] redirects: [] ) ] right: ) redirects: [] ) (command.Simple words: [ {} { (DQ (BracedVarSub left: token: var_name: flags bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [{} {<-s>} {} {}] redirects: [] more_env: [] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (ShArrayLiteral left: words:[{} {}]) ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (ShArrayLiteral left: words:[]) ) (command.ForEach keyword: iter_names: [r] iterable: (for_iter.Words words:[{}]) body: (command.DoGroup left: children: [ (command.Simple words: [ {} { } {(DQ <'--regex='> ($ Id.VSub_DollarName r))} ] redirects: [] more_env: [] do_fork: T ) ] right: ) redirects: [] ) (command.Simple words: [{} {}] redirects: [] more_env: [] do_fork: T ) ] ) --- (command.CommandList children: [ (command.Simple words: [{} {(SQ <'This is a shell script with OSH extensions!'>)}] redirects: [] more_env: [] do_fork: T ) (command.Simple words:[{}] redirects:[] more_env:[] do_fork:T) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.Binary op: left: (expr.Const c:) right: (expr.Binary op: left: (expr.Const c:) right: (expr.Const c:) ) ) ) (command.Simple words: [{} {(DQ <'x: '> ($ Id.VSub_DollarName x))}] redirects: [] more_env: [] do_fork: T ) (command.PlaceMutation keyword: lhs: [(place_expr.Var name:)] op: rhs: (expr.Const c:) ) (command.Simple words: [{} {(DQ <'x: '> ($ Id.VSub_DollarName x))}] redirects: [] more_env: [] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.List elts: [ (expr.Const c:) (expr.Const c:) (expr.Const c:) ] ctx: expr_context.Store ) ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.Binary op: left: (Subscript obj: (expr.Var name:) indices: [(expr.Const c:)] ) right: (expr.Const c:) ) ) (command.Simple words: [{} {(DQ <'y: '> ($ Id.VSub_DollarName y))}] redirects: [] more_env: [] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.Binary op: left: (expr.Var name:) right: (expr.List elts: [(expr.Const c:) (expr.Const c:)] ctx: expr_context.Store ) ) ) (command.Simple words:[{} {} {}] redirects:[] more_env:[] do_fork:T) (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left:)} spids: [130] ) ] redirects: [] ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (DQ <'Oil string'>) ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.Binary op: left: (expr.Var name:) right: (expr.Var name:) ) ) (command.Simple words: [{} {(DQ <'str3 = '> ($ Id.VSub_DollarName str3))}] redirects: [] more_env: [] do_fork: T ) ] ) --- (command.CommandList children: [ (command.ShFunction name: argv body: (BraceGroup left: children: [ (command.Simple words: [ {} {<-c>} {(SQ <'import sys;print(sys.argv[1:])'>)} {} ] redirects: [] more_env: [] do_fork: T ) ] redirects: [] right: ) ) (command.ShFunction name: show body: (BraceGroup left: children: [ (command.Simple words: [{} {(SQ <'====='>)}] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [{} {}] redirects: [] more_env: [] do_fork: T ) (command.Simple words:[{}] redirects:[] more_env:[] do_fork:T) ] redirects: [] right: ) ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (ShArrayLiteral left: words: [ {} {} { <.sh>} (word.BracedTree parts: [(word_part.BracedTuple words:[{} {}]) <.com>] ) {(SQ )} { (DQ <'dq '> (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) } ] ) ) (command.Simple words: [{} {}] redirects: [] more_env: [] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (CommandSub left_token: child: (command.Simple words: [ {} {} {} { <.sh>} (word.BracedTree parts: [(word_part.BracedTuple words:[{} {}]) <.com>] ) {(SQ )} { (DQ <'dq '> (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) } ] redirects: [] more_env: [] do_fork: T ) right: ) ) (command.Simple words: [{} {($ Id.VSub_DollarName cmd_sub)}] redirects: [] more_env: [] do_fork: T ) (command.Simple words: [ {} { (word_part.ExprSub left: child: (expr.Binary op: left: (SQ <'quoted '>) right: (expr.Binary op: left: (SQ <'words '>) right: (DQ <'dq '> (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) ) ) ) } ] redirects: [] more_env: [] do_fork: T ) ] ) --- (command.CommandList children: [ (command.Simple words: [ {} { (SingleQuoted left: tokens: [ ] right: ) } ] redirects: [] more_env: [] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType name:)] rhs: (expr.Binary op: left: (expr.Const c:) right: (expr.Binary op: left: (expr.Const c:) right: (expr.Const c:) ) ) ) (command.Simple words: [{} { child: (command.Simple words:[{} {}] redirects:[] more_env:[] do_fork:T) right: ) right: (DQ (CommandSub left_token: child: (command.Simple words:[{} {}] redirects:[] more_env:[] do_fork:T) right: ) ) ) ) (command.Simple words: [{} { children: [ (command.Sentence child: (command.Simple words: [{<'spec/bin/argv.py'>} {(DQ ($ Id.VSub_At '@'))}] redirects: [] more_env: [] do_fork: T ) terminator: ) ] redirects: [] right: ) ) (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left:)} spids: [51] ) ] redirects: [] ) (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left:} {<-n>} {(DQ (${ Id.VSub_Name CONFIG_HAVE_FOO))} {} ] redirects: [] more_env: [] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left:} {<-n>} {(DQ (${ Id.VSub_Name CONFIG_HAVE_BAR))} {} ] redirects: [] more_env: [] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left:)} spids: [110] ) ] redirects: [] ) ] spids: [92 107] ) ] else_action: [] fi_kw: redirects: [] ) (command.Simple words: [{} {(${ Id.VSub_Name flags)}] redirects: [] more_env: [] do_fork: T ) (command.Simple words:[{} {<-o>} {}] redirects:[] more_env:[] do_fork:T) (command.Simple words: [{} {<-s>} {} {}] redirects: [] more_env: [] do_fork: T ) (command.PlaceMutation keyword: lhs: [(place_expr.Var name:)] op: rhs: (DQ ) ) (command.PlaceMutation keyword: lhs: [(place_expr.Var name:)] op: rhs: (DQ <'/etc/path with spaces'>) ) (command.PlaceMutation keyword: lhs: [(place_expr.Var name:)] op: rhs: (ShArrayLiteral left: words:[]) ) (command.If if_kw: arms: [ (IfArm keyword: cond: (condition.Shell commands: [ (command.Sentence child: (command.Simple words: [{} {<-n>} {($ Id.VSub_DollarName CONFIG_HAVE_FOO)}] redirects: [] more_env: [] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.Simple words: [ {} { } {<--foo> } {<--bar>}] redirects: [] more_env: [] do_fork: T ) ] spids: [228 237] ) ] else_action: [] fi_kw: redirects: [] ) (command.Simple words: [{} {}] redirects: [] more_env: [] do_fork: T ) ] ) --- (command.CommandList children: [ (command.ShAssignment pairs: [ (AssignPair lhs: (sh_lhs_expr.Name left: children: [ (command.Simple words: [{} { ) ) (command.ShFunction name: f body: (BraceGroup left: children: [ (command.Simple words: [{} { ) ) (command.Simple words:[{}] redirects:[] more_env:[] do_fork:T) ] ) OK test-parse-osh *** Running test-run-oil --- hello 42 --- + Call in expression context: 3 + Inline call that coerces to string: 3 3 + Inline calls can be part of a word: --length=3 33 + Caveat: can't double quote. It would break programs. Should we add an option 'shopt -s parse_dparen'? --length=3 + Just as you can splice @myarray spam eggs ham + You can also splice the result of a function returning a sequence: Notes: - the sorted() function is from Python. - sorting utf-8 encoded strings as bytes is well-defined eggs ham spam Parts: aaa BB c join(parts): aaaBBc + Another way of doing it, without creating another variable: aaaBBc j => aaa:BB:c When IFS is the default, split(j) => aaa:BB:c When IFS is :, split(j) => aaa BB c + Since there is no word splitting of unquoted $(ls), here is an idiom: bin/ lib/ --- Hello world! first line second line Some string Some string $myvar Some string Some st Some s 11 DefaultValueIfFooIsMissingOrEmpty --- perhaps it's already here 42 I am just a normal string I am just a normal string and I am just a normal string I am just a normal string_ I am some string \n mu = μ Hello world! I'm just a string it's true I really do it's true I really do Not a file I'm an abstraction I'm passed hi OK 2023 Here I am! date: unrecognized option '--wrong-flag' Try 'date --help' for more information. will never be executed number 2023-05-03 2023 OK test-run-oil *** Running test-run-osh oil_lang/testdata/array-rewrite-1.sh --- ['--regex=old1', '--regex=old2'] ['--regex=new1', '--regex=new2'] oil_lang/testdata/array-rewrite-2.sh --- ['--foo=/etc/path', 'with', 'spaces'] ['--foo=/etc/path with spaces'] oil_lang/testdata/sigil-pairs.sh --- ===== ['@ARGV'] ===== ['@ARGV'] ===== ['@ARGV'] oil_lang/testdata/array-splice-demo.osh --- shopt -s oil-parse-at static-word-eval ^~~~~ 'oil_lang/testdata/array-splice-demo.osh':2: 'shopt' got invalid option 'oil-parse-at' ['@myarray'] len=3 ['@myarray'] len=6 global line default _ 1 2 global oil_lang/testdata/assign.osh skipping oil_lang/testdata/assign.osh oil_lang/testdata/hello.osh --- This is a shell script with OSH extensions! x: 7 x: 8 y: 20 list2 = (Cell exported:F readonly:F nameref:F val:(value.Obj obj:[1, 2, 3, 4, 5])) str3 = shell stringOil string oil_lang/testdata/no-dynamic-scope.osh skipping oil_lang/testdata/no-dynamic-scope.osh OK test-run-osh oil_lang/run.sh: 3 tests passed.