*** Running test-parse-osh (command.CommandList children: [ (C {} {<-s>} {} {}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left: words: [ {($ Id.VSub_DollarName myglobal)} { (single_quoted left: tokens: [ ] right: ) } { (braced_var_sub left: token: var_name: z suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) } ] ) ) (C {<'spec/bin/argv.py'>} {}) (C {} { token: var_name: myarray prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ) (C {}) (C {} {} {} {(SQ <'1 2'>)} { (braced_var_sub left: token: var_name: myglobal suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) } ) (C {<'spec/bin/argv.py'>} {}) (C {} { token: var_name: myarray prefix_op: bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) } ) (C {}) (command.ForEach iter_names: [item] iterable: (for_iter.Words words: [ { (DQ (braced_var_sub left: token: var_name: myarray bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] ) body: (command.DoGroup children:[(C {} {(DQ <' '> ($ Id.VSub_DollarName item))})]) redirects: [] ) ] ) (command.CommandList children: [ (command.ShFunction name: argv body: (BraceGroup left: children: [ (command.Sentence child: (C {<'spec/bin/argv.py'>} {(DQ ($ Id.VSub_At '@'))}) terminator: ) ] redirects: [] right: ) ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left: token: var_name: regex bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] ) body: (command.DoGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.IndexedName left: name: flags index: { (braced_var_sub 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: [] ) ] ) redirects: [] ) (C {} { (DQ (braced_var_sub left: token: var_name: flags bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ) (C {} {<-s>} {} {}) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (sh_array_literal left: words:[{} {}]) ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (sh_array_literal left: words:[]) ) (command.ForEach iter_names: [r] iterable: (for_iter.Words words:[{}]) body: (command.DoGroup children: [ (C {} { } {(DQ <'--regex='> ($ Id.VSub_DollarName r))}) ] ) redirects: [] ) (C {} {}) ] ) (command.CommandList children: [ (C {} {(SQ <'This is a shell script with OSH extensions!'>)}) (C {}) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.Binary op: left: (Const Id.Expr_DecInt 1) right: (expr.Binary op: left: (Const Id.Expr_DecInt 2) right: (Const Id.Expr_DecInt 3) ) ) ) (C {} {(DQ <'x: '> ($ Id.VSub_DollarName x))}) (command.PlaceMutation keyword: lhs: [(place_expr.Var name:)] op: rhs: (Const Id.Expr_DecInt 1) ) (C {} {(DQ <'x: '> ($ Id.VSub_DollarName x))}) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.List elts: [(Const Id.Expr_DecInt 1) (Const Id.Expr_DecInt 2) (Const Id.Expr_DecInt 3)] ctx: expr_context.Store ) ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.Binary op: left: (subscript obj:(Var mylist) indices:[(Const Id.Expr_DecInt 1)]) right: (Const Id.Expr_DecInt 10) ) ) (C {} {(DQ <'y: '> ($ Id.VSub_DollarName y))}) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.Binary op: left: (Var mylist) right: (expr.List elts: [(Const Id.Expr_DecInt 4) (Const Id.Expr_DecInt 5)] ctx: expr_context.Store ) ) ) (C {} {} {}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:)} spids: [130] ) ] redirects: [] ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (DQ <'Oil string'>) ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.Binary op: left:(Var str1) right:(Var str2)) ) (C {} {(DQ <'str3 = '> ($ Id.VSub_DollarName str3))}) ] ) (command.CommandList children: [ (command.ShFunction name: argv body: (BraceGroup left: children: [ (C {} {<-c>} {(SQ <'import sys;print(sys.argv[1:])'>)} {}) ] redirects: [] right: ) ) (command.ShFunction name: show body: (BraceGroup left: children: [(C {} {(SQ <'====='>)}) (C {} {}) (C {})] redirects: [] right: ) ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (sh_array_literal left: words: [ {} {} { <.sh>} (word.BracedTree parts: [(word_part.BracedTuple words:[{} {}]) <.com>] ) {(SQ )} { (DQ <'dq '> (braced_var_sub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) } ] ) ) (C {} {}) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (command_sub left_token: child: (C {} {} {} { <.sh>} (word.BracedTree parts: [(word_part.BracedTuple words:[{} {}]) <.com>] ) {(SQ )} { (DQ <'dq '> (braced_var_sub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) } ) right: ) ) (C {} {($ Id.VSub_DollarName cmd_sub)}) (C {} { (word_part.ExprSub left: child: (expr.Binary op: left: (SQ <'quoted '>) right: (expr.Binary op: left: (SQ <'words '>) right: (DQ <'dq '> (braced_var_sub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word:{}) right: ) ) ) ) ) } ) ] ) (command.CommandList children: [ (C {} { (single_quoted left: tokens: [ ] right: ) } ) (command.VarDecl keyword: lhs: [(name_type name:)] rhs: (expr.Binary op: left: (Const Id.Expr_DecInt 1) right: (expr.Binary op: left: (Const Id.Expr_DecInt 2) right: (Const Id.Expr_DecInt 3) ) ) ) (C {} { child: (C {} {}) right: ) right: (DQ (command_sub left_token: child: (C {} {}) right: ) ) ) ) (C {} { children: [ (command.Sentence child: (C {<'spec/bin/argv.py'>} {(DQ ($ Id.VSub_At '@'))}) terminator: ) ] redirects: [] right: ) ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:)} spids: [51] ) ] redirects: [] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:} {<-n>} {(DQ (${ Id.VSub_Name CONFIG_HAVE_FOO))} {} ) terminator: ) ] ) action: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:} {<-n>} {(DQ (${ Id.VSub_Name CONFIG_HAVE_BAR))} {} ) terminator: ) ] ) action: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left:)} spids: [110] ) ] redirects: [] ) ] spids: [92 107] ) ] else_action: [] redirects: [] ) (C {} {(${ Id.VSub_Name flags)}) (C {} {<-o>} {}) (C {} {<-s>} {} {}) (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: (sh_array_literal left: words:[]) ) (command.If arms: [ (if_arm cond: (condition.Shell commands: [ (command.Sentence child: (C {} {<-n>} {($ Id.VSub_DollarName CONFIG_HAVE_FOO)}) terminator: ) ] ) action: [ (C {} { } {<--foo> } {<--bar>})] spids: [228 237] ) ] else_action: [] redirects: [] ) (C {} {}) ] ) (command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name left: children: [ (C {} { ) ) (command.ShFunction name: f body: (BraceGroup left: children: [ (C {} { ) ) (C {}) ] ) 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-03-08 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.