/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.cli.impl.tokenizer;
import org.crsh.cli.impl.line.LineParser;
import org.crsh.cli.impl.line.Quoting;
import java.util.LinkedList;
/**
* @author Julien Viet
*/
class Automaton extends LineParser.Visitor {
/** . */
private Status status = Status.WHITESPACE;
/** . */
private final StringBuilder buffer = new StringBuilder();
/** . */
final LinkedList<Token> tokens = new LinkedList<Token>();
/** . */
private int from = 0;
/** . */
private int lastWhitespace = 0;
/** . */
private final CharSequence s;
Automaton(CharSequence s) {
this.s = s;
}
void close() {
if (buffer.length() > 0) {
if (status == Status.WHITESPACE) {
next(lastWhitespace);
} else {
next(s.length());
}
}
}
private void next(int current) {
Token token;
switch (status) {
case WHITESPACE:
token = new Token.Whitespace(from, s.subSequence(from, current).toString());
break;
case WORD:
token = new Token.Literal.Word(from, s.subSequence(from, current).toString(), buffer.toString());
break;
case SHORT_OPTION:
token = new Token.Literal.Option.Short(from, s.subSequence(from, current).toString(), buffer.toString());
break;
case LONG_OPTION:
token = new Token.Literal.Option.Long(from, s.subSequence(from, current).toString(), buffer.toString());
break;
default:
throw new AssertionError();
}
tokens.add(token);
status = Status.WHITESPACE;
buffer.setLength(0);
from = current;
}
@Override
public void onChar(int index, Quoting quoting, boolean backslash, char c) {
if (Character.isWhitespace(c) && quoting == null && !backslash) {
lastWhitespace = index + 1;
if (status != Status.WHITESPACE) {
next(index);
}
buffer.append(c);
} else {
switch (status) {
case WHITESPACE:
if (buffer.length() > 0) {
next(lastWhitespace);
}
buffer.append(c);
if (c == '-') {
status = Status.SHORT_OPTION;
} else {
status = Status.WORD;
}
break;
case WORD:
buffer.append(c);
break;
case SHORT_OPTION:
if (c == '-') {
buffer.append('-');
status = Status.LONG_OPTION;
} else if (Character.isLetter(c)) {
buffer.append(c);
} else {
status = Status.WORD;
buffer.append(c);
}
break;
case LONG_OPTION:
if (c == '-') {
if (buffer.length() > 2) {
buffer.append(c);
} else {
status = Status.WORD;
buffer.append(c);
}
} else if (Character.isLetter(c)) {
buffer.append(c);
} else {
status = Status.WORD;
buffer.append(c);
}
}
}
}
enum Status { WHITESPACE, WORD, SHORT_OPTION, LONG_OPTION }
}