| 1 | ---
 | 
| 2 | default_highlighter: oils-sh
 | 
| 3 | in_progress: true
 | 
| 4 | ---
 | 
| 5 | 
 | 
| 6 | Block Literals
 | 
| 7 | ==============
 | 
| 8 | 
 | 
| 9 | Procs are shell like-functions, but they can have declared parameters, and lack
 | 
| 10 | dynamic scope.
 | 
| 11 | 
 | 
| 12 |     proc p(name, age) {
 | 
| 13 |       echo "$name is $age years old"
 | 
| 14 |     }
 | 
| 15 | 
 | 
| 16 |     p alice 42  # => alice is 42 years old
 | 
| 17 | 
 | 
| 18 | Blocks are fragments of code within `{ }` that can be passed to builtins (and
 | 
| 19 | eventually procs):
 | 
| 20 | 
 | 
| 21 |     cd /tmp {
 | 
| 22 |       echo $PWD  # prints /tmp
 | 
| 23 |     }
 | 
| 24 |     echo $PWD  # prints original dir
 | 
| 25 | 
 | 
| 26 | - See [YSH Idioms](idioms.html) for examples of procs.
 | 
| 27 | 
 | 
| 28 | <!--
 | 
| 29 | 
 | 
| 30 | - Block literals are  a syntax for unevaluated code like `cd /tmp { echo $ PWD
 | 
| 31 |   }`. They are instances of "quotation type" `value.Command`.  The  `{ }`
 | 
| 32 |   syntax is niec for passing to blocks to procs, but they can be passed to
 | 
| 33 |   funcs as well.
 | 
| 34 | 
 | 
| 35 | You don't define blocks.  Blocks are data types.
 | 
| 36 | 
 | 
| 37 | -->
 | 
| 38 | 
 | 
| 39 | <div id="toc">
 | 
| 40 | </div>
 | 
| 41 | 
 | 
| 42 | ## Syntax
 | 
| 43 | 
 | 
| 44 | These forms work:
 | 
| 45 | 
 | 
| 46 |     cd / {
 | 
| 47 |       echo $PWD
 | 
| 48 |     }
 | 
| 49 |     cd / { echo $PWD }
 | 
| 50 |     cd / { echo $PWD }; cd / { echo $PWD }
 | 
| 51 | 
 | 
| 52 | These are syntax errors:
 | 
| 53 | 
 | 
| 54 |     a=1 { echo bad };        # assignments can't take blocks
 | 
| 55 |     >out.txt { echo bad };   # bare redirects can't take blocks
 | 
| 56 |     break { echo bad };      # control flow can't take blocks
 | 
| 57 | 
 | 
| 58 | Runtime error:
 | 
| 59 | 
 | 
| 60 |     local a=1 { echo bad };  # assignment builtins can't take blocks
 | 
| 61 | 
 | 
| 62 | Caveat: Blocks Are Space Sensitive
 | 
| 63 | 
 | 
| 64 |     cd {a,b}  # brace substitution
 | 
| 65 |     cd { a,b }  # tries to run command 'a,b', which probably doesn't exist
 | 
| 66 | 
 | 
| 67 | Quoting of `{ }` obeys the normal rules:
 | 
| 68 | 
 | 
| 69 |     echo 'literal braces not a block' \{ \}
 | 
| 70 |     echo 'literal braces not a block' '{' '}'
 | 
| 71 | 
 | 
| 72 | ## Semantics 
 | 
| 73 | 
 | 
| 74 | TODO: This section has to be implemented and tested.
 | 
| 75 | 
 | 
| 76 | ### Use `eval` to evaluate a block
 | 
| 77 | 
 | 
| 78 | TODO: use `eval`
 | 
| 79 | 
 | 
| 80 | 
 | 
| 81 |     proc p(&block) {
 | 
| 82 |       echo '>'
 | 
| 83 |       $block    # call it?
 | 
| 84 |                 # or maybe just 'block' -- it's a new word in the "proc" namespace?
 | 
| 85 |       echo '<'
 | 
| 86 |     }
 | 
| 87 | 
 | 
| 88 |     # Invoke it
 | 
| 89 |     p {
 | 
| 90 |       echo 'hello'
 | 
| 91 |     }
 | 
| 92 |     # Output:
 | 
| 93 |     # >
 | 
| 94 |     # hello
 | 
| 95 |     # <
 | 
| 96 | 
 | 
| 97 | ### Hay Config Blocks
 | 
| 98 | 
 | 
| 99 | TODO
 | 
| 100 | 
 | 
| 101 | ### Errors
 | 
| 102 | 
 | 
| 103 | Generally, errors occur *inside* blocks, not outside:
 | 
| 104 | 
 | 
| 105 |     cd /tmp {
 | 
| 106 |        cp myfile /bad   # error happens here
 | 
| 107 |        echo 'done'
 | 
| 108 |     }                   # not here
 | 
| 109 | 
 | 
| 110 | ### Control Flow
 | 
| 111 | 
 | 
| 112 | - `break` and `continue` are disallowed inside blocks.
 | 
| 113 | - You can exit a block early with `return` (not the enclosing function).
 | 
| 114 | - `exit` is identical: it exits the program.
 | 
| 115 | 
 | 
| 116 | ### 16 Use Cases for Blocks
 | 
| 117 | 
 | 
| 118 | See 16 use cases on the blog: [Sketches of YSH
 | 
| 119 | Features](https://www.oilshell.org/blog/2023/06/ysh-features.html).
 | 
| 120 | 
 | 
| 121 | <!--
 | 
| 122 | ### Configuration Files
 | 
| 123 | 
 | 
| 124 | Evaluates to JSON (like YAML and TOML):
 | 
| 125 | 
 | 
| 126 |     server foo {
 | 
| 127 |       port = 80
 | 
| 128 |     }
 | 
| 129 | 
 | 
| 130 | And can also be serialized as command line flags.
 | 
| 131 | 
 | 
| 132 | Replaces anti-patterns:
 | 
| 133 | 
 | 
| 134 | - Docker has shell
 | 
| 135 | - Ruby DSLs like chef have shell
 | 
| 136 | - similar to HCL I think, and Jsonnet?  But it's IMPERATIVE.  Probably.  It
 | 
| 137 |   might be possible to do dataflow variables... not sure.  Maybe x = 1 is a
 | 
| 138 |   dataflow var?
 | 
| 139 | 
 | 
| 140 | ### Awk Dialect
 | 
| 141 | 
 | 
| 142 |     BEGIN {
 | 
| 143 |       end
 | 
| 144 |     }
 | 
| 145 | 
 | 
| 146 |     when x {
 | 
| 147 |     }
 | 
| 148 | 
 | 
| 149 | ### Make Dialect
 | 
| 150 | 
 | 
| 151 |     rule foo.c : foo.bar {
 | 
| 152 |       cc -o out @srcs
 | 
| 153 |     }
 | 
| 154 | 
 | 
| 155 | ### Flag Parsing to replace getopts
 | 
| 156 | 
 | 
| 157 | Probably use a block format.  Compare with Python's optparse.o
 | 
| 158 | 
 | 
| 159 | See issue.
 | 
| 160 | 
 | 
| 161 | ### Unit Tests
 | 
| 162 | 
 | 
| 163 | Haven't decided on this yet.
 | 
| 164 | 
 | 
| 165 |     check {
 | 
| 166 |     }
 | 
| 167 | -->
 | 
| 168 | 
 |