001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: */
005: /*
006: * Licensed to the Apache Software Foundation (ASF) under one or more
007: * contributor license agreements. See the NOTICE file distributed with
008: * this work for additional information regarding copyright ownership.
009: * The ASF licenses this file to You under the Apache License, Version 2.0
010: * (the "License"); you may not use this file except in compliance with
011: * the License. You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021: package org.h2.test.trace;
022:
023: import java.math.BigDecimal;
024: import java.sql.SQLException;
025: import java.util.ArrayList;
026:
027: import org.h2.util.StringUtils;
028:
029: /**
030: * Parses an entry in a Java-style log file.
031: */
032: class Parser {
033: private static final int STRING = 0, NAME = 1, NUMBER = 2,
034: SPECIAL = 3;
035: private Player player;
036: private Statement stat;
037: private String line;
038: private String token;
039: private int tokenType;
040: private int pos;
041:
042: static Statement parseStatement(Player player, String line) {
043: Parser p = new Parser(player, line);
044: p.parseStatement();
045: return p.stat;
046: }
047:
048: private Parser(Player player, String line) {
049: this .player = player;
050: this .line = line;
051: read();
052: }
053:
054: private Statement parseStatement() {
055: stat = new Statement(player);
056: String name = readToken();
057: Object o = player.getObject(name);
058: if (o == null) {
059: if (readIf(".")) {
060: // example: java.lang.System.exit(0);
061: parseStaticCall(name);
062: } else {
063: // example: Statement s1 = ...
064: stat.setAssign(name, readToken());
065: read("=");
066: name = readToken();
067: o = player.getObject(name);
068: if (o != null) {
069: // example: ... = s1.executeQuery();
070: read(".");
071: parseCall(name, o, readToken());
072: } else if (readIf(".")) {
073: // ... = x.y.z("...");
074: parseStaticCall(name);
075: }
076: }
077: } else {
078: // example: s1.execute()
079: read(".");
080: String methodName = readToken();
081: parseCall(name, o, methodName);
082: }
083: return stat;
084: }
085:
086: private void read() {
087: while (line.charAt(pos) == ' ') {
088: pos++;
089: }
090: int start = pos;
091: char ch = line.charAt(pos);
092: switch (ch) {
093: case '\"':
094: tokenType = STRING;
095: pos++;
096: while (pos < line.length()) {
097: ch = line.charAt(pos);
098: if (ch == '\\') {
099: pos += 2;
100: } else if (ch == '\"') {
101: pos++;
102: break;
103: } else {
104: pos++;
105: }
106: }
107: break;
108: case '.':
109: case ',':
110: case '(':
111: case ')':
112: case ';':
113: case '{':
114: case '}':
115: case '[':
116: case ']':
117: case '=':
118: tokenType = SPECIAL;
119: pos++;
120: break;
121: default:
122: if (Character.isLetter(ch) || ch == '_') {
123: tokenType = NAME;
124: pos++;
125: while (true) {
126: ch = line.charAt(pos);
127: if (Character.isLetterOrDigit(ch) || ch == '_') {
128: pos++;
129: } else {
130: break;
131: }
132: }
133: } else if (ch == '-' || Character.isDigit(ch)) {
134: tokenType = NUMBER;
135: pos++;
136: while (true) {
137: ch = line.charAt(pos);
138: if (Character.isDigit(ch)
139: || ".+-eElLxabcdefABCDEF".indexOf(ch) >= 0) {
140: pos++;
141: } else {
142: break;
143: }
144: }
145: }
146: }
147: token = line.substring(start, pos);
148: }
149:
150: private boolean readIf(String s) {
151: if (token.equals(s)) {
152: read();
153: return true;
154: }
155: return false;
156: }
157:
158: private String readToken() {
159: String s = token;
160: read();
161: return s;
162: }
163:
164: private void read(String s) {
165: if (!readIf(s)) {
166: throw new Error("Expected: " + s + " got: " + token
167: + " in " + line);
168: }
169: }
170:
171: private Arg parseValue() {
172: if (tokenType == STRING) {
173: String s = readToken();
174: try {
175: s = StringUtils.javaDecode(s.substring(1,
176: s.length() - 1));
177: } catch (SQLException e) {
178: throw new Error(e);
179: }
180: return new Arg(player, String.class, s);
181: } else if (tokenType == NUMBER) {
182: String number = readToken().toLowerCase();
183: if (number.endsWith("f")) {
184: Float v = new Float(Float.parseFloat(number));
185: return new Arg(player, float.class, v);
186: } else if (number.endsWith("d") || number.indexOf("e") >= 0
187: || number.indexOf(".") >= 0) {
188: Double v = new Double(Double.parseDouble(number));
189: return new Arg(player, double.class, v);
190: } else if (number.endsWith("L") || number.endsWith("l")) {
191: Long v = new Long(Long.parseLong(number.substring(0,
192: number.length() - 1)));
193: return new Arg(player, long.class, v);
194: } else {
195: Integer v = new Integer(Integer.parseInt(number));
196: return new Arg(player, int.class, v);
197: }
198: } else if (tokenType == NAME) {
199: if (readIf("true")) {
200: return new Arg(player, boolean.class, Boolean.TRUE);
201: } else if (readIf("false")) {
202: return new Arg(player, boolean.class, Boolean.FALSE);
203: } else if (readIf("null")) {
204: throw new Error(
205: "Null: class not specified. Example: (java.lang.String)null");
206: } else if (readIf("new")) {
207: if (readIf("String")) {
208: read("[");
209: read("]");
210: read("{");
211: ArrayList values = new ArrayList();
212: do {
213: values.add(parseValue().getValue());
214: } while (readIf(","));
215: read("}");
216: String[] list = new String[values.size()];
217: values.toArray(list);
218: return new Arg(player, String[].class, list);
219: } else if (readIf("BigDecimal")) {
220: read("(");
221: BigDecimal value = new BigDecimal(
222: (String) parseValue().getValue());
223: read(")");
224: return new Arg(player, BigDecimal.class, value);
225: } else {
226: throw new Error("Unsupported constructor: "
227: + readToken());
228: }
229: }
230: String name = readToken();
231: Object obj = player.getObject(name);
232: if (obj != null) {
233: return new Arg(player, obj.getClass(), obj);
234: }
235: read(".");
236: Statement outer = stat;
237: stat = new Statement(player);
238: parseStaticCall(name);
239: Arg s = new Arg(stat);
240: stat = outer;
241: return s;
242: } else if (readIf("(")) {
243: read("short");
244: read(")");
245: String number = readToken();
246: return new Arg(player, short.class, new Short(Short
247: .parseShort(number)));
248: } else {
249: throw new Error("Value expected, got: " + readToken()
250: + " in " + line);
251: }
252: }
253:
254: private void parseCall(String objectName, Object o,
255: String methodName) {
256: stat.setMethodCall(objectName, o, methodName);
257: ArrayList args = new ArrayList();
258: read("(");
259: while (true) {
260: if (readIf(")")) {
261: break;
262: }
263: Arg p = parseValue();
264: args.add(p);
265: if (readIf(")")) {
266: break;
267: }
268: read(",");
269: }
270: stat.setArgs(args);
271: }
272:
273: private void parseStaticCall(String clazz) {
274: String last = readToken();
275: while (readIf(".")) {
276: clazz += last == null ? "" : "." + last;
277: last = readToken();
278: }
279: String methodName = last;
280: stat.setStaticCall(clazz);
281: parseCall(null, null, methodName);
282: }
283:
284: }
|