// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.tools.template_engine; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class Tokenizer { public static class Token { private final TokenType type; private final int position; private final String text; public Token(TokenType type, int position) { this(type, position, null); } public Token(TokenType type, int position, String text) { this.type = type; this.position = position; this.text = text; } public TokenType getType() { return type; } public int getPosition() { return position; } public String getText() { return text; } @Override public String toString() { return type + (text != null ? ' ' + text : ""); } } public enum TokenType { CONDITION_START, VARIABLE_START, CONTEXT_SWITCH_START, END, PIPE, APOSTROPHE, TEXT, EOF } private final Set<Character> specialCharaters = new HashSet<>(Arrays.asList(new Character[] {'$', '?', '{', '}', '|', '\'', '!'})); private final String template; private int c; private int index; private Token currentToken; private final StringBuilder text = new StringBuilder(); public Tokenizer(String template) { this.template = template; getChar(); } private void getChar() { if (index >= template.length()) { c = -1; } else { c = template.charAt(index++); } } public Token nextToken() throws ParseError { if (currentToken != null) { Token result = currentToken; currentToken = null; return result; } int position = index; text.setLength(0); switch (c) { case -1: return new Token(TokenType.EOF, position); case '{': getChar(); return new Token(TokenType.VARIABLE_START, position); case '?': getChar(); if (c == '{') { getChar(); return new Token(TokenType.CONDITION_START, position); } else throw ParseError.unexpectedChar('{', (char) c, position); case '!': getChar(); if (c == '{') { getChar(); return new Token(TokenType.CONTEXT_SWITCH_START, position); } else throw ParseError.unexpectedChar('{', (char) c, position); case '}': getChar(); return new Token(TokenType.END, position); case '|': getChar(); return new Token(TokenType.PIPE, position); case '\'': getChar(); return new Token(TokenType.APOSTROPHE, position); default: while (c != -1 && !specialCharaters.contains((char) c)) { if (c == '\\') { getChar(); if (c == 'n') { c = '\n'; } } text.append((char) c); getChar(); } return new Token(TokenType.TEXT, position, text.toString()); } } public Token lookAhead() throws ParseError { if (currentToken == null) { currentToken = nextToken(); } return currentToken; } public Token skip(char lastChar) { currentToken = null; int position = index; StringBuilder result = new StringBuilder(); while (c != lastChar && c != -1) { if (c == '\\') { getChar(); } result.append((char) c); getChar(); } return new Token(TokenType.TEXT, position, result.toString()); } }