servo: Merge #2519 - Throw DOMExceptions where appropriate (fixes #2518) (from Ms2ger:exn); r=jdm

Source-Repo: https://github.com/servo/servo
Source-Revision: 39e3c64ead997b3a8c6be6e188aad27fcbe3220b
This commit is contained in:
Ms2ger 2014-05-30 12:22:02 -04:00
Родитель 5788f29d55
Коммит e642799ed4
3 изменённых файлов: 66 добавлений и 41 удалений

Просмотреть файл

@ -2129,19 +2129,21 @@ class CGCallGenerator(CGThing):
A class to generate an actual call to a C++ object. Assumes that the C++ A class to generate an actual call to a C++ object. Assumes that the C++
object is stored in a variable whose name is given by the |object| argument. object is stored in a variable whose name is given by the |object| argument.
errorReport should be a CGThing for an error report or None if no errorResult should be a string for the value to return in case of an
error reporting is needed. exception from the native code, or None if no error reporting is needed.
""" """
def __init__(self, errorReport, arguments, argsPre, returnType, def __init__(self, errorResult, arguments, argsPre, returnType,
extendedAttributes, descriptorProvider, nativeMethodName, extendedAttributes, descriptorProvider, nativeMethodName,
static, object="this"): static, object="this"):
CGThing.__init__(self) CGThing.__init__(self)
assert errorReport is None or isinstance(errorReport, CGThing) assert errorResult is None or isinstance(errorResult, str)
isFallible = errorReport is not None isFallible = errorResult is not None
result = getRetvalDeclarationForType(returnType, descriptorProvider) result = getRetvalDeclarationForType(returnType, descriptorProvider)
if isFallible:
result = CGWrapper(result, pre="Result<", post=", Error>")
args = CGList([CGGeneric(arg) for arg in argsPre], ", ") args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
for (a, name) in arguments: for (a, name) in arguments:
@ -2172,26 +2174,29 @@ class CGCallGenerator(CGThing):
call = CGWrapper(call, pre="(*%s)." % object) call = CGWrapper(call, pre="(*%s)." % object)
call = CGList([call, CGWrapper(args, pre="(", post=");")]) call = CGList([call, CGWrapper(args, pre="(", post=");")])
if isFallible: self.cgRoot.append(CGList([
self.cgRoot.prepend(CGWrapper(result, CGGeneric("let result: "),
pre="let result_fallible: Result<", post=",Error>;")) result,
CGGeneric(" = "),
result = CGWrapper(result, pre="let result: ", post=";") call,
self.cgRoot.prepend(result) CGGeneric(";"),
]))
if isFallible: if isFallible:
call = CGWrapper(call, pre="result_fallible = ") if static:
else: glob = ""
call = CGWrapper(call, pre="result = ") else:
glob = " let global = global_object_for_js_object(this.reflector().get_jsobject()).root();\n"
call = CGWrapper(call) self.cgRoot.append(CGGeneric(
self.cgRoot.append(call) "let result = match result {\n"
" Ok(result) => result,\n"
if isFallible: " Err(e) => {\n"
self.cgRoot.append(CGGeneric("if result_fallible.is_err() {")) "%s"
self.cgRoot.append(CGIndenter(errorReport)) " throw_dom_exception(cx, &*global, e);\n"
self.cgRoot.append(CGGeneric("}")) " return%s;"
self.cgRoot.append(CGGeneric("result = result_fallible.unwrap();")) " },\n"
"};\n" % (glob, errorResult)))
if typeRetValNeedsRooting(returnType): if typeRetValNeedsRooting(returnType):
self.cgRoot.append(CGGeneric("let result = result.root();")) self.cgRoot.append(CGGeneric("let result = result.root();"))
@ -2250,7 +2255,7 @@ class CGPerSignatureCall(CGThing):
i in range(argConversionStartsAt, self.argCount)]) i in range(argConversionStartsAt, self.argCount)])
cgThings.append(CGCallGenerator( cgThings.append(CGCallGenerator(
self.getErrorReport() if self.isFallible() else None, ' false as JSBool' if self.isFallible() else None,
self.getArguments(), self.argsPre, returnType, self.getArguments(), self.argsPre, returnType,
self.extendedAttributes, descriptor, nativeMethodName, self.extendedAttributes, descriptor, nativeMethodName,
static)) static))
@ -2276,12 +2281,6 @@ class CGPerSignatureCall(CGThing):
def wrap_return_value(self): def wrap_return_value(self):
return wrapForType('*vp') return wrapForType('*vp')
def getErrorReport(self):
return CGGeneric(
'return throw_method_failed_with_details(cx, result_fallible, "%s", "%s");' %
(self.descriptor.interface.identifier.name,
self.idlNode.identifier.name))
def define(self): def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value()) return (self.cgRoot.define() + "\n" + self.wrap_return_value())
@ -4302,7 +4301,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::codegen::BindingDeclarations::*', 'dom::bindings::codegen::BindingDeclarations::*',
'dom::bindings::codegen::UnionTypes::*', 'dom::bindings::codegen::UnionTypes::*',
'dom::bindings::error::{FailureUnknown, Fallible, Error, ErrorResult}', 'dom::bindings::error::{FailureUnknown, Fallible, Error, ErrorResult}',
'dom::bindings::error::{throw_method_failed_with_details}', 'dom::bindings::error::throw_dom_exception',
'dom::bindings::error::throw_type_error', 'dom::bindings::error::throw_type_error',
'dom::bindings::proxyhandler', 'dom::bindings::proxyhandler',
'dom::bindings::proxyhandler::{_obj_toString, defineProperty}', 'dom::bindings::proxyhandler::{_obj_toString, defineProperty}',

Просмотреть файл

@ -2,8 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::js::JSRef;
use dom::domexception::DOMException;
use dom::window::Window;
use js::jsapi::{JSContext, JSBool}; use js::jsapi::{JSContext, JSBool};
use js::jsapi::{JS_IsExceptionPending}; use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR}; use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::glue::{ReportError}; use js::glue::{ReportError};
@ -29,17 +34,14 @@ pub type Fallible<T> = Result<T, Error>;
pub type ErrorResult = Fallible<()>; pub type ErrorResult = Fallible<()>;
pub fn throw_method_failed_with_details<T>(cx: *mut JSContext, pub fn throw_dom_exception(cx: *mut JSContext, global: &JSRef<Window>,
result: Result<T, Error>, result: Error) {
interface: &'static str,
member: &'static str) -> JSBool {
assert!(result.is_err());
assert!(unsafe { JS_IsExceptionPending(cx) } == 0); assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
let message = format!("Method failed: {}.{}", interface, member); let exception = DOMException::new_from_error(global, result).root();
message.with_c_str(|string| { let thrown = exception.to_jsval(cx);
unsafe { ReportError(cx, string) }; unsafe {
}); JS_SetPendingException(cx, thrown);
return 0; }
} }
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool { pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {

Просмотреть файл

@ -4,6 +4,8 @@
use dom::bindings::codegen::BindingDeclarations::DOMExceptionBinding; use dom::bindings::codegen::BindingDeclarations::DOMExceptionBinding;
use dom::bindings::codegen::BindingDeclarations::DOMExceptionBinding::DOMExceptionConstants; use dom::bindings::codegen::BindingDeclarations::DOMExceptionBinding::DOMExceptionConstants;
use dom::bindings::error;
use dom::bindings::error::Error;
use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::window::Window; use dom::window::Window;
@ -35,6 +37,24 @@ pub enum DOMErrorName {
EncodingError EncodingError
} }
impl DOMErrorName {
fn from_error(error: Error) -> DOMErrorName {
match error {
error::IndexSize => IndexSizeError,
error::NotFound => NotFoundError,
error::HierarchyRequest => HierarchyRequestError,
error::InvalidCharacter => InvalidCharacterError,
error::NotSupported => NotSupportedError,
error::InvalidState => InvalidStateError,
error::NamespaceError => NamespaceError,
error::Syntax => SyntaxError,
error::Security => SecurityError,
error::Network => NetworkError,
error::FailureUnknown => fail!(),
}
}
}
#[deriving(Encodable)] #[deriving(Encodable)]
pub struct DOMException { pub struct DOMException {
pub code: DOMErrorName, pub code: DOMErrorName,
@ -52,6 +72,10 @@ impl DOMException {
pub fn new(window: &JSRef<Window>, code: DOMErrorName) -> Temporary<DOMException> { pub fn new(window: &JSRef<Window>, code: DOMErrorName) -> Temporary<DOMException> {
reflect_dom_object(box DOMException::new_inherited(code), window, DOMExceptionBinding::Wrap) reflect_dom_object(box DOMException::new_inherited(code), window, DOMExceptionBinding::Wrap)
} }
pub fn new_from_error(window: &JSRef<Window>, code: Error) -> Temporary<DOMException> {
DOMException::new(window, DOMErrorName::from_error(code))
}
} }
impl Reflectable for DOMException { impl Reflectable for DOMException {