Skip to content

Commit ac9a3b9

Browse files
Clean up reserved grammar changes and add tests
1 parent e5ca5c8 commit ac9a3b9

File tree

3 files changed

+71
-25
lines changed

3 files changed

+71
-25
lines changed

src/parse.js

+21-19
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ function parse(source, root, options) {
8080
pkg,
8181
imports,
8282
weakImports,
83-
edition = "proto2",
84-
isProto3 = false,
85-
isProto2 = true;
83+
edition = "proto2";
8684

8785
var ptr = root;
8886

@@ -151,13 +149,17 @@ function parse(source, root, options) {
151149
function readRanges(target, acceptStrings) {
152150
var token, start;
153151
do {
154-
if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
155-
target.push(readString());
156-
else {
152+
if (acceptStrings && ((token = peek()) === "\"" || token === "'")) {
153+
var str = readString();
154+
target.push(str);
155+
if (edition >= 2023) {
156+
throw illegal(str, "id");
157+
}
158+
} else {
157159
try {
158160
target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
159161
} catch (err) {
160-
if (typeRefRe.test(token) && (!isProto2 && !isProto3)) {
162+
if (acceptStrings && typeRefRe.test(token) && edition >= 2023) {
161163
target.push(token);
162164
} else {
163165
throw err;
@@ -278,11 +280,9 @@ function parse(source, root, options) {
278280
function parseSyntax() {
279281
skip("=");
280282
edition = readString();
281-
isProto3 = edition === "proto3";
282-
isProto2 = edition === "proto2";
283283

284284
/* istanbul ignore if */
285-
if (!isProto3 && !isProto2)
285+
if (edition < 2023)
286286
throw illegal(edition, "syntax");
287287

288288
skip(";");
@@ -291,8 +291,6 @@ function parse(source, root, options) {
291291
function parseEdition() {
292292
skip("=");
293293
edition = readString();
294-
isProto3 = false;
295-
isProto2 = false;
296294
const supportedEditions = ["2023"];
297295

298296
/* istanbul ignore if */
@@ -370,7 +368,7 @@ function parse(source, root, options) {
370368
break;
371369

372370
case "required":
373-
if (!isProto2)
371+
if (edition !== "proto2")
374372
throw illegal(token);
375373
/* eslint-disable no-fallthrough */
376374
case "repeated":
@@ -379,9 +377,9 @@ function parse(source, root, options) {
379377

380378
case "optional":
381379
/* istanbul ignore if */
382-
if (isProto3) {
380+
if (edition === "proto3") {
383381
parseField(type, "proto3_optional");
384-
} else if (!isProto2) {
382+
} else if (edition !== "proto2") {
385383
throw illegal(token);
386384
} else {
387385
parseField(type, "optional");
@@ -402,7 +400,7 @@ function parse(source, root, options) {
402400

403401
default:
404402
/* istanbul ignore if */
405-
if (isProto2 || !typeRefRe.test(token)) {
403+
if (edition === "proto2" || !typeRefRe.test(token)) {
406404
throw illegal(token);
407405
}
408406

@@ -478,6 +476,9 @@ function parse(source, root, options) {
478476
}
479477

480478
function parseGroup(parent, rule) {
479+
if (edition >= 2023) {
480+
throw illegal("group");
481+
}
481482
var name = next();
482483

483484
/* istanbul ignore if */
@@ -507,7 +508,7 @@ function parse(source, root, options) {
507508

508509
case "optional":
509510
/* istanbul ignore if */
510-
if (isProto3) {
511+
if (edition === "proto3") {
511512
parseField(type, "proto3_optional");
512513
} else {
513514
parseField(type, "optional");
@@ -605,6 +606,7 @@ function parse(source, root, options) {
605606

606607
case "reserved":
607608
readRanges(enm.reserved || (enm.reserved = []), true);
609+
if(enm.reserved === undefined) enm.reserved = [];
608610
break;
609611

610612
default:
@@ -865,7 +867,7 @@ function parse(source, root, options) {
865867

866868
case "optional":
867869
/* istanbul ignore if */
868-
if (isProto3) {
870+
if (edition === "proto3") {
869871
parseField(parent, "proto3_optional", reference);
870872
} else {
871873
parseField(parent, "optional", reference);
@@ -874,7 +876,7 @@ function parse(source, root, options) {
874876

875877
default:
876878
/* istanbul ignore if */
877-
if (isProto2 || !typeRefRe.test(token))
879+
if (edition === "proto2" || !typeRefRe.test(token))
878880
throw illegal(token);
879881
push(token);
880882
parseField(parent, "optional", reference);

tests/feature_grammar.js

+49-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ tape.test("editions required keyword", function(test) {
88
message A {\
99
required uint32 a = 1;\
1010
}`);
11-
}, Error, "Error: illegal token 'required'");
11+
}, /Error: illegal token 'required'/);
1212

1313
test.end();
1414
});
@@ -19,7 +19,7 @@ tape.test("editions optional keyword", function(test) {
1919
message A {\
2020
optional uint32 a = 1;\
2121
}`);
22-
}, Error, "Error: illegal token 'optional'");
22+
}, /Error: illegal token 'optional'/);
2323

2424
test.end();
2525
});
@@ -28,9 +28,9 @@ tape.test("editions group keyword", function(test) {
2828
test.throws(function() {
2929
protobuf.parse(`edition = "2023";
3030
message A {\
31-
group uint32 a = 1;\
32-
}`);
33-
}, Error, "Error: illegal token 'group'");
31+
group uint32 a = 1;\
32+
}`);
33+
}, /Error: illegal token 'group'/);
3434

3535
test.end();
3636
});
@@ -44,3 +44,47 @@ tape.test("editions no quote", function(test) {
4444
test.end();
4545
});
4646

47+
48+
tape.test("edition 2023 reserved", function(test) {
49+
var root = protobuf.parse(`edition = "2023";
50+
message Foo {
51+
reserved bar, baz;
52+
}`).root.resolveAll();
53+
test.same(root.Foo.reserved, ["bar", "baz"], "reserved fields should be parsed");
54+
55+
root = protobuf.parse(`edition = "2023";
56+
enum Foo {
57+
reserved BAR, BAZ_BAZ;
58+
}`).root.resolveAll();
59+
test.same(root.nested.Foo.reserved, ["BAR", "BAZ_BAZ"], "reserved values should be parsed");
60+
61+
test.throws(function() {
62+
protobuf.parse(`edition = "2023";
63+
message Foo {
64+
reserved "bar", "baz";
65+
}`);
66+
}, /Error: illegal id 'bar'/, "reserved field strings should be banned");
67+
68+
test.throws(function() {
69+
protobuf.parse(`edition = "2023";
70+
enum Foo {
71+
reserved "BAR", "BAZ";
72+
}`);
73+
}, /Error: illegal id 'BAR'/, "reserved enum value strings should be banned");
74+
75+
test.throws(function() {
76+
protobuf.parse(`syntax = "proto3";
77+
message Foo {
78+
reserved bar, baz;
79+
}`);
80+
}, /Error: illegal id 'bar'/, "reserved field strings should be banned");
81+
82+
test.throws(function() {
83+
protobuf.parse(`syntax = "proto3";
84+
enum Foo {
85+
reserved BAR, BAZ;
86+
}`);
87+
}, /Error: illegal id 'BAR'/, "reserved enum value strings should be banned");
88+
89+
test.end();
90+
});

tests/feature_resolution_editions.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ tape.test("feature resolution extension sister", function(test) {
492492
message B {
493493
message One {
494494
extensions 1000 to max;
495-
reserved 900 to 999, 899, "a", 'b';
495+
reserved 900 to 999, 899, a, b;
496496
}
497497
}
498498
message C {

0 commit comments

Comments
 (0)