package mireka.address.parser; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import mireka.address.parser.Ipv6Token.Kind; import mireka.address.parser.base.CharClass; import mireka.address.parser.base.CharScanner; import mireka.address.parser.base.CharToken; public class Ipv6Scanner { private CharScanner charScanner; private CharToken currentCharToken; private List<CharToken> currentSpelling = new ArrayList<CharToken>(); public Ipv6Scanner(CharScanner charScanner) { this.charScanner = charScanner; currentCharToken = charScanner.scan(); } public Ipv6Token scan() throws ParseException { int position = currentCharToken.position; currentSpelling.clear(); Kind kind = scanToken(); return new Ipv6Token(position, currentSpelling, kind); } private Kind scanToken() throws ParseException { if (CharClasses.HEX.isSatisfiedBy(currentCharToken.ch)) { scanHexDigits(); return Kind.NUM; } else if (currentCharToken.ch == '.') { takeIt(); return Kind.DOT; } else if (currentCharToken.ch == ':') { takeIt(); if (currentCharToken.ch == ':') { takeIt(); return Kind.DOUBLE_COLON; } else { return Kind.COLON; } } else if (currentCharToken.ch == -1) { takeIt(); return Kind.EOF; } else { takeIt(); return Kind.OTHER; } } private void scanHexDigits() throws ParseException { take(CharClasses.HEX); for (int i = 0; i < 3; i++) { if (CharClasses.HEX.isSatisfiedBy(currentCharToken.ch)) { takeIt(); } } } private void take(CharClass charClass) throws ParseException { if (charClass.isSatisfiedBy(currentCharToken.ch)) takeIt(); else throw currentCharToken.syntaxException(charClass); } private void takeIt() { currentSpelling.add(currentCharToken); currentCharToken = charScanner.scan(); } /** * Unreads lookahead data from the underlying character scanner. */ public void finish(Ipv6Token lastUnparsedToken) { charScanner.pushBack(currentCharToken); charScanner.pushBack(lastUnparsedToken); } }