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:
Jon Siwek 2012-12-20 17:13:06 -06:00
parent ea6b62f586
commit 55c515d50a
5 changed files with 115 additions and 10 deletions

View file

@ -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);