View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.subst;
15  
16  import ch.qos.logback.core.CoreConstants;
17  import ch.qos.logback.core.spi.ScanException;
18  
19  import java.util.List;
20  
21  // E = TE|T
22  //   = T(E|~)
23  // E = TEopt where Eopt = E|~
24  // T = LITERAL | { C } |'${' V '}'
25  // C = E|E :- E
26  //   = E(':-'E|~)
27  // V = E|E :- E
28  //   = E(':-'E|~)
29  
30  /**
31   * Parse a token list returning a node chain.
32   *
33   * @author Ceki Gulcu
34   */
35  public class Parser {
36  
37      final List<Token> tokenList;
38      int pointer = 0;
39  
40      public Parser(List<Token> tokenList) {
41          this.tokenList = tokenList;
42      }
43  
44      public Node parse() throws ScanException {
45          if (tokenList == null || tokenList.isEmpty())
46              return null;
47          return E();
48      }
49  
50      private Node E() throws ScanException {
51          Node t = T();
52          if (t == null) {
53              return null;
54          }
55          Node eOpt = Eopt();
56          if (eOpt != null) {
57              t.append(eOpt);
58          }
59          return t;
60      }
61  
62      // Eopt = E|~
63      private Node Eopt() throws ScanException {
64          Token next = peekAtCurentToken();
65          if (next == null) {
66              return null;
67          } else {
68              return E();
69          }
70      }
71  
72      // T = LITERAL | '${' V '}'
73      private Node T() throws ScanException {
74          Token t = peekAtCurentToken();
75  
76          switch (t.type) {
77          case LITERAL:
78              advanceTokenPointer();
79              return makeNewLiteralNode(t.payload);
80          case CURLY_LEFT:
81              advanceTokenPointer();
82              Node innerNode = C();
83              Token right = peekAtCurentToken();
84              expectCurlyRight(right);
85              advanceTokenPointer();
86              Node curlyLeft = makeNewLiteralNode(CoreConstants.LEFT_ACCOLADE);
87              curlyLeft.append(innerNode);
88              curlyLeft.append(makeNewLiteralNode(CoreConstants.RIGHT_ACCOLADE));
89              return curlyLeft;
90          case START:
91              advanceTokenPointer();
92              Node v = V();
93              Token w = peekAtCurentToken();
94              expectCurlyRight(w);
95              advanceTokenPointer();
96              return v;
97          default:
98              return null;
99          }
100     }
101 
102     private Node makeNewLiteralNode(String s) {
103         return new Node(Node.Type.LITERAL, s);
104     }
105 
106     // V = E(':='E|~)
107     private Node V() throws ScanException {
108         Node e = E();
109         Node variable = new Node(Node.Type.VARIABLE, e);
110         Token t = peekAtCurentToken();
111         if (isDefaultToken(t)) {
112             advanceTokenPointer();
113             Node def = E();
114             variable.defaultPart = def;
115         }
116         return variable;
117     }
118 
119     // C = E(':='E|~)
120     private Node C() throws ScanException {
121         Node e0 = E();
122         Token t = peekAtCurentToken();
123         if (isDefaultToken(t)) {
124             advanceTokenPointer();
125             Node literal = makeNewLiteralNode(CoreConstants.DEFAULT_VALUE_SEPARATOR);
126             e0.append(literal);
127             Node e1 = E();
128             e0.append(e1);
129         }
130         return e0;
131     }
132 
133     private boolean isDefaultToken(Token t) {
134         return t != null && t.type == Token.Type.DEFAULT;
135     }
136 
137     void advanceTokenPointer() {
138         pointer++;
139     }
140 
141     void expectNotNull(Token t, String expected) {
142         if (t == null) {
143             throw new IllegalArgumentException("All tokens consumed but was expecting \"" + expected + "\"");
144         }
145     }
146 
147     void expectCurlyRight(Token t) throws ScanException {
148         expectNotNull(t, "}");
149         if (t.type != Token.Type.CURLY_RIGHT) {
150             throw new ScanException("Expecting }");
151         }
152     }
153 
154     Token peekAtCurentToken() {
155         if (pointer < tokenList.size()) {
156             return tokenList.get(pointer);
157         }
158         return null;
159     }
160 
161 }