All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Anderson <seanga2@gmail.com>
To: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de, "Marek Behún" <marek.behun@nic.cz>,
	"Wolfgang Denk" <wd@denx.de>, "Simon Glass" <sjg@chromium.org>,
	"Roland Gaudig" <roland.gaudig-oss@weidmueller.com>,
	"Heinrich Schuchardt" <xypron.glpk@gmx.de>,
	"Kostas Michalopoulos" <badsector@runtimeterror.com>
Subject: Re: [RFC PATCH 00/28] cli: Add a new shell
Date: Fri, 2 Jul 2021 10:07:54 -0400	[thread overview]
Message-ID: <d4fa6cf0-1aae-311e-3a32-ce4d400b0d3e@gmail.com> (raw)
In-Reply-To: <20210701202155.GQ9516@bill-the-cat>

On 7/1/21 4:21 PM, Tom Rini wrote:
> On Thu, Jul 01, 2021 at 02:15:43AM -0400, Sean Anderson wrote:
> 
>> Well, this has been sitting on my hard drive for too long without feedback
>> ("Release early, release often"), so here's the first RFC. This is not ready to
>> merge (see the "Future work" section below), but the shell is functional and at
>> least partially tested.
>>
>> The goal is to have 0 bytes gained over Hush. Currently we are around 800 bytes
>> over on sandbox.
> 
> A good goal, but perhaps slightly too strict?

Perhaps. But I think getting in the ballpark will significantly help
drive adoption. I want to make it as easy as possible for maintainers to
enable LIL and start using it.

> 
>>
>> add/remove: 90/54 grow/shrink: 3/7 up/down: 12834/-12042 (792)
>>
>> = Getting started
>>
>> Enable CONFIG_LIL. If you would like to run tests, enable CONFIG_LIL_FULL. Note
>> that dm_test_acpi_cmd_dump and setexpr_test_str_oper will fail. CONFIG_LIL_POOLS
>> is currently broken (with what appears to be a double free).
>>
>> For an overview of the language as a whole, refer to the original readme [1].
>>
>> [1] http://runtimeterror.com/tech/lil/readme.txt
>>
>> == Key patches
>>
>> The following patches are particularly significant for reviewing and
>> understanding this series:
>>
>> cli: Add LIL shell
>> 	This contains the LIL shell as originally written by Kostas with some
>> 	major deletions and some minor additions.
>> cli: lil: Wire up LIL to the rest of U-Boot
>> 	This allows you to use LIL as a shell just like Hush.
>> cli: lil: Document structures
>> 	This adds documentation for the major structures of LIL. It is a good
>> 	place to start looking at the internals.
>> test: Add tests for LIL
>> 	This adds some basic integration tests and provides some examples of
>> 	LIL code.
>> cli: lil: Add a distinct parsing step
>> 	This adds a parser separate from the interpreter. This patch is the
>> 	largest original work in this series.
>> cli: lil: Load procs from the environment
>> 	This allows procedures to be saved and loaded like variables.
>>
>> = A new shell
>>
>> This series adds a new shell for U-Boot. The aim is to eventually replace Hush
>> as the primary shell for all boards which currently use it. Hush should be
>> replaced because it has several major problems:
>>
>> - It has not had a major update in two decades, resulting in duplication of
>>    effort in finding bugs. Regarding a bug in variable setting, Wolfgang remarks
>>
>>      So the specific problem has (long) been fixed in upstream, and
>>      instead of adding a patch to our old version, thus cementing the
>>      broken behaviour, we should upgrade hush to recent upstream code.
>>
>>      -- Wolfgang Denk [2]
>>
>>    These lack of updates are further compounded by a significant amount of
>>    ifdef-ing in the Hush code. This makes the shell hard to read and debug.
>>    Further, the original purpose of such ifdef-ing (upgrading to a newer Hush)
>>    has never happened.
>>
>> - It was designed for a preempting OS which supports pipes and processes. This
>>    fundamentally does not match the computing model of U-Boot where there is
>>    exactly one thread (and every other CPU is spinning or sleeping). Working
>>    around these design differences is a significant cause of the aformentioned
>>    ifdef-ing.
>>
>> - It lacks many major features expected of even the most basic shells, such
>>    as functions and command substitution ($() syntax). This makes it difficult
>>    to script with Hush. While it is desirable to write some code in C, much code
>>    *must* be written in C because there is no way to express the logic in Hush.
>>
>> I believe that U-Boot should have a shell which is more featureful, has cleaner
>> code, and which is the same size as Hush (or less). The ergonomic advantages
>> afforded by a new shell will make U-Boot easier to use and customize.
>>
>> [2] https://lore.kernel.org/u-boot/872080.1614764732@gemini.denx.de/
> 
> First, great!  Thanks for doing this.  A new shell really is the only
> viable path forward here, and I appreciate you taking the time to
> evaluate several and implement one.
> 
>> = Open questions
>>
>> While the primary purpose of this series is of course to get feedback on the
>> code I have already written, there are several decisions where I am not sure
>> what the best course of action is.
>>
>> - What should be done about 'expr'? The 'expr' command is a significant portion
>>    of the final code size. It cannot be removed outright, because it is used by
>>    several builtin functions like 'if', 'while', 'for', etc. The way I see it,
>>    there are two general approaches to take
>>
>>    - Rewrite expr to parse expressions and then evaluate them. The parsing could
>>      re-use several of the existing parse functions like how parse_list does.
>>      This could reduce code, as instead of many functions each with their own
>>      while/switch statements, we could have two while/switch statements (one to
>>      parse, and one to evaluate). However, this may end up increasing code size
>>      (such as when the main language had evaluation split from parsing).
>>
>>    - Don't parse infix expressions, and just make arithmetic operators normal
>>      functions. This would affect ergonomics a bit. For example, instead of
>>
>> 	if {$i < 10} { ... }
>>
>>      one would need to write
>>
>> 	if {< $i 10} { ... }
>>
>>      and instead of
>>
>> 	if {$some_bool} { ... }
>>
>>      one would need to write
>>
>> 	if {quote $some_bool} { ... }
>>
>>      Though, given how much setexpr is used (not much), this may not be such a
>>      big price to pay. This route is almost certain to reduce code size.
> 
> So, this is a question because we have cmd/setexpr.c that provides
> "expr" today?  Or because this is a likely place to reclaim some of that
> 800 byte growth?

The latter. setexpr cannot be used because it does not return a result,
and instead sets a (global) variable. The expression parsing
functionality is core to LIL and used in many builtin commands (such as
`if` above), and really needs to return a lil_value.

> 
>> - How should LIL functions integrate with the rest of U-Boot? At the moment, lil
>>    functions and procedures exist in a completely separate world from normal
>>    commands. I would like to integrate them more closely, but I am not sure the
>>    best way to go about this. At the very minimum, each LIL builtin function
>>    needs to get its hands on the LIL interpreter somehow. I'd rather this didn't
>>    happen through gd_t or similar so that it is easier to unit test.
>>    Additionally, LIL functions expect an array of lil_values instead of strings.
>>    We could strip them out, but I worry that might start to impact performance
>>    (from all the copying).
> 
> I might be missing something here.  But, given that whenever we have C
> code run-around and generate a string to then pass to the interpreter to
> run, someone asks why we don't just make API calls directly, perhaps the
> answer is that we don't need to?

err, the issue here is that the signature for regular commands is rougly

	int cmd(..., int argc, char **argv, ...)

and the signature for LIL commands is

	struct lil_value *cmd(struct lil *lil, size_t argc, struct lil_value **argv)

where lil_value is

	struct lil_value {
		size_t l;
		char *d;
	};

so while regular commands can be reimplemented as LIL commands (just
create a new argv containing the strings directly), it is more difficult
to go the other way. I bring this up because I think having two separate
ways to write a command is not the best way to do things going forward.

>>
>>    The other half of this is adding LIL features into regular commands. The most
>>    important feature here is being able to return a string result. I took an
>>    initial crack at it [3], but I think with this series there is a stronger
>>    motivating factor (along with things like [4]).
>>
>> [3] https://patchwork.ozlabs.org/project/uboot/list/?series=231377
>> [4] https://patchwork.ozlabs.org/project/uboot/list/?series=251013
>>
>> = Future work
>>
>> The series as presented today is incomplete. The following are the major issues
>> I see with it at the moment. I would like to address all of these issues, but
>> some of them might be postponed until after first merging this series.
>>
>> - There is a serious error handling problem. Most original LIL code never
>>    checked errors. In almost every case, errors were silently ignored, even
>>    malloc failures! While I have designed new code to handle errors properly,
>>    there still remains a significant amount of original code which just ignores
>>    errors. In particular, I would like to ensure that the following categories of
>>    error conditions are handled:
>>
>>    - Running out of memory.
>>    - Access to a nonexistant variable.
>>    - Passing the wrong number of arguments to a function.
>>    - Interpreting a value as the wrong type (e.g. "foo" should not have a numeric
>>      representation, instead of just being treated as 1).
>>
>> - There are many deviations from TCL with no purpose. For example, the list
>>    indexing function is named "index" and not "lindex". It is perfectly fine to
>>    drop features or change semantics to reduce code size, make parsing easier,
>>    or make execution easier. But changing things for the sake of it should be
>>    avoided.
>>
>> - The test suite is rather anemic compared with the amount of code this
>>    series introduces. I would like to expand it significantly. In particular,
>>    error conditions are not well tested (only the "happy path" is tested).
>>
>> - While I have documented all new functions I have written, there are many
>>    existing functions which remain to be documented. In addition, there is no
>>    user documentation, which is critical in driving adoption of any new
>>    programming language. Some of this cover letter might be integrated with any
>>    documentation written.
>>
>> - Some shell features such as command repetition and secondary shell prompts
>>    have not been implemented.
>>
>> - Arguments to native lil functions are incompatible with U-Boot functions. For
>>    example, the command
>>
>> 	foo bar baz
>>
>>    would be passed to a U-Boot command as
>>
>> 	{ "foo", "bar", "baz", NULL }
>>
>>    but would be passed to a LIL function as
>>
>> 	{ "bar", "baz" }
>>
>>    This makes it more difficult to use the same function to parse several
>>    different commands. At the moment this is solved by passing the command name
>>    in lil->env->proc, but I would like to switch to the U-Boot argument list
>>    style.
>>
>> - Several existing tests break when using LIL because they expect no output on
>>    failure, but LIL produces some output notifying the user of the failure.
>>
>> - Implement DISTRO_BOOT in LIL. I think this is an important proof-of-concept to
>>    show what can be done with LIL, and to determine which features should be
>>    moved to LIL_FULL.
>>
>> = Why Lil?
>>
>> When looking for a suitable replacement shell, I evaluated implementations using
>> the following criteria:
>>
>> - It must have a GPLv2-compatible license.
>> - It must be written in C, and have no major external dependencies.
>> - It must support bare function calls. That is, a script such as 'foo bar'
>>    should invoke the function 'foo' with the argument 'bar'. This preserves the
>>    shell-like syntax we expect.
>> - It must be small. The eventual target is that it compiles to around 10KiB with
>>    -Os and -ffunction-sections.
>> - There should be good tests. Any tests at all are good, but a functioning suite
>>    is better.
>> - There should be good documentation
>> - There should be comments in the source.
>> - It should be "finished" or have only slow development. This will hopefully
>>    make it easier to port changes.
> 
> On this last point, I believe this is based on lil20190821 and current
> is now lil20210502.  With a quick diff between them, I can see that the
> changes there are small enough that while you've introduced a number of
> changes here, it would be a very easy update.

 From what I understand, the only changes are updated copyrights and the
addition of a license file to cover the tests.

--Sean

  parent reply	other threads:[~2021-07-02 14:08 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-01  6:15 [RFC PATCH 00/28] cli: Add a new shell Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 01/28] Add Zlib License Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-01  6:15 ` [RFC PATCH 02/28] cli: Add LIL shell Sean Anderson
2021-07-02 11:03   ` Wolfgang Denk
2021-07-02 13:33     ` Sean Anderson
2021-07-03  2:12       ` Sean Anderson
2021-07-03 19:33         ` Wolfgang Denk
2021-07-05 15:29           ` Simon Glass
2021-07-05 19:10           ` Tom Rini
2021-07-05 19:47             ` Sean Anderson
2021-07-05 19:53               ` Tom Rini
2021-07-05 19:55                 ` Sean Anderson
2021-07-06  7:46               ` Wolfgang Denk
2021-07-06  7:52                 ` Michael Nazzareno Trimarchi
2021-07-06 14:57                   ` Simon Glass
2021-07-06 15:48                     ` Tom Rini
2021-07-07  8:22                     ` Michael Nazzareno Trimarchi
2021-07-06 14:54                 ` Tom Rini
2021-07-07  8:15                   ` Wolfgang Denk
2021-07-07 13:58                     ` Tom Rini
2021-07-07 14:10                       ` Wolfgang Denk
2021-07-07 14:14                         ` Tom Rini
2021-07-07 14:23                           ` Wolfgang Denk
2021-07-06  7:44             ` Wolfgang Denk
2021-07-06 15:43               ` Tom Rini
2021-07-06 16:09                 ` Kostas Michalopoulos
2021-07-07 13:32                   ` Sean Anderson
2021-07-07  8:15                 ` Wolfgang Denk
2021-07-07 13:46                   ` Sean Anderson
2021-07-07 13:51                     ` Tom Rini
2021-07-07 13:58                   ` Tom Rini
2021-07-07 14:48                   ` Marek Behun
2021-07-08  5:19                     ` Michael Nazzareno Trimarchi
2021-07-08 15:33                       ` Tom Rini
2021-07-08  4:56               ` Sean Anderson
2021-07-08 17:00                 ` Wolfgang Denk
2021-07-03 19:23       ` Wolfgang Denk
2021-07-01  6:15 ` [RFC PATCH 03/28] cli: lil: Replace strclone with strdup Sean Anderson
2021-07-02  8:36   ` Rasmus Villemoes
2021-07-02 11:38     ` Wolfgang Denk
2021-07-02 13:38     ` Sean Anderson
2021-07-02 14:28       ` Tom Rini
2021-07-02 22:18       ` Kostas Michalopoulos
2021-07-03  2:28         ` Sean Anderson
2021-07-03 19:26       ` Wolfgang Denk
2021-07-05  5:07         ` Steve Bennett
2021-07-05 14:42           ` Sean Anderson
2021-07-05 15:29             ` Simon Glass
2021-07-05 15:42               ` Sean Anderson
2021-07-05 17:50             ` Wolfgang Denk
2021-07-08  4:37               ` Sean Anderson
2021-07-08 16:13                 ` Wolfgang Denk
2021-07-01  6:15 ` [RFC PATCH 04/28] cli: lil: Remove most functions by default Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-01  6:15 ` [RFC PATCH 05/28] cli: lil: Rename some functions to be more like TCL Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-05 15:54     ` Sean Anderson
2021-07-05 17:58       ` Wolfgang Denk
2021-07-05 18:51         ` Tom Rini
2021-07-05 21:02           ` Simon Glass
2021-07-05 21:36             ` Tom Rini
2021-07-06  7:52           ` Wolfgang Denk
2021-07-06 15:21             ` Simon Glass
2021-07-06 15:33             ` Tom Rini
2021-07-06 16:00               ` Kostas Michalopoulos
2021-07-07  8:16               ` Wolfgang Denk
2021-07-07 13:58                 ` Tom Rini
2021-07-05 19:46         ` Sean Anderson
2021-07-06  7:50           ` Wolfgang Denk
2021-07-08  4:47             ` Sean Anderson
2021-07-08 16:21               ` Wolfgang Denk
2021-07-01  6:15 ` [RFC PATCH 06/28] cli: lil: Convert some defines to enums Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 07/28] cli: lil: Simplify callbacks Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 08/28] cli: lil: Handle commands with dots Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 09/28] cli: lil: Use error codes Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 10/28] cli: lil: Add printf-style format helper for errors Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 11/28] cli: lil: Add several helper functions " Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 12/28] cli: lil: Check for ctrl-c Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-01  6:15 ` [RFC PATCH 13/28] cli: lil: Wire up LIL to the rest of U-Boot Sean Anderson
2021-07-02  8:18   ` Rasmus Villemoes
2021-07-02 13:40     ` Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-01  6:15 ` [RFC PATCH 14/28] cli: lil: Document structures Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 15/28] cli: lil: Convert LIL_ENABLE_POOLS to Kconfig Sean Anderson
2021-07-01  6:15 ` [RFC PATCH 16/28] cli: lil: Convert LIL_ENABLE_RECLIMIT to KConfig Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 17/28] test: Add tests for LIL Sean Anderson
2021-07-05 15:29   ` Simon Glass
2021-07-01  6:16 ` [RFC PATCH 18/28] cli: lil: Remove duplicate function bodies Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 19/28] cli: lil: Add "symbol" structure Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 20/28] cli: lil: Add config to enable debug output Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 21/28] cli: lil: Add a distinct parsing step Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 22/28] env: Add a priv pointer to hwalk_r Sean Anderson
2021-07-01 20:10   ` Tom Rini
2021-07-01  6:16 ` [RFC PATCH 23/28] cli: lil: Handle OOM for hm_put Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 24/28] cli: lil: Make proc always take 3 arguments Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 25/28] cli: lil: Always quote items in lil_list_to_value Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 26/28] cli: lil: Allocate len even when str is NULL in alloc_value_len Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 27/28] cli: lil: Add a function to quote values Sean Anderson
2021-07-01  6:16 ` [RFC PATCH 28/28] cli: lil: Load procs from the environment Sean Anderson
2021-07-01 20:21 ` [RFC PATCH 00/28] cli: Add a new shell Tom Rini
2021-07-02 11:30   ` Wolfgang Denk
2021-07-02 13:56     ` Sean Anderson
2021-07-02 14:07   ` Sean Anderson [this message]
2021-07-08  3:49 ` Heiko Schocher
2021-07-08  4:26   ` Sean Anderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d4fa6cf0-1aae-311e-3a32-ce4d400b0d3e@gmail.com \
    --to=seanga2@gmail.com \
    --cc=badsector@runtimeterror.com \
    --cc=marek.behun@nic.cz \
    --cc=roland.gaudig-oss@weidmueller.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=wd@denx.de \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.