-
-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New features and some fixes - Variadic arguments flexibility and grouping, Negative numbers #94
Conversation
…t I keep it for future use.
…gs that pepole are complaining about
…panded to constants
oh, just saw this and looks great. i will check indepth from PC soon. thanks for working out the PR |
@adhocore Take your time and test it carefully. I really did my best to cover any weird (sensible) combination, but you can never be sure. |
|
||
$this->set(null, $arg->value()); | ||
|
||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the if/else looks a bit oddly. can we refactor it? maybe a method extraction for non-constant case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean? I'm still determining...
I had another version which was recursive and messy.
I think the naive way of simple, expressive conditions is the simplest and easiest way (and performant)
Can you elaborate on that?
if (!$argument = reset($this->_arguments)) { | ||
return $this->set(null, $arg); | ||
// Its variadic, so we need to collect all the remaining args: | ||
if ($argument->variadic() && $arg->isConstant()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this block should be a different method
} | ||
|
||
$this->setValue($argument, $arg); | ||
// Its variadic, and we have a variadic grouped arg: | ||
if ($argument->variadic() && $arg->isVariadic()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be extracted to different method
if ($option->variadic() && $next->isVariadic()) { | ||
|
||
foreach ($next->nested as $token) { | ||
if ($token->isConstant()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see many code repetition of this nature:
if (token isConstant) {
setValue
} else {
throw ...
}
--- should be extracted to some helper (setConstantOrFail()
) that can be used like this:
$this->setConstantOrFail($token)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because I want to avoid recursion (as much as possible), and as a general rule I normally don't add more abstraction, especially for internal code which probably will not be used anywhere else...
That said I can add more methods if it's a design rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this loop is convoluted so if the command definitions for options don't contain any variadic option at all, we should have a way to just use older approach of parsing for performance reasons. i think variadic options are only a small percentage of non variadic options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry I don't really understand the point.
My reasoning is:
- The number of tokens we will iterate through will most of the time, be meaningless, I mean it's a CLI arguments parser...
- I wanted to reduce function calls as much as possible (for performance) and I wanted to avoid unnecessary Iterations/function calls.
- I chose this pattern because it's simple, bulletproof, and only consumes/loops/passes values if it's absolutely needed.
In this case unless $option->variadic()
which means it was declared as variadic and I have a specific $next->isVariadic()
(which means it's a specific variadic group i.e. [ 1 2 3 ]) - no loop will be reached.
If this is the case all the "grouped" arguments will be consumed in one pass.
Please elaborate
} | ||
// If its a single hyphen, maybe its a negative number: | ||
if ( | ||
($arg[0] ?? '') === '-' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw we cant assume -N
where N is number, to be a number it can be a option as well
eg curl
uses -1
-2
-3
as option for ssl v1 to v3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty rare and usually confusing, I can think of a way to support numerical names for options by checking first if the current identified number is defined as an option.
That said, it still introduces some extra complexity and weirdness : -10 -12 ...
case Token::TYPE_LONG: | ||
case Token::TYPE_CONSTANT: | ||
if ($variadic) { | ||
$this->tokens[count($this->tokens) - 1]->addNested($token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the nesting goes quite deep: class -> func -> foreach -> foreach -> switch -> case -> if
probably need to optimize, specially loop inside loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is wrong with that? It's a lot cheaper than function/method calls...
1 scope block + 4 code blocks are not considered as deep I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hello @shlomohass so too many things and big scope, i think i have left enough comments in review for now. (will check again later again with more comments lol).
quick update we can do here besides addressing reviews; i guess, is firstly using a proper linting/php-cs-fixer and secondly removing code-comments that is not absolutely necessary. thank you
@adhocore Sure I'll start making the edits. I thought the |
This is the result of / and fixes #93
What has changed:
Introduced a new
Tokenizer
class to enable a more advanced syntax to be parsed (Normalizer now only handles the value filtering)->option("--names [items...]")
is now working as expected.Tested on/with:
AdvacedArgsTest.php
with many edge cases and crazy scenarios.Notes:
I have some more ideas for future improvements 😄