Commit Graph

123 Commits

Author SHA1 Message Date
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
Timothy Sample 6b6ca11bce Add command substitution semantics
* geesh/shell.scm (%subshell): New function factored out from 'subshell'.
(subshell): Use it.
(substitute-command): New public function.
* tests/shell.scm: Test it.
* .dir-locals.el: Indent it nicely.
2018-12-03 20:06:47 -05:00
Timothy Sample 3148f66a21 Add subshell support
* geesh/eval.scm (exps->thunk): New function.
(eval-sh): Handle '<sh-subshell>'.
2018-12-03 20:04:55 -05:00
Timothy Sample 8739cafad9 Add subshell semantics
* geesh/shell.scm (subshell): New public function.
* tests/shell.scm: Test it.
* .dir-locals.el: Indent it nicely.
2018-11-28 23:07:03 -05:00
Timothy Sample b5e77fc27b Add support for '<sh-begin>'
* geesh/eval.scm (eval-sh): Handle '<sh-begin>'.
2018-11-28 23:07:03 -05:00
Timothy Sample d171a8cd15 Add support for setting variables
* geesh/eval.scm (eval-sh): Handle '<sh-set!>' forms.
2018-11-28 23:07:03 -05:00
Timothy Sample 5384009f75 Add redirect support
* geesh/eval.scm (eval-redir): New function.
(exp->thunk): New function.
(eval-sh): Handle '<sh-with-redirects>' forms.
2018-11-28 23:07:03 -05:00
Timothy Sample e6f732ada9 Add redirect semantics
* geesh/shell.scm (save-and-install-redirect!): New function.
(restore-saved-fdes!): New function.
(with-redirects): New public function.
* tests/shell.scm: Test it.
* .dir-locals.el: Indent it nicely.
2018-11-28 23:07:03 -05:00
Timothy Sample 9b879623de Import existing variables into the REPL
* geesh/repl.scm (run-repl): Use existing environment variables for
the initial environment.
2018-11-28 23:07:03 -05:00
Timothy Sample 737ed6a1b7 Add function for reading an 'environ'
* geesh/environment.scm (environ->alist): New function.
* tests/environment.scm: Test it.
2018-11-28 23:07:03 -05:00
Timothy Sample d7d26534b2 Remove prompt-printing from the REPL
This will have to be added again later, but for now it is getting in
the way of automated testing.

* geesh/repl.scm (run-repl): Do not print prompts.
2018-11-28 23:07:03 -05:00
Timothy Sample 93b238d9fd Use parser and interpreter in the REPL
* geesh/repl.scm (run-repl): Actually read and evaluate input.
2018-11-28 23:07:03 -05:00
Timothy Sample 83c5d603ee Add eval module
* geesh/eval.scm: New file.
* Makefile.am: Add it.
2018-11-28 23:07:03 -05:00
Timothy Sample e1f139b841 Add support for built-ins, starting with 'echo'
* geesh/built-ins/echo.scm: New file.
* geesh/built-ins.scm: New file.
* Makefile.scm: Add them.
* geesh/shell.scm (exec-let): Include built-ins in command search.
* tests/shell.scm: Add a test for this.
2018-11-28 23:07:03 -05:00
Timothy Sample 7cc94e88e1 Add PATH searching
* geesh/shell.scm (slashless?) New function.
(split-search-path): New function.
(find-utility): New function.
(exec-let): Use them to search PATH for a utility when appropriate.
(exec): Update doc string.
* tests/shell.scm: Test it.
2018-11-28 23:07:03 -05:00
Timothy Sample 020adfc58b Add convenience function 'var-ref*'
* geesh/environment.scm (var-ref*): New public function.
* geesh/word.scm (word->qword): Use it to simplify things.
2018-11-28 23:07:03 -05:00
Timothy Sample da1746f2d6 Add missing doc strings in environment
* geesh/environment.scm (var-ref): Add doc string.
(set-var!): Add doc string.
2018-11-28 23:07:03 -05:00
Timothy Sample b9ec924bbe Add shell module
* geesh/shell.scm: New file.
* tests/shell.scm: New file.
* Makefile.am: Add them.
* tests/config.scm.in: New file.
* configure.ac: Add it.
* .gitignore: Add its generated form.
* .dir-locals.el: Add indentation rule for 'make-script'.
2018-11-28 23:07:03 -05:00
Timothy Sample cfb2b5b99b Add function for creating an 'environ'
* geesh/environment.scm (environment->environ): New function.
* tests/environment.scm: Test it.
2018-11-28 23:07:03 -05:00
Timothy Sample 9d834d0767 Fix parsing of for loops
* geesh/parser.scm (make-parser): When parsing for loops, make all
word-lists actual lists, and make an empty word-list with the 'in'
keyword yield an empty list rather than a reference to '$@'.
* tests/parser.scm: Update tests.
2018-11-28 23:04:30 -05:00
Timothy Sample 91cfdac307 Throw an error when missing a single quote
We used to loop forever here because of the lack of 'eof-object?'
test!

* geesh/lexer.scm (get-single-quotation): Throw an error on unexpected
end-of-file.
2018-11-28 23:00:10 -05:00
Timothy Sample 48e122c42f Fix AST for redirects and assignments
This should have been in 2b05199562, but
it was overlooked.

* geesh/parser.scm (make-parser): Splice in arguments in the redirect
case (to be consistent with the non-redirect case).
* tests/parser.scm: Add a test for this.
2018-11-28 22:09:34 -05:00
Timothy Sample 73414716bb Fix lexing of empty double quotes
* geesh/lexer.scm (get-double-quotation): Handle empty quotation.
* tests/lexer.scm: Add a test for this and for empty single
quotes (which already worked correctly).
2018-11-09 16:22:11 -05:00
Timothy Sample ff14ea0097 Rename '<sh-define>' to '<sh-defun>' and simplify
This change is already in the syntax document.

* geesh/parser.scm (make-parser): Rename '<sh-define>' to '<sh-defun>'
and use the function name directly instead of making it a singleton
list.
* tests/parser.scm: Update tests.
* .dir-locals.el: Update indentation.
2018-11-02 14:35:34 -04:00
Timothy Sample 2d61e91b27 Flatten AST form for pipelines
* geesh/parser.scm (make-parser): Splice in commands to keep
'<sh-pipeline>' flat.
* tests/parser.scm: Adjust and add tests accordingly.
2018-07-19 01:28:43 -04:00
Timothy Sample c79cea756d Rename '<sh-pipe>' to '<sh-pipeline>'
* doc/syntax.txt: Rename '<sh-pipe>' to '<sh-pipeline>'.
* geesh/parser.scm (make-parser): Ditto.
* tests/parser.scm: Fix test accordingly.
2018-07-19 01:19:00 -04:00
Timothy Sample 12b0354233 Rename '<sh-bang>' to '<sh-not>'
* geesh/parser.scm (make-parser): Rename '<sh-bang>' to '<sh-not>'.
2018-07-19 01:02:08 -04:00
Timothy Sample 2aa8615f9e Update AST for command substitutions
The AST generated by the parser did not match the syntax document.
However, neither were right.  This commit updates the syntax document
to describe a more consistent form, and fixes the code to follow it.

* doc/syntax.txt (word): Make the children of '<sh-cmd-sub>' a
possibly empty list of 'list's.
* geesh/lexer.scm (get-bracketed-command): Splice in children for
'<sh-cmd-sub>'.
(get-backquoted-command): Ditto.
* geesh/parser.scm (read-sh/bracketed): Make sure that result is
always a list.
(read-sh/backquoted): Ditto.
* tests/lexer.scm: Update tests accordingly.
* tests/parser.scm: Ditto.
2018-07-18 14:27:11 -04:00
Timothy Sample 5605ea993a Fix AST for quoted words
* geesh/lexer.scm (get-double-quotation): Make sure that '<sh-quote>'
forms only have one sub-word.
(get-unquoted-here-doc): Ditto.
* tests/lexer.scm: Update tests accordingly.
2018-07-18 09:29:33 -04:00
Timothy Sample a2f5403367 Fix field splitting on outside spaces
* geesh/word.scm (split-fields): Make outside spaces in word-parts
count for field splitting.
* tests/word.scm: Test this.
2018-07-18 02:33:08 -04:00
Timothy Sample da1d561f22 Fix AST to prevent empty '<sh-exec-let>' bindings
Commands with prefix redirects and no arguments or assignments would
generate '<sh-exec-let>' forms with an empty list for bindings.

* geesh/parser.scm (make-parser): Check for and handle an empty
assignment list.
* tests/parser.scm: Add test.
2018-07-17 22:27:10 -04:00
Timothy Sample 8b945a77a9 Fix reading multi-line quoted here-documents
* geesh/lexer.scm (get-quoted-here-doc): Use the correct line-reading
procedure when looping.
* tests/lexer.scm: Add test.
2018-07-17 21:59:09 -04:00
Timothy Sample a711daefa8 Fix an accidental AST format change
Commit b807b72a7c changed the AST format
when reading single commands by mistake.  It caused 'read-sh' to
return a singleton list.

* geesh/parser.scm (make-parser): Restore old behaviour.
(read-sh-all): Convert the output from the parser into a list.
* tests/parser.scm: Add tests to make sure 'read-sh-all' always
returns a list.
2018-07-16 13:09:51 -04:00
Timothy Sample b807b72a7c Add function for reading whole files
* geesh/parser.scm (read-sh-all): New public function for reading all
commands from a port.
(make-parser): Simplify AST forms when reading multiple commands.
* tests/parser.scm: Test it.
2018-07-16 10:18:59 -04:00
Timothy Sample 3ec520596c Fix 'read-sh' to default to current input port
* geesh/parser.scm (read-sh): Make the 'port' argument optional and
default to using 'current-input-port'.
2018-07-16 10:03:58 -04:00
Timothy Sample aabfd76beb Add parser support for here-documents
* geesh/parser.scm (map+fold): New function.
(merge-here-docs): New function.
(remove-quotes): New function.
(read-here-docs): New function.
(make-lexer): Handle newlines and here-document operators specially,
and emit special 'HERE-DOC' and 'HERE-DOC-SEP' tokens.
(make-parser): Use new tokens to support here-documents.
* tests/parser.scm: Add tests for here-documents.
2018-07-15 20:28:04 -04:00
Timothy Sample 3e0872ee3e Add a function for more accurate here-end lexing
When lexing a here-end word, expansions should be ignored.  That is,
"$x" should be treated as the string "$x" and not a reference to the
parameter named "x".

* geesh/lexer.scm (expansions?): New parameter to enable or disable
treating expansions specially.
(get-double-quotation): Use it.
(get-word): Ditto.
(get-here-end): New public function that reads a token without
treating expansions specially.
* tests/lexer.scm: Test it.
2018-07-15 20:16:27 -04:00
Timothy Sample a43d97dd09 Add here-document support to the lexer
* geesh/lexer.scm (get-quoted-here-doc): New function.
(get-unquoted-here-doc): New function.
(wrap-port-with-tab-trimming): New function.
(get-here-doc): New public function.
* tests/lexer.scm: Test it.
2018-07-15 20:16:17 -04:00
Timothy Sample be5b305de6 Fix dollar sign handling before non-name
If a dollar sign does not precede a name, it gets treated normally.

* geesh/lexer.scm (get-parameter): Return '#f' if the first character
is not a name character.
(get-parameter-expansion): Propagate the '#f' value.
(get-word): Replace the '#f' value with last character read.
(get-parameter-word): Ditto.
(get-double-quotation): Ditto.
* tests/lexer.scm: Test this.
2018-07-15 19:48:20 -04:00
Timothy Sample 01e8a7bf24 Fix line-joining when there are extra spaces
* geesh/lexer.scm (get-token): Add a case to skip an escaped newline.
* tests/lexer.scm: Test it.
2018-07-15 19:48:20 -04:00
Timothy Sample faf89ad173 Delay processing of dup redirect words
The right-hand side of a dup redirect ("<&" and ">&") may contain
expansions, so we cannot process it during parsing.

* geesh/parser.scm (process-dup-or-close-word): Remove function.
(make-parser): Return the raw word from a dup redirect instead of
trying to convert it into a number or a symbol.
* tests/parser.scm: Fix tests accordingly.
2018-07-15 19:47:10 -04:00
Timothy Sample 7cf2c3d806 Fix handling of reserved words in commands
A reserved word should not be special when it is an argument to a
command.  This commit makes the parser treat reserved words as normal
arguments.  Note that this change exposed problems in many of the
parser tests, which relied on reserved words delimiting commands where
they should not.  Those are now fixed.

* geesh/parser.scm (make-parser): Add reserved words to the default
'WORD*' rule, and use a new rule without reserved words for command
names.
* tests/parser.scm: Add a test for reserved words as arguments, and
fix old tests that relied on the old, incorrect behaviour.
2018-07-15 19:46:14 -04:00
Timothy Sample 7d27433a32 Use '<sh-begin>' for lists of commands
* geesh/parser.scm (make-parser): Put '<sh-begin>' at the beginning of
lists of commands.
* tests/parser.scm: Update tests accordingly.
2018-07-15 19:46:14 -04:00
Timothy Sample a5773e90eb Add word
* geesh/word.scm: New file.
* tests/word.scm: New file.
* Makefile.am: Add them.
2018-07-15 19:46:14 -04:00
Timothy Sample 6678ae1e59 Add environment
* geesh/environment.scm: New file.
* tests/environment.scm: New file.
* Makefile.am: Add them.
2018-07-15 19:46:14 -04:00
Timothy Sample 2b05199562 Flatten AST form for multiple assignments
* geesh/parser.scm (make-parser): Instead of using a nested list for
assignments, use a flat list.
* tests/parser.scm: Adjust existing test for this (which checks a
single assignment) and add a second test which checks multiple
assignments.
2018-07-15 19:45:31 -04:00
Timothy Sample 0afb2523f7 Make reference operators more consistent
* geesh/lexer.scm (get-parameter-expression): Use '#f' to signal an
omitted optional word instead of just omitting the word in the
resulting form.
* tests/lexer.scm: Add a test for omitted optional words.
2018-07-11 21:54:43 -04:00
Timothy Sample c802fd2fca Make reference operator names more "Scheme-y"
* geesh/lexer.scm (*parameter-operators*): Update the names of the
operators.
* tests/lexer.scm: Fix tests accordingly.
2018-07-11 21:54:35 -04:00
Timothy Sample 69c3f9e6ad Add parser
* geesh/parser.scm: New file.
* tests/parser.scm: New file.
* Makefile.am: Add them.
* .dir-locals.el: New file. Include indenting rules for Shell AST
forms and 'call-with-backquoted-input-port'.
2018-02-01 00:14:12 -05:00
Timothy Sample 95181a98b5 Add lexer
* geesh/lexer.scm: New file.
* tests/lexer.scm: New file.
* Makefile.am: Add them.
2018-01-31 15:09:51 -05:00
Timothy Sample cdded95d88 Initial commit 2018-01-31 14:52:05 -05:00