*** Running test-parse-osh --- (command.CommandList children: [ (command.Simple blame_tok: more_env: [] words: [ {} { (SingleQuoted left: sval: "one\ntwo" right: ) } ] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:a typ:(TypeExpr tok: name:Int))] rhs: (expr.Binary op: left: (expr.Const c: val:(value.Int i:1)) right: (expr.Binary op: left: (expr.Const c: val:(value.Int i:2)) right: (expr.Const c: val:(value.Int i:3)) ) ) ) (command.Simple blame_tok: more_env: [] words: [{} { rhs: (expr.Var left: name:b) ) terminator: ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) ] ) (command.Mutation keyword: lhs: [] op: rhs: (expr.Const c: val:(value.Int i:1)) ) (command.VarDecl keyword: lhs: [(NameType left: name:y)] rhs: (expr.Var left: name:a) ) (command.VarDecl keyword: lhs: [(NameType left: name:z)] rhs: (expr.Var left: name:b) ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:mycmd)] rhs: (expr.Binary op: left: (CommandSub left_token: child: (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) right: ) right: (DQ (CommandSub left_token: child: (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) right: ) ) ) ) (command.Simple blame_tok: more_env: [] words: [{} { left:(${ Id.VSub_Name b) right:(DQ (${ Id.VSub_Name b))) ) (command.Simple blame_tok: more_env: [] words: [{} { left: (expr.Binary op: left: (expr.Const c: val:(value.Int i:1)) right: (expr.Const c: val:(value.Int i:2)) ) right: (expr.Const c: val:(value.Int i:3)) ) ) (command.Simple blame_tok: more_env: [] words: [{} { left: (expr.Const c: val:(value.Int i:4)) right: (expr.Const c: val:(value.Int i:5)) ) ) (command.Simple blame_tok: more_env: [] words: [{} { left: (expr.Const c: val:(value.Int i:6)) right: (expr.Const c: val:(value.Int i:7)) ) ) (command.Simple blame_tok: more_env: [] words: [{} { words: [ {($ myglobal)} { (SingleQuoted left: sval: "line\n" right: ) } { (BracedVarSub left: token: var_name: z suffix_op: (suffix_op.Unary op: arg_word: {} ) right: ) } ] right: ) ) (command.Simple blame_tok: more_env: [] words: [ { } {} ] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} { child: (expr.FuncCall func: (expr.Var left: name:len) args: (ArgList left: pos_args: [(expr.Var left: name:myarray)] named_args: [] right: ) ) right: ) } ] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} {} {(SQ "1 2")} { (BracedVarSub left: token: var_name: myglobal suffix_op: (suffix_op.Unary op: arg_word: {} ) right: ) } ] typed_args: (ArgList left: pos_args: [(expr.Var left: name:myarray)] named_args: [] right: ) do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ { } {} ] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} { child: (expr.FuncCall func: (expr.Var left: name:len) args: (ArgList left: pos_args: [(expr.Var left: name:myarray)] named_args: [] right: ) ) right: ) } ] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{}] do_fork: T ) (command.ForEach keyword: iter_names: [item] iterable: (for_iter.YshExpr e: (expr.Var left: name:myarray) blame: ) body: (BraceGroup left: children: [ (command.Simple blame_tok: more_env: [] words: [{} {(DQ ($ item))}] do_fork: T ) ] right: ) ) ] ) --- (command.CommandList children: [ (command.ShAssignment left: children: [ (command.Simple blame_tok: more_env: [] words: [{} { ) ) (command.ShFunction name_tok: name: f body: (BraceGroup left: children: [ (command.Simple blame_tok: more_env: [] words: [{} { ) ) (command.Simple blame_tok: more_env:[] words:[{}] do_fork:T) ] ) --- (command.CommandList children: [ (command.Simple blame_tok: more_env: [] words: [{} {(SQ "This is a shell script with OSH extensions!")}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{}] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:x)] rhs: (expr.Binary op: left: (expr.Const c: val:(value.Int i:1)) right: (expr.Binary op: left: (expr.Const c: val:(value.Int i:2)) right: (expr.Const c: val:(value.Int i:3)) ) ) ) (command.Simple blame_tok: more_env: [] words: [{} {(DQ ($ x))}] do_fork: T ) (command.Mutation keyword: lhs: [] op: ($ x))}] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:mylist)] rhs: (expr.List left: elts: [ (expr.Const c: val:(value.Int i:1)) (expr.Const c: val:(value.Int i:2)) (expr.Const c: val:(value.Int i:3)) ] ctx: expr_context.Store ) ) (command.VarDecl keyword: lhs: [(NameType left: name:y)] rhs: (expr.Binary op: left: (Subscript left: obj: (expr.Var left: name:mylist) index: (expr.Const c: val:(value.Int i:1)) ) right: (expr.Const c: val:(value.Int i:10)) ) ) (command.Simple blame_tok: more_env: [] words: [{} {(DQ ($ y))}] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:list2)] rhs: (expr.Binary op: left: (expr.Var left: name:mylist) right: (expr.List left: elts: [ (expr.Const c: val:(value.Int i:4)) (expr.Const c: val:(value.Int i:5)) ] ctx: expr_context.Store ) ) ) (command.Simple blame_tok: more_env: [] words: [{} {} {}] do_fork: T ) (command.ShAssignment left: lhs: [(NameType left: name:str2)] rhs: (DQ ) ) (command.VarDecl keyword: lhs: [(NameType left: name:str3)] rhs: (expr.Binary op: left: (expr.Var left: name:str1) right: (expr.Var left: name:str2) ) ) (command.Simple blame_tok: more_env: [] words: [{} {(DQ children: [ (command.Simple blame_tok: more_env: [] words: [ {} {} {(SQ "import sys;print(sys.argv[1:])")} {} ] do_fork: T ) ] right: ) ) (command.ShFunction name_tok: name: show body: (BraceGroup left: children: [ (command.Simple blame_tok: more_env: [] words: [{} {(SQ "=====")}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{}] do_fork: T ) ] right: ) ) (command.VarDecl keyword: lhs: [(NameType left: name:strarray)] rhs: (ShArrayLiteral left: words: [ {} {} { } (word.BracedTree parts: [ (word_part.BracedTuple words:[{} {}]) ] ) {(SQ sq)} { (DQ (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word: {} ) right: ) ) } ] right: ) ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:cmd_sub)] rhs: (CommandSub left_token: child: (command.Simple blame_tok: more_env: [] words: [ {} {} {} { } (word.BracedTree parts: [ (word_part.BracedTuple words: [{} {}] ) ] ) {(SQ sq)} { (DQ (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word: {} ) right: ) ) } ] do_fork: T ) right: ) ) (command.Simple blame_tok: more_env: [] words: [{} {($ cmd_sub)}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} { (word_part.ExprSub left: child: (expr.Binary op: left: (expr.Binary op: left:(SQ "quoted ") right:(SQ "words ")) right: (DQ (BracedVarSub left: token: var_name: x suffix_op: (suffix_op.Unary op: arg_word: {} ) right: ) ) ) right: ) } ] do_fork: T ) ] ) --- (command.CommandList children: [ (command.ShFunction name_tok: name: argv body: (BraceGroup left: children: [ (command.Sentence child: (command.Simple blame_tok: more_env: [] words: [ { } {(DQ ($ Id.VSub_At))} ] do_fork: T ) terminator: ) ] right: ) ) (command.ShAssignment left: arms: [ (IfArm keyword: cond: (condition.Shell commands: [ (command.Sentence child: (command.Simple blame_tok: more_env: [] words: [ {} {} {(DQ (${ Id.VSub_Name CONFIG_HAVE_FOO))} {} ] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.ShAssignment left: more_env: [] words: [ {} {} {(DQ (${ Id.VSub_Name CONFIG_HAVE_BAR))} {} ] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.ShAssignment left: )} ) ] ) ] then_tok: ) ] else_action: [] fi_kw: ) (command.Simple blame_tok: more_env: [] words: [{} {(${ Id.VSub_Name flags)}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [{} {} {}] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} {} {} {} ] do_fork: T ) (command.Mutation keyword: lhs: [] op: rhs: (DQ ) ) (command.Mutation keyword: lhs: [] op: words: [] right: ) ) (command.If if_kw: arms: [ (IfArm keyword: cond: (condition.Shell commands: [ (command.Sentence child: (command.Simple blame_tok: more_env: [] words: [{} {} {($ CONFIG_HAVE_FOO)}] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.Simple blame_tok: more_env: [] words: [ {} {} { pos_args: [(expr.Var left: name:flags)] named_args: [] right: ) do_fork: T ) ] then_tok: ) ] else_action: [] fi_kw: ) (command.If if_kw: arms: [ (IfArm keyword: cond: (condition.Shell commands: [ (command.Sentence child: (command.Simple blame_tok: more_env: [] words: [{} {} {($ CONFIG_HAVE_BAR)}] do_fork: T ) terminator: ) ] ) then_kw: action: [ (command.Simple blame_tok: more_env: [] words: [{} {} {}] typed_args: (ArgList left: pos_args: [(expr.Var left: name:flags)] named_args: [] right: ) do_fork: T ) ] then_tok: ) ] else_action: [] fi_kw: ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) ] ) --- (command.CommandList children: [ (command.ShFunction name_tok: name: argv body: (BraceGroup left: children: [ (command.Sentence child: (command.Simple blame_tok: more_env: [] words: [ { } {(DQ ($ Id.VSub_At))} ] do_fork: T ) terminator: ) ] right: ) ) (command.ShAssignment left: words: [{} {}] right: ) } ) ] ) (command.ShAssignment left: words:[] right:)} ) ] ) (command.ForEach keyword: iter_names: [r] iterable: (for_iter.Words words: [ { (DQ (BracedVarSub left: token: var_name: regex bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] ) semi_tok: body: (command.DoGroup left: children: [ (command.ShAssignment left: pairs: [ (AssignPair left: lhs: (sh_lhs.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 token: var_name: flags bracket_op: (bracket_op.WholeArray op_id:Id.Lit_At) right: ) ) } ] do_fork: T ) (command.Simple blame_tok: more_env: [] words: [ {} {} {} {} ] do_fork: T ) (command.VarDecl keyword: lhs: [(NameType left: name:regex2)] rhs: (ShArrayLiteral left: words: [{} {}] right: ) ) (command.VarDecl keyword: lhs: [(NameType left: name:flags2)] rhs: (ShArrayLiteral left: words: [] right: ) ) (command.ForEach keyword: iter_names: [r] iterable: (for_iter.Words words:[{}]) semi_tok: body: (command.DoGroup left: children: [ (command.Simple blame_tok: more_env: [] words: [{} {(DQ pos_args: [(expr.Var left: name:flags2)] named_args: [] right: ) do_fork: T ) ] right: ) ) (command.Simple blame_tok: more_env: [] words: [{} {}] do_fork: T ) ] ) OK test-parse-osh *** Running test-run-osh ysh/testdata/array-rewrite-1.sh --- ['--regex=old1', '--regex=old2'] append "--regex=$r" (flags2) ^ ysh/testdata/array-rewrite-1.sh:40: 'append' doesn't accept flag -- append "--regex=$r" (flags2) ^ ysh/testdata/array-rewrite-1.sh:40: 'append' doesn't accept flag -- [] ysh/testdata/array-rewrite-2.sh --- ['--foo=/etc/path', 'with', 'spaces'] ['--foo=/etc/path with spaces'] ysh/testdata/sigil-pairs.sh --- ===== ['@ARGV'] ===== ['@ARGV'] ===== ['@ARGV'] ysh/testdata/array-splice-demo.osh --- shopt -s oil-parse-at static-word-eval ^~~~~ ysh/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 ysh/testdata/assign.osh skipping ysh/testdata/assign.osh ysh/testdata/hello.osh --- This is a shell script with OSH extensions! x: 7 x: 8 y: 20 pp cell list2 ^~~~ ysh/testdata/hello.osh:26: 'pp' got invalid action 'cell' str3 = shell stringOil string ysh/testdata/no-dynamic-scope.osh skipping ysh/testdata/no-dynamic-scope.osh OK test-run-osh *** Running test-run-ysh --- + 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 Dict->reverse() method is from Python. hello world 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 42 --- 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 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 failure 2024 Here I am! could be anything really date: unrecognized option '--wrong-flag' Try 'date --help' for more information. there was an error number 2024-08-04 2024 OK test-run-ysh ysh/run.sh: 3 tests passed.