diff --git a/src/com/annimon/everlastingsummer/transitions/TransitionsParser.java b/src/com/annimon/everlastingsummer/transitions/TransitionsParser.java new file mode 100644 index 0000000..3baf4ab --- /dev/null +++ b/src/com/annimon/everlastingsummer/transitions/TransitionsParser.java @@ -0,0 +1,117 @@ +package com.annimon.everlastingsummer.transitions; + +import java.util.List; +import android.graphics.Color; +import com.annimon.everlastingsummer.Token; +import com.annimon.everlastingsummer.TokenType; + +/** + * @author aNNiMON + */ +public final class TransitionsParser { + + private static final Token EOF = new Token("", TokenType.EOF); + + public static void parse(List tokens) { + new TransitionsParser(tokens).parse(); + } + + private final List tokens; + private final int tokensCount; + private int position; + + private TransitionsParser(List tokens) { + this.tokens = tokens; + tokensCount = tokens.size(); + position = 0; + } + + private void parse() { + while (!match(TokenType.EOF)) { + if (match(TokenType.DEFINE)) { + final String name = consume(TokenType.WORD).getText(); + consume(TokenType.EQ); + final String type = consume(TokenType.WORD).getText(); + if ("Fade".equals(type)) parseFade(name); + else if ("Dissolve".equals(type)) parseDissolve(name); + } else { + position++; + } + } + tokens.clear(); + } + + private void parseFade(String name) { + consume(TokenType.LPAREN); + final int outTime = consumeTime(); + // TODO: consume(TokenType.COMMA) + final int holdTime = consumeTime(); + // TODO: consume(TokenType.COMMA) + final int inTime = consumeTime(); + + int color = Color.BLACK; + if (!lookMatch(0, TokenType.RPAREN)) { + // TODO: consume(TokenType.COMMA) + // color? =? + match(TokenType.WORD); + match(TokenType.EQ); + color = consumeColor(); + } + consume(TokenType.RPAREN); + Transitions.set(name, new Fade(outTime, holdTime, inTime, color)); + } + + private void parseDissolve(String name) { + consume(TokenType.LPAREN); + final int time = consumeTime(); + consume(TokenType.RPAREN); + Transitions.set(name, new Dissolve(time)); + } + + + private int consumeTime() { + return (int) (1000 * Double.parseDouble(consume(TokenType.NUMBER).getText())); + } + + private int consumeColor() { + return parseColor( consume(TokenType.TEXT).getText() ); + } + + private int parseColor(String text) { + try { + return Color.parseColor(text); + } catch (IllegalArgumentException iae) { + // #fff + int index = text.charAt(0) == '#' ? 1 : 0; + if (text.length() != (index + 3)) return Color.BLACK; + final StringBuilder sb = new StringBuilder(7); + sb.append("#"); + sb.append(text.charAt(index)).append(text.charAt(index)); + index++; + sb.append(text.charAt(index)).append(text.charAt(index)); + index++; + sb.append(text.charAt(index)).append(text.charAt(index)); + return parseColor(sb.toString()); + } + } + + private boolean match(TokenType type) { + if (get(0).getType() != type) return false; + position++; + return true; + } + + private Token consume(TokenType type) { + if (get(0).getType() != type) throw new RuntimeException("Ожидался токен " + type + "."); + return tokens.get(position++); + } + + private boolean lookMatch(int pos, TokenType type) { + return (type == get(pos).getType()); + } + + private Token get(int offset) { + if (position + offset >= tokensCount) return EOF; + return tokens.get(position + offset); + } +}