1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.diag; 18 19 import static com.google.common.base.MoreObjects.firstNonNull; 20 21 import com.google.common.base.CharMatcher; 22 import com.google.common.base.Strings; 23 24 /** A compilation error. */ 25 public class TurbineError extends Error { 26 27 /** A diagnostic kind. */ 28 public enum ErrorKind { 29 UNEXPECTED_INPUT("unexpected input: %c"), 30 UNEXPECTED_IDENTIFIER("unexpected identifier '%s'"), 31 UNEXPECTED_EOF("unexpected end of input"), 32 EXPECTED_TOKEN("expected token %s"), 33 INVALID_LITERAL("invalid literal: %s"), 34 UNEXPECTED_TYPE_PARAMETER("unexpected type parameter %s"), 35 SYMBOL_NOT_FOUND("symbol not found %s"), 36 TYPE_PARAMETER_QUALIFIER("type parameter used as type qualifier"), 37 UNEXPECTED_TOKEN("unexpected token: %s"), 38 INVALID_ANNOTATION_ARGUMENT("invalid annotation argument"), 39 CANNOT_RESOLVE("cannot resolve %s"), 40 EXPRESSION_ERROR("could not evaluate constant expression"), 41 CYCLIC_HIERARCHY("cycle in class hierarchy: %s"), 42 NOT_AN_ANNOTATION("%s is not an annotation"), 43 NONREPEATABLE_ANNOTATION("%s is not @Repeatable"), 44 DUPLICATE_DECLARATION("duplicate declaration of %s"); 45 46 private final String message; 47 48 ErrorKind(String message) { 49 this.message = message; 50 } 51 52 String format(Object... args) { 53 return String.format(message, args); 54 } 55 } 56 57 /** 58 * Formats a diagnostic. 59 * 60 * @param source the source file 61 * @param position the diagnostic position 62 * @param kind the error kind 63 * @param args format args 64 */ 65 public static TurbineError format( 66 SourceFile source, int position, ErrorKind kind, Object... args) { 67 String path = firstNonNull(source.path(), "<>"); 68 LineMap lineMap = LineMap.create(source.source()); 69 int lineNumber = lineMap.lineNumber(position); 70 int column = lineMap.column(position); 71 String message = kind.format(args); 72 73 StringBuilder sb = new StringBuilder(path).append(":"); 74 sb.append(lineNumber).append(": error: "); 75 sb.append(message.trim()).append(System.lineSeparator()); 76 sb.append(CharMatcher.breakingWhitespace().trimTrailingFrom(lineMap.line(position))) 77 .append(System.lineSeparator()); 78 sb.append(Strings.repeat(" ", column)).append('^'); 79 String diagnostic = sb.toString(); 80 return new TurbineError(kind, diagnostic); 81 } 82 83 final ErrorKind kind; 84 85 private TurbineError(ErrorKind kind, String diagnostic) { 86 super(diagnostic); 87 this.kind = kind; 88 } 89 90 /** The diagnostic kind. */ 91 public ErrorKind kind() { 92 return kind; 93 } 94 } 95