DelegatingScanner.java

package org.sterling.source.scanner;

import static java.util.Arrays.asList;
import static org.sterling.source.scanner.ScannerUtil.unexpectedInput;
import static org.sterling.source.syntax.NodeKind.ANYTHING;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.sterling.SterlingException;
import org.sterling.source.syntax.NodeKind;
import org.sterling.source.syntax.Token;

public class DelegatingScanner implements Scanner {

    private final InputReader reader;
    private final Map<NodeKind, ScannerDelegate> delegates;

    public DelegatingScanner(InputReader reader, Map<NodeKind, ScannerDelegate> delegates) {
        this.reader = reader;
        this.delegates = new HashMap<>(delegates);
    }

    @Override
    public void begin() {
        reader.begin();
    }

    @Override
    public void close() {
        reader.close();
    }

    @Override
    public void end() {
        reader.end();
    }

    @Override
    public boolean expect(NodeKind kind) {
        if (delegates.containsKey(kind)) {
            return delegates.get(kind).expect(kind, reader);
        } else if (ANYTHING == kind) {
            return true;
        } else {
            throw new IllegalArgumentException("No delegate registered to token kind " + 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(Iterable<NodeKind> kinds) {
        for (NodeKind kind : kinds) {
            if (expect(kind)) {
                return kind;
            }
        }
        return ANYTHING;
    }

    @Override
    public NodeKind expected(NodeKind... kinds) {
        return expected(asList(kinds));
    }

    @Override
    public Token require(NodeKind kind) throws SterlingException {
        if (expect(kind)) {
            return delegates.get(kind).require(kind, reader);
        } else {
            throw unexpectedInput(reader, kind);
        }
    }

    @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 unexpectedInput(reader, kinds);
    }

    @Override
    public void restore() {
        reader.rollback();
    }
}