Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Typeset with array

On Fri, 12 Jun 2015 09:42:37 +0100
Peter Stephenson <p.stephenson@xxxxxxxxxxx> wrote:
> > } > }     local cword words=()
> It could, in principle, be very difficultly and time-consumingly
> improved.
> We need in any case to keep the builtin interface to handle cases like
>   local=local
>   $local -i i
> which are valid --- the case
>   $local array=(one two)
> is not valid as there's no keyword to signal special parsing.

Building on the above, I've developed a Cunning Plan so that it's not
too disruptive and is a few days rather than weeks of spare time.

It works like this.

Reserved words are added for typeset synonyms that can handle arrays:
declare, local, readonly, typeset.  On second thoughts I added it to
export which supports "export -T"; it's a bit arbitrary if you can't
assign to the array component in that case, even though export isn't
generally useful for arrays.  For numeric builtins there's no point.

The reserved words trigger variant handling in par_simple(): WC_TYPESET
is very similar to WC_SIMPLE but there's an extra count and set of
assignments tacked on the end.

Here's where the Cunning Plan comes in: the spcial assignment behaviour
only kicks in where there's an actual assignment.  For consistency I did
it for scalars as well as arrays.  So if it comes across something like

  typeset -L2 name foo=bar array=(here there)

then the "-L2 name" is handled in the original way, but the
last two arguments are bundled up as assigments.  This means,
later on, the option parsing code needs no changes at all --
typeset options are simple and can't include arbitrary strings
with "=", so this doesn't confuse the parser.  To preserve
order, bare names after the first assignment are treated
as pseudo-assignments, specially marked as having no value
(which is different from an assignment with an empty value).

The execcmd code then handles WC_TYPESET much like WC_SIMPLE, but if
it's executing a builtin it extracts the assignments, sticks them in a
linked list, and performs prefork and globbing expansion.  I enhanced
struct asgment to do this: it's got an embedded LinkNode, which we do a
lot with HashNode but not elsewhere with LinkNode, however I think it
works OK.

The bin_typeset handler has a different interface from the other
builtins, accepting this extra linked list.  The flag BINF_ASSIGN in the
table indicates this (obviously it's needed for all instances of
bin_typeset, not just those that handle the extra assignments --- which
just get a null list).

There are other tweaks to bin_typeset() and typeset_single() to handle
the new cases.  This is already hairy code, so there could easily be
oddities here, but they don't generally affect things that already work,
so far as I can see.  The key changes are that getasg() is enhanced to
pull values off argv and the new list; when creating a parameter with an
array assignment it's turned into PM_ARRAY; and setsparam() calls now
have parallel setaparam() calls for the other case.

Currently the reserved words are enabled since in theory the disruption
to existing working code should be minimal.  If we find a good reason we
can disable them by default in native mode.

I've got as far as a successful

% typeset array=(one two buckle my shoe)
% print -l $array

but there's a lot more debugging and testing to do.  Also, execcmd()
needs some work --- currently, the reserved word doesn't actually force
you to use a builtin of the same name, we just rely on execcmd() finding
the builtin in the hash table.  If that was disabled but there was an
external command of the same name it would execute that, missing the
special assigment commands on the end.  This probably isn't the right
thing to do.

This is on a branch typeset-array, which I'll push so you can have a
look.  When it's stable I'll rebase, squash and merge -ff-only onto the
end of master.


Messages sorted by: Reverse Date, Date, Thread, Author