001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.subst; 015 016import ch.qos.logback.core.CoreConstants; 017import ch.qos.logback.core.spi.ScanException; 018 019import java.util.List; 020 021// E = TE|T 022// = T(E|~) 023// E = TEopt where Eopt = E|~ 024// T = LITERAL | { C } |'${' V '}' 025// C = E|E :- E 026// = E(':-'E|~) 027// V = E|E :- E 028// = E(':-'E|~) 029 030// new definition 031 032// V = E | E :- Eopt 033// = E (~| :- Eopt) 034 035/** 036 * Parse a token list returning a node chain. 037 * 038 * @author Ceki Gulcu 039 */ 040public class Parser { 041 042 static final public String EXPECTING_DATA_AFTER_LEFT_ACCOLADE = "Expecting at least a literal between left accolade and ':-'"; 043 044 final List<Token> tokenList; 045 int pointer = 0; 046 047 public Parser(List<Token> tokenList) { 048 this.tokenList = tokenList; 049 } 050 051 public Node parse() throws ScanException { 052 if (tokenList == null || tokenList.isEmpty()) 053 return null; 054 return E(); 055 } 056 057 private Node E() throws ScanException { 058 Node t = T(); 059 if (t == null) { 060 return null; 061 } 062 Node eOpt = Eopt(); 063 if (eOpt != null) { 064 t.append(eOpt); 065 } 066 return t; 067 } 068 069 // Eopt = E|~ 070 private Node Eopt() throws ScanException { 071 Token next = peekAtCurentToken(); 072 if (next == null) { 073 return null; 074 } else { 075 return E(); 076 } 077 } 078 079 // T = LITERAL | '${' V '}' 080 private Node T() throws ScanException { 081 Token t = peekAtCurentToken(); 082 if(t == null) { 083 return null; 084 } 085 switch (t.type) { 086 case LITERAL: 087 advanceTokenPointer(); 088 return makeNewLiteralNode(t.payload); 089 case CURLY_LEFT: 090 advanceTokenPointer(); 091 Node innerNode = C(); 092 Token right = peekAtCurentToken(); 093 expectCurlyRight(right); 094 advanceTokenPointer(); 095 Node curlyLeft = makeNewLiteralNode(CoreConstants.LEFT_ACCOLADE); 096 curlyLeft.append(innerNode); 097 curlyLeft.append(makeNewLiteralNode(CoreConstants.RIGHT_ACCOLADE)); 098 return curlyLeft; 099 case START: 100 advanceTokenPointer(); 101 Node v = V(); 102 Token w = peekAtCurentToken(); 103 expectCurlyRight(w); 104 advanceTokenPointer(); 105 return v; 106 default: 107 return null; 108 } 109 } 110 111 private Node makeNewLiteralNode(String s) { 112 return new Node(Node.Type.LITERAL, s); 113 } 114 115 // V = E (~| :- Eopt) 116 private Node V() throws ScanException { 117 Node e = E(); 118 Node variable = new Node(Node.Type.VARIABLE, e); 119 Token t = peekAtCurentToken(); 120 if (isDefaultToken(t)) { 121 advanceTokenPointer(); 122 Node def = Eopt(); 123 if(def != null) { 124 variable.defaultPart = def; 125 } else { 126 variable.defaultPart = makeNewLiteralNode(CoreConstants.EMPTY_STRING); 127 } 128 } 129 return variable; 130 } 131 132 133 // C = E(':-'E|~) 134 private Node C() throws ScanException { 135 Node e0 = E(); 136 Token t = peekAtCurentToken(); 137 if (isDefaultToken(t)) { 138 advanceTokenPointer(); 139 Node literal = makeNewLiteralNode(CoreConstants.DEFAULT_VALUE_SEPARATOR); 140 if(e0 == null) { 141 throw new ScanException(EXPECTING_DATA_AFTER_LEFT_ACCOLADE); 142 } 143 e0.append(literal); 144 Node e1 = E(); 145 e0.append(e1); 146 } 147 return e0; 148 } 149 150 private boolean isDefaultToken(Token t) { 151 return t != null && t.type == Token.Type.DEFAULT; 152 } 153 154 void advanceTokenPointer() { 155 pointer++; 156 } 157 158 void expectNotNull(Token t, String expected) { 159 if (t == null) { 160 throw new IllegalArgumentException("All tokens consumed but was expecting \"" + expected + "\""); 161 } 162 } 163 164 void expectCurlyRight(Token t) throws ScanException { 165 expectNotNull(t, "}"); 166 if (t.type != Token.Type.CURLY_RIGHT) { 167 throw new ScanException("Expecting }"); 168 } 169 } 170 171 Token peekAtCurentToken() { 172 if (pointer < tokenList.size()) { 173 return tokenList.get(pointer); 174 } 175 return null; 176 } 177 178}