All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrick.template.Errors Maven / Gradle / Ivy

There is a newer version: 2.1.10
Show newest version
/**
 * Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 *   Author: Guoqiang Chen
 *    Email: [email protected]
 *   WebURL: https://github.com/subchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrick.template;

import jetbrick.template.parser.Source;
import jetbrick.template.parser.ast.Position;
import jetbrick.util.StringUtils;

public final class Errors {
    public static final String JETX_ERROR_SOURCE_DISABLED = "JETX_ERROR_SOURCE_DISABLED";

    // general error
    public static final String UNREACHABLE_CODE = "unreachable code";
    public static final String TEMPLATE_PATH_ERROR = "path is outside of template root: %s";

    // syntax error
    public static final String VARIABLE_UNDEFINED = "undefined variable found in strict mode: %s";
    public static final String VARIABLE_REDEFINE = "cannot redefine variable: %s";
    public static final String VARIABLE_DEFAINE_AFTER_USE = "cannot define variable after use it: %s";
    public static final String VARIABLE_IS_KEYWORD = "syntax error on token `%s`, It is a reserved/keyword identifier";
    public static final String VARIABLE_IS_RESERVED = "local variable `%s` cannot start with '$', it is a reserved identifier";
    public static final String ARGUMENT_TYPE_MISSING = "argument type is missing in strict mode: %s";
    public static final String ARGUMENTS_NOT_MATCH = "arguments not match";
    public static final String ARGUMENTS_MISSING = "arguments is missing: %s";

    public static final String OPTION_NAME_INVALID = "#option name is unknown: %s";
    public static final String OPTION_VALUE_INVALID = "#option value is invalid: %s";

    public static final String DIRECTIVE_OUTSIDE_OF_FOR = "`%s` cannot be used outside of `#for(...)`";
    public static final String DIRECTIVE_MACRO_NAME_DUPLICATED = "duplicated macro name: %s";
    public static final String UNICODE_STRING_INVALID = "invalid unicode in string constant";

    // interpret error
    public static final String CLASS_NOT_FOUND = "cannot resolve class: %s";
    public static final String CONSTRUCTOR_NOT_FOUND = "cannot resolve constructor: %s";
    public static final String METHOD_NOT_FOUND = "cannot resolve method: %s";
    public static final String PROPERTY_NOT_FOUND = "cannot resolve property: %s";
    public static final String STATIC_METHOD_NOT_FOUND = "cannot resolve static method: %s";
    public static final String STATIC_FIELD_NOT_FOUND = "cannot resolve static field: %s";
    public static final String FUNCTION_NOT_FOUND = "cannot resolve function: %s";
    public static final String TAG_NOT_FOUND = "cannot resolve tag: %s";
    public static final String MACRO_NOT_FOUND = "cannot resolve macro: %s";
    public static final String INCLUDE_FILE_NOT_FOUND = "include file not found: %s";

    public static final String CONSTRUCTOR_INVOKE_ERROR = "constructor invoke error: %s";
    public static final String METHOD_INVOKE_ERROR = "method invoke error: %s";
    public static final String FUNCTION_INVOKE_ERROR = "function invoke error: %s";
    public static final String STATIC_METHOD_INVOKE_ERROR = "static method invoke error: %s";
    public static final String STATIC_FIELD_GET_ERROR = "static field get error: %s#%s";
    public static final String PROPERTY_GET_ERROR = "property get error: %s";
    public static final String FOR_ITERATOR_ERROR = "iterate error when index = %s";

    public static final String EXPRESSION_OBJECT_IS_NULL = "object is null";
    public static final String EXPRESSION_INDEX_IS_NULL = "index is null";
    public static final String EXPRESSION_LHS_IS_NULL = "left operand is null";
    public static final String EXPRESSION_RHS_IS_NULL = "right operand is null";
    public static final String EXPRESSION_ARRAY_LENGTH_NULL = "array length is null";
    public static final String EXPRESSION_NTH_ARGUMENT_IS_NULL = "the %s argument is null";
    public static final String EXPRESSION_OBJECT_IS_VOID = "object is void";
    public static final String EXPRESSION_INDEX_IS_VOID = "index is void";
    public static final String EXPRESSION_ARGUMENT_IS_VOID = "argument is void";

    public static final String VARIABLE_TYPE_INCONSISTENT = "inconsistent class for variable: `%s` is not %s, got %s";
    public static final String VARIABLE_TYPE_MISMATCH = "type mismatch: the %s argument cannot convert from %s to %s";

    public static final String OPERATION_UNARY_UNDEFINED = "the operator `%s` is undefined for the argument type: %s";
    public static final String OPERATION_BINARY_UNDEFINED = "the operator `%s` is undefined for the argument type(s): %s, %s";

    // ---------------------------------------------------------------------------------

    // 判断是否是因为参数不匹配导致的错误
    public static boolean isReflectIllegalArgument(Throwable e) {
        Class cls = e.getClass();
        if (cls == IllegalArgumentException.class || cls == ClassCastException.class) {
            // https://github.com/subchen/jetbrick-template-2x/issues/17
            StackTraceElement[] elements = e.getStackTrace();
            if (elements == null || elements.length == 0) {
                return false;
            }

            String className = elements[0].getClassName();
            if (className == null) {
                return false;
            }

            //@formatter:off
            return "sun.reflect.NativeMethodAccessorImpl".equals(className)
                || "sun.reflect.GeneratedMethodAccessor1".equals(className)
                || className.startsWith("jetbrick.bean.asm.delegate.");
            //@formatter:on
        }
        return false;
    }

    public static String typeName(Object object) {
        if (object == null) {
            return "";
        } else {
            return StringUtils.removeStart(object.getClass().getName(), "java.lang.");
        }
    }

    public static String format(String message, Object... args) {
        if (args == null || args.length == 0) {
            return message;
        }
        return String.format(message, args);
    }

    public static String format(String message, Source source, Position position) {
        if (source == null || position == null) {
            return message;
        }

        // 允许用户禁止输出模板源码
        if ("true".equals(System.getProperty(JETX_ERROR_SOURCE_DISABLED))) {
            return message;
        }

        StringBuilder sb = new StringBuilder(256);
        sb.append(message);
        sb.append("\n\n");
        sb.append("template: ");
        sb.append(source.getFilename());
        sb.append(": ");
        sb.append(position.getLine());
        sb.append(',');
        sb.append(position.getColumn());
        sb.append('\n');
        sb.append("-------------------------------------------------------------------------------\n");
        markSourceLines(sb, source.getLines(), position.getLine(), position.getColumn());
        sb.append("-------------------------------------------------------------------------------\n");
        return sb.toString();
    }

    // 输出错误对应的模板源码
    static void markSourceLines(StringBuilder sb, String[] sourceLines, int line, int column) {
        int lineStart = Math.max(line - 3, 0);
        int lineEnd = Math.min(line + 2, sourceLines.length);

        // 自动计算最大行数占用的宽度
        int digits = Math.max(2, String.valueOf(lineEnd).length()) + 1;
        String pattern = "%" + digits + "d: %s%n";
        String indicator = StringUtils.repeat(' ', digits + 2);

        for (int i = lineStart; i < lineEnd; i++) {
            String sourceLine = sourceLines[i];

            if (i == line - 1) {
                // 修正 column (可能存在宽字符)
                int origin_column = Math.min(column, sourceLine.length() - 1);
                for (int j = 0; j < origin_column; j++) {
                    char c = sourceLine.charAt(j);
                    if (c == '\t') {
                        column += 3; // 1 个 Tab 变成 4 个空格
                    } else if (c >= '\u2E80' && c <= '\uFE4F') {
                        column++; // 中日韩统一表意文字(CJK Unified Ideographs)
                    }
                }
            }

            sourceLine = sourceLine.replace("\t", "    ");
            sb.append(String.format(pattern, Integer.valueOf(i + 1), sourceLine));

            // 插入错误提示符
            if (i == line - 1) {
                sb.append(indicator);
                for (int j = 0; j < column; j++) {
                    sb.append(' ');
                }
                sb.append("^ -- here\n");
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy