Commit Graph

100 Commits

Author SHA1 Message Date
Timothy Sample a1bd8d0681 Add basic option processing to the main script
* geesh/repl.scm (run-repl): Add optional port parameter.
* scripts/geesh.in: Add '--command' and '--stdin' flags, and if
neither flag is provided, treat the first argument as a file to
interpret.
2018-12-05 16:08:09 -05:00
Timothy Sample 271301e77d Add the cd and pwd built-ins
* geesh/built-ins/cd.scm: New file.
* geesh/built-ins/pwd.scm: New file.
* Makefile.am: Add them.
* geesh/built-ins.scm (*built-ins*): Add cd and pwd.
2018-12-05 16:08:09 -05:00
Timothy Sample 4ef6907851 Globalize the environment module
Instead of passing around references to the environment, just treat it
as a global.  The old way was just the remains of an idea to make the
environment immutable and keep the interpreter from manipulating any
global state.  By making everything global and mutable, we will have
less impedance mismatch with POSIX going forward.

The following changelog is only a sketch, since nearly every function
has changed.

* geesh/environment.scm: Replace this module with one that treats the
environment as a global resource.
* tests/environment.scm: Delete file.
* Makefile.am: Remove it from the list of tests.
* geesh/shell.scm, geesh/eval.scm, geesh/repl.scm, geesh/word.scm,
geesh/built-ins/break.scm, geesh/built-ins/continue.scm,
geesh/built-ins/echo.scm, geesh/built-ins/export.scm,
geesh/built-ins/false.scm, geesh/built-ins/read.scm,
geesh/built-ins/readonly.scm, geesh/built-ins/set.scm,
geesh/built-ins/true.scm, geesh/built-ins/unset.scm: Remove 'env'
parameters and use the new environment module.
* .dir-locals.el: Update indentation of functions that no longer take
an 'env' parameter and add with-arguments, with-environ, and
with-variables from the new environment module.
* tests/shell.scm, tests/word.scm: Update environment creation and
manipulation in tests.
2018-12-05 16:08:09 -05:00
Timothy Sample 0d41cec2d6 Add the set built-in
* geesh/environment.scm: Export set-environment-arguments!.
* geesh/built-ins/set.scm: New file.
* Makefile.am: Add them.
* geesh/built-ins.scm: Add set.
2018-12-05 16:08:09 -05:00
Timothy Sample 671a926011 Add readonly built-in
* geesh/built-ins/utils.scm: New file.
* geesh/built-ins/readonly.scm: New file.
* Makefile.am: Add them.
* geesh/built-ins/export.scm (split-assignments): Move to utils.
* geesh/built-ins.scm (*special-built-ins*): Add readonly.
2018-12-05 16:08:09 -05:00
Timothy Sample c5ac41b0f8 Check for EOF in read built-in
* geesh/built-ins/read.scm (main): Check for EOF.
2018-12-05 16:08:09 -05:00
Timothy Sample 279ef0cd35 Add the export built-in
* geesh/built-ins/export.scm: New file.
* Makefile.am: Add it.
* geesh/built-ins.scm (*special-built-ins*): Add export.
2018-12-05 16:08:09 -05:00
Timothy Sample e784aaa658 Add export and read-only attributes to variables
* geesh/environment.scm (<variable>): New record type.
(make-environment): Initialize variables as records.
(var-ref): Extract value from record.
(set-var!): Inject value into record and throw an error if variable
is read-only.
(set-var-export!): New public function.
(set-var-read-only!): New public function.
(environment->environ): Only include exported variables.
2018-12-05 16:08:09 -05:00
Timothy Sample d4bb8ae438 Add 'true' built-in
* geesh/built-ins/true.scm: New file.
* Makefile.am: Add it.
* geesh/built-ins.scm (*built-ins*): Add true.
2018-12-05 16:08:09 -05:00
Timothy Sample eae9857f5e Add case and cond support
* geesh/eval.scm (eval-sh) Handle '<sh-case>' and '<sh-cond>' cases.
2018-12-05 16:08:09 -05:00
Timothy Sample 3ffcd0c498 Add case and cond semantics
* geesh/shell.scm (sh:case): New public function.
(sh:cond): New public function.
2018-12-05 16:08:09 -05:00
Timothy Sample 4d6e91565e Add while and until loop support
* geesh/eval.scm (eval-sh): Handle '<sh-while>' and '<sh-until>'
cases.
2018-12-05 16:08:09 -05:00
Timothy Sample 2335298226 Add while and until loop semantics
* geesh/shell.scm (sh:while): New public function.
(sh:until): New public function.
2018-12-05 16:08:09 -05:00
Timothy Sample 06db42088a Add 'break' and 'continue'
* geesh/environment.scm (<environment>): Add 'break-prompt' and
'continue-prompt' fields.
(make-environment): Initialize them.
* geesh/shell.scm (sh:for): Setup break and continue prompts.
* geesh/built-ins/break.scm: New file.
* geesh/built-ins/continue.scm: New file.
* Makefile.am: Add them.
* geesh/built-ins.scm (*special-built-ins*): Add break and continue.
2018-12-05 16:08:09 -05:00
Timothy Sample 1601a8d8b3 Add pattern returns from 'expand-word'
* geesh/word.scm (expand-word): Change the 'split?' keyword argument
to 'output', accepting one of 'fields', 'string', or 'pattern'.
(word->qword): Update calls.
* geesh/eval.scm (eval-word): Same as 'expand-word' above.
(eval-redir): Update call.
(eval-sh): Update calls.
2018-12-05 16:08:09 -05:00
Timothy Sample 6df6eb3f1d Add pathname expansion
* geesh/word.scm (qword->pattern): New function.
(expand-pathnames): New function.
(expand-word): Use it to expand pathnames when possible.
2018-12-05 16:08:09 -05:00
Timothy Sample e1ab2ccd94 Add pattern module
* geesh/pattern.scm: New file.
* tests/pattern.scm: New file.
* Makefile.am: Add them.
2018-12-05 16:08:09 -05:00
Timothy Sample 7e3bbda4cb Add 'unset' built-in
* geesh/environment.scm (delete-environment-vars!): New public function.
(delete-environment-functions!): New public function.
* geesh/built-ins/unset.scm: New file.
* Makefile.am: Add it.
* geesh/built-ins.scm: Enable 'unset'.
2018-12-05 16:08:09 -05:00
Timothy Sample 76bbe01edc Let the 'exec' built-in manipulate files
* geesh/shell.scm (sh:set-redirects): New public function.
* geesh/eval.scm (eval-sh): Use it to handle 'exec' specially when
called with redirects but no arguments.
2018-12-05 16:08:09 -05:00
Timothy Sample 0c0227d523 Add support for file descriptors 3 to 9
* geesh/shell.scm (*fd-count*) Increase to 10.
(current-3-port, current-4-port, current-5-port, current-6-port,
current-7-port, current-8-port, current-9-port): New variables.
(fd->current-port): Handle file descriptors 3 to 9.
2018-12-05 16:08:09 -05:00
Timothy Sample 5a4816dabf Add 'exec-let' support
* geesh/eval.scm (eval-sh): Handle '<sh-exec-let>'.
2018-12-05 16:08:09 -05:00
Timothy Sample d0e5c3f5ae Handle redirect errors in 'eval'
* geesh/eval.scm (eval-sh): Handle redirect errors.
2018-12-05 16:08:09 -05:00
Timothy Sample 0ae52599c4 Preserve input and error ports in substitutions
This was simply a mistake.

* geesh/shell.scm (sh:substitute-command): Leave 'current-input-port'
and 'current-error-port' alone.
* tests/shell.scm: Remove tests that check that input and error gets
ignored during substitutions.
2018-12-05 16:08:09 -05:00
Timothy Sample 085c35a833 Use 'parameterize' for redirects
Instead of saving and restoring redirects manually, if we let them all
be parameters (like 'current-input-port'), we can use 'parameterize'
and make Guile take of this for us.  As a side-effect of this change,
redirect errors get handled.

* geesh/shell.scm (save-and-set-redirect): Rename this...
(redir->parameter+port): ...to this and change the return value to be
a pair consisting of a parameter and a port.
(restore-saved-port): Remove function.
(sh:with-redirects): Use 'parameterize' to effect redirects rather
than updating them and restoring them manually.
2018-12-05 16:08:09 -05:00
Timothy Sample b92630b39d Flush ports before forking
There are two issues that arise due to output port buffers and
forking.  If we run Scheme code in a child process, we need to avoid
copying buffered output into the child process.  Otherwise, the
buffered output could be written twice.  If we run non-Scheme
code (i.e., exec), we need to flush the ports to ensure proper
sequencing of writes since the non-Scheme code will not know about the
buffered output and will write its output before the buffer gets
flushed.

* geesh/shell.scm (exec-utility): Flush all ports before forking.
(%subshell): Ditto.
2018-12-05 16:08:09 -05:00
Timothy Sample 4b7d2404f3 Fix handling of non-whitespace IFS separators
* geesh/word.scm (string-tokenize*): New function.
(split-fields): Use it to handle non-whitespace IFS separators.
* tests/word.scm: Add tests.
2018-12-05 16:08:09 -05:00
Timothy Sample 3e6d7830a9 Fix splitting nested words
* geesh/word.scm (split-fields): Move handling of list words into
'wedge-apart' so that they get handled in recursive calls.
* tests/word.scm: Add a test for this.
2018-12-05 16:08:01 -05:00
Timothy Sample 765e91eb88 Elide unquoted empty and unset variables
* geesh/word.scm (split-fields): Make an empty string yield zero
fields (an empty list).
* tests/word.scm: Update tests and add tests to make sure that quoted
empty strings are preserved.
2018-12-05 16:06:14 -05:00
Timothy Sample eb4b8bb61b Handle '$@' and '$*' parameters
* geesh/word.scm (parameter-ref): Handle '$@' and '$*' parameters.
2018-12-05 16:06:14 -05:00
Timothy Sample e6347dc37f Handle field splitting with quoted '$@'
* geesh/word.scm (split-fields): Handle a special '<sh-at>' qword
form, so that a quoted '$@' reference can still be split.
(argument-separator): New function.
(remove-quotes): Handle the '<sh-at>' form when it should not be
split.  This requires knowing how to concatenate arguments, so add an
'ifs' parameter.
(expand-word): Pass 'ifs' to 'remove-quotes'.
2018-12-05 16:05:36 -05:00
Timothy Sample 7fe940e852 Use '$IFS' as a string when splitting words
We used to model 'IFS' as a character set, but when handling special
parameters, the order of the characters matters.  Since it is also an
environment variable, it makes sense to treat as a string (rather than
a list).

* geesh/word.scm (split-fields): Treat 'ifs' as a string instead of a
character set.
(expand-word): Get 'ifs' from the environment if available or use a
default string otherwise.
2018-12-03 20:20:56 -05:00
Timothy Sample 3fad06a756 Add function definition support
* geesh/eval.scm (eval-sh): Handle '<sh-defun>'.
2018-12-03 20:19:56 -05:00
Timothy Sample 93a5cba568 Add function call semantics
* geesh/shell.scm (exec-let): Find and use functions when appropriate.
2018-12-03 20:19:39 -05:00
Timothy Sample 58f5644d2a Add 'arguments' field to environment
* geesh/environment.scm (<environment>): Add an 'arguments' field.
(make-environment): Add an optional 'arguments' parameter.
(with-environment-arguments): New public function.
.dir-locals.el: Indent it nicely.
2018-12-03 20:19:22 -05:00
Timothy Sample f03b438009 Keep track of functions in the environment
* geesh/environment.scm (<environment>): Add a 'functions' field.
(make-environment): Initialize it to the empty list.
(environment-function-ref): New public function.
(define-environment-function!): New public function.
2018-12-03 20:18:50 -05:00
Timothy Sample e43e6a88c4 Add 'status' field to environment
Instead of using an environment variable named '?', we will use a
special environment field called 'status'.  This lets us get rid of a
lot of number-string conversions (since an environment variable has to
have a string value).

* geesh/environment.scm (<environment>): Add a 'status' field.
(make-environment): Set it to 0 by default.
* geesh/repl.scm (run-repl): Use new field in place of '?' variable.
* geesh/shell.scm (exec-utility, sh:and, sh:exec-let, sh:for, sh:not,
sh:or, sh:pipeline, sh:subshell, sh:substitute-command): Ditto.
* geesh/word.scm (parameter-ref): New function that handles both
special parameters (e.g., '?') and variables.
(parameter-ref*): Like 'var-ref*', but for 'parameter-ref'.
(word->qword): Replace 'var-ref' and 'var-ref*' with 'parameter-ref'
and 'parameter-ref*' respectively.
2018-12-03 20:17:56 -05:00
Timothy Sample 801e9c8012 Use '$?' as the return value of the REPL
* geesh/repl.scm (run-repl): Return the value of '$?' (converted to a
number).
2018-12-03 20:16:01 -05:00
Timothy Sample fb493cc5f4 Process the return value of built-ins
* geesh/shell.scm (sh:exec-let): Set the '$?' variable to the return
value of built-in utilities.
2018-12-03 20:15:40 -05:00
Timothy Sample 21b862d326 Add the 'false' utility
* geesh/built-ins/false.scm: New file.
* Makefile.am: Add it.
* geesh/built-ins.scm (*built-ins*): Define 'false'.
2018-12-03 20:15:19 -05:00
Timothy Sample 5dae68d90a Make echo return a status code
* geesh/built-ins/echo.scm (echo): Return a status a code.
2018-12-03 20:14:57 -05:00
Timothy Sample 339f59d639 Add the 'read' utility
* geesh/built-ins/read.scm: New file.
* Makefile.am: Add it.
* geesh/built-ins.scm (*built-ins*): Define 'read'.
2018-12-03 20:14:36 -05:00
Timothy Sample 2db7833d61 Add for-loop support
* geesh/eval.scm (eval-sh): Handle '<sh-for>'.
2018-12-03 20:13:23 -05:00
Timothy Sample db56b1cc0a Add for-loop semantics
* geesh/shell.scm (sh:for): New public function.
* .dir-locals.el: Indent it nicely.
2018-12-03 20:12:51 -05:00
Timothy Sample 46ae7129d5 Add boolean support
* geesh/eval.scm (eval-sh): Handle '<sh-and>', '<sh-not>', and '<sh-or>'.
2018-12-03 20:12:22 -05:00
Timothy Sample 240ca130e8 Add boolean semantics
* geesh/shell.scm (sh:and, sh:not, sh:or): New public functions.
2018-12-03 20:12:02 -05:00
Timothy Sample 211e73ca43 Add pipeline support
* geesh/eval.scm (eval-sh): Handle '<sh-pipeline>'.
2018-12-03 20:11:28 -05:00
Timothy Sample 37f4ce6ea8 Add pipeline semantics
* geesh/shell.scm (swap-and-shift-pairs): New function.
(make-pipes): New function.
(plumb): New function.
(sh:pipeline): New public function.
* tests/shell.scm: Test it.
2018-12-03 20:09:55 -05:00
Timothy Sample 553b8f2b96 Use ports for redirects
Before, we were using raw file descriptors.  This worked okay, but
there was interference caused by port buffering.  Doing everything at
the port level avoids this problem, and has the added benefit of
allowing one to use the 'current-*-port' parameters with the shell
module (in a limited way, but there is room for improvement).

* geesh/shell.scm (*fd-count*): New variable.
(fd->current-port): New function.
(install-current-ports!): New function.
(exec-utility): Use it to set up file descriptors.
(save-and-install-redirect!): Rename this...
(save-and-set-redirect): ...to this and modify the current port
parameters instead of raw file descriptors.
(restore-saved-fdes!): Rename this...
(restore-saved-port): ...to this.
(sh:with-redirects): Adjust to use the renamed functions.
(sh:substitute-command): Parameterize the current ports directly
instead of using redirects.
* tests/shell.scm: Add tests to check if port buffers cause problems.
2018-12-03 20:07:53 -05:00
Timothy Sample 00d50fe7fd Add '-n' support to echo
* geesh/built-ins/echo.scm (echo): Omit trailing newline when '-n' is
the first argument.
2018-12-03 20:07:22 -05:00
Timothy Sample a6ceb8f3f2 Add command substitution support
* geesh/eval.scm (eval-word): Parameterize 'eval-cmd-sub' so that the
word module can substitute commands.
2018-12-03 20:07:06 -05:00