ListScanner.java
package org.sterling.source.scanner;
import static java.util.Arrays.asList;
import static org.sterling.source.syntax.NodeKind.ANYTHING;
import static org.sterling.source.syntax.NodeKind.END_OF_INPUT;
import static org.sterling.source.syntax.Token.token;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import org.sterling.SterlingException;
import org.sterling.source.LocationRange;
import org.sterling.source.exception.ScannerException;
import org.sterling.source.syntax.NodeKind;
import org.sterling.source.syntax.Token;
public class ListScanner implements Scanner {
private final Deque<Token> tokens;
private final StateManager<Token> transactions;
public ListScanner(List<Token> tokens) {
this.tokens = new ArrayDeque<>(tokens);
this.transactions = new StateManager<>(this.tokens);
this.tokens.add(token(END_OF_INPUT, "\0", LocationRange.NULL));
}
@Override
public void begin() {
transactions.begin();
}
@Override
public void close() {
transactions.close();
tokens.clear();
}
@Override
public void end() {
transactions.end();
}
@Override
public boolean expect(NodeKind kind) {
Token token = tokens.peek();
if (token == null) {
token = Token.NULL;
}
return token.is(kind);
}
@Override
public boolean expectOne(NodeKind... kinds) {
return expectOne(asList(kinds));
}
@Override
public boolean expectOne(Iterable<NodeKind> kinds) {
return ANYTHING != expected(kinds);
}
@Override
public NodeKind expected(NodeKind... kinds) {
return expected(asList(kinds));
}
@Override
public NodeKind expected(Iterable<NodeKind> kinds) {
for (NodeKind kind : kinds) {
if (expect(kind)) {
return kind;
}
}
return ANYTHING;
}
@Override
public Token require(NodeKind kind) throws SterlingException {
if (expect(kind)) {
Token next = tokens.poll();
transactions.push(next);
return next;
} else {
throw unexpectedToken();
}
}
@Override
public Token requireOne(NodeKind... kinds) throws SterlingException {
return requireOne(asList(kinds));
}
@Override
public Token requireOne(Collection<NodeKind> kinds) throws SterlingException {
for (NodeKind kind : kinds) {
if (expect(kind)) {
return require(kind);
}
}
throw unexpectedToken();
}
@Override
public void restore() {
transactions.restore();
}
private ScannerException unexpectedToken() {
return new ScannerException("Unexpected token: " + tokens.peek());
}
}