And changed the endianness parameter of bytestring_to_count() BIF to
default to false (big endian), mostly just to prove that the BIF parser
doesn't choke on default parameters.
- 'when' statements were problematic when used in a function/event/hook
that had local variables with an assigned function value. This was
because 'when' blocks operate on a clone of the frame and the cloning
process serializes locals and the serialization of functions had an
infinite cycle in it (ID -> BroFunc -> ID -> BroFunc ...). The ID
was only used for the function name and type information, so
refactoring Func and subclasses to depend on those two things instead
fixes the issue.
- 'return when' blocks, specifically, didn't work whenever execution
of the containing function's body does another function call before
reaching the 'return when' block, because of an assertion. This was
was due to logic in CallExpr::Eval always clearing the CallExpr
associated with the Frame after doing the call, instead of restoring
any previous CallExpr, which the code in Trigger::Eval expected to
have available.
- An assert could be reached when the condition of a 'when' statement
depended on checking the value of global state variables. The assert
in Trigger::QueueTrigger that checks that the Trigger isn't disabled
would get hit because Trigger::Eval/Timeout disable themselves after
running, but don't unregister themselves from the NotifierRegistry,
which keeps calling QueueTrigger for every state access of the global.
These cases should be avoidable by fixing scripts where they occur and
they can also help catch typos that would lead to unintentional runtime
behavior.
Adding this already revealed several scripts where a field in an inlined
record was never removed after a code refactor.
* origin/topic/jsiwek/no-switch-fallthrough:
Add "fallthrough" keyword, require a flow statement to end case blocks.
Disable automatic case fallthrough in switch stmts. Addresses #754.
I've added a test for the error case where no break/fallthrough/return
is given.
Closes#754.
Since values for local variables are referenced by offset within a Frame
(not by identifier name), and event/hook handler bodies share a common
Frame, the value offsets for local variables in different handlers may
overlap. This meant locals in a handler without an initialization may
actually end up referring to the value of a previous handler's local
that has the same Frame offset. When executing the body, that can
possibly result in a type-conflict error or give give unexpected
results instead of a "use of uninitialized value" error.
This patch makes it so uninitialized locals do always refer to a null
value before executing the body of a event/hook handler, so that using
them without assigning a value within the body will connsistently give
a "use of uninitialized value" error.
Addresses #932.
Case blocks in switch statements now must end in a break, return, or
fallthrough statement to give best mix of safety, readability, and
flexibility.
The new fallthrough keyword explicitly allows control to be passed to the
next case block in a switch statement.
Addresses #754.
Case bodies now don't require a "break" statement to prevent fallthrough
to case bodies below. Empty case bodies generate an error message at
parse-time to help indicate the absence of automatic fallthrough; to
associate multiple values with a case, use "case 1, 2:" instead of
"case 1: case 2:".
The index expression can take up to two indices for the start and end
index of the substring to return (e.g. "mystring[1,3]"). Negative
indices are allowed, with -1 representing the last character in the
string. The indexing is not cyclic -- if the starting index is >= the
length of the string an empty string is returned, and if the ending
index is >= the length of the string then it's interpreted as the last
index of the string. Assigning to substrings accessed like this isn't
allowed.
They behave like C-style switches except case labels can be comprised
of multiple literal constants delimited by commas. Only atomic types
are allowed for now. Case label bodies that don't execute a "return"
or "break" statement will fall through to subsequent cases. A default
case label is allowed.
Both local and global variables declared with "const" could be modified,
but now expressions that would modify them should generate an error
message at parse-time.
For an index expression list, ListExpr::InitVal() passed the TypeList
to Expr::InitVal() for each expression element in the list instead of
the type for that element. This made RecordConstructorExpr::InitVal()
complain since it expects a RecordType and not a TypeList with a
RecordType element as an argument. In most other cases, Expr::InitVal()
worked because check_and_promote() "flattens" the list to a single type.
* origin/topic/jsiwek/table-init-container-ctors:
Add test of record() constructor to table initializer unit test.
Fix table(), set(), vector() constructors in table initializer lists.
Closes#5.
* origin/topic/jsiwek/hook:
Change hook calls to only be allowed when preceded by "hook" keyword.
Clarification in hook documentation.
Hook functions now directly callable instead of w/ "hook" statements.
Closes#918.
- Identifiers that are initialized with set()/table() constructor
expressions now inherit attributes from the expression. Before,
statements like
const i: set[string] = set() &redef;
associated the attribute with the set() constructor, but not the
"i" identifier, preventing redefinition. Addresses #866.
- Allow &default attribute to apply to tables initialized as empty
(via either "{ }" or "table()") or if the expression supplied to it
can evaluate to a type that's promotable to the same yield type as
the table.
The return value of the call is an implicit boolean value of T if all
hook handlers ran, or F if one hook handler exited as a result of a
break statement and potentially prevented other handlers from running.
Scripts don't need to declare hooks with an explicit return type of bool
(internally, that's assumed), and any values given to (optional) return
statements in handler definitions are just ignored.
Addresses #918.
For tables of a composite index type with the first type being a
record, membership checks with an inline index key could be
misinterpreted as a record constructor instead of an expression list.
E.g, if the table type is "global t = table[conn_id, bool] of count",
then checking membership like "[c$id, is_orig] in t" now works.
Addresses #80.