| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package com.android.tools.r8.naming; |
| |
| import static com.android.tools.r8.position.TextPosition.UNKNOWN_COLUMN; |
| |
| import com.android.tools.r8.origin.PathOrigin; |
| import com.android.tools.r8.position.TextPosition; |
| import com.android.tools.r8.utils.ExceptionDiagnostic; |
| import com.android.tools.r8.utils.Reporter; |
| import com.android.tools.r8.utils.StringDiagnostic; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableList.Builder; |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| public class DictionaryReader implements AutoCloseable { |
| |
| private final BufferedReader reader; |
| private final Path path; |
| |
| public DictionaryReader(Path path) throws IOException { |
| this.path = path; |
| this.reader = Files.newBufferedReader(path); |
| } |
| |
| public String readName(Reporter reporter) throws IOException { |
| assert reader != null; |
| |
| StringBuilder name = new StringBuilder(); |
| int readCharAsInt; |
| int lineNumber = 1; |
| |
| while ((readCharAsInt = reader.read()) != -1) { |
| char readChar = (char) readCharAsInt; |
| |
| if ((name.length() != 0 && Character.isJavaIdentifierPart(readChar)) |
| || (name.length() == 0 && Character.isJavaIdentifierStart(readChar))) { |
| name.append(readChar); |
| } else { |
| boolean isCommentChar = readChar == '#'; |
| boolean isValidEndOfLineInput = readChar == '\n' || readChar == '\r'; |
| if (isCommentChar || isValidEndOfLineInput) { |
| if (isCommentChar) { |
| reader.readLine(); |
| } |
| lineNumber++; |
| } |
| if (isValidEndOfLineInput && name.length() != 0) { |
| return name.toString(); |
| } |
| name = new StringBuilder(); |
| // An illegal character was in the input. We discard the entire line instead of returning as |
| // much as possible, to ensure us not throwing an error in the case of duplicates. |
| if (!isValidEndOfLineInput) { |
| reporter.info( |
| new StringDiagnostic( |
| "Invalid character in dictionary '" + readChar + "'", |
| new PathOrigin(path), |
| new TextPosition(0, lineNumber, UNKNOWN_COLUMN))); |
| reader.readLine(); |
| lineNumber++; |
| } |
| } |
| } |
| |
| return name.toString(); |
| } |
| |
| @Override |
| public void close() throws IOException { |
| if (reader != null) { |
| reader.close(); |
| } |
| } |
| |
| public static ImmutableList<String> readAllNames(Path path, Reporter reporter) { |
| if (path != null) { |
| Set<String> seenNames = new HashSet<>(); |
| Builder<String> namesBuilder = new ImmutableList.Builder<String>(); |
| try (DictionaryReader reader = new DictionaryReader(path);) { |
| String name = reader.readName(reporter); |
| while (!name.isEmpty()) { |
| if (!seenNames.add(name)) { |
| reporter.error( |
| new StringDiagnostic( |
| "Duplicate entry for '" + name + "' in dictionary", new PathOrigin(path))); |
| } |
| namesBuilder.add(name); |
| name = reader.readName(reporter); |
| } |
| } catch (IOException e) { |
| reporter.error(new ExceptionDiagnostic(e, new PathOrigin(path))); |
| } |
| return namesBuilder.build(); |
| } else { |
| return ImmutableList.of(); |
| } |
| } |
| } |