From 3057091ca1ffb3ed653b0b1cc3c537e6a0dd9220 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 19 Jan 2018 13:23:13 +0900 Subject: [PATCH 1/5] error containing the current definition name --- lib/webidl2.js | 26 ++++++++++++++----- test/invalid/json/array.json | 4 +-- test/invalid/json/caller.json | 2 +- test/invalid/json/dict-required-default.json | 2 +- test/invalid/json/duplicate.json | 4 +-- test/invalid/json/enum.json | 2 +- test/invalid/json/exception.json | 2 +- test/invalid/json/iterator.json | 2 +- test/invalid/json/maplike-1type.json | 4 +-- test/invalid/json/module.json | 2 +- test/invalid/json/nonnullableany.json | 2 +- test/invalid/json/nonnullableobjects.json | 2 +- .../json/promise-with-extended-attribute.json | 2 +- test/invalid/json/raises.json | 2 +- test/invalid/json/readonly-iterable.json | 4 +-- .../record-key-with-extended-attribute.json | 2 +- test/invalid/json/record-key.json | 2 +- test/invalid/json/scopedname.json | 2 +- test/invalid/json/sequenceAsAttribute.json | 2 +- test/invalid/json/setlike-2types.json | 4 +-- test/invalid/json/setter-creator.json | 2 +- test/invalid/json/special-omittable.json | 2 +- test/invalid/json/stringconstants.json | 2 +- test/invalid/json/typedef-nested.json | 4 +-- 24 files changed, 48 insertions(+), 36 deletions(-) diff --git a/lib/webidl2.js b/lib/webidl2.js index 3771031c..658b8948 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.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) { @@ -489,7 +500,7 @@ 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(); @@ -679,7 +690,7 @@ all_ws(); const name = consume(ID) || error("No name for interface"); const mems = []; - const ret = { + const ret = current = { type: "interface", name: isPartial ? name.value : sanitize_name(name.value, "interface"), partial: false, @@ -721,7 +732,7 @@ 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, @@ -767,7 +778,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, @@ -846,7 +857,7 @@ 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, @@ -892,7 +903,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 +943,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/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/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 +} From c36e446c8ae9eabbc4d6000a640aaef2af772072 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 19 Jan 2018 13:27:23 +0900 Subject: [PATCH 2/5] add a no-semicolon test --- test/invalid/idl/no-semicolon.widl | 7 +++++++ test/invalid/json/no-semicolon.json | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 test/invalid/idl/no-semicolon.widl create mode 100644 test/invalid/json/no-semicolon.json diff --git a/test/invalid/idl/no-semicolon.widl b/test/invalid/idl/no-semicolon.widl new file mode 100644 index 00000000..b48fc229 --- /dev/null +++ b/test/invalid/idl/no-semicolon.widl @@ -0,0 +1,7 @@ +interface NoSemicolon { + attribute boolean noSemiColon; +} + +enum YouNeedOne { + "really" +} diff --git a/test/invalid/json/no-semicolon.json b/test/invalid/json/no-semicolon.json new file mode 100644 index 00000000..1b0be301 --- /dev/null +++ b/test/invalid/json/no-semicolon.json @@ -0,0 +1,4 @@ +{ + "message": "Got an error during or right after parsing `interface NoSemicolon`: Missing semicolon after interface", + "line": 5 +} From 04ebd9eb8127424ea4af107dd8bab978e3cc6c02 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 19 Jan 2018 14:02:34 +0900 Subject: [PATCH 3/5] mark partial: true earlier --- lib/webidl2.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/webidl2.js b/lib/webidl2.js index 658b8948..05cbd6ec 100644 --- a/lib/webidl2.js +++ b/lib/webidl2.js @@ -495,7 +495,7 @@ all_ws(); const tok = consume(ID, "interface"); if (tok) { - ret = interface_rest(); + ret = interface_rest(false); ret.type = "callback interface"; return ret; } @@ -693,7 +693,7 @@ const ret = current = { type: "interface", name: isPartial ? name.value : sanitize_name(name.value, "interface"), - partial: false, + partial: isPartial, members: mems }; if (!isPartial) ret.inheritance = inheritance() || null; @@ -735,7 +735,7 @@ const ret = current = { type: "interface mixin", name: isPartial ? name.value : sanitize_name(name.value, "interface mixin"), - partial: false, + partial: isPartial, members: mems }; all_ws(); @@ -847,7 +847,6 @@ interface_(true, store) || namespace(true, store) || error("Partial doesn't apply to anything"); - thing.partial = true; return thing; }; @@ -860,7 +859,7 @@ 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; From 51d8702e226a1bd4faeab5c1007d803764c090c7 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 19 Jan 2018 14:04:45 +0900 Subject: [PATCH 4/5] error should say partial interface --- lib/webidl2.js | 2 +- test/invalid/idl/no-semicolon.widl | 2 +- test/invalid/json/no-semicolon.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/webidl2.js b/lib/webidl2.js index 05cbd6ec..296a4574 100644 --- a/lib/webidl2.js +++ b/lib/webidl2.js @@ -73,7 +73,7 @@ let message; if (current) { - message = `Got an error during or right after parsing \`${current.type} ${current.name}\`: ${str}` + message = `Got an error during or right after parsing \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`: ${str}` } else { // throwing before any valid definition diff --git a/test/invalid/idl/no-semicolon.widl b/test/invalid/idl/no-semicolon.widl index b48fc229..10bc7162 100644 --- a/test/invalid/idl/no-semicolon.widl +++ b/test/invalid/idl/no-semicolon.widl @@ -1,4 +1,4 @@ -interface NoSemicolon { +partial interface NoSemicolon { attribute boolean noSemiColon; } diff --git a/test/invalid/json/no-semicolon.json b/test/invalid/json/no-semicolon.json index 1b0be301..087532a0 100644 --- a/test/invalid/json/no-semicolon.json +++ b/test/invalid/json/no-semicolon.json @@ -1,4 +1,4 @@ { - "message": "Got an error during or right after parsing `interface NoSemicolon`: Missing semicolon after interface", + "message": "Got an error during or right after parsing `partial interface NoSemicolon`: Missing semicolon after interface", "line": 5 } From 1a0032ac77ca4ef9671745936ff2f5ffaeaa2c3d Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 19 Jan 2018 14:11:15 +0900 Subject: [PATCH 5/5] early typename for callback interfaces --- lib/webidl2.js | 7 +++---- test/invalid/idl/no-semicolon-callback.widl | 7 +++++++ test/invalid/json/no-semicolon-callback.json | 4 ++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 test/invalid/idl/no-semicolon-callback.widl create mode 100644 test/invalid/json/no-semicolon-callback.json diff --git a/lib/webidl2.js b/lib/webidl2.js index 296a4574..45cccc3f 100644 --- a/lib/webidl2.js +++ b/lib/webidl2.js @@ -495,8 +495,7 @@ all_ws(); const tok = consume(ID, "interface"); if (tok) { - ret = interface_rest(false); - ret.type = "callback interface"; + ret = interface_rest(false, store, "callback interface"); return ret; } const name = consume(ID) || error("No name for callback"); @@ -686,12 +685,12 @@ 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 = current = { - type: "interface", + type: typeName, name: isPartial ? name.value : sanitize_name(name.value, "interface"), partial: isPartial, members: mems 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/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 +}