mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
parse.y: Allow trailing commas for table, set, vector and record construction
Python, Ruby, Javascript, Go, ..., allow use of trailing commas and is even recommended in some style-guides as it keeps diffs smaller. The black formatter for Python even goes as far to take a trailing comma as an indication to format a list one-item on a line. It has been a bit unusual to not be able to put trailing commas in Zeek scripts, so this change allows for it. It explicitly prevents trailing commas in list expressions on the left hand side. Concretely, this disallows trailing commas in the key list expression during table initializations. It probably allows for commas in more places that I haven't fully grasped. Maybe we should tighten those down again if we find them surprising.
This commit is contained in:
parent
017525af71
commit
203a309612
20 changed files with 288 additions and 14 deletions
25
NEWS
25
NEWS
|
@ -81,6 +81,31 @@ New Functionality
|
||||||
As noted under breaking changes, the blank identifier ``_`` cannot be
|
As noted under breaking changes, the blank identifier ``_`` cannot be
|
||||||
referenced in expression anymore.
|
referenced in expression anymore.
|
||||||
|
|
||||||
|
- It is now possible to put trailing commas within table, vector, set and record
|
||||||
|
construction. For example, the following code is now valid, which can make
|
||||||
|
for more uniform style and smaller diffs.
|
||||||
|
|
||||||
|
local vec = vector(
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
);
|
||||||
|
|
||||||
|
local tab: table[string] of count = [
|
||||||
|
["a"] = 1,
|
||||||
|
["b"] = 2,
|
||||||
|
];
|
||||||
|
|
||||||
|
Function calls and record constructors can have a trailing comma after the
|
||||||
|
last argument.
|
||||||
|
|
||||||
|
Analyzer::schedule_analyzer(
|
||||||
|
chan$orig_h,
|
||||||
|
chan$resp_h,
|
||||||
|
chan$resp_p,
|
||||||
|
Analyzer::ANALYZER_FTP_DATA,
|
||||||
|
5mins,
|
||||||
|
);
|
||||||
|
|
||||||
- Re-introduce event groups. Allow the ``&group`` attribute on event and hook
|
- Re-introduce event groups. Allow the ``&group`` attribute on event and hook
|
||||||
handlers for annotating them with one or more event groups. These groups
|
handlers for annotating them with one or more event groups. These groups
|
||||||
can be disabled and enable during runtime. Disabling an event group implies
|
can be disabled and enable during runtime. Disabling an event group implies
|
||||||
|
|
33
src/parse.y
33
src/parse.y
|
@ -146,6 +146,7 @@ static int in_enum_redef = 0;
|
||||||
bool resolving_global_ID = false;
|
bool resolving_global_ID = false;
|
||||||
bool defining_global_ID = false;
|
bool defining_global_ID = false;
|
||||||
std::vector<int> saved_in_init;
|
std::vector<int> saved_in_init;
|
||||||
|
static int expr_list_has_opt_comma = 0;
|
||||||
|
|
||||||
std::vector<std::set<const ID*>> locals_at_this_scope;
|
std::vector<std::set<const ID*>> locals_at_this_scope;
|
||||||
static std::unordered_set<const ID*> out_of_scope_locals;
|
static std::unordered_set<const ID*> out_of_scope_locals;
|
||||||
|
@ -719,7 +720,16 @@ expr:
|
||||||
$$ = new CondExpr({AdoptRef{}, $1}, {AdoptRef{}, $3}, {AdoptRef{}, $5});
|
$$ = new CondExpr({AdoptRef{}, $1}, {AdoptRef{}, $3}, {AdoptRef{}, $5});
|
||||||
}
|
}
|
||||||
|
|
||||||
| expr '=' rhs
|
| expr '='
|
||||||
|
{
|
||||||
|
// Prevent usage of trailing commas on the left-hand
|
||||||
|
// side of list expressions (e.g. in table inits).
|
||||||
|
if ( $1->Tag() == EXPR_LIST && expr_list_has_opt_comma )
|
||||||
|
$1->Error("incorrect syntax for list expression "
|
||||||
|
"on left-hand side of assignment: "
|
||||||
|
"trailing comma not allowed");
|
||||||
|
}
|
||||||
|
rhs
|
||||||
{
|
{
|
||||||
set_location(@1, @3);
|
set_location(@1, @3);
|
||||||
|
|
||||||
|
@ -728,7 +738,7 @@ expr:
|
||||||
" in arbitrary expression contexts, only"
|
" in arbitrary expression contexts, only"
|
||||||
" as a statement");
|
" as a statement");
|
||||||
|
|
||||||
$$ = get_assign_expr({AdoptRef{}, $1}, {AdoptRef{}, $3}, in_init).release();
|
$$ = get_assign_expr({AdoptRef{}, $1}, {AdoptRef{}, $4}, in_init).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_WHEN_LOCAL local_id '=' rhs
|
| TOK_WHEN_LOCAL local_id '=' rhs
|
||||||
|
@ -787,7 +797,7 @@ expr:
|
||||||
ExprPtr{AdoptRef{}, $3}));
|
ExprPtr{AdoptRef{}, $3}));
|
||||||
}
|
}
|
||||||
|
|
||||||
| '[' expr_list ']'
|
| '[' opt_expr_list ']'
|
||||||
{
|
{
|
||||||
set_location(@1, @3);
|
set_location(@1, @3);
|
||||||
|
|
||||||
|
@ -795,7 +805,8 @@ expr:
|
||||||
|
|
||||||
// If every expression in the list is a field assignment,
|
// If every expression in the list is a field assignment,
|
||||||
// then treat it as a record constructor, else as a list
|
// then treat it as a record constructor, else as a list
|
||||||
// used for an initializer.
|
// used for an initializer. Interpret no expressions
|
||||||
|
// as an empty record constructor.
|
||||||
|
|
||||||
for ( int i = 0; i < $2->Exprs().length(); ++i )
|
for ( int i = 0; i < $2->Exprs().length(); ++i )
|
||||||
{
|
{
|
||||||
|
@ -812,13 +823,6 @@ expr:
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
|
|
||||||
| '[' ']'
|
|
||||||
{
|
|
||||||
// We interpret this as an empty record constructor.
|
|
||||||
$$ = new RecordConstructorExpr(make_intrusive<ListExpr>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
| TOK_RECORD '(' expr_list ')'
|
| TOK_RECORD '(' expr_list ')'
|
||||||
{
|
{
|
||||||
set_location(@1, @4);
|
set_location(@1, @4);
|
||||||
|
@ -1044,7 +1048,7 @@ rhs: '{' { ++in_init; } rhs_expr_list '}'
|
||||||
| expr
|
| expr
|
||||||
;
|
;
|
||||||
|
|
||||||
rhs_expr_list: expr_list opt_comma
|
rhs_expr_list: expr_list expr_list_opt_comma
|
||||||
|
|
|
|
||||||
{ $$ = new ListExpr(); }
|
{ $$ = new ListExpr(); }
|
||||||
;
|
;
|
||||||
|
@ -1059,12 +1063,13 @@ expr_list:
|
||||||
| expr
|
| expr
|
||||||
{
|
{
|
||||||
set_location(@1);
|
set_location(@1);
|
||||||
|
expr_list_has_opt_comma = 0;
|
||||||
$$ = new ListExpr({AdoptRef{}, $1});
|
$$ = new ListExpr({AdoptRef{}, $1});
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_expr_list:
|
opt_expr_list:
|
||||||
expr_list
|
expr_list expr_list_opt_comma
|
||||||
|
|
|
|
||||||
{ $$ = new ListExpr(); }
|
{ $$ = new ListExpr(); }
|
||||||
;
|
;
|
||||||
|
@ -2259,7 +2264,7 @@ opt_deprecated:
|
||||||
{ $$ = nullptr; }
|
{ $$ = nullptr; }
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_comma: ','
|
expr_list_opt_comma: ',' { expr_list_has_opt_comma = 1; }
|
||||||
|
|
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
1
testing/btest/Baseline/language.trailing-comma-2/.stderr
Normal file
1
testing/btest/Baseline/language.trailing-comma-2/.stderr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
2
testing/btest/Baseline/language.trailing-comma-2/out
Normal file
2
testing/btest/Baseline/language.trailing-comma-2/out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
f() x=1 y=2
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: incorrect syntax for list expression on left-hand side of assignment: trailing comma not allowed (abc, def)
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: incorrect syntax for list expression on left-hand side of assignment: trailing comma not allowed (abc, def)
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 1: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 1: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 4: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 4: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 1: syntax error, at or near ")"
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: syntax error, at or near ","
|
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 2: syntax error, at or near "]"
|
2
testing/btest/Baseline/language.trailing-comma-error/out
Normal file
2
testing/btest/Baseline/language.trailing-comma-error/out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
error in <...>/trailing-comma-error.zeek, line 5: syntax error, at or near ","
|
1
testing/btest/Baseline/language.trailing-comma/.stderr
Normal file
1
testing/btest/Baseline/language.trailing-comma/.stderr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
51
testing/btest/Baseline/language.trailing-comma/out
Normal file
51
testing/btest/Baseline/language.trailing-comma/out
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
vec1, vector of count, [1, 2]
|
||||||
|
vec2, vector of count, [1, 2]
|
||||||
|
vec3, vector of count, [1, 2]
|
||||||
|
set1, set[count], {
|
||||||
|
2,
|
||||||
|
1
|
||||||
|
}
|
||||||
|
set2, set[count], {
|
||||||
|
2,
|
||||||
|
1
|
||||||
|
}
|
||||||
|
set3, set[count], {
|
||||||
|
2,
|
||||||
|
1
|
||||||
|
}
|
||||||
|
rec1, MyRecord, [a=a, b=<uninitialized>]
|
||||||
|
rec2, MyRecord, [a=a, b=<uninitialized>]
|
||||||
|
rec3, record { }, []
|
||||||
|
tab1, table[string] of count, {
|
||||||
|
[a] = 1
|
||||||
|
}
|
||||||
|
tab2, table[string,string] of count, {
|
||||||
|
[a, b] = 1
|
||||||
|
}
|
||||||
|
tab3, table[string,string] of count, {
|
||||||
|
[a, b] = 1
|
||||||
|
}
|
||||||
|
tab4, table[string,string] of vector of count, {
|
||||||
|
[a, b] = [1, 2],
|
||||||
|
[c, d] = [3, 4]
|
||||||
|
}
|
||||||
|
tab5, table[string,string] of vector of count, {
|
||||||
|
[a, b] = [1, 2],
|
||||||
|
[c, d] = [3, 4]
|
||||||
|
}
|
||||||
|
tab6, table[string,string] of vector of count, {
|
||||||
|
[a, b] = [1, 2],
|
||||||
|
[c, d] = [3, 4]
|
||||||
|
}
|
||||||
|
tab7, table[string,string] of list of count,count, {
|
||||||
|
[a, b] = 1, 2,
|
||||||
|
[c, d] = 3, 4
|
||||||
|
}
|
||||||
|
tab8, table[MyRecord] of count, {
|
||||||
|
[[a=c, b=d]] = 43,
|
||||||
|
[[a=a, b=b]] = 42
|
||||||
|
}
|
||||||
|
tab9, table[MyRecord] of count, {
|
||||||
|
[[a=abc, b=def]] = 42
|
||||||
|
}
|
52
testing/btest/language/trailing-comma-error.zeek
Normal file
52
testing/btest/language/trailing-comma-error.zeek
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# @TEST-EXEC: cat %INPUT
|
||||||
|
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
|
||||||
|
|
||||||
|
global vec = vector(, 99, 99);
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global vec = vector(99, 99, , );
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global rec = [,];
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
type MyRecord: record {
|
||||||
|
a: string;
|
||||||
|
};
|
||||||
|
global rec = MyRecord(,$a="aaa");
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
type MyRecord: record {
|
||||||
|
a: string;
|
||||||
|
};
|
||||||
|
global rec = MyRecord($a="aaa", ,);
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
function f(x: count, y: count, ) { }
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
function f(x: count, y: count) { }
|
||||||
|
f(, 1, 2);
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
function f(x: count, y: count) { }
|
||||||
|
f(1, 2, ,);
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global tab: table[string, string] of string;
|
||||||
|
tab["abc", "def", ] = "ghi";
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global tab: table[string, string] of string;
|
||||||
|
tab[, "abc", "def"] = "ghi";
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global tab: table[string, string] of string = {
|
||||||
|
["abc", "def", ] = "ghi",
|
||||||
|
};
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
global tab = table(
|
||||||
|
["abc", "def", ] = "ghi",
|
||||||
|
);
|
113
testing/btest/language/trailing-comma.zeek
Normal file
113
testing/btest/language/trailing-comma.zeek
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
# @TEST-EXEC: btest-diff .stderr
|
||||||
|
|
||||||
|
type MyRecord: record {
|
||||||
|
a: string;
|
||||||
|
b: string &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
local vec1 = vector(1, 2, );
|
||||||
|
print "vec1", type_name(vec1), vec1;
|
||||||
|
|
||||||
|
local vec2: vector of count = [1, 2, ];
|
||||||
|
print "vec2", type_name(vec2), vec2;
|
||||||
|
|
||||||
|
local vec3: vector of count = {1, 2, };
|
||||||
|
print "vec3", type_name(vec3), vec3;
|
||||||
|
|
||||||
|
local set1 = set(1, 2, );
|
||||||
|
print "set1", type_name(set1), set1;
|
||||||
|
|
||||||
|
local set2 = [1, 2, ];
|
||||||
|
print "set2", type_name(set2), set2;
|
||||||
|
|
||||||
|
local set3 = {1, 2, };
|
||||||
|
print "set3", type_name(set3), set3;
|
||||||
|
|
||||||
|
local rec1 = MyRecord($a="a", );
|
||||||
|
print "rec1", type_name(rec1), rec1;
|
||||||
|
|
||||||
|
local rec2: MyRecord = [$a="a", ];
|
||||||
|
print "rec2", type_name(rec2), rec2;
|
||||||
|
|
||||||
|
local rec3 = [];
|
||||||
|
print "rec3", type_name(rec3), rec3;
|
||||||
|
|
||||||
|
local tab1: table[string] of count = [
|
||||||
|
["a"] = 1,
|
||||||
|
];
|
||||||
|
print "tab1", type_name(tab1), tab1;
|
||||||
|
|
||||||
|
local tab2: table[string, string] of count = [
|
||||||
|
["a", "b"] = 1,
|
||||||
|
];
|
||||||
|
print "tab2", type_name(tab2), tab2;
|
||||||
|
|
||||||
|
local tab3: table[string, string] of count = {
|
||||||
|
["a", "b"] = 1,
|
||||||
|
};
|
||||||
|
print "tab3", type_name(tab3), tab3;
|
||||||
|
|
||||||
|
# Very verbose
|
||||||
|
local tab4: table[string, string] of vector of count = {
|
||||||
|
["a", "b"] = vector(
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
["c", "d"] = vector(
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
print "tab4", type_name(tab4), tab4;
|
||||||
|
|
||||||
|
# Slightly compressed
|
||||||
|
local tab5: table[string, string] of vector of count = {
|
||||||
|
["a", "b"] = vector(1, 2,),
|
||||||
|
["c", "d"] = vector(3, 4,),
|
||||||
|
};
|
||||||
|
print "tab5", type_name(tab5), tab5;
|
||||||
|
|
||||||
|
# Inferred types
|
||||||
|
local tab6 = table(
|
||||||
|
["a", "b"] = vector(1,2,),
|
||||||
|
["c", "d"] = vector(3,4,),
|
||||||
|
);
|
||||||
|
print "tab6", type_name(tab6), tab6;
|
||||||
|
|
||||||
|
local tab7 = table(
|
||||||
|
["a", "b"] = [1, 2, ],
|
||||||
|
["c", "d"] = [3, 4, ],
|
||||||
|
);
|
||||||
|
print "tab7", type_name(tab7), tab7;
|
||||||
|
|
||||||
|
# Trailing comma in left-hand side in record constructor expression
|
||||||
|
# I'm not saying these look good, just that they are possible.
|
||||||
|
local tab8: table[MyRecord] of count = {
|
||||||
|
[MyRecord(
|
||||||
|
$a="a",
|
||||||
|
$b="b",
|
||||||
|
)] = 42,
|
||||||
|
[MyRecord(
|
||||||
|
$a="c",
|
||||||
|
$b="d",
|
||||||
|
)] = 43,
|
||||||
|
};
|
||||||
|
print "tab8", type_name(tab8), tab8;
|
||||||
|
|
||||||
|
local tab9: table[MyRecord] of count = {
|
||||||
|
[[
|
||||||
|
$a="abc",
|
||||||
|
$b="def",
|
||||||
|
]] = 42,
|
||||||
|
};
|
||||||
|
print "tab9", type_name(tab9), tab9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@TEST-START-NEXT
|
||||||
|
# Function calls can have trailing commas.
|
||||||
|
function f(x: count, y: count) { print fmt("f() x=%s y=%s", x, y); }
|
||||||
|
f(1, 2,);
|
Loading…
Add table
Add a link
Reference in a new issue