diff --git a/design-docs/0009-oil-builtins.md b/design-docs/0009-oil-builtins.md new file mode 100644 index 0000000000..6c99bd0285 --- /dev/null +++ b/design-docs/0009-oil-builtins.md @@ -0,0 +1,151 @@ +Oil Builtins +------------ + +We're upgrading builtins. + +### Compatible Enhancements + + +### Related Shell Options + +#### `shopt -s longopts` + +Builtins take long flags, e.g. + + read -timeout 1.0 + read -timeout=1.0 + + read --timeout 1.0 + read --timeout=1.0 + +So flags can't be smooshed together: + + set -eu # NO + set -e -u # YES + set -o errexit -o nounset # better + +### Changed by Options + + +#### `shopt -s oil-echo` + +- echo accepts -- for consistency. We want `mybuiltin @flags -- @args` to be + valid no matter what. +- It accepts `-sep` and `-end` flags like Python's `print`. + - The default separator is a NEWLINE. This is more useful and less + confusing. + - The default end is a NEWLINE, like Python. +- `echo -n` is an alias for `echo -end ''` +- `echo -e` is disallowed in favor of C strings: + - `echo $'\n'` (unfortunate wart, but statically parsed and has to exist) + - `var s=c'\n'; echo $s` + +Examples: + + echo -sep ' ' -- @words # instead of the default $'\n' + + echo -end $'\r\n' -- @words # plausible use case? + +A raw `write` can be an alias for this: + + echo -sep '' -end '' -- @ARGV + + +#### `shopt -s oil-eval-builtin` + +The args aren't joined. Zero args or More than one arg is an error + +Also accepts -- (but there are no flags). + +- Or should it allow parse time flags? + - eval -O oil-parse-at ? + - or instead of -O and +O, should it be -s and -u ? + +#### `shopt -s oil-trap` + +It takes a function name, not a code string + +This is better for parse time options (`shopt -s oil-parse-*`). The parsing is +dictated by the surrounding file. + +#### `shopt -s oil-test-builtin` + +test -file + + +### Builtins Upgraded With a Block + +#### cd, shopt, env + +- we're not changing `set`, only `shopt` +- `env` is backward-compatible with /usr/bin/env + +- should `shopt` unify `set` and `shopt`? + - the `-o` flag is ugly + + +#### fork, wait + +- fork is new. wait is old. + +#### each + +This is "xargs v2", and it takes both flags and a block. + +### Other Builtins + +#### repr + +For debugging variable representations. + +Should there also be a 'trace' builtin? To show line numbers? Better than +xtrace. Or maybe just CALL it `xtrace` or `xt`. + +Or maybe it should be + + repr -v x y # -v flag shows soure location and indents with + # call stack maybe? + +#### push + +To append to an array. The name is borrowed from Perl/JavaScript. + +#### log, die (polyfill) + +And maybe 'write'? Although the sep can't be ''. + +#### dirname, basename (optimizations) + +#### use (modules with namespaces) + + +### Deprecated + +- **All assignment builtins** are deprecated, except `export`. +- `export` becomes a regular builtin that only takes names, not an assignment + builtin with statically and dynamically parsed `name=val`. + - An `env` block is generally better. + - And you can use `declare -x`. + +Maybe there should be `shopt -u old-builtins` (make them invisible, default is +visible). + +- `pushd`, `popd` -- use `cd ~/src { ... }` instead + - and `dirs` + +- alias, unalias -- not sure how we would deprecate + - bash already has `shopt -s expand_alias` + +- `source` in favor of use? +- `printf` in favor of statically parsed `${x %02d}` + +- `getopts` in favor of something nicer, `optspec` or `argspec` based on oil + blocks? + - or just `opts` or `args`? + +Speculative: + +- `command` and `builtin` could be subsumed by some more general $PATH + mechanism? + + diff --git a/doc/osh-quick-ref-toc.txt b/doc/osh-quick-ref-toc.txt index c087b516d7..c1b677e00a 100644 --- a/doc/osh-quick-ref-toc.txt +++ b/doc/osh-quick-ref-toc.txt @@ -113,10 +113,9 @@ BUILTIN COMMANDS X [Unsupported] enable X [Oil Builtins] log die common functions dirname basename simple optimization - env shopt compatible, and takes a block + cd shopt env compatible, and takes a block fork wait replaces & and (), takes a block use source with namespace, file-relative - write sugar for 'do write(s)' push sugar for 'do array.push( @(a b) )' SHELL OPTIONS diff --git a/oil_lang/builtin_oil.py b/oil_lang/builtin_oil.py index 9ba03bd482..7961b9fac3 100644 --- a/oil_lang/builtin_oil.py +++ b/oil_lang/builtin_oil.py @@ -2,12 +2,11 @@ """ builtin_oil.py - Oil builtins. -fork, wait - wait is in osh/builtin_process.py, so I guess fork can go there. -env - builtin_compat.py? -log, die - oil-polyfill.sh -shopt, set - add blocks to osh/builtin_pure.py -write -push +See design-docs/0009-oil-builtins.md for notes. + +env: Should be in builtin_compat.py? + +It's sort of like xargs too. """ from __future__ import print_function diff --git a/test/parse-errors.sh b/test/parse-errors.sh index 98e51b003c..a55b31ed12 100755 --- a/test/parse-errors.sh +++ b/test/parse-errors.sh @@ -464,6 +464,16 @@ EOF _error-case 'var x = $(var x = 1))' } +push-builtin() { + set +o errexit + + # Unterminated + _error-case 'push' + #_error-case 'push notarray' # returns status 1 + _error-case 'a=(1 2); push a' + _error-case 'a=(1 2); push a zz' # points at 'zz' +} + cases-in-strings() { set +o errexit @@ -497,6 +507,7 @@ cases-in-strings() { invalid-brace-ranges # osh/braces.py oil-language # oil_lang/ + push-builtin } # Cases in their own file