mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 01:28:20 +00:00
Add array-style index accessor for strings. Addresses #422.
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.
This commit is contained in:
parent
ea6b62f586
commit
55c515d50a
5 changed files with 115 additions and 10 deletions
59
src/Expr.cc
59
src/Expr.cc
|
@ -2808,11 +2808,17 @@ IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2)
|
|||
SetError("not an index type");
|
||||
|
||||
else if ( ! op1->Type()->YieldType() )
|
||||
{
|
||||
if ( IsString(op1->Type()->Tag()) &&
|
||||
match_type == MATCHES_INDEX_SCALAR )
|
||||
SetType(base_type(TYPE_STRING));
|
||||
else
|
||||
// It's a set - so indexing it yields void. We don't
|
||||
// directly generate an error message, though, since this
|
||||
// expression might be part of an add/delete statement,
|
||||
// rather than yielding a value.
|
||||
SetType(base_type(TYPE_VOID));
|
||||
SetType(base_type(TYPE_VOID));
|
||||
}
|
||||
|
||||
else if ( match_type == MATCHES_INDEX_SCALAR )
|
||||
SetType(op1->Type()->YieldType()->Ref());
|
||||
|
@ -2888,6 +2894,9 @@ void IndexExpr::Delete(Frame* f)
|
|||
|
||||
Expr* IndexExpr::MakeLvalue()
|
||||
{
|
||||
if ( IsString(op1->Type()->Tag()) )
|
||||
ExprError("cannot assign to string index expression");
|
||||
|
||||
return new RefExpr(this);
|
||||
}
|
||||
|
||||
|
@ -2961,10 +2970,34 @@ Val* IndexExpr::Fold(Val* v1, Val* v2) const
|
|||
|
||||
Val* v = 0;
|
||||
|
||||
if ( v1->Type()->Tag() == TYPE_VECTOR )
|
||||
switch ( v1->Type()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
v = v1->AsVectorVal()->Lookup(v2);
|
||||
else
|
||||
break;
|
||||
case TYPE_TABLE:
|
||||
v = v1->AsTableVal()->Lookup(v2);
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
{
|
||||
const ListVal* lv = v2->AsListVal();
|
||||
const BroString* s = v1->AsString();
|
||||
int len = s->Len();
|
||||
bro_int_t first = lv->Index(0)->AsInt();
|
||||
bro_int_t last = lv->Length() > 1 ? lv->Index(1)->AsInt() : first;
|
||||
|
||||
if ( first < 0 )
|
||||
first += len;
|
||||
if ( last < 0 )
|
||||
last += len;
|
||||
|
||||
BroString* substring = s->GetSubstring(first, last - first + 1);
|
||||
return new StringVal(substring ? substring : new BroString(""));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Error("type cannot be indexed");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( v )
|
||||
return v->Ref();
|
||||
|
@ -2991,14 +3024,22 @@ void IndexExpr::Assign(Frame* f, Val* v, Opcode op)
|
|||
return;
|
||||
}
|
||||
|
||||
if ( v1->Type()->Tag() == TYPE_VECTOR )
|
||||
{
|
||||
switch ( v1->Type()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
if ( ! v1->AsVectorVal()->Assign(v2, v, this, op) )
|
||||
Internal("assignment failed");
|
||||
}
|
||||
|
||||
else if ( ! v1->AsTableVal()->Assign(v2, v, op) )
|
||||
Internal("assignment failed");
|
||||
break;
|
||||
case TYPE_TABLE:
|
||||
if ( ! v1->AsTableVal()->Assign(v2, v, op) )
|
||||
Internal("assignment failed");
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
Internal("assignment via string index accessor not allowed");
|
||||
break;
|
||||
default:
|
||||
Internal("bad index expression type in assignment");
|
||||
break;
|
||||
}
|
||||
|
||||
Unref(v1);
|
||||
Unref(v2);
|
||||
|
|
10
src/Type.cc
10
src/Type.cc
|
@ -114,8 +114,16 @@ BroType::~BroType()
|
|||
delete [] type_id;
|
||||
}
|
||||
|
||||
int BroType::MatchesIndex(ListExpr*& /* index */) const
|
||||
int BroType::MatchesIndex(ListExpr*& index) const
|
||||
{
|
||||
if ( Tag() == TYPE_STRING )
|
||||
{
|
||||
if ( index->Exprs().length() != 1 && index->Exprs().length() != 2 )
|
||||
return DOES_NOT_MATCH_INDEX;
|
||||
if ( check_and_promote_exprs_to_type(index, ::base_type(TYPE_INT)) )
|
||||
return MATCHES_INDEX_SCALAR;
|
||||
}
|
||||
|
||||
return DOES_NOT_MATCH_INDEX;
|
||||
}
|
||||
|
||||
|
|
13
testing/btest/Baseline/language.string-indexing/out
Normal file
13
testing/btest/Baseline/language.string-indexing/out
Normal file
|
@ -0,0 +1,13 @@
|
|||
1
|
||||
12
|
||||
123456
|
||||
0123456789
|
||||
8
|
||||
789
|
||||
9
|
||||
9
|
||||
9
|
||||
|
||||
|
||||
2
|
||||
1
|
26
testing/btest/core/leaks/string-indexing.bro
Normal file
26
testing/btest/core/leaks/string-indexing.bro
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Needs perftools support.
|
||||
#
|
||||
# @TEST-GROUP: leaks
|
||||
#
|
||||
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
|
||||
#
|
||||
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local bro -m -b -r $TRACES/wikipedia.trace %INPUT
|
||||
|
||||
|
||||
event new_connection(c: connection)
|
||||
{
|
||||
local s = "0123456789";
|
||||
print s[1];
|
||||
print s[1,2];
|
||||
print s[1,6];
|
||||
print s[0,20];
|
||||
print s[-2];
|
||||
print s[-3,-1];
|
||||
print s[-1,-10];
|
||||
print s[-1,0];
|
||||
print s[-1,5];
|
||||
print s[20, 23];
|
||||
print s[-20, 23];
|
||||
print s[0,5][2];
|
||||
print s[0,5][1,3][0];
|
||||
}
|
17
testing/btest/language/string-indexing.bro
Normal file
17
testing/btest/language/string-indexing.bro
Normal file
|
@ -0,0 +1,17 @@
|
|||
# @TEST-EXEC: bro -b %INPUT >out
|
||||
# @TEST-EXEC: btest-diff out
|
||||
|
||||
local s = "0123456789";
|
||||
print s[1];
|
||||
print s[1,2];
|
||||
print s[1,6];
|
||||
print s[0,20];
|
||||
print s[-2];
|
||||
print s[-3,-1];
|
||||
print s[-1,-10];
|
||||
print s[-1,0];
|
||||
print s[-1,5];
|
||||
print s[20, 23];
|
||||
print s[-20, 23];
|
||||
print s[0,5][2];
|
||||
print s[0,5][1,3][0];
|
Loading…
Add table
Add a link
Reference in a new issue