Abstract the alias set interface used in the Parser
Define the new trait
Define implementors of the trait
Change Parser::aliases's type
Extract the verbose option behavior from FdReader to a new Input decorator.
Define the new decorator struct
Implement Input for the struct
Deprecate FdReader::set_echo
Migrate to the new read_eval_loop function
Define the new read_eval_loop function
Replace existing uses of ReadEvalLoop with calls to the read_eval_loop function
Deprecate ReadEvalLoop
[x] Add an Input decorator that expands and prints the prompt #376
Add functions that expand the value of $PS1 and $PS2
Define the new decorator
Insert the decorator in yash_cli::startup::prepare_input
[x] Change prompt string depending on whether a command is continued #379
Extend yash_syntax::input::Context so Input implementors can decide which prompt to print
Use $PS2 instead of $PS1 if reading a next line after an incomplete command
[ ] #382
[x] Print $PS2 on line continuation in the read built-in #380
The overall structure of the Input object will be Echo<Prompter<FdReader>>. Note that FdReader should be the direct child of Prompter so that Prompter<FdReader> can be replaced with a rich line-editing input in the future.
Design considerations
[x] Expanding $PS1 and $PS2 would require a mutable reference to the whole Env. How can it be accessed from the Input::next_line function?
The most promising solution seems to be sharing a RefCell<&mut Env>.
RefCell<Env> would not be feasible when we need to create a lexer and read-eval loop from &mut Env where we don't have the whole Env ownership as in the eval and source built-ins.
Probably, we don't need to wrap the RefCell in an Rc because the lifetime of the RefCell is local to the context running the loop.
[x] The Parser depends on a reference to the alias set. How can it co-exist with the mutable reference to Env used for prompting in Input implementations?
The most promising solution seems to be RefCell again. However, the Parser cannot (should not) directly contain a field of type RefCell<&mut Env> for interface segregation principle. The Parser should depend on an abstract interface of the alias set, which would probably be a new trait that replaces the existing AliasSet type alias. The implementor of the trait would contain the RefCell.
[x] Should the verbose option still be implemented in FdReader? Specifically, do we still need the echo: Option<Rc<Cell<State>>> field?
Note that the dot built-in would also need to support the verbose option.
Also, this design is closely coupled with yash_semantics::runner::ReadEvelLoop::set_verbose.
Maybe the verbose option's behavior can be implemented with the decorator pattern.
[x] What is the new API of ReadEvalLoop?
If the Lexer (indirectly) contains RefCell<&mut Env> in the Input implementor as discussed above, ReadEvalLoop can no longer directly hold a mutable reference to Env.
The most promising solution seems to have a &RefCell<&mut Env> as a field of ReadEvalLoop, that is, replace the env: &'a mut Env parameter for ReadEvalLoop::new with env: &'a RefCell<&'b mut Env>.
If the verbose option can be handled within the Input implementor, the ReadEvalLoop::verbose field is no longer necessary. Then, the ReadEvalLoop does not have to be a struct. A simple function will suffice.
[x] Should we directly add the new read_eval_loop function and deprecate the existing ReadEvalLoop struct rather than modifying ReadEvalLoop first then converting it into a function?
The new function will not support the verbose option in itself. The verbose option will be implemented in the Input decorator, which depends on the shared reference to Env. Which means, we need to migrate to the new Input decorator and the new ReadEvalLoop function at the same time.
The new function also needs to support fine-grained borrowing of the Env so that the decorator can borrow the Env without conflict. This depends on the new alias set interface.
To be implemented
Parser
Parser::aliases
's typeFdReader
to a newInput
decorator.FdReader::set_echo
read_eval_loop
functionread_eval_loop
functionReadEvalLoop
with calls to theread_eval_loop
functionReadEvalLoop
Input
decorator that expands and prints the prompt #376$PS1
and$PS2
yash_cli::startup::prepare_input
yash_syntax::input::Context
soInput
implementors can decide which prompt to print$PS2
instead of$PS1
if reading a next line after an incomplete command$PS2
on line continuation in the read built-in #380The overall structure of the
Input
object will beEcho<Prompter<FdReader>>
. Note thatFdReader
should be the direct child ofPrompter
so thatPrompter<FdReader>
can be replaced with a rich line-editing input in the future.Design considerations
$PS1
and$PS2
would require a mutable reference to the wholeEnv
. How can it be accessed from theInput::next_line
function?RefCell<&mut Env>
.RefCell<Env>
would not be feasible when we need to create a lexer and read-eval loop from&mut Env
where we don't have the wholeEnv
ownership as in the eval and source built-ins.RefCell
in anRc
because the lifetime of theRefCell
is local to the context running the loop.Parser
depends on a reference to the alias set. How can it co-exist with the mutable reference toEnv
used for prompting inInput
implementations?RefCell
again. However, theParser
cannot (should not) directly contain a field of typeRefCell<&mut Env>
for interface segregation principle. TheParser
should depend on an abstract interface of the alias set, which would probably be a new trait that replaces the existingAliasSet
type alias. The implementor of the trait would contain theRefCell
.FdReader
? Specifically, do we still need theecho: Option<Rc<Cell<State>>>
field?yash_semantics::runner::ReadEvelLoop::set_verbose
.ReadEvalLoop
?Lexer
(indirectly) containsRefCell<&mut Env>
in theInput
implementor as discussed above,ReadEvalLoop
can no longer directly hold a mutable reference toEnv
.&RefCell<&mut Env>
as a field ofReadEvalLoop
, that is, replace theenv: &'a mut Env
parameter forReadEvalLoop::new
withenv: &'a RefCell<&'b mut Env>
.Input
implementor, theReadEvalLoop::verbose
field is no longer necessary. Then, theReadEvalLoop
does not have to be a struct. A simple function will suffice.read_eval_loop
function and deprecate the existingReadEvalLoop
struct rather than modifyingReadEvalLoop
first then converting it into a function?Input
decorator, which depends on the shared reference toEnv
. Which means, we need to migrate to the newInput
decorator and the newReadEvalLoop
function at the same time.Env
so that the decorator can borrow theEnv
without conflict. This depends on the new alias set interface.