From febe9b6177b94be563549a26f7e48321ce0e4d2c Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 3 Jul 2025 15:56:53 -0700 Subject: [PATCH] Add *= and /= operators for arithmetic types --- src/parse.y | 57 ++++++++++++++++++- src/scan.l | 2 + testing/btest/Baseline/language.count/out | 2 + testing/btest/Baseline/language.double/out | 2 + .../Baseline/language.init-mismatch/.stderr | 1 + testing/btest/Baseline/language.int/out | 2 + testing/btest/language/count.zeek | 7 ++- testing/btest/language/double.zeek | 7 ++- testing/btest/language/init-mismatch.zeek | 2 + testing/btest/language/int.zeek | 6 ++ 10 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/parse.y b/src/parse.y index 09db942d53..5308a31909 100644 --- a/src/parse.y +++ b/src/parse.y @@ -5,11 +5,12 @@ // Switching parser table type fixes ambiguity problems. %define lr.type ielr -%expect 217 +%expect 221 %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY TOK_ASSERT %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_BOOL TOK_BREAK TOK_CASE TOK_OPTION TOK_CONST +%token TOK_COMPOUND_MULTIPLY TOK_COMPOUND_DIVIDE %token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_DEFAULT TOK_DELETE %token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FALLTHROUGH %token TOK_FILE TOK_FOR TOK_FUNCTION TOK_GLOBAL TOK_HOOK TOK_ID TOK_IF TOK_INT @@ -37,7 +38,7 @@ %token TOK_NO_TEST %left ',' -%right '=' TOK_ADD_TO TOK_REMOVE_FROM TOK_ADD TOK_DELETE +%right '=' TOK_ADD_TO TOK_REMOVE_FROM TOK_ADD TOK_DELETE TOK_COMPOUND_MULTIPLY TOK_COMPOUND_DIVIDE %right '?' ':' %left TOK_OR_OR %left TOK_AND_AND @@ -610,6 +611,32 @@ expr: $$ = new TimesExpr({AdoptRef{}, $1}, {AdoptRef{}, $3}); } + | expr TOK_COMPOUND_MULTIPLY rhs + { + set_location(@1, @3); + + ExprPtr lhs = {AdoptRef{}, $1}; + ExprPtr rhs = {AdoptRef{}, $3}; + auto tag1 = $1->GetType()->Tag(); + + if ( IsArithmetic($1->GetType()->Tag()) ) { + // Script optimization assumes that each AST + // node is distinct, hence the call to + // Duplicate() here. + ExprPtr result = make_intrusive(lhs->Duplicate(), rhs); + + if ( result->GetType()->Tag() != tag1 ) + result = make_intrusive(result, tag1); + + $$ = new AssignExpr(lhs, result, false); + } + else { + $$->Error("Compound multiplication operator is only allowed for arithmetic types"); + $$->SetError(); + YYERROR; + } + } + | expr '/' expr { set_location(@1, @3); @@ -619,6 +646,32 @@ expr: $$ = new DivideExpr({AdoptRef{}, $1}, {AdoptRef{}, $3}); } + | expr TOK_COMPOUND_DIVIDE rhs + { + set_location(@1, @3); + + ExprPtr lhs = {AdoptRef{}, $1}; + ExprPtr rhs = {AdoptRef{}, $3}; + auto tag1 = $1->GetType()->Tag(); + + if ( IsArithmetic($1->GetType()->Tag()) ) { + // Script optimization assumes that each AST + // node is distinct, hence the call to + // Duplicate() here. + ExprPtr result = make_intrusive(lhs->Duplicate(), rhs); + + if ( result->GetType()->Tag() != tag1 ) + result = make_intrusive(result, tag1); + + $$ = new AssignExpr(lhs, result, false); + } + else { + $$->Error("Compound division operator is only allowed for arithmetic types"); + $$->SetError(); + YYERROR; + } + } + | expr '%' expr { set_location(@1, @3); diff --git a/src/scan.l b/src/scan.l index 9777996852..ca127eff15 100644 --- a/src/scan.l +++ b/src/scan.l @@ -304,6 +304,8 @@ ESCSEQ (\\([^\r\n]|[0-7]+|x[[:xdigit:]]+)) "+=" return TOK_ADD_TO; "-=" return TOK_REMOVE_FROM; +"*=" return TOK_COMPOUND_MULTIPLY; +"/=" return TOK_COMPOUND_DIVIDE; "==" return TOK_EQ; "!=" return TOK_NE; diff --git a/testing/btest/Baseline/language.count/out b/testing/btest/Baseline/language.count/out index 0d1b3cab6a..97e8488777 100644 --- a/testing/btest/Baseline/language.count/out +++ b/testing/btest/Baseline/language.count/out @@ -24,5 +24,7 @@ bitwise lshift (PASS) bitwise rshift (PASS) bitwise complement (PASS) bitwise complement (PASS) +compound division operator (PASS) +compound multiplication operator (PASS) max count value = 18446744073709551615 (PASS) max count value = 18446744073709551615 (PASS) diff --git a/testing/btest/Baseline/language.double/out b/testing/btest/Baseline/language.double/out index 143e1a7c81..f757da27b2 100644 --- a/testing/btest/Baseline/language.double/out +++ b/testing/btest/Baseline/language.double/out @@ -26,6 +26,8 @@ relational operator (PASS) relational operator (PASS) relational operator (PASS) division operator (PASS) +compound division operator (PASS) +compound multiplcation operator (PASS) max double value = 1.7976931348623157e+308 (PASS) 4.9999999999999999e-13 diff --git a/testing/btest/Baseline/language.init-mismatch/.stderr b/testing/btest/Baseline/language.init-mismatch/.stderr index 294a1efe24..64e13c7a5a 100644 --- a/testing/btest/Baseline/language.init-mismatch/.stderr +++ b/testing/btest/Baseline/language.init-mismatch/.stderr @@ -19,3 +19,4 @@ error in <...>/init-mismatch.zeek, line 34: not a list of indices (s2) error in <...>/init-mismatch.zeek, line 34: type clash in assignment (s3 = set(s2)) error in <...>/init-mismatch.zeek, line 36: pattern += op requires op to be a pattern (p += 3) error in <...>/init-mismatch.zeek, line 38: illegal table constructor element (1.2.3.4) +error in <...>/init-mismatch.zeek, line 40: Compound multiplication operator is only allowed for arithmetic types (v) diff --git a/testing/btest/Baseline/language.int/out b/testing/btest/Baseline/language.int/out index 99cf1eb829..74630b8d45 100644 --- a/testing/btest/Baseline/language.int/out +++ b/testing/btest/Baseline/language.int/out @@ -20,3 +20,5 @@ assignment operator (PASS) assignment operator (PASS) bitwise lshift (PASS) bitwise rshift (PASS) +compound division operator (FAIL) +compound multiplication operator (FAIL) diff --git a/testing/btest/language/count.zeek b/testing/btest/language/count.zeek index ae6a52665e..c5835ee2a8 100644 --- a/testing/btest/language/count.zeek +++ b/testing/btest/language/count.zeek @@ -14,6 +14,7 @@ global c4: count = 255; global c5: count = 18446744073709551615; # maximum allowed value global c6: count = 0xffffffffffffffff; # maximum allowed value global c7 = 1; +global c8: count = 10; event zeek_init() { @@ -52,6 +53,11 @@ event zeek_init() test_case( "bitwise complement", ~c6 == 0 ); test_case( "bitwise complement", ~~c4 == c4 ); + c8 /= 5; + test_case( "compound division operator", c8 == 2 ); + c8 *= 3; + test_case( "compound multiplication operator", c8 == 6 ); + # Max. value tests local str1 = fmt("max count value = %d", c5); @@ -59,4 +65,3 @@ event zeek_init() local str2 = fmt("max count value = %d", c6); test_case( str2, str2 == "max count value = 18446744073709551615" ); } - diff --git a/testing/btest/language/double.zeek b/testing/btest/language/double.zeek index 8334657b98..bfbb791b90 100644 --- a/testing/btest/language/double.zeek +++ b/testing/btest/language/double.zeek @@ -29,6 +29,7 @@ global d19: double = 1.7976931348623157e308; # maximum allowed value global d20 = 7.0; global d21 = 7e0; global d22 = 7e+1; +global d23 = 7.0; event zeek_init() { @@ -70,6 +71,11 @@ event zeek_init() test_case( "relational operator", d17 > d3 ); test_case( "division operator", d3/2 == 1.5 ); + d23 /= 3.5; + test_case( "compound division operator", d23 == 2.0 ); + d23 *= 1.75; + test_case( "compound multiplcation operator", d23 == 3.5 ); + # Max. value test local str1 = fmt("max double value = %.16e", d19); @@ -111,4 +117,3 @@ event zeek_init() print 0.1; print 1.0; } - diff --git a/testing/btest/language/init-mismatch.zeek b/testing/btest/language/init-mismatch.zeek index 2153ca6efd..154e1d65a1 100644 --- a/testing/btest/language/init-mismatch.zeek +++ b/testing/btest/language/init-mismatch.zeek @@ -37,4 +37,6 @@ p += 3; t += { 1.2.3.4, F }; +v *= vector(); + print a, b; diff --git a/testing/btest/language/int.zeek b/testing/btest/language/int.zeek index df1e20aed5..6a092604f1 100644 --- a/testing/btest/language/int.zeek +++ b/testing/btest/language/int.zeek @@ -18,6 +18,7 @@ global i8: int = 0xC; global i9: int = -0xC; global i10: int = -12; global i11 = +3; +global i12: int = 10; event zeek_init() { @@ -52,4 +53,9 @@ event zeek_init() test_case( "assignment operator", i2 == 5 ); test_case( "bitwise lshift", i6 << 1 == 24 ); test_case( "bitwise rshift", i6 >> 1 == 6 ); + + i11 /= 5; + test_case( "compound division operator", i11 == 2 ); + i11 *= 3; + test_case( "compound multiplication operator", i11 == 6 ); }