diff --git a/lib/webidl2.js b/lib/webidl2.js index 3771031c..45cccc3f 100644 --- a/lib/webidl2.js +++ b/lib/webidl2.js @@ -45,6 +45,7 @@ let line = 1; tokens = tokens.slice(); const names = new Map(); + let current = null; const FLOAT = "float"; const INT = "integer"; @@ -69,7 +70,17 @@ tok += tokens[numTokens].value; numTokens++; } - throw new WebIDLParseError(str, line, tok, tokens.slice(0, maxTokens)); + + let message; + if (current) { + message = `Got an error during or right after parsing \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`: ${str}` + } + else { + // throwing before any valid definition + message = `Got an error before parsing any named definition: ${str}`; + } + + throw new WebIDLParseError(message, line, tok, tokens.slice(0, maxTokens)); }; function sanitize_name(name, type) { @@ -484,12 +495,11 @@ all_ws(); const tok = consume(ID, "interface"); if (tok) { - ret = interface_rest(); - ret.type = "callback interface"; + ret = interface_rest(false, store, "callback interface"); return ret; } const name = consume(ID) || error("No name for callback"); - ret = { type: "callback", name: sanitize_name(name.value, "callback") }; + ret = current = { type: "callback", name: sanitize_name(name.value, "callback") }; all_ws(); consume(OTHER, "=") || error("No assignment in callback"); all_ws(); @@ -675,14 +685,14 @@ return ret; }; - function interface_rest(isPartial, store) { + function interface_rest(isPartial, store, typeName = "interface") { all_ws(); const name = consume(ID) || error("No name for interface"); const mems = []; - const ret = { - type: "interface", + const ret = current = { + type: typeName, name: isPartial ? name.value : sanitize_name(name.value, "interface"), - partial: false, + partial: isPartial, members: mems }; if (!isPartial) ret.inheritance = inheritance() || null; @@ -721,10 +731,10 @@ all_ws(); const name = consume(ID) || error("No name for interface mixin"); const mems = []; - const ret = { + const ret = current = { type: "interface mixin", name: isPartial ? name.value : sanitize_name(name.value, "interface mixin"), - partial: false, + partial: isPartial, members: mems }; all_ws(); @@ -767,7 +777,7 @@ all_ws(); const name = consume(ID) || error("No name for namespace"); const mems = []; - const ret = { + const ret = current = { type: "namespace", name: isPartial ? name.value : sanitize_name(name.value, "namespace"), partial: isPartial, @@ -836,7 +846,6 @@ interface_(true, store) || namespace(true, store) || error("Partial doesn't apply to anything"); - thing.partial = true; return thing; }; @@ -846,10 +855,10 @@ all_ws(); const name = consume(ID) || error("No name for dictionary"); const mems = []; - const ret = { + const ret = current = { type: "dictionary", name: isPartial ? name.value : sanitize_name(name.value, "dictionary"), - partial: false, + partial: isPartial, members: mems }; if (!isPartial) ret.inheritance = inheritance() || null; @@ -892,7 +901,7 @@ all_ws(); const name = consume(ID) || error("No name for enum"); const vals = []; - const ret = { + const ret = current = { type: "enum", name: sanitize_name(name.value, "enum"), values: vals @@ -932,6 +941,7 @@ all_ws(); const name = consume(ID) || error("No name in typedef"); ret.name = sanitize_name(name.value, "typedef"); + current = ret; all_ws(); consume(OTHER, ";") || error("Unterminated typedef"); return ret; diff --git a/test/invalid/idl/no-semicolon-callback.widl b/test/invalid/idl/no-semicolon-callback.widl new file mode 100644 index 00000000..cb205571 --- /dev/null +++ b/test/invalid/idl/no-semicolon-callback.widl @@ -0,0 +1,7 @@ +callback interface NoSemicolon { + attribute boolean noSemiColon; +} + +enum YouNeedOne { + "really" +} diff --git a/test/invalid/idl/no-semicolon.widl b/test/invalid/idl/no-semicolon.widl new file mode 100644 index 00000000..10bc7162 --- /dev/null +++ b/test/invalid/idl/no-semicolon.widl @@ -0,0 +1,7 @@ +partial interface NoSemicolon { + attribute boolean noSemiColon; +} + +enum YouNeedOne { + "really" +} diff --git a/test/invalid/json/array.json b/test/invalid/json/array.json index 30b377fc..898b2d83 100644 --- a/test/invalid/json/array.json +++ b/test/invalid/json/array.json @@ -1,4 +1,4 @@ { - "message": "No name in attribute", + "message": "Got an error during or right after parsing `interface LotteryResults`: No name in attribute", "line": 5 -} \ No newline at end of file +} diff --git a/test/invalid/json/caller.json b/test/invalid/json/caller.json index 79b8ecac..567fa336 100644 --- a/test/invalid/json/caller.json +++ b/test/invalid/json/caller.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation", + "message": "Got an error during or right after parsing `interface NumberQuadrupler`: Invalid operation", "line": 6 } diff --git a/test/invalid/json/dict-required-default.json b/test/invalid/json/dict-required-default.json index c5afeca8..82b6b2ae 100644 --- a/test/invalid/json/dict-required-default.json +++ b/test/invalid/json/dict-required-default.json @@ -1,4 +1,4 @@ { - "message": "Required member must not have a default" + "message": "Got an error during or right after parsing `dictionary Dict`: Required member must not have a default" , "line": 4 } diff --git a/test/invalid/json/duplicate.json b/test/invalid/json/duplicate.json index cef33587..e88a7156 100644 --- a/test/invalid/json/duplicate.json +++ b/test/invalid/json/duplicate.json @@ -1,4 +1,4 @@ { - "message": "The name \"Test\" of type \"typedef\" is already seen", + "message": "Got an error during or right after parsing `typedef Test`: The name \"Test\" of type \"typedef\" is already seen", "line": 3 -} \ No newline at end of file +} diff --git a/test/invalid/json/enum.json b/test/invalid/json/enum.json index 16611580..073ff6c2 100644 --- a/test/invalid/json/enum.json +++ b/test/invalid/json/enum.json @@ -1,4 +1,4 @@ { - "message": "Unexpected value in enum" + "message": "Got an error during or right after parsing `enum foo`: Unexpected value in enum" , "line": 1 } diff --git a/test/invalid/json/exception.json b/test/invalid/json/exception.json index f52cda13..ad9fac6c 100644 --- a/test/invalid/json/exception.json +++ b/test/invalid/json/exception.json @@ -1,4 +1,4 @@ { - "message": "Unrecognised tokens", + "message": "Got an error before parsing any named definition: Unrecognised tokens", "line": 4 } diff --git a/test/invalid/json/iterator.json b/test/invalid/json/iterator.json index 7cc2f94e..e46d653a 100644 --- a/test/invalid/json/iterator.json +++ b/test/invalid/json/iterator.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation", + "message": "Got an error during or right after parsing `interface SessionManager`: Invalid operation", "line": 5 } diff --git a/test/invalid/json/maplike-1type.json b/test/invalid/json/maplike-1type.json index 859a820a..75e7a35e 100644 --- a/test/invalid/json/maplike-1type.json +++ b/test/invalid/json/maplike-1type.json @@ -1,4 +1,4 @@ { - "message": "Missing second type argument in maplike declaration", + "message": "Got an error during or right after parsing `interface MapLikeOneType`: Missing second type argument in maplike declaration", "line": 2 -} \ No newline at end of file +} diff --git a/test/invalid/json/module.json b/test/invalid/json/module.json index 3b0984d9..9c071cdd 100644 --- a/test/invalid/json/module.json +++ b/test/invalid/json/module.json @@ -1,4 +1,4 @@ { - "message": "Unrecognised tokens" + "message": "Got an error before parsing any named definition: Unrecognised tokens" , "line": 2 } diff --git a/test/invalid/json/no-semicolon-callback.json b/test/invalid/json/no-semicolon-callback.json new file mode 100644 index 00000000..1db9d14c --- /dev/null +++ b/test/invalid/json/no-semicolon-callback.json @@ -0,0 +1,4 @@ +{ + "message": "Got an error during or right after parsing `callback interface NoSemicolon`: Missing semicolon after interface", + "line": 5 +} diff --git a/test/invalid/json/no-semicolon.json b/test/invalid/json/no-semicolon.json new file mode 100644 index 00000000..087532a0 --- /dev/null +++ b/test/invalid/json/no-semicolon.json @@ -0,0 +1,4 @@ +{ + "message": "Got an error during or right after parsing `partial interface NoSemicolon`: Missing semicolon after interface", + "line": 5 +} diff --git a/test/invalid/json/nonnullableany.json b/test/invalid/json/nonnullableany.json index cf5229e8..8a1f9004 100644 --- a/test/invalid/json/nonnullableany.json +++ b/test/invalid/json/nonnullableany.json @@ -1,4 +1,4 @@ { - "message": "Type any cannot be made nullable" + "message": "Got an error during or right after parsing `interface NonNullable`: Type any cannot be made nullable" , "line": 2 } diff --git a/test/invalid/json/nonnullableobjects.json b/test/invalid/json/nonnullableobjects.json index 23cbb3e5..52bd8dac 100644 --- a/test/invalid/json/nonnullableobjects.json +++ b/test/invalid/json/nonnullableobjects.json @@ -1,4 +1,4 @@ { - "message": "Can't nullable more than once" + "message": "Got an error during or right after parsing `interface NonNullable`: Can't nullable more than once" , "line": 4 } diff --git a/test/invalid/json/promise-with-extended-attribute.json b/test/invalid/json/promise-with-extended-attribute.json index e9623ce7..71212d46 100644 --- a/test/invalid/json/promise-with-extended-attribute.json +++ b/test/invalid/json/promise-with-extended-attribute.json @@ -1,4 +1,4 @@ { - "message": "Promise type cannot have extended attribute", + "message": "Got an error during or right after parsing `interface Foo`: Promise type cannot have extended attribute", "line": 2 } diff --git a/test/invalid/json/raises.json b/test/invalid/json/raises.json index 8b67afe4..3165b874 100644 --- a/test/invalid/json/raises.json +++ b/test/invalid/json/raises.json @@ -1,4 +1,4 @@ { - "message": "Unterminated attribute" + "message": "Got an error during or right after parsing `interface Person`: Unterminated attribute" , "line": 5 } diff --git a/test/invalid/json/readonly-iterable.json b/test/invalid/json/readonly-iterable.json index c6f52a24..1a09264a 100644 --- a/test/invalid/json/readonly-iterable.json +++ b/test/invalid/json/readonly-iterable.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation", + "message": "Got an error during or right after parsing `interface ReadonlyIterable`: Invalid operation", "line": 2 -} \ No newline at end of file +} diff --git a/test/invalid/json/record-key-with-extended-attribute.json b/test/invalid/json/record-key-with-extended-attribute.json index 3945825c..4002e7fe 100644 --- a/test/invalid/json/record-key-with-extended-attribute.json +++ b/test/invalid/json/record-key-with-extended-attribute.json @@ -1,4 +1,4 @@ { - "message": "Record key cannot have extended attribute", + "message": "Got an error during or right after parsing `interface Foo`: Record key cannot have extended attribute", "line": 2 } diff --git a/test/invalid/json/record-key.json b/test/invalid/json/record-key.json index 3b929b92..179d645d 100644 --- a/test/invalid/json/record-key.json +++ b/test/invalid/json/record-key.json @@ -1,4 +1,4 @@ { - "message": "Record key must be DOMString, USVString, or ByteString", + "message": "Got an error during or right after parsing `interface Foo`: Record key must be DOMString, USVString, or ByteString", "line": 2 } diff --git a/test/invalid/json/scopedname.json b/test/invalid/json/scopedname.json index 8e2cd803..4620d2df 100644 --- a/test/invalid/json/scopedname.json +++ b/test/invalid/json/scopedname.json @@ -1,4 +1,4 @@ { - "message": "No name in typedef" + "message": "Got an error before parsing any named definition: No name in typedef" , "line": 2 } diff --git a/test/invalid/json/sequenceAsAttribute.json b/test/invalid/json/sequenceAsAttribute.json index b714f5d9..5b4314a6 100644 --- a/test/invalid/json/sequenceAsAttribute.json +++ b/test/invalid/json/sequenceAsAttribute.json @@ -1,4 +1,4 @@ { - "message": "Attributes cannot accept sequence types" + "message": "Got an error during or right after parsing `interface sequenceAsAttribute`: Attributes cannot accept sequence types" , "line": 2 } diff --git a/test/invalid/json/setlike-2types.json b/test/invalid/json/setlike-2types.json index c9e49b67..2900e1ba 100644 --- a/test/invalid/json/setlike-2types.json +++ b/test/invalid/json/setlike-2types.json @@ -1,4 +1,4 @@ { - "message": "Unterminated setlike declaration", + "message": "Got an error during or right after parsing `interface SetLikeTwoTypes`: Unterminated setlike declaration", "line": 2 -} \ No newline at end of file +} diff --git a/test/invalid/json/setter-creator.json b/test/invalid/json/setter-creator.json index 07b9f1f4..25decb37 100644 --- a/test/invalid/json/setter-creator.json +++ b/test/invalid/json/setter-creator.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation", + "message": "Got an error during or right after parsing `interface OrderedMap`: Invalid operation", "line": 3 } diff --git a/test/invalid/json/special-omittable.json b/test/invalid/json/special-omittable.json index 7acb0883..c20b28e0 100644 --- a/test/invalid/json/special-omittable.json +++ b/test/invalid/json/special-omittable.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation" + "message": "Got an error during or right after parsing `interface Dictionary`: Invalid operation" , "line": 6 } diff --git a/test/invalid/json/stringconstants.json b/test/invalid/json/stringconstants.json index d5bf1a88..1eeb31cd 100644 --- a/test/invalid/json/stringconstants.json +++ b/test/invalid/json/stringconstants.json @@ -1,4 +1,4 @@ { - "message": "No value for const" + "message": "Got an error during or right after parsing `interface Util`: No value for const" , "line": 2 } diff --git a/test/invalid/json/typedef-nested.json b/test/invalid/json/typedef-nested.json index d7fb9182..8c608149 100644 --- a/test/invalid/json/typedef-nested.json +++ b/test/invalid/json/typedef-nested.json @@ -1,4 +1,4 @@ { - "message": "Invalid operation" + "message": "Got an error during or right after parsing `interface Widget`: Invalid operation" , "line": 14 -} \ No newline at end of file +}