Skip to content

Commit

Permalink
Recoded string parsing to ArgumentQueue.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mqzn committed Nov 4, 2024
1 parent eba444f commit 1a71e45
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import dev.velix.imperat.context.Source;
import dev.velix.imperat.context.internal.CommandInputStream;
import dev.velix.imperat.exception.ImperatException;
import dev.velix.imperat.util.ImperatDebugger;
import dev.velix.imperat.util.TypeWrap;
import org.jetbrains.annotations.NotNull;

import static dev.velix.imperat.util.StringUtils.isQuoteChar;

public final class ParameterString<S extends Source> extends BaseParameterType<S, String> {

private final static char DOUBLE_QUOTE = '"', SINGLE_QUOTE = '\'';

ParameterString() {
super(TypeWrap.of(String.class));
Expand All @@ -29,12 +29,11 @@ public final class ParameterString<S extends Source> extends BaseParameterType<S

if (!isQuoteChar(current)) {

builder.append(inputStream.currentRaw().orElse(""));
if (parameter.isGreedy()) {
handleGreedy(builder, inputStream);
} else {
builder.append(inputStream.currentRaw().orElse(""));
}
ImperatDebugger.debug("Read string input= '%s'", builder.toString());

return builder.toString();
}

Expand All @@ -45,32 +44,20 @@ public final class ParameterString<S extends Source> extends BaseParameterType<S
next = inputStream.popLetter().orElse(null);
if (next == null) break;
builder.append(next);

} while (inputStream.hasNextLetter() &&
inputStream.peekLetter().filter((ch) -> !isQuoteChar(ch)).isPresent());

if (parameter.isGreedy()) {
handleGreedy(builder, inputStream);
}
ImperatDebugger.debug("Read string input= '%s'", builder.toString());
} while (inputStream.hasNextRaw() && inputStream.peekLetter().map((ch) -> !isQuoteChar(ch)).orElse(false));

return builder.toString();
}

private boolean isQuoteChar(char ch) {
return ch == DOUBLE_QUOTE || ch == SINGLE_QUOTE;
}

private void handleGreedy(StringBuilder builder, CommandInputStream<S> inputStream) {
builder.append(" ");
while (inputStream.hasNextRaw()) {
inputStream.popRaw()
.ifPresent((raw) -> {
builder.append(raw);
if (inputStream.peekRaw().isPresent()) {
builder.append(" ");
}
});
var raw = inputStream.currentRaw().orElse(null);
if (raw == null) return;

while (inputStream.hasNextLetter()) {
inputStream.currentLetter()
.ifPresent((builder::append));
inputStream.skipLetter();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ static ArgumentQueue parseAutoCompletion(String string, boolean extraLastSpace)
/**
* @return a new, empty {@link ArgumentQueue}.
*/
static ArgumentQueue empty() {
return new ArgumentQueueImpl();
static ArgumentQueue empty(String originalLine) {
return new ArgumentQueueImpl(originalLine);
}

String getOriginalRaw();

/**
* Fetches the element at the specified index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,28 @@
@ApiStatus.Internal
final class ArgumentQueueImpl extends LinkedList<String> implements ArgumentQueue {

private final String originalRaw;
private final List<String> unmodifiableView;

ArgumentQueueImpl(@NotNull Collection<? extends String> input) {
ArgumentQueueImpl(String originalRaw, @NotNull Collection<? extends String> input) {
super(input);
this.originalRaw = originalRaw;
this.unmodifiableView = Collections.unmodifiableList(this);
}


public ArgumentQueueImpl(@NotNull String... rawArgs) {
public ArgumentQueueImpl(String originalRaw, @NotNull String... rawArgs) {
this.originalRaw = originalRaw;
Collections.addAll(this, rawArgs);
this.unmodifiableView = Collections.unmodifiableList(this);
}

@Override
public String getOriginalRaw() {
return originalRaw;
}


@Override
public @NotNull String join(String delimiter) {
return String.join(delimiter, this);
Expand All @@ -49,7 +58,7 @@ public ArgumentQueueImpl(@NotNull String... rawArgs) {

@Override
public @NotNull ArgumentQueue copy() {
return new ArgumentQueueImpl(this);
return new ArgumentQueueImpl(originalRaw, this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ public interface CommandInputStream<S extends Source> {

@NotNull CommandUsage<S> getUsage();

default boolean skip() {
final Cursor<S> cursor = cursor();
int prevRaw = cursor.raw;
cursor.shift(ShiftTarget.ALL, ShiftOperation.RIGHT);
return cursor.raw > prevRaw;
}
boolean skip();

boolean skipLetter();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class CommandInputStreamImpl<S extends Source> implements CommandInputStre
private final static char WHITE_SPACE = ' ';

private int letterPos = 0;
private final String inputLine;

private final Cursor<S> cursor;

Expand All @@ -21,6 +22,7 @@ final class CommandInputStreamImpl<S extends Source> implements CommandInputStre

CommandInputStreamImpl(ArgumentQueue queue, CommandUsage<S> usage) {
this.queue = queue;
this.inputLine = queue.getOriginalRaw();
this.usage = usage;
this.cursor = new Cursor<>(this, 0, 0);
}
Expand Down Expand Up @@ -57,48 +59,29 @@ public Optional<CommandParameter<S>> popParameter() {

@Override
public @NotNull Optional<Character> currentLetter() {
if (cursor.raw >= queue.size()) {
if (letterPos >= inputLine.length()) {
return Optional.empty();
}
return currentRaw().map((raw) -> raw.charAt(letterPos));
return Optional.of(inputLine.charAt(letterPos));
}

@Override
public Optional<Character> peekLetter() {
int nextLetterPos = letterPos + 1;
return currentRaw().flatMap((currentRaw) -> {
if (nextLetterPos == currentRaw.length()) {
return Optional.of(WHITE_SPACE);
} else if (nextLetterPos > currentRaw.length()) {
//next raw
return peekRaw().map((nextRaw) -> nextRaw.charAt(0));
} else {
//nextLetterPos < currentRaw.length()
return Optional.of(currentRaw.charAt(nextLetterPos));
}
});
if (nextLetterPos >= inputLine.length()) return Optional.empty();
return Optional.of(inputLine.charAt(nextLetterPos));
}

@Override
public Optional<Character> popLetter() {
letterPos++;
return currentRaw().flatMap((currentRaw) -> {
if (letterPos == currentRaw.length()) {
return Optional.of(WHITE_SPACE);
} else if (letterPos > currentRaw.length()) {
//next raw
letterPos = 0;
return popRaw().map((nextRaw) -> nextRaw.charAt(0));
} else {
//nextLetterPos < currentRaw.length()
return Optional.of(currentRaw.charAt(letterPos));
}
});
return currentLetter();
}

@Override
public Optional<String> peekRaw() {
int next = cursor.raw + 1;

return Optional.ofNullable(
queue.getOr(next, null)
);
Expand All @@ -107,18 +90,14 @@ public Optional<String> peekRaw() {
@Override
public Optional<String> popRaw() {
cursor.shift(ShiftTarget.RAW_ONLY, ShiftOperation.RIGHT);
return currentRaw();
return currentRaw().stream().peek((raw) -> {
letterPos += raw.length() + 1; //we shift the raw length + the white space
}).findFirst();
}

@Override
public boolean hasNextLetter() {
return currentRaw()
.map((raw) -> {
if (letterPos >= raw.length()) {
return peekRaw().isPresent();
}
return true;
}).orElse(false);
return letterPos < inputLine.length();
}

@Override
Expand All @@ -141,6 +120,20 @@ public boolean hasNextParameter() {
return usage;
}

@Override
public boolean skip() {
final Cursor<S> cursor = cursor();
int prevRaw = cursor.raw;
cursor.shift(ShiftTarget.ALL, ShiftOperation.RIGHT);

var currentRaw = currentRaw().orElse(null);
if (currentRaw == null) return false;

int diff = inputLine.indexOf(WHITE_SPACE, letterPos) + 1 - letterPos;
letterPos += diff;
return cursor.raw > prevRaw;
}

@Override
public boolean skipLetter() {
return popLetter().isPresent();
Expand Down
47 changes: 43 additions & 4 deletions core/src/main/java/dev/velix/imperat/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class StringUtils {
public final static char DOUBLE_QUOTE = '"', SINGLE_QUOTE = '\'';

/**
* Pattern to extract snowflake IDs. Useful for JDA
Expand Down Expand Up @@ -49,10 +49,40 @@ public static String normalizedParameterFormatting(String parameterContent, bool

public static ArgumentQueue parseToQueue(String argumentsInOneLine, boolean autoCompletion, boolean extraSpace) {
if (argumentsInOneLine.isEmpty())
return !autoCompletion ? ArgumentQueue.empty() : ArgumentQueue.parse(" ");
return !autoCompletion ? ArgumentQueue.empty(argumentsInOneLine) : ArgumentQueue.parse(" ");

ArgumentQueue toCollect = ArgumentQueue.empty();
toCollect.addAll(Arrays.asList(argumentsInOneLine.split(" ")));
ArgumentQueue toCollect = ArgumentQueue.empty(argumentsInOneLine);
System.out.println("ARGUMENT ONE LINE= '" + argumentsInOneLine + "'");
char[] chars = argumentsInOneLine.toCharArray();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];

if (isQuoteChar(c) && i != chars.length - 1) {
int start = i + 1;
while (start < chars.length && !isEndOfQuote(c, chars[start])) {
builder.append(chars[start]);
start++;
}
i = start;

toCollect.add(builder.toString());
builder = new StringBuilder();
continue;
}

if (Character.isWhitespace(c)) {
toCollect.add(builder.toString());
builder = new StringBuilder();
continue;
}

builder.append(c);

}
if (!builder.isEmpty()) {
toCollect.add(builder.toString());
}

if (autoCompletion && extraSpace)
toCollect.add(" ");
Expand All @@ -63,5 +93,14 @@ public static ArgumentQueue parseToQueue(String argumentsInOneLine, boolean auto
public static ArgumentQueue parseToQueue(String argumentsInOneLine, boolean autoCompletion) {
return parseToQueue(argumentsInOneLine, autoCompletion, false);
}


public static boolean isQuoteChar(char ch) {
return ch == DOUBLE_QUOTE || ch == SINGLE_QUOTE;
}

public static boolean isEndOfQuote(char quoteStarter, char value) {
return isQuoteChar(value) && isQuoteChar(quoteStarter) && quoteStarter == value;
}
}

0 comments on commit 1a71e45

Please sign in to comment.