ECMAErrors.java revision 953:221a84ef44c0
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime;
27
28import java.text.MessageFormat;
29import java.util.Locale;
30import java.util.ResourceBundle;
31
32import jdk.nashorn.internal.codegen.CompilerConstants;
33import jdk.nashorn.internal.objects.Global;
34import jdk.nashorn.internal.scripts.JS;
35
36/**
37 * Helper class to throw various standard "ECMA error" exceptions such as Error, ReferenceError, TypeError etc.
38 */
39public final class ECMAErrors {
40    private static final String MESSAGES_RESOURCE = "jdk.nashorn.internal.runtime.resources.Messages";
41
42    private static final ResourceBundle MESSAGES_BUNDLE;
43    static {
44        MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault());
45    }
46
47    /** We assume that compiler generates script classes into the known package. */
48    private static final String scriptPackage;
49    static {
50        final String name = JS.class.getName();
51        scriptPackage = name.substring(0, name.lastIndexOf('.'));
52    }
53
54    private ECMAErrors() {
55    }
56
57    private static ECMAException error(final Object thrown, final Throwable cause) {
58        return new ECMAException(thrown, cause);
59    }
60
61     /**
62     * Error dispatch mechanism.
63     * Create a {@link ParserException} as the correct JavaScript error
64     *
65     * @param e {@code ParserException} for error dispatcher
66     *
67     * @return the resulting {@link ECMAException}
68     */
69    public static ECMAException asEcmaException(final ParserException e) {
70        return asEcmaException(Context.getGlobal(), e);
71    }
72
73    /**
74     * Error dispatch mechanism.
75     * Create a {@link ParserException} as the correct JavaScript error
76     *
77     * @param global global scope object
78     * @param e {@code ParserException} for error dispatcher
79     *
80     * @return the resulting {@link ECMAException}
81     */
82    public static ECMAException asEcmaException(final Global global, final ParserException e) {
83        final JSErrorType errorType = e.getErrorType();
84        assert errorType != null : "error type for " + e + " was null";
85
86        final Global globalObj    = global;
87        final String       msg    = e.getMessage();
88
89        // translate to ECMAScript Error object using error type
90        switch (errorType) {
91        case ERROR:
92            return error(globalObj.newError(msg), e);
93        case EVAL_ERROR:
94            return error(globalObj.newEvalError(msg), e);
95        case RANGE_ERROR:
96            return error(globalObj.newRangeError(msg), e);
97        case REFERENCE_ERROR:
98            return error(globalObj.newReferenceError(msg), e);
99        case SYNTAX_ERROR:
100            return error(globalObj.newSyntaxError(msg), e);
101        case TYPE_ERROR:
102            return error(globalObj.newTypeError(msg), e);
103        case URI_ERROR:
104            return error(globalObj.newURIError(msg), e);
105        default:
106            // should not happen - perhaps unknown error type?
107            throw new AssertionError(e.getMessage());
108        }
109    }
110
111    /**
112     * Create a syntax error (ECMA 15.11.6.4)
113     *
114     * @param msgId   resource tag for error message
115     * @param args    arguments to resource
116     *
117     * @return the resulting {@link ECMAException}
118     */
119    public static ECMAException syntaxError(final String msgId, final String... args) {
120        return syntaxError(Context.getGlobal(), msgId, args);
121    }
122
123    /**
124     * Create a syntax error (ECMA 15.11.6.4)
125     *
126     * @param global  global scope object
127     * @param msgId   resource tag for error message
128     * @param args    arguments to resource
129     *
130     * @return the resulting {@link ECMAException}
131     */
132    public static ECMAException syntaxError(final Global global, final String msgId, final String... args) {
133        return syntaxError(global, null, msgId, args);
134    }
135
136    /**
137     * Create a syntax error (ECMA 15.11.6.4)
138     *
139     * @param cause   native Java {@code Throwable} that is the cause of error
140     * @param msgId   resource tag for error message
141     * @param args    arguments to resource
142     *
143     * @return the resulting {@link ECMAException}
144     */
145    public static ECMAException syntaxError(final Throwable cause, final String msgId, final String... args) {
146        return syntaxError(Context.getGlobal(), cause, msgId, args);
147    }
148
149    /**
150     * Create a syntax error (ECMA 15.11.6.4)
151     *
152     * @param global  global scope object
153     * @param cause   native Java {@code Throwable} that is the cause of error
154     * @param msgId   resource tag for error message
155     * @param args    arguments to resource
156     *
157     * @return the resulting {@link ECMAException}
158     */
159    public static ECMAException syntaxError(final Global global, final Throwable cause, final String msgId, final String... args) {
160        final String msg = getMessage("syntax.error." + msgId, args);
161        return error(global.newSyntaxError(msg), cause);
162    }
163
164    /**
165     * Create a type error (ECMA 15.11.6.5)
166     *
167     * @param msgId   resource tag for error message
168     * @param args    arguments to resource
169     *
170     * @return the resulting {@link ECMAException}
171     */
172    public static ECMAException typeError(final String msgId, final String... args) {
173        return typeError(Context.getGlobal(), msgId, args);
174    }
175
176    /**
177     * Create a type error (ECMA 15.11.6.5)
178     *
179     * @param global  global scope object
180     * @param msgId   resource tag for error message
181     * @param args    arguments to resource
182     *
183     * @return the resulting {@link ECMAException}
184     */
185    public static ECMAException typeError(final Global global, final String msgId, final String... args) {
186        return typeError(global, null, msgId, args);
187    }
188
189    /**
190     * Create a type error (ECMA 15.11.6.5)
191     *
192     * @param cause   native Java {@code Throwable} that is the cause of error
193     * @param msgId   resource tag for error message
194     * @param args    arguments to resource
195     *
196     * @return the resulting {@link ECMAException}
197     */
198    public static ECMAException typeError(final Throwable cause, final String msgId, final String... args) {
199        return typeError(Context.getGlobal(), cause, msgId, args);
200    }
201
202    /**
203     * Create a type error (ECMA 15.11.6.5)
204     *
205     * @param global  global scope object
206     * @param cause   native Java {@code Throwable} that is the cause of error
207     * @param msgId   resource tag for error message
208     * @param args    arguments to resource
209     *
210     * @return the resulting {@link ECMAException}
211     */
212    public static ECMAException typeError(final Global global, final Throwable cause, final String msgId, final String... args) {
213        final String msg = getMessage("type.error." + msgId, args);
214        return error(global.newTypeError(msg), cause);
215    }
216
217    /**
218     * Create a range error (ECMA 15.11.6.2)
219     *
220     * @param msgId   resource tag for error message
221     * @param args    arguments to resource
222     *
223     * @return the resulting {@link ECMAException}
224     */
225    public static ECMAException rangeError(final String msgId, final String... args) {
226        return rangeError(Context.getGlobal(), msgId, args);
227    }
228
229    /**
230     * Create a range error (ECMA 15.11.6.2)
231     *
232     * @param global  global scope object
233     * @param msgId   resource tag for error message
234     * @param args    arguments to resource
235     *
236     * @return the resulting {@link ECMAException}
237     */
238    public static ECMAException rangeError(final Global global, final String msgId, final String... args) {
239        return rangeError(global, null, msgId, args);
240    }
241
242    /**
243     * Create a range error (ECMA 15.11.6.2)
244     *
245     * @param cause   native Java {@code Throwable} that is the cause of error
246     * @param msgId   resource tag for error message
247     * @param args    arguments to resource
248     *
249     * @return the resulting {@link ECMAException}
250     */
251    public static ECMAException rangeError(final Throwable cause, final String msgId, final String... args) {
252        return rangeError(Context.getGlobal(), cause, msgId, args);
253    }
254
255    /**
256     * Create a range error (ECMA 15.11.6.2)
257     *
258     * @param global  global scope object
259     * @param cause   native Java {@code Throwable} that is the cause of error
260     * @param msgId   resource tag for error message
261     * @param args    arguments to resource
262     *
263     * @return the resulting {@link ECMAException}
264     */
265    public static ECMAException rangeError(final Global global, final Throwable cause, final String msgId, final String... args) {
266        final String msg = getMessage("range.error." + msgId, args);
267        return error(global.newRangeError(msg), cause);
268    }
269
270    /**
271     * Create a reference error (ECMA 15.11.6.3)
272     *
273     * @param msgId   resource tag for error message
274     * @param args    arguments to resource
275     *
276     * @return the resulting {@link ECMAException}
277     */
278    public static ECMAException referenceError(final String msgId, final String... args) {
279        return referenceError(Context.getGlobal(), msgId, args);
280    }
281
282    /**
283     * Create a reference error (ECMA 15.11.6.3)
284     *
285     * @param global  global scope object
286     * @param msgId   resource tag for error message
287     * @param args    arguments to resource
288     *
289     * @return the resulting {@link ECMAException}
290     */
291    public static ECMAException referenceError(final Global global, final String msgId, final String... args) {
292        return referenceError(global, null, msgId, args);
293    }
294
295    /**
296     * Create a reference error (ECMA 15.11.6.3)
297     *
298     * @param cause   native Java {@code Throwable} that is the cause of error
299     * @param msgId   resource tag for error message
300     * @param args    arguments to resource
301     *
302     * @return the resulting {@link ECMAException}
303     */
304    public static ECMAException referenceError(final Throwable cause, final String msgId, final String... args) {
305        return referenceError(Context.getGlobal(), cause, msgId, args);
306    }
307
308    /**
309     * Create a reference error (ECMA 15.11.6.3)
310     *
311     * @param global  global scope object
312     * @param cause   native Java {@code Throwable} that is the cause of error
313     * @param msgId   resource tag for error message
314     * @param args    arguments to resource
315     *
316     * @return the resulting {@link ECMAException}
317     */
318    public static ECMAException referenceError(final Global global, final Throwable cause, final String msgId, final String... args) {
319        final String msg = getMessage("reference.error." + msgId, args);
320        return error(global.newReferenceError(msg), cause);
321    }
322
323    /**
324     * Create a URI error (ECMA 15.11.6.6)
325     *
326     * @param msgId   resource tag for error message
327     * @param args    arguments to resource
328     *
329     * @return the resulting {@link ECMAException}
330     */
331    public static ECMAException uriError(final String msgId, final String... args) {
332        return uriError(Context.getGlobal(), msgId, args);
333    }
334
335    /**
336     * Create a URI error (ECMA 15.11.6.6)
337     *
338     * @param global  global scope object
339     * @param msgId   resource tag for error message
340     * @param args    arguments to resource
341     *
342     * @return the resulting {@link ECMAException}
343     */
344    public static ECMAException uriError(final Global global, final String msgId, final String... args) {
345        return uriError(global, null, msgId, args);
346    }
347
348    /**
349     * Create a URI error (ECMA 15.11.6.6)
350     *
351     * @param cause   native Java {@code Throwable} that is the cause of error
352     * @param msgId   resource tag for error message
353     * @param args    arguments to resource
354     *
355     * @return the resulting {@link ECMAException}
356     */
357    public static ECMAException uriError(final Throwable cause, final String msgId, final String... args) {
358        return uriError(Context.getGlobal(), cause, msgId, args);
359    }
360
361    /**
362     * Create a URI error (ECMA 15.11.6.6)
363     *
364     * @param global  global scope object
365     * @param cause   native Java {@code Throwable} that is the cause of error
366     * @param msgId   resource tag for error message
367     * @param args    arguments to resource
368     *
369     * @return the resulting {@link ECMAException}
370     */
371    public static ECMAException uriError(final Global global, final Throwable cause, final String msgId, final String... args) {
372        final String msg = getMessage("uri.error." + msgId, args);
373        return error(global.newURIError(msg), cause);
374    }
375
376    /**
377     * Get the exception message by placing the args in the resource defined
378     * by the resource tag. This is visible to, e.g. the {@link jdk.nashorn.internal.parser.Parser}
379     * can use it to generate compile time messages with the correct locale
380     *
381     * @param msgId the resource tag (message id)
382     * @param args  arguments to error string
383     *
384     * @return the filled out error string
385     */
386    public static String getMessage(final String msgId, final String... args) {
387        try {
388            return new MessageFormat(MESSAGES_BUNDLE.getString(msgId)).format(args);
389        } catch (final java.util.MissingResourceException e) {
390            throw new RuntimeException("no message resource found for message id: "+ msgId);
391        }
392    }
393
394
395    /**
396     * Check if a stack trace element is in JavaScript
397     *
398     * @param frame frame
399     *
400     * @return true if frame is in the script
401     */
402    public static boolean isScriptFrame(final StackTraceElement frame) {
403        final String className = frame.getClassName();
404
405        // Look for script package in class name (into which compiler puts generated code)
406        if (className.startsWith(scriptPackage) && !CompilerConstants.isInternalMethodName(frame.getMethodName())) {
407            final String source = frame.getFileName();
408            // Make sure that it is not some Java code that Nashorn has in that package!
409            return source != null && !source.endsWith(".java");
410        }
411        return false;
412    }
413}
414