PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/h2/src/tools/org/h2/java/JavaParser.java

http://h2database.googlecode.com/
Java | 1854 lines | 1674 code | 76 blank | 104 comment | 528 complexity | 083d194d482a96a08c3a496e7cc4a102 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
  3. * Version 1.0, and under the Eclipse Public License, Version 1.0
  4. * (http://h2database.com/html/license.html).
  5. * Initial Developer: H2 Group
  6. */
  7. package org.h2.java;
  8. import java.io.IOException;
  9. import java.io.PrintWriter;
  10. import java.io.RandomAccessFile;
  11. import java.text.ParseException;
  12. import java.util.ArrayList;
  13. import java.util.Collections;
  14. import java.util.HashMap;
  15. import java.util.HashSet;
  16. import java.util.LinkedHashMap;
  17. import org.h2.util.New;
  18. /**
  19. * Converts Java to C.
  20. */
  21. public class JavaParser {
  22. /**
  23. * Whether ref-counting is used.
  24. */
  25. public static final boolean REF_COUNT = false;
  26. /**
  27. * Whether ref-counting is used for constants.
  28. */
  29. public static final boolean REF_COUNT_STATIC = false;
  30. private static final HashMap<String, ClassObj> BUILT_IN_CLASSES = New
  31. .hashMap();
  32. private static final int TOKEN_LITERAL_CHAR = 0;
  33. private static final int TOKEN_LITERAL_STRING = 1;
  34. private static final int TOKEN_LITERAL_NUMBER = 2;
  35. private static final int TOKEN_RESERVED = 3;
  36. private static final int TOKEN_IDENTIFIER = 4;
  37. private static final int TOKEN_OTHER = 5;
  38. private static final HashSet<String> RESERVED = New.hashSet();
  39. private static final HashMap<String, String> JAVA_IMPORT_MAP = New
  40. .hashMap();
  41. private final ArrayList<ClassObj> allClasses = New.arrayList();
  42. private String source;
  43. private ParseState current = new ParseState();
  44. private String packageName;
  45. private ClassObj classObj;
  46. private int nextClassId;
  47. private MethodObj method;
  48. private FieldObj thisPointer;
  49. private final HashMap<String, String> importMap = New.hashMap();
  50. private final HashMap<String, ClassObj> classes = New.hashMap();
  51. private final LinkedHashMap<String, FieldObj> localVars =
  52. new LinkedHashMap<String, FieldObj>();
  53. private final HashMap<String, MethodObj> allMethodsMap = New.hashMap();
  54. private final ArrayList<Statement> nativeHeaders = New.arrayList();
  55. private final HashMap<String, String> stringToStringConstantMap = New
  56. .hashMap();
  57. private final HashMap<String, String> stringConstantToStringMap = New
  58. .hashMap();
  59. public JavaParser() {
  60. addBuiltInTypes();
  61. }
  62. private void addBuiltInTypes() {
  63. String[] list = { "abstract", "continue", "for", "new", "switch",
  64. "assert", "default", "if", "package", "synchronized",
  65. "boolean", "do", "goto", "private", "this", "break", "double",
  66. "implements", "protected", "throw", "byte", "else", "import",
  67. "public", "throws", "case", "enum", "instanceof", "return",
  68. "transient", "catch", "extends", "int", "short", "try", "char",
  69. "final", "interface", "static", "void", "class", "finally",
  70. "long", "strictfp", "volatile", "const", "float", "native",
  71. "super", "while", "true", "false", "null" };
  72. for (String s : list) {
  73. RESERVED.add(s);
  74. }
  75. int id = 0;
  76. addBuiltInType(id++, true, 0, "void");
  77. addBuiltInType(id++, true, 1, "boolean");
  78. addBuiltInType(id++, true, 2, "byte");
  79. addBuiltInType(id++, true, 3, "short");
  80. addBuiltInType(id++, true, 4, "char");
  81. addBuiltInType(id++, true, 5, "int");
  82. addBuiltInType(id++, true, 6, "long");
  83. addBuiltInType(id++, true, 7, "float");
  84. addBuiltInType(id++, true, 8, "double");
  85. String[] java = { "Boolean", "Byte", "Character", "Class",
  86. "ClassLoader", "Double", "Float", "Integer", "Long", "Math",
  87. "Number", "Object", "Runtime", "Short", "String",
  88. "StringBuffer", "StringBuilder", "System", "Thread",
  89. "ThreadGroup", "ThreadLocal", "Throwable", "Void" };
  90. for (String s : java) {
  91. JAVA_IMPORT_MAP.put(s, "java.lang." + s);
  92. addBuiltInType(id++, false, 0, "java.lang." + s);
  93. }
  94. nextClassId = id;
  95. }
  96. /**
  97. * Get the wrapper class for the given primitive class.
  98. *
  99. * @param c the class
  100. * @return the wrapper class
  101. */
  102. ClassObj getWrapper(ClassObj c) {
  103. switch (c.id) {
  104. case 1:
  105. return getClass("java.lang.Boolean");
  106. case 2:
  107. return getClass("java.lang.Byte");
  108. case 3:
  109. return getClass("java.lang.Short");
  110. case 4:
  111. return getClass("java.lang.Character");
  112. case 5:
  113. return getClass("java.lang.Integer");
  114. case 6:
  115. return getClass("java.lang.Long");
  116. case 7:
  117. return getClass("java.lang.Float");
  118. case 8:
  119. return getClass("java.lang.Double");
  120. }
  121. throw new RuntimeException("not a primitive type: " + classObj);
  122. }
  123. private void addBuiltInType(int id, boolean primitive, int primitiveType,
  124. String type) {
  125. ClassObj c = new ClassObj();
  126. c.id = id;
  127. c.className = type;
  128. c.isPrimitive = primitive;
  129. c.primitiveType = primitiveType;
  130. BUILT_IN_CLASSES.put(type, c);
  131. addClass(c);
  132. }
  133. private void addClass(ClassObj c) {
  134. int id = c.id;
  135. while (id >= allClasses.size()) {
  136. allClasses.add(null);
  137. }
  138. allClasses.set(id, c);
  139. }
  140. /**
  141. * Parse the source code.
  142. *
  143. * @param baseDir the base directory
  144. * @param className the fully qualified name of the class to parse
  145. */
  146. void parse(String baseDir, String className) {
  147. String fileName = baseDir + "/" + className.replace('.', '/') + ".java";
  148. current = new ParseState();
  149. try {
  150. RandomAccessFile file = new RandomAccessFile(fileName, "r");
  151. byte[] buff = new byte[(int) file.length()];
  152. file.readFully(buff);
  153. source = new String(buff, "UTF-8");
  154. file.close();
  155. } catch (IOException e) {
  156. throw new RuntimeException(e);
  157. }
  158. source = replaceUnicode(source);
  159. source = removeRemarks(source);
  160. try {
  161. readToken();
  162. parseCompilationUnit();
  163. } catch (Exception e) {
  164. throw new RuntimeException(source.substring(0, current.index)
  165. + "[*]" + source.substring(current.index), e);
  166. }
  167. }
  168. private static String cleanPackageName(String name) {
  169. if (name.startsWith("org.h2.java.lang")
  170. || name.startsWith("org.h2.java.io")) {
  171. return name.substring("org.h2.".length());
  172. }
  173. return name;
  174. }
  175. private void parseCompilationUnit() {
  176. if (readIf("package")) {
  177. packageName = cleanPackageName(readQualifiedIdentifier());
  178. read(";");
  179. }
  180. while (readIf("import")) {
  181. String importPackageName = cleanPackageName(readQualifiedIdentifier());
  182. String importClass = importPackageName.substring(importPackageName
  183. .lastIndexOf('.') + 1);
  184. importMap.put(importClass, importPackageName);
  185. read(";");
  186. }
  187. while (true) {
  188. Statement s = readNativeStatementIf();
  189. if (s == null) {
  190. break;
  191. }
  192. nativeHeaders.add(s);
  193. }
  194. while (true) {
  195. boolean isPublic = readIf("public");
  196. boolean isInterface;
  197. if (readIf("class")) {
  198. isInterface = false;
  199. } else {
  200. read("interface");
  201. isInterface = true;
  202. }
  203. String name = readIdentifier();
  204. classObj = BUILT_IN_CLASSES.get(packageName + "." + name);
  205. if (classObj == null) {
  206. classObj = new ClassObj();
  207. classObj.id = nextClassId++;
  208. }
  209. classObj.isPublic = isPublic;
  210. classObj.isInterface = isInterface;
  211. classObj.className = packageName == null ? "" : (packageName + ".")
  212. + name;
  213. // import this class
  214. importMap.put(name, classObj.className);
  215. addClass(classObj);
  216. classes.put(classObj.className, classObj);
  217. if (readIf("extends")) {
  218. classObj.superClassName = readQualifiedIdentifier();
  219. }
  220. if (readIf("implements")) {
  221. while (true) {
  222. classObj.interfaceNames.add(readQualifiedIdentifier());
  223. if (!readIf(",")) {
  224. break;
  225. }
  226. }
  227. }
  228. parseClassBody();
  229. if (current.token == null) {
  230. break;
  231. }
  232. }
  233. }
  234. private boolean isTypeOrIdentifier() {
  235. if (BUILT_IN_CLASSES.containsKey(current.token)) {
  236. return true;
  237. }
  238. return current.type == TOKEN_IDENTIFIER;
  239. }
  240. private ClassObj getClass(String type) {
  241. ClassObj c = getClassIf(type);
  242. if (c == null) {
  243. throw new RuntimeException("Unknown type: " + type);
  244. }
  245. return c;
  246. }
  247. /**
  248. * Get the class for a built-in type.
  249. *
  250. * @param type the type
  251. * @return the class or null if not found
  252. */
  253. static ClassObj getBuiltInClass(String type) {
  254. return BUILT_IN_CLASSES.get(type);
  255. }
  256. private ClassObj getClassIf(String type) {
  257. ClassObj c = BUILT_IN_CLASSES.get(type);
  258. if (c != null) {
  259. return c;
  260. }
  261. c = classes.get(type);
  262. if (c != null) {
  263. return c;
  264. }
  265. String mappedType = importMap.get(type);
  266. if (mappedType == null) {
  267. mappedType = JAVA_IMPORT_MAP.get(type);
  268. if (mappedType == null) {
  269. return null;
  270. }
  271. }
  272. c = classes.get(mappedType);
  273. if (c == null) {
  274. c = BUILT_IN_CLASSES.get(mappedType);
  275. if (c == null) {
  276. throw new RuntimeException("Unknown class: " + mappedType);
  277. }
  278. }
  279. return c;
  280. }
  281. private void parseClassBody() {
  282. read("{");
  283. localVars.clear();
  284. while (true) {
  285. if (readIf("}")) {
  286. break;
  287. }
  288. thisPointer = null;
  289. while (true) {
  290. Statement s = readNativeStatementIf();
  291. if (s == null) {
  292. break;
  293. }
  294. classObj.nativeCode.add(s);
  295. }
  296. thisPointer = null;
  297. HashSet<String> annotations = New.hashSet();
  298. while (readIf("@")) {
  299. String annotation = readIdentifier();
  300. annotations.add(annotation);
  301. }
  302. boolean isIgnore = annotations.contains("Ignore");
  303. boolean isLocalField = annotations.contains("Local");
  304. boolean isStatic = false;
  305. boolean isFinal = false;
  306. boolean isPrivate = false;
  307. boolean isPublic = false;
  308. boolean isNative = false;
  309. while (true) {
  310. if (readIf("static")) {
  311. isStatic = true;
  312. } else if (readIf("final")) {
  313. isFinal = true;
  314. } else if (readIf("native")) {
  315. isNative = true;
  316. } else if (readIf("private")) {
  317. isPrivate = true;
  318. } else if (readIf("public")) {
  319. isPublic = true;
  320. } else {
  321. break;
  322. }
  323. }
  324. if (readIf("{")) {
  325. method = new MethodObj();
  326. method.isIgnore = isIgnore;
  327. method.name = isStatic ? "cl_init_obj" : "";
  328. method.isStatic = isStatic;
  329. localVars.clear();
  330. if (!isStatic) {
  331. initThisPointer();
  332. }
  333. method.block = readStatement();
  334. classObj.addMethod(method);
  335. } else {
  336. String typeName = readTypeOrIdentifier();
  337. Type type = readType(typeName);
  338. method = new MethodObj();
  339. method.isIgnore = isIgnore;
  340. method.returnType = type;
  341. method.isStatic = isStatic;
  342. method.isFinal = isFinal;
  343. method.isPublic = isPublic;
  344. method.isPrivate = isPrivate;
  345. method.isNative = isNative;
  346. localVars.clear();
  347. if (!isStatic) {
  348. initThisPointer();
  349. }
  350. if (readIf("(")) {
  351. if (type.classObj != classObj) {
  352. throw getSyntaxException("Constructor of wrong type: "
  353. + type);
  354. }
  355. method.name = "";
  356. method.isConstructor = true;
  357. parseFormalParameters(method);
  358. if (!readIf(";")) {
  359. method.block = readStatement();
  360. }
  361. classObj.addMethod(method);
  362. addMethod(method);
  363. } else {
  364. String name = readIdentifier();
  365. if (name.endsWith("Method")) {
  366. name = name.substring(0,
  367. name.length() - "Method".length());
  368. }
  369. method.name = name;
  370. if (readIf("(")) {
  371. parseFormalParameters(method);
  372. if (!readIf(";")) {
  373. method.block = readStatement();
  374. }
  375. classObj.addMethod(method);
  376. addMethod(method);
  377. } else {
  378. FieldObj field = new FieldObj();
  379. field.isIgnore = isIgnore;
  380. field.isLocalField = isLocalField;
  381. field.type = type;
  382. field.name = name;
  383. field.isStatic = isStatic;
  384. field.isFinal = isFinal;
  385. field.isPublic = isPublic;
  386. field.isPrivate = isPrivate;
  387. field.declaredClass = classObj;
  388. if (readIf("=")) {
  389. if (field.type.arrayLevel > 0 && readIf("{")) {
  390. field.value = readArrayInit(field.type);
  391. } else {
  392. field.value = readExpr();
  393. }
  394. } else {
  395. field.value = field.type.getDefaultValue(this);
  396. }
  397. read(";");
  398. if (isStatic) {
  399. classObj.addStaticField(field);
  400. } else {
  401. classObj.addInstanceField(field);
  402. }
  403. }
  404. }
  405. }
  406. }
  407. }
  408. private void addMethod(MethodObj m) {
  409. if (m.isStatic) {
  410. return;
  411. }
  412. MethodObj old = allMethodsMap.get(m.name);
  413. if (old != null) {
  414. old.isVirtual = true;
  415. m.isVirtual = true;
  416. } else {
  417. allMethodsMap.put(m.name, m);
  418. }
  419. }
  420. private Expr readArrayInit(Type type) {
  421. ArrayInitExpr expr = new ArrayInitExpr();
  422. expr.type = new Type();
  423. expr.type.classObj = type.classObj;
  424. expr.type.arrayLevel = type.arrayLevel - 1;
  425. if (!readIf("}")) {
  426. while (true) {
  427. expr.list.add(readExpr());
  428. if (readIf("}")) {
  429. break;
  430. }
  431. read(",");
  432. if (readIf("}")) {
  433. break;
  434. }
  435. }
  436. }
  437. return expr;
  438. }
  439. private void initThisPointer() {
  440. thisPointer = new FieldObj();
  441. thisPointer.isVariable = true;
  442. thisPointer.name = "this";
  443. thisPointer.type = new Type();
  444. thisPointer.type.classObj = classObj;
  445. }
  446. private Type readType(String name) {
  447. Type type = new Type();
  448. type.classObj = getClass(name);
  449. while (readIf("[")) {
  450. read("]");
  451. type.arrayLevel++;
  452. }
  453. if (readIf("...")) {
  454. type.arrayLevel++;
  455. type.isVarArgs = true;
  456. }
  457. return type;
  458. }
  459. private void parseFormalParameters(MethodObj methodObj) {
  460. if (readIf(")")) {
  461. return;
  462. }
  463. while (true) {
  464. FieldObj field = new FieldObj();
  465. field.isVariable = true;
  466. String typeName = readTypeOrIdentifier();
  467. field.type = readType(typeName);
  468. if (field.type.isVarArgs) {
  469. methodObj.isVarArgs = true;
  470. }
  471. field.name = readIdentifier();
  472. methodObj.parameters.put(field.name, field);
  473. if (readIf(")")) {
  474. break;
  475. }
  476. read(",");
  477. }
  478. }
  479. private String readTypeOrIdentifier() {
  480. if (current.type == TOKEN_RESERVED) {
  481. if (BUILT_IN_CLASSES.containsKey(current.token)) {
  482. return read();
  483. }
  484. }
  485. String s = readIdentifier();
  486. while (readIf(".")) {
  487. s += "." + readIdentifier();
  488. }
  489. return s;
  490. }
  491. private Statement readNativeStatementIf() {
  492. if (readIf("//")) {
  493. boolean isC = readIdentifierIf("c");
  494. int start = current.index;
  495. while (source.charAt(current.index) != '\n') {
  496. current.index++;
  497. }
  498. String s = source.substring(start, current.index).trim();
  499. StatementNative stat = new StatementNative(s);
  500. read();
  501. return isC ? stat : null;
  502. } else if (readIf("/*")) {
  503. boolean isC = readIdentifierIf("c");
  504. int start = current.index;
  505. while (source.charAt(current.index) != '*'
  506. || source.charAt(current.index + 1) != '/') {
  507. current.index++;
  508. }
  509. String s = source.substring(start, current.index).trim();
  510. StatementNative stat = new StatementNative(s);
  511. current.index += 2;
  512. read();
  513. return isC ? stat : null;
  514. }
  515. return null;
  516. }
  517. private Statement readStatement() {
  518. Statement s = readNativeStatementIf();
  519. if (s != null) {
  520. return s;
  521. }
  522. if (readIf(";")) {
  523. return new EmptyStatement();
  524. } else if (readIf("{")) {
  525. StatementBlock stat = new StatementBlock();
  526. while (true) {
  527. if (readIf("}")) {
  528. break;
  529. }
  530. stat.instructions.add(readStatement());
  531. }
  532. return stat;
  533. } else if (readIf("if")) {
  534. IfStatement ifStat = new IfStatement();
  535. read("(");
  536. ifStat.condition = readExpr();
  537. read(")");
  538. ifStat.block = readStatement();
  539. if (readIf("else")) {
  540. ifStat.elseBlock = readStatement();
  541. }
  542. return ifStat;
  543. } else if (readIf("while")) {
  544. WhileStatement whileStat = new WhileStatement();
  545. read("(");
  546. whileStat.condition = readExpr();
  547. read(")");
  548. whileStat.block = readStatement();
  549. return whileStat;
  550. } else if (readIf("break")) {
  551. read(";");
  552. return new BreakStatement();
  553. } else if (readIf("continue")) {
  554. read(";");
  555. return new ContinueStatement();
  556. } else if (readIf("switch")) {
  557. read("(");
  558. SwitchStatement switchStat = new SwitchStatement(readExpr());
  559. read(")");
  560. read("{");
  561. while (true) {
  562. if (readIf("default")) {
  563. read(":");
  564. StatementBlock block = new StatementBlock();
  565. switchStat.setDefaultBlock(block);
  566. while (true) {
  567. block.instructions.add(readStatement());
  568. if (current.token.equals("case")
  569. || current.token.equals("default")
  570. || current.token.equals("}")) {
  571. break;
  572. }
  573. }
  574. } else if (readIf("case")) {
  575. Expr expr = readExpr();
  576. read(":");
  577. StatementBlock block = new StatementBlock();
  578. while (true) {
  579. block.instructions.add(readStatement());
  580. if (current.token.equals("case")
  581. || current.token.equals("default")
  582. || current.token.equals("}")) {
  583. break;
  584. }
  585. }
  586. switchStat.addCase(expr, block);
  587. } else if (readIf("}")) {
  588. break;
  589. }
  590. }
  591. return switchStat;
  592. } else if (readIf("for")) {
  593. ForStatement forStat = new ForStatement();
  594. read("(");
  595. ParseState back = copyParseState();
  596. try {
  597. String typeName = readTypeOrIdentifier();
  598. Type type = readType(typeName);
  599. String name = readIdentifier();
  600. FieldObj f = new FieldObj();
  601. f.name = name;
  602. f.type = type;
  603. f.isVariable = true;
  604. localVars.put(name, f);
  605. read(":");
  606. forStat.iterableType = type;
  607. forStat.iterableVariable = name;
  608. forStat.iterable = readExpr();
  609. } catch (Exception e) {
  610. current = back;
  611. forStat.init = readStatement();
  612. forStat.condition = readExpr();
  613. read(";");
  614. do {
  615. forStat.updates.add(readExpr());
  616. } while (readIf(","));
  617. }
  618. read(")");
  619. forStat.block = readStatement();
  620. return forStat;
  621. } else if (readIf("do")) {
  622. DoWhileStatement doWhileStat = new DoWhileStatement();
  623. doWhileStat.block = readStatement();
  624. read("while");
  625. read("(");
  626. doWhileStat.condition = readExpr();
  627. read(")");
  628. read(";");
  629. return doWhileStat;
  630. } else if (readIf("return")) {
  631. ReturnStatement returnStat = new ReturnStatement();
  632. if (!readIf(";")) {
  633. returnStat.expr = readExpr();
  634. read(";");
  635. }
  636. return returnStat;
  637. } else {
  638. if (isTypeOrIdentifier()) {
  639. ParseState start = copyParseState();
  640. String name = readTypeOrIdentifier();
  641. ClassObj c = getClassIf(name);
  642. if (c != null) {
  643. VarDecStatement dec = new VarDecStatement();
  644. dec.type = readType(name);
  645. while (true) {
  646. String varName = readIdentifier();
  647. Expr value = null;
  648. if (readIf("=")) {
  649. if (dec.type.arrayLevel > 0 && readIf("{")) {
  650. value = readArrayInit(dec.type);
  651. } else {
  652. value = readExpr();
  653. }
  654. }
  655. FieldObj f = new FieldObj();
  656. f.isVariable = true;
  657. f.type = dec.type;
  658. f.name = varName;
  659. localVars.put(varName, f);
  660. dec.addVariable(varName, value);
  661. if (readIf(";")) {
  662. break;
  663. }
  664. read(",");
  665. }
  666. return dec;
  667. }
  668. current = start;
  669. // ExprStatement
  670. }
  671. ExprStatement stat = new ExprStatement(readExpr());
  672. read(";");
  673. return stat;
  674. }
  675. }
  676. private ParseState copyParseState() {
  677. ParseState state = new ParseState();
  678. state.index = current.index;
  679. state.line = current.line;
  680. state.token = current.token;
  681. state.type = current.type;
  682. return state;
  683. }
  684. private Expr readExpr() {
  685. Expr expr = readExpr1();
  686. String assign = current.token;
  687. if (readIf("=") || readIf("+=") || readIf("-=") || readIf("*=")
  688. || readIf("/=") || readIf("&=") || readIf("|=") || readIf("^=")
  689. || readIf("%=") || readIf("<<=") || readIf(">>=")
  690. || readIf(">>>=")) {
  691. AssignExpr assignOp = new AssignExpr();
  692. assignOp.left = expr;
  693. assignOp.op = assign;
  694. assignOp.right = readExpr1();
  695. expr = assignOp;
  696. }
  697. return expr;
  698. }
  699. private Expr readExpr1() {
  700. Expr expr = readExpr2();
  701. if (readIf("?")) {
  702. ConditionalExpr ce = new ConditionalExpr();
  703. ce.condition = expr;
  704. ce.ifTrue = readExpr();
  705. read(":");
  706. ce.ifFalse = readExpr();
  707. return ce;
  708. }
  709. return expr;
  710. }
  711. private Expr readExpr2() {
  712. Expr expr = readExpr2a();
  713. while (true) {
  714. String infixOp = current.token;
  715. if (readIf("||")) {
  716. OpExpr opExpr = new OpExpr(this);
  717. opExpr.left = expr;
  718. opExpr.op = infixOp;
  719. opExpr.right = readExpr2a();
  720. expr = opExpr;
  721. } else {
  722. break;
  723. }
  724. }
  725. return expr;
  726. }
  727. private Expr readExpr2a() {
  728. Expr expr = readExpr2b();
  729. while (true) {
  730. String infixOp = current.token;
  731. if (readIf("&&")) {
  732. OpExpr opExpr = new OpExpr(this);
  733. opExpr.left = expr;
  734. opExpr.op = infixOp;
  735. opExpr.right = readExpr2b();
  736. expr = opExpr;
  737. } else {
  738. break;
  739. }
  740. }
  741. return expr;
  742. }
  743. private Expr readExpr2b() {
  744. Expr expr = readExpr2c();
  745. while (true) {
  746. String infixOp = current.token;
  747. if (readIf("|")) {
  748. OpExpr opExpr = new OpExpr(this);
  749. opExpr.left = expr;
  750. opExpr.op = infixOp;
  751. opExpr.right = readExpr2c();
  752. expr = opExpr;
  753. } else {
  754. break;
  755. }
  756. }
  757. return expr;
  758. }
  759. private Expr readExpr2c() {
  760. Expr expr = readExpr2d();
  761. while (true) {
  762. String infixOp = current.token;
  763. if (readIf("^")) {
  764. OpExpr opExpr = new OpExpr(this);
  765. opExpr.left = expr;
  766. opExpr.op = infixOp;
  767. opExpr.right = readExpr2d();
  768. expr = opExpr;
  769. } else {
  770. break;
  771. }
  772. }
  773. return expr;
  774. }
  775. private Expr readExpr2d() {
  776. Expr expr = readExpr2e();
  777. while (true) {
  778. String infixOp = current.token;
  779. if (readIf("&")) {
  780. OpExpr opExpr = new OpExpr(this);
  781. opExpr.left = expr;
  782. opExpr.op = infixOp;
  783. opExpr.right = readExpr2e();
  784. expr = opExpr;
  785. } else {
  786. break;
  787. }
  788. }
  789. return expr;
  790. }
  791. private Expr readExpr2e() {
  792. Expr expr = readExpr2f();
  793. while (true) {
  794. String infixOp = current.token;
  795. if (readIf("==") || readIf("!=")) {
  796. OpExpr opExpr = new OpExpr(this);
  797. opExpr.left = expr;
  798. opExpr.op = infixOp;
  799. opExpr.right = readExpr2f();
  800. expr = opExpr;
  801. } else {
  802. break;
  803. }
  804. }
  805. return expr;
  806. }
  807. private Expr readExpr2f() {
  808. Expr expr = readExpr2g();
  809. while (true) {
  810. String infixOp = current.token;
  811. if (readIf("<") || readIf(">") || readIf("<=") || readIf(">=")) {
  812. OpExpr opExpr = new OpExpr(this);
  813. opExpr.left = expr;
  814. opExpr.op = infixOp;
  815. opExpr.right = readExpr2g();
  816. expr = opExpr;
  817. } else {
  818. break;
  819. }
  820. }
  821. return expr;
  822. }
  823. private Expr readExpr2g() {
  824. Expr expr = readExpr2h();
  825. while (true) {
  826. String infixOp = current.token;
  827. if (readIf("<<") || readIf(">>") || readIf(">>>")) {
  828. OpExpr opExpr = new OpExpr(this);
  829. opExpr.left = expr;
  830. opExpr.op = infixOp;
  831. opExpr.right = readExpr2h();
  832. expr = opExpr;
  833. } else {
  834. break;
  835. }
  836. }
  837. return expr;
  838. }
  839. private Expr readExpr2h() {
  840. Expr expr = readExpr2i();
  841. while (true) {
  842. String infixOp = current.token;
  843. if (readIf("+") || readIf("-")) {
  844. OpExpr opExpr = new OpExpr(this);
  845. opExpr.left = expr;
  846. opExpr.op = infixOp;
  847. opExpr.right = readExpr2i();
  848. expr = opExpr;
  849. } else {
  850. break;
  851. }
  852. }
  853. return expr;
  854. }
  855. private Expr readExpr2i() {
  856. Expr expr = readExpr3();
  857. while (true) {
  858. String infixOp = current.token;
  859. if (readIf("*") || readIf("/") || readIf("%")) {
  860. OpExpr opExpr = new OpExpr(this);
  861. opExpr.left = expr;
  862. opExpr.op = infixOp;
  863. opExpr.right = readExpr3();
  864. expr = opExpr;
  865. } else {
  866. break;
  867. }
  868. }
  869. return expr;
  870. }
  871. private Expr readExpr3() {
  872. if (readIf("(")) {
  873. if (isTypeOrIdentifier()) {
  874. ParseState start = copyParseState();
  875. String name = readTypeOrIdentifier();
  876. ClassObj c = getClassIf(name);
  877. if (c != null) {
  878. read(")");
  879. CastExpr expr = new CastExpr();
  880. expr.type = new Type();
  881. expr.type.classObj = c;
  882. expr.expr = readExpr();
  883. return expr;
  884. }
  885. current = start;
  886. }
  887. Expr expr = readExpr();
  888. read(")");
  889. return expr;
  890. }
  891. String prefix = current.token;
  892. if (readIf("++") || readIf("--") || readIf("!") || readIf("~")
  893. || readIf("+") || readIf("-")) {
  894. OpExpr expr = new OpExpr(this);
  895. expr.op = prefix;
  896. expr.right = readExpr3();
  897. return expr;
  898. }
  899. Expr expr = readExpr4();
  900. String suffix = current.token;
  901. if (readIf("++") || readIf("--")) {
  902. OpExpr opExpr = new OpExpr(this);
  903. opExpr.left = expr;
  904. opExpr.op = suffix;
  905. expr = opExpr;
  906. }
  907. return expr;
  908. }
  909. private Expr readExpr4() {
  910. if (readIf("false")) {
  911. LiteralExpr expr = new LiteralExpr(this, "boolean");
  912. expr.literal = "false";
  913. return expr;
  914. } else if (readIf("true")) {
  915. LiteralExpr expr = new LiteralExpr(this, "boolean");
  916. expr.literal = "true";
  917. return expr;
  918. } else if (readIf("null")) {
  919. LiteralExpr expr = new LiteralExpr(this, "java.lang.Object");
  920. expr.literal = "null";
  921. return expr;
  922. } else if (current.type == TOKEN_LITERAL_NUMBER) {
  923. // TODO or long, float, double
  924. LiteralExpr expr = new LiteralExpr(this, "int");
  925. expr.literal = current.token.substring(1);
  926. readToken();
  927. return expr;
  928. } else if (current.type == TOKEN_LITERAL_CHAR) {
  929. LiteralExpr expr = new LiteralExpr(this, "char");
  930. expr.literal = current.token + "'";
  931. readToken();
  932. return expr;
  933. } else if (current.type == TOKEN_LITERAL_STRING) {
  934. String text = current.token.substring(1);
  935. StringExpr expr = getStringConstant(text);
  936. readToken();
  937. return expr;
  938. }
  939. Expr expr;
  940. expr = readExpr5();
  941. while (true) {
  942. if (readIf(".")) {
  943. String n = readIdentifier();
  944. if (readIf("(")) {
  945. CallExpr e2 = new CallExpr(this, expr, null, n);
  946. if (!readIf(")")) {
  947. while (true) {
  948. e2.args.add(readExpr());
  949. if (!readIf(",")) {
  950. read(")");
  951. break;
  952. }
  953. }
  954. }
  955. expr = e2;
  956. } else {
  957. VariableExpr e2 = new VariableExpr(this);
  958. e2.base = expr;
  959. expr = e2;
  960. e2.name = n;
  961. }
  962. } else if (readIf("[")) {
  963. ArrayAccessExpr arrayExpr = new ArrayAccessExpr();
  964. arrayExpr.base = expr;
  965. arrayExpr.index = readExpr();
  966. read("]");
  967. return arrayExpr;
  968. } else {
  969. break;
  970. }
  971. }
  972. return expr;
  973. }
  974. private StringExpr getStringConstant(String s) {
  975. String c = stringToStringConstantMap.get(s);
  976. if (c == null) {
  977. StringBuilder buff = new StringBuilder();
  978. for (int i = 0; i < s.length() && i < 16; i++) {
  979. char ch = s.charAt(i);
  980. if (ch >= 'a' && ch <= 'z') {
  981. // don't use Character.toUpperCase
  982. // to avoid locale problems
  983. // (the uppercase of 'i' is not always 'I')
  984. buff.append((char) (ch + 'A' - 'a'));
  985. } else if (ch >= 'A' && ch <= 'Z') {
  986. buff.append(ch);
  987. } else if (ch == '_' || ch == ' ') {
  988. buff.append('_');
  989. }
  990. }
  991. c = buff.toString();
  992. if (c.length() == 0 || stringConstantToStringMap.containsKey(c)) {
  993. if (c.length() == 0) {
  994. c = "X";
  995. }
  996. int i = 2;
  997. for (;; i++) {
  998. String c2 = c + "_" + i;
  999. if (!stringConstantToStringMap.containsKey(c2)) {
  1000. c = c2;
  1001. break;
  1002. }
  1003. }
  1004. }
  1005. c = "STRING_" + c;
  1006. stringToStringConstantMap.put(s, c);
  1007. stringConstantToStringMap.put(c, s);
  1008. }
  1009. StringExpr expr = new StringExpr(this);
  1010. expr.text = s;
  1011. expr.constantName = c;
  1012. return expr;
  1013. }
  1014. private Expr readExpr5() {
  1015. if (readIf("new")) {
  1016. NewExpr expr = new NewExpr();
  1017. String typeName = readTypeOrIdentifier();
  1018. expr.classObj = getClass(typeName);
  1019. if (readIf("(")) {
  1020. if (!readIf(")")) {
  1021. while (true) {
  1022. expr.args.add(readExpr());
  1023. if (!readIf(",")) {
  1024. read(")");
  1025. break;
  1026. }
  1027. }
  1028. }
  1029. } else {
  1030. while (readIf("[")) {
  1031. expr.arrayInitExpr.add(readExpr());
  1032. read("]");
  1033. }
  1034. }
  1035. return expr;
  1036. }
  1037. if (readIf("this")) {
  1038. VariableExpr expr = new VariableExpr(this);
  1039. if (thisPointer == null) {
  1040. throw getSyntaxException("'this' used in a static context");
  1041. }
  1042. expr.field = thisPointer;
  1043. return expr;
  1044. }
  1045. String name = readIdentifier();
  1046. if (readIf("(")) {
  1047. VariableExpr t;
  1048. if (thisPointer == null) {
  1049. // static method calling another static method
  1050. t = null;
  1051. } else {
  1052. // non-static method calling a static or non-static method
  1053. t = new VariableExpr(this);
  1054. t.field = thisPointer;
  1055. }
  1056. CallExpr expr = new CallExpr(this, t, classObj.className, name);
  1057. if (!readIf(")")) {
  1058. while (true) {
  1059. expr.args.add(readExpr());
  1060. if (!readIf(",")) {
  1061. read(")");
  1062. break;
  1063. }
  1064. }
  1065. }
  1066. return expr;
  1067. }
  1068. VariableExpr expr = new VariableExpr(this);
  1069. FieldObj f = localVars.get(name);
  1070. if (f == null) {
  1071. f = method.parameters.get(name);
  1072. }
  1073. if (f == null) {
  1074. f = classObj.staticFields.get(name);
  1075. }
  1076. if (f == null) {
  1077. f = classObj.instanceFields.get(name);
  1078. }
  1079. if (f == null) {
  1080. String imp = importMap.get(name);
  1081. if (imp == null) {
  1082. imp = JAVA_IMPORT_MAP.get(name);
  1083. }
  1084. if (imp != null) {
  1085. name = imp;
  1086. if (readIf(".")) {
  1087. String n = readIdentifier();
  1088. if (readIf("(")) {
  1089. CallExpr e2 = new CallExpr(this, null, imp, n);
  1090. if (!readIf(")")) {
  1091. while (true) {
  1092. e2.args.add(readExpr());
  1093. if (!readIf(",")) {
  1094. read(")");
  1095. break;
  1096. }
  1097. }
  1098. }
  1099. return e2;
  1100. }
  1101. VariableExpr e2 = new VariableExpr(this);
  1102. // static member variable
  1103. e2.name = imp + "." + n;
  1104. ClassObj c = classes.get(imp);
  1105. FieldObj sf = c.staticFields.get(n);
  1106. e2.field = sf;
  1107. return e2;
  1108. }
  1109. // TODO static field or method of a class
  1110. }
  1111. }
  1112. expr.field = f;
  1113. if (f != null && (!f.isVariable && !f.isStatic)) {
  1114. VariableExpr ve = new VariableExpr(this);
  1115. ve.field = thisPointer;
  1116. expr.base = ve;
  1117. if (thisPointer == null) {
  1118. throw getSyntaxException("'this' used in a static context");
  1119. }
  1120. }
  1121. expr.name = name;
  1122. return expr;
  1123. }
  1124. private void read(String string) {
  1125. if (!readIf(string)) {
  1126. throw getSyntaxException(string + " expected, got " + current.token);
  1127. }
  1128. }
  1129. private String readQualifiedIdentifier() {
  1130. String id = readIdentifier();
  1131. if (localVars.containsKey(id)) {
  1132. return id;
  1133. }
  1134. if (classObj != null) {
  1135. if (classObj.staticFields.containsKey(id)) {
  1136. return id;
  1137. }
  1138. if (classObj.instanceFields.containsKey(id)) {
  1139. return id;
  1140. }
  1141. }
  1142. String fullName = importMap.get(id);
  1143. if (fullName != null) {
  1144. return fullName;
  1145. }
  1146. while (readIf(".")) {
  1147. id += "." + readIdentifier();
  1148. }
  1149. return id;
  1150. }
  1151. private String readIdentifier() {
  1152. if (current.type != TOKEN_IDENTIFIER) {
  1153. throw getSyntaxException("identifier expected, got "
  1154. + current.token);
  1155. }
  1156. String result = current.token;
  1157. readToken();
  1158. return result;
  1159. }
  1160. private boolean readIdentifierIf(String token) {
  1161. if (current.type == TOKEN_IDENTIFIER && token.equals(current.token)) {
  1162. readToken();
  1163. return true;
  1164. }
  1165. return false;
  1166. }
  1167. private boolean readIf(String token) {
  1168. if (current.type != TOKEN_IDENTIFIER && token.equals(current.token)) {
  1169. readToken();
  1170. return true;
  1171. }
  1172. return false;
  1173. }
  1174. private String read() {
  1175. String token = current.token;
  1176. readToken();
  1177. return token;
  1178. }
  1179. private RuntimeException getSyntaxException(String message) {
  1180. return new RuntimeException(message, new ParseException(source,
  1181. current.index));
  1182. }
  1183. /**
  1184. * Replace all Unicode escapes.
  1185. *
  1186. * @param s the text
  1187. * @return the cleaned text
  1188. */
  1189. static String replaceUnicode(String s) {
  1190. if (s.indexOf("\\u") < 0) {
  1191. return s;
  1192. }
  1193. StringBuilder buff = new StringBuilder(s.length());
  1194. for (int i = 0; i < s.length(); i++) {
  1195. if (s.substring(i).startsWith("\\\\")) {
  1196. buff.append("\\\\");
  1197. i++;
  1198. } else if (s.substring(i).startsWith("\\u")) {
  1199. i += 2;
  1200. while (s.charAt(i) == 'u') {
  1201. i++;
  1202. }
  1203. String c = s.substring(i, i + 4);
  1204. buff.append((char) Integer.parseInt(c, 16));
  1205. i += 4;
  1206. } else {
  1207. buff.append(s.charAt(i));
  1208. }
  1209. }
  1210. return buff.toString();
  1211. }
  1212. /**
  1213. * Replace all Unicode escapes and remove all remarks.
  1214. *
  1215. * @param s the source code
  1216. * @return the cleaned source code
  1217. */
  1218. static String removeRemarks(String s) {
  1219. char[] chars = s.toCharArray();
  1220. for (int i = 0; i >= 0 && i < s.length(); i++) {
  1221. if (s.charAt(i) == '\'') {
  1222. i++;
  1223. while (true) {
  1224. if (s.charAt(i) == '\\') {
  1225. i++;
  1226. } else if (s.charAt(i) == '\'') {
  1227. break;
  1228. }
  1229. i++;
  1230. }
  1231. continue;
  1232. } else if (s.charAt(i) == '\"') {
  1233. i++;
  1234. while (true) {
  1235. if (s.charAt(i) == '\\') {
  1236. i++;
  1237. } else if (s.charAt(i) == '\"') {
  1238. break;
  1239. }
  1240. i++;
  1241. }
  1242. continue;
  1243. }
  1244. String sub = s.substring(i);
  1245. if (sub.startsWith("/*") && !sub.startsWith("/* c:")) {
  1246. int j = i;
  1247. i = s.indexOf("*/", i + 2) + 2;
  1248. for (; j < i; j++) {
  1249. if (chars[j] > ' ') {
  1250. chars[j] = ' ';
  1251. }
  1252. }
  1253. } else if (sub.startsWith("//") && !sub.startsWith("// c:")) {
  1254. int j = i;
  1255. i = s.indexOf('\n', i);
  1256. while (j < i) {
  1257. chars[j++] = ' ';
  1258. }
  1259. }
  1260. }
  1261. return new String(chars) + " ";
  1262. }
  1263. private void readToken() {
  1264. int ch;
  1265. while (true) {
  1266. if (current.index >= source.length()) {
  1267. current.token = null;
  1268. return;
  1269. }
  1270. ch = source.charAt(current.index);
  1271. if (ch == '\n') {
  1272. current.line++;
  1273. } else if (ch > ' ') {
  1274. break;
  1275. }
  1276. current.index++;
  1277. }
  1278. int start = current.index;
  1279. if (Character.isJavaIdentifierStart(ch)) {
  1280. while (Character.isJavaIdentifierPart(source.charAt(current.index))) {
  1281. current.index++;
  1282. }
  1283. current.token = source.substring(start, current.index);
  1284. if (RESERVED.contains(current.token)) {
  1285. current.type = TOKEN_RESERVED;
  1286. } else {
  1287. current.type = TOKEN_IDENTIFIER;
  1288. }
  1289. return;
  1290. } else if (Character.isDigit(ch)
  1291. || (ch == '.' && Character.isDigit(source
  1292. .charAt(current.index + 1)))) {
  1293. String s = source.substring(current.index);
  1294. current.token = "0" + readNumber(s);
  1295. current.index += current.token.length() - 1;
  1296. current.type = TOKEN_LITERAL_NUMBER;
  1297. return;
  1298. }
  1299. current.index++;
  1300. switch (ch) {
  1301. case '\'': {
  1302. while (true) {
  1303. if (source.charAt(current.index) == '\\') {
  1304. current.index++;
  1305. } else if (source.charAt(current.index) == '\'') {
  1306. break;
  1307. }
  1308. current.index++;
  1309. }
  1310. current.index++;
  1311. current.token = source.substring(start + 1, current.index);
  1312. current.token = "\'" + javaDecode(current.token, '\'');
  1313. current.type = TOKEN_LITERAL_CHAR;
  1314. return;
  1315. }
  1316. case '\"': {
  1317. while (true) {
  1318. if (source.charAt(current.index) == '\\') {
  1319. current.index++;
  1320. } else if (source.charAt(current.index) == '\"') {
  1321. break;
  1322. }
  1323. current.index++;
  1324. }
  1325. current.index++;
  1326. current.token = source.substring(start + 1, current.index);
  1327. current.token = "\"" + javaDecode(current.token, '\"');
  1328. current.type = TOKEN_LITERAL_STRING;
  1329. return;
  1330. }
  1331. case '(':
  1332. case ')':
  1333. case '[':
  1334. case ']':
  1335. case '{':
  1336. case '}':
  1337. case ';':
  1338. case ',':
  1339. case '?':
  1340. case ':':
  1341. case '@':
  1342. break;
  1343. case '.':
  1344. if (source.charAt(current.index) == '.'
  1345. && source.charAt(current.index + 1) == '.') {
  1346. current.index += 2;
  1347. }
  1348. break;
  1349. case '+':
  1350. if (source.charAt(current.index) == '='
  1351. || source.charAt(current.index) == '+') {
  1352. current.index++;
  1353. }
  1354. break;
  1355. case '-':
  1356. if (source.charAt(current.index) == '='
  1357. || source.charAt(current.index) == '-') {
  1358. current.index++;
  1359. }
  1360. break;
  1361. case '>':
  1362. if (source.charAt(current.index) == '>') {
  1363. current.index++;
  1364. if (source.charAt(current.index) == '>') {
  1365. current.index++;
  1366. }
  1367. }
  1368. if (source.charAt(current.index) == '=') {
  1369. current.index++;
  1370. }
  1371. break;
  1372. case '<':
  1373. if (source.charAt(current.index) == '<') {
  1374. current.index++;
  1375. }
  1376. if (source.charAt(current.index) == '=') {
  1377. current.index++;
  1378. }
  1379. break;
  1380. case '/':
  1381. if (source.charAt(current.index) == '*'
  1382. || source.charAt(current.index) == '/'
  1383. || source.charAt(current.index) == '=') {
  1384. current.index++;
  1385. }
  1386. break;
  1387. case '*':
  1388. case '~':
  1389. case '!':
  1390. case '=':
  1391. case '%':
  1392. case '^':
  1393. if (source.charAt(current.index) == '=') {
  1394. current.index++;
  1395. }
  1396. break;
  1397. case '&':
  1398. if (source.charAt(current.index) == '&') {
  1399. current.index++;
  1400. } else if (source.charAt(current.index) == '=') {
  1401. current.index++;
  1402. }
  1403. break;
  1404. case '|':
  1405. if (source.charAt(current.index) == '|') {
  1406. current.index++;
  1407. } else if (source.charAt(current.index) == '=') {
  1408. current.index++;
  1409. }
  1410. break;
  1411. }
  1412. current.type = TOKEN_OTHER;
  1413. current.token = source.substring(start, current.index);
  1414. }
  1415. /**
  1416. * Parse a number literal and returns it.
  1417. *
  1418. * @param s the source code
  1419. * @return the number
  1420. */
  1421. static String readNumber(String s) {
  1422. int i = 0;
  1423. if (s.startsWith("0x") || s.startsWith("0X")) {
  1424. i = 2;
  1425. while (true) {
  1426. char ch = s.charAt(i);
  1427. if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f')
  1428. && (ch < 'A' || ch > 'F')) {
  1429. break;
  1430. }
  1431. i++;
  1432. }
  1433. if (s.charAt(i) == 'l' || s.charAt(i) == 'L') {
  1434. i++;
  1435. }
  1436. } else {
  1437. while (true) {
  1438. char ch = s.charAt(i);
  1439. if ((ch < '0' || ch > '9') && ch != '.') {
  1440. break;
  1441. }
  1442. i++;
  1443. }
  1444. if (s.charAt(i) == 'e' || s.charAt(i) == 'E') {
  1445. i++;
  1446. if (s.charAt

Large files files are truncated, but you can click here to view the full file