Skip to content

Commit 775fc3a

Browse files
authored
feat: support byte slice in matches operator (#876)
The matches operator now supports matching against byte slices in addition to strings. This allows expressions like `b matches "pattern"` where `b` is a byte slice. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
1 parent 593f93f commit 775fc3a

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

checker/checker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
462462
return v.error(node, err.Error())
463463
}
464464
}
465-
if l.IsString() && r.IsString() {
465+
if (l.IsString() || l.IsByteSlice()) && r.IsString() {
466466
return v.config.NtCache.FromType(boolType)
467467
}
468468
if l.MaybeCompatible(&v.config.NtCache, r, StringCheck) {

checker/nature/nature.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import (
1010
)
1111

1212
var (
13-
intType = reflect.TypeOf(0)
14-
floatType = reflect.TypeOf(float64(0))
15-
arrayType = reflect.TypeOf([]any{})
16-
timeType = reflect.TypeOf(time.Time{})
17-
durationType = reflect.TypeOf(time.Duration(0))
13+
intType = reflect.TypeOf(0)
14+
floatType = reflect.TypeOf(float64(0))
15+
arrayType = reflect.TypeOf([]any{})
16+
byteSliceType = reflect.TypeOf([]byte{})
17+
timeType = reflect.TypeOf(time.Time{})
18+
durationType = reflect.TypeOf(time.Duration(0))
1819

1920
builtinInt = map[reflect.Type]struct{}{
2021
reflect.TypeOf(int(0)): {},
@@ -502,6 +503,10 @@ func (n *Nature) IsString() bool {
502503
return n.Kind == reflect.String
503504
}
504505

506+
func (n *Nature) IsByteSlice() bool {
507+
return n.Type == byteSliceType
508+
}
509+
505510
func (n *Nature) IsArray() bool {
506511
return n.Kind == reflect.Slice || n.Kind == reflect.Array
507512
}

vm/vm.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,13 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
299299
vm.push(false)
300300
break
301301
}
302-
match, err := regexp.MatchString(b.(string), a.(string))
302+
var match bool
303+
var err error
304+
if s, ok := a.(string); ok {
305+
match, err = regexp.MatchString(b.(string), s)
306+
} else {
307+
match, err = regexp.Match(b.(string), a.([]byte))
308+
}
303309
if err != nil {
304310
panic(err)
305311
}
@@ -312,7 +318,11 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
312318
break
313319
}
314320
r := program.Constants[arg].(*regexp.Regexp)
315-
vm.push(r.MatchString(a.(string)))
321+
if s, ok := a.(string); ok {
322+
vm.push(r.MatchString(s))
323+
} else {
324+
vm.push(r.Match(a.([]byte)))
325+
}
316326

317327
case OpContains:
318328
b := vm.pop()

vm/vm_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,18 @@ func TestVM_OpcodeOperations(t *testing.T) {
368368
expr: `"hello123" matches "^hello\\d+$"`,
369369
want: true,
370370
},
371+
{
372+
name: "byte slice matches regex",
373+
expr: `b matches "^hello\\d+$"`,
374+
env: map[string]any{"b": []byte("hello123")},
375+
want: true,
376+
},
377+
{
378+
name: "byte slice matches dynamic regex",
379+
expr: `b matches pattern`,
380+
env: map[string]any{"b": []byte("hello123"), "pattern": "^hello\\d+$"},
381+
want: true,
382+
},
371383

372384
// Data Structure Operations
373385
{

0 commit comments

Comments
 (0)