|
|
|
@ -24,8 +24,43 @@ class CommandParser extends AcediaObject
|
|
|
|
|
dependson(Command); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* `CommandParser` stores both it's state and command data, relevant to |
|
|
|
|
* parsing, as it's member variables during the whole parsing process, |
|
|
|
|
* # `CommandParser` |
|
|
|
|
* |
|
|
|
|
* Class specialized for parsing user input of the command's call into |
|
|
|
|
* `Command.CallData` structure with the information about all parsed |
|
|
|
|
* arguments. |
|
|
|
|
* `CommandParser` is not made to parse the whole input: |
|
|
|
|
* |
|
|
|
|
* * Command's name needs to be parsed and resolved as an alias before |
|
|
|
|
* using this parser - it won't do this hob for you; |
|
|
|
|
* * List of targeted players must also be parsed using `PlayersParser` - |
|
|
|
|
* `CommandParser` won't do this for you; |
|
|
|
|
* * Optionally one can also decide on the referred subcommand and pass it |
|
|
|
|
* into `ParseWith()` method. If subcommand's name is not passed - |
|
|
|
|
* `CommandParser` will try to parse it itself. This feature is used to |
|
|
|
|
* add support for subcommand aliases. |
|
|
|
|
* |
|
|
|
|
* However, above steps are handled by `Commands_Feature` and one only needs to |
|
|
|
|
* call that feature's `HandleInput()` methods to pass user input with command |
|
|
|
|
* call line there. |
|
|
|
|
* |
|
|
|
|
* ## Usage |
|
|
|
|
* |
|
|
|
|
* Allocate `CommandParser` and call `ParseWith()` method, providing it with: |
|
|
|
|
* |
|
|
|
|
* 1. `Parser`, filled with command call input; |
|
|
|
|
* 2. Command's data that describes subcommands, options and their |
|
|
|
|
* parameters for the command, which call we are parsing; |
|
|
|
|
* 3. (Optionally) `EPlayer` reference to the player that initiated |
|
|
|
|
* the command call; |
|
|
|
|
* 4. (Optionally) Subcommand to be used - this will prevent |
|
|
|
|
* `CommandParser` from parsing subcommand name itself. Used for |
|
|
|
|
* implementing aliases that refer to a particular subcommand. |
|
|
|
|
* |
|
|
|
|
* ## Implementation |
|
|
|
|
* |
|
|
|
|
* `CommandParser` stores both its state and command data, relevant to |
|
|
|
|
* parsing, as its member variables during the whole parsing process, |
|
|
|
|
* instead of passing that data around in every single method. |
|
|
|
|
* |
|
|
|
|
* We will give a brief overview of how around 20 parsing methods below |
|
|
|
@ -43,6 +78,7 @@ class CommandParser extends AcediaObject
|
|
|
|
|
* it is called once for single-valued parameters, but possibly several times |
|
|
|
|
* for list parameters that can contain several values. |
|
|
|
|
* So main parsing method looks something like: |
|
|
|
|
* |
|
|
|
|
* ParseParameterArrays() { |
|
|
|
|
* loop ParseParameter() { |
|
|
|
|
* loop ParseSingleValue() |
|
|
|
@ -235,6 +271,7 @@ public final function Command.CallData ParseWith(
|
|
|
|
|
local HashTable commandParameters; |
|
|
|
|
// Temporary object to return `nextResult` while setting variable to `none` |
|
|
|
|
local Command.CallData toReturn; |
|
|
|
|
|
|
|
|
|
nextResult.parameters = _.collections.EmptyHashTable(); |
|
|
|
|
nextResult.options = _.collections.EmptyHashTable(); |
|
|
|
|
if (commandData.subCommands.length == 0) |
|
|
|
@ -279,6 +316,7 @@ public final function Command.CallData ParseWith(
|
|
|
|
|
private final function AssertNoTrailingInput() |
|
|
|
|
{ |
|
|
|
|
local Text remainder; |
|
|
|
|
|
|
|
|
|
if (!commandParser.Ok()) return; |
|
|
|
|
if (commandParser.Skip().GetRemainingLength() <= 0) return; |
|
|
|
|
|
|
|
|
@ -297,6 +335,7 @@ private final function HashTable ParseParameterArrays(
|
|
|
|
|
array<Command.Parameter> optionalParameters) |
|
|
|
|
{ |
|
|
|
|
local HashTable parsedParameters; |
|
|
|
|
|
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return none; |
|
|
|
|
} |
|
|
|
@ -317,6 +356,7 @@ private final function ParseRequiredParameterArray(
|
|
|
|
|
array<Command.Parameter> requiredParameters) |
|
|
|
|
{ |
|
|
|
|
local int i; |
|
|
|
|
|
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
@ -355,6 +395,7 @@ private final function ParseOptionalParameterArray(
|
|
|
|
|
array<Command.Parameter> optionalParameters) |
|
|
|
|
{ |
|
|
|
|
local int i; |
|
|
|
|
|
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
@ -387,6 +428,7 @@ private final function bool ParseParameter(
|
|
|
|
|
Command.Parameter expectedParameter) |
|
|
|
|
{ |
|
|
|
|
local bool parsedEnough; |
|
|
|
|
|
|
|
|
|
confirmedState = commandParser.GetCurrentState(); |
|
|
|
|
while (ParseSingleValue(parsedParameters, expectedParameter)) |
|
|
|
|
{ |
|
|
|
@ -494,6 +536,7 @@ private final function bool ParseBooleanValue(
|
|
|
|
|
local bool isValidBooleanLiteral; |
|
|
|
|
local bool booleanValue; |
|
|
|
|
local MutableText parsedLiteral; |
|
|
|
|
|
|
|
|
|
commandParser.Skip().MUntil(parsedLiteral,, true); |
|
|
|
|
if (!commandParser.Ok()) |
|
|
|
|
{ |
|
|
|
@ -538,6 +581,7 @@ private final function bool ParseIntegerValue(
|
|
|
|
|
Command.Parameter expectedParameter) |
|
|
|
|
{ |
|
|
|
|
local int integerValue; |
|
|
|
|
|
|
|
|
|
commandParser.Skip().MInteger(integerValue); |
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return false; |
|
|
|
@ -555,6 +599,7 @@ private final function bool ParseNumberValue(
|
|
|
|
|
Command.Parameter expectedParameter) |
|
|
|
|
{ |
|
|
|
|
local float numberValue; |
|
|
|
|
|
|
|
|
|
commandParser.Skip().MNumber(numberValue); |
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return false; |
|
|
|
@ -656,6 +701,7 @@ private final function bool ParseObjectValue(
|
|
|
|
|
Command.Parameter expectedParameter) |
|
|
|
|
{ |
|
|
|
|
local HashTable objectValue; |
|
|
|
|
|
|
|
|
|
objectValue = _.json.ParseHashTableWith(commandParser); |
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return false; |
|
|
|
@ -672,6 +718,7 @@ private final function bool ParseArrayValue(
|
|
|
|
|
Command.Parameter expectedParameter) |
|
|
|
|
{ |
|
|
|
|
local ArrayList arrayValue; |
|
|
|
|
|
|
|
|
|
arrayValue = _.json.ParseArrayListWith(commandParser); |
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return false; |
|
|
|
@ -729,7 +776,7 @@ private final function bool ParsePlayersValue(
|
|
|
|
|
private final function RecordParameter( |
|
|
|
|
HashTable parametersArray, |
|
|
|
|
Command.Parameter parameter, |
|
|
|
|
/* take */AcediaObject value) |
|
|
|
|
/* take */ AcediaObject value) |
|
|
|
|
{ |
|
|
|
|
local ArrayList parameterVariable; |
|
|
|
|
|
|
|
|
@ -761,6 +808,7 @@ private final function RecordParameter(
|
|
|
|
|
private final function bool TryParsingOptions() |
|
|
|
|
{ |
|
|
|
|
local int temporaryInt; |
|
|
|
|
|
|
|
|
|
if (!commandParser.Ok()) return false; |
|
|
|
|
|
|
|
|
|
confirmedState = commandParser.GetCurrentState(); |
|
|
|
@ -803,6 +851,7 @@ private final function bool ParseLongOption()
|
|
|
|
|
{ |
|
|
|
|
local int i, optionIndex; |
|
|
|
|
local MutableText optionName; |
|
|
|
|
|
|
|
|
|
commandParser.MUntil(optionName,, true); |
|
|
|
|
if (!commandParser.Ok()) { |
|
|
|
|
return false; |
|
|
|
@ -843,6 +892,7 @@ private final function bool ParseShortOption()
|
|
|
|
|
local int i; |
|
|
|
|
local bool pickedOptionWithParameters; |
|
|
|
|
local MutableText optionsList; |
|
|
|
|
|
|
|
|
|
commandParser.MUntil(optionsList,, true); |
|
|
|
|
if (!commandParser.Ok()) |
|
|
|
|
{ |
|
|
|
@ -881,6 +931,7 @@ private final function bool AddOptionByCharacter(
|
|
|
|
|
{ |
|
|
|
|
local int i; |
|
|
|
|
local bool optionHasParameters; |
|
|
|
|
|
|
|
|
|
// Prevent same option appearing twice |
|
|
|
|
for (i = 0; i < usedOptions.length; i += 1) |
|
|
|
|
{ |
|
|
|
@ -923,6 +974,7 @@ private final function bool AddOptionByCharacter(
|
|
|
|
|
private final function bool ParseOptionParameters(Command.Option pickedOption) |
|
|
|
|
{ |
|
|
|
|
local HashTable optionParameters; |
|
|
|
|
|
|
|
|
|
// If we are already parsing other option's parameters and did not finish |
|
|
|
|
// parsing all required ones - we cannot start another option |
|
|
|
|
if (currentTargetIsOption && currentTarget != CPT_ExtraParameter) |
|
|
|
|