1 | // Copyright (C) 2005 Google Inc. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package com.google.caja.reporting; |
16 | |
17 | import java.io.IOException; |
18 | import java.util.Formatter; |
19 | |
20 | /** |
21 | * The type of a {@link Message message}. |
22 | * |
23 | * @author mikesamuel@gmail.com |
24 | */ |
25 | public enum MessageType implements MessageTypeInt { |
26 | // TODO(mikesamuel): rename this to CommonMessageType and rename |
27 | // MessageTypeInt to MessageType |
28 | |
29 | INTERNAL_ERROR("Internal error: %s", MessageLevel.FATAL_ERROR), |
30 | IO_ERROR("I/O Error: %s", MessageLevel.FATAL_ERROR), |
31 | NO_SUCH_FILE("%s: could not read input", MessageLevel.FATAL_ERROR), |
32 | |
33 | // lexing messages |
34 | UNTERMINATED_STRING_TOKEN("%s: Unclosed string", MessageLevel.FATAL_ERROR), |
35 | UNTERMINATED_COMMENT_TOKEN( |
36 | "%s: Unclosed comment", MessageLevel.FATAL_ERROR), |
37 | UNREPRESENTABLE_INTEGER_LITERAL( |
38 | "%s: Integer literal %s doesn't fit in 51 bits", MessageLevel.WARNING), |
39 | MALFORMED_NUMBER("%s: Malformed number %s", MessageLevel.FATAL_ERROR), |
40 | UNRECOGNIZED_ESCAPE("%s: Unrecognized escape '%s'", MessageLevel.FATAL_ERROR), |
41 | MALFORMED_STRING("%s: Illegal char in string '%s'", MessageLevel.FATAL_ERROR), |
42 | MALFORMED_URI("%s: Not a valid uri: '%s'", MessageLevel.FATAL_ERROR), |
43 | MALFORMED_XHTML("%s: malformed xhtml: %s", MessageLevel.FATAL_ERROR), |
44 | MALFORMED_HTML_ENTITY( |
45 | "%s: HTML entity missing closing semicolon %s", MessageLevel.WARNING), |
46 | REDUNDANT_ESCAPE_SEQUENCE( |
47 | "%s: escape %s is redundant in a quoted string", MessageLevel.LINT), |
48 | AMBIGUOUS_ESCAPE_SEQUENCE( |
49 | "%s: escape sequence %s does not work in all interpreters", |
50 | MessageLevel.WARNING), |
51 | INVALID_CSS_COMMENT( |
52 | "%s: Line comments non-standard in CSS.", MessageLevel.LINT), |
53 | |
54 | // parsing |
55 | END_OF_FILE("Unexpected end of input in %s", MessageLevel.ERROR), |
56 | EXPECTED_TOKEN("%s: Expected %s not %s", MessageLevel.ERROR), |
57 | UNUSED_TOKENS("%s: Unused tokens: %s ...", MessageLevel.ERROR), |
58 | MAYBE_MISSING_SEMI("%s: Maybe missing semicolon", MessageLevel.WARNING), |
59 | SEMICOLON_INSERTED("%s: Semicolon inserted", MessageLevel.LINT), |
60 | PLACEHOLDER_INSERTED("%s: Placeholder inserted", MessageLevel.WARNING), |
61 | RESERVED_WORD_USED_AS_IDENTIFIER( |
62 | "%s: Reserved word %s used as an identifier", MessageLevel.ERROR), |
63 | INVALID_IDENTIFIER("%s: Malformed identifier %s", MessageLevel.ERROR), |
64 | UNEXPECTED_TOKEN("%s: Unexpected token %s", MessageLevel.ERROR), |
65 | DUPLICATE_FORMAL_PARAM( |
66 | "%s: Duplicate formal parameter %s", MessageLevel.ERROR), |
67 | UNRECOGNIZED_REGEX_MODIFIERS( |
68 | "%s: Unrecognized regular expression modifiers %s", MessageLevel.ERROR), |
69 | PARSE_ERROR("%s: Parse error", MessageLevel.ERROR), |
70 | AMBIGUOUS_ATTRIBUTE_VALUE( |
71 | "%s: attribute %s has ambiguous value \"%s\"", MessageLevel.WARNING), |
72 | MISSING_ATTRIBUTE_VALUE( |
73 | "%s: missing value for attribute %s", MessageLevel.FATAL_ERROR), |
74 | OCTAL_LITERAL("%s: octal literal %s", MessageLevel.LINT), |
75 | UNRECOGNIZED_DIRECTIVE_IN_PROLOGUE( |
76 | "%s: unrecognized directive in prologue: %s", |
77 | MessageLevel.WARNING), |
78 | SKIPPING("%s: Skipping malformed content", MessageLevel.WARNING), |
79 | DUPLICATE_ATTRIBUTE( |
80 | "%s: attribute %s duplicates one at %s", MessageLevel.WARNING), |
81 | NO_SUCH_NAMESPACE( |
82 | "%s: unrecognized namespace %s on %s", MessageLevel.WARNING), |
83 | ILLEGAL_NAMESPACE_NAME( |
84 | "%s: illegal namespace name: %s", MessageLevel.WARNING), |
85 | CANNOT_OVERRIDE_DEFAULT_NAMESPACE_IN_HTML( |
86 | "%s: cannot override default XML namespace in HTML", |
87 | MessageLevel.WARNING), |
88 | |
89 | // platform context |
90 | NOT_IE("%s: Will not work in IE", MessageLevel.WARNING), |
91 | |
92 | // symbol errors |
93 | SYMBOL_REDEFINED("%s: %s originally defined at %s", MessageLevel.ERROR), |
94 | UNDOCUMENTED_GLOBAL("%s: Undocumented global %s", MessageLevel.LINT), |
95 | INVALID_ASSIGNMENT( |
96 | "%s: Invalid assignment to %s", MessageLevel.ERROR), |
97 | MASKING_SYMBOL( |
98 | "%s: Declaration of %s masks declaration at %s", MessageLevel.LINT), |
99 | UNDEFINED_SYMBOL( |
100 | "%s: Symbol %s has not been defined", MessageLevel.ERROR), |
101 | ASSIGN_TO_NON_LVALUE( |
102 | "%s: Assignment to non lvalue: %s", MessageLevel.ERROR), |
103 | |
104 | // runtime, as during constant folding |
105 | DIVISION_BY_ZERO("%s: Division by zero", MessageLevel.WARNING), |
106 | INDEX_OUT_OF_BOUNDS("%s: Index out of bounds %s", MessageLevel.WARNING), |
107 | INVALID_MEMBER_ACCESS("%s: Invalid member %s", MessageLevel.WARNING), |
108 | INVALID_REGEXP_FLAGS("%s: Invalid regexp flags %s", MessageLevel.WARNING), |
109 | INVALID_SHIFT_AMOUNT("%s: Cannot shift by %s bits", MessageLevel.WARNING), |
110 | INVALID_MASK("%s: Masking outside 32 bits: %s", MessageLevel.WARNING), |
111 | POSSIBLE_SIDE_EFFECT("%s: Possible side-effecting operation's value not used", |
112 | MessageLevel.WARNING), |
113 | NO_SIDE_EFFECT("%s: Operation has no effect", MessageLevel.WARNING), |
114 | |
115 | // logging |
116 | CHECKPOINT("Checkpoint: %s at T+%s seconds", MessageLevel.LOG), |
117 | BUILD_INFO("Google Caja. Copyright (C) 2008, Google Inc. Rev %s built on %s.", |
118 | MessageLevel.LOG), |
119 | ; |
120 | |
121 | private final String formatString; |
122 | private final MessageLevel level; |
123 | private final int paramCount; |
124 | |
125 | MessageType(String formatString, MessageLevel level) { |
126 | this.formatString = formatString; |
127 | this.level = level; |
128 | this.paramCount = formatStringArity(formatString); |
129 | } |
130 | |
131 | public void format(MessagePart[] parts, MessageContext context, |
132 | Appendable out) throws IOException { |
133 | formatMessage(formatString, parts, context, out); |
134 | } |
135 | |
136 | public MessageLevel getLevel() { return level; } |
137 | |
138 | public int getParamCount() { |
139 | return paramCount; |
140 | } |
141 | |
142 | public static void formatMessage( |
143 | String formatString, MessagePart[] parts, MessageContext context, |
144 | Appendable out) |
145 | throws IOException { |
146 | Object[] partStrings = new Object[parts.length]; |
147 | for (int i = 0; i < parts.length; ++i) { |
148 | StringBuilder sb = new StringBuilder(); |
149 | parts[i].format(context, sb); |
150 | partStrings[i] = sb.toString(); |
151 | } |
152 | new Formatter(out).format(formatString, partStrings); |
153 | } |
154 | |
155 | public static int formatStringArity(String formatString) { |
156 | int count = 0; |
157 | for (int i = 0, n = formatString.length(); i < n; ++i) { |
158 | char ch = formatString.charAt(i); |
159 | if ('%' == ch) { |
160 | if (i + 1 < n && '%' != formatString.charAt(i + 1)) { |
161 | ++count; |
162 | } else { |
163 | ++i; |
164 | } |
165 | } |
166 | } |
167 | return count; |
168 | } |
169 | } |