Skip to content

Commit

Permalink
Add initial matching for charstrings (#601)
Browse files Browse the repository at this point in the history
  • Loading branch information
nnnnblaser authored Sep 5, 2022
1 parent e697203 commit 1c391c8
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 16 deletions.
17 changes: 15 additions & 2 deletions builtins/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ func match(a, b runtime.Object) (bool, error) {
default:
return matchRecordOf(a.(*runtime.List), b)
}
case *runtime.String:
//Leaving out this Comparision would create an endless loop where the same
//function is called with the same parameters recursively
if c := a.(*runtime.String); c.Len() == 1 && b.Len() == 1 {
if b.Value[0] == rune('?') || b.Value[0] == rune('*') || b.Value[0] == c.Value[0] {
return true, nil
}
return false, runtime.Errorf("tried to match %d with %d", c.Value[0], b.Value[0])

}
return matchRecordOf(a.(*runtime.String), b)
default:
return a.Equal(b), nil
}
Expand Down Expand Up @@ -57,7 +68,9 @@ func matchRecordOf(val, pat sliceHolder) (bool, error) {
i, back_i := 0, -1
j, back_j := 0, -1
for i < val.Len() && j < pat.Len() {
if pat.Get(j) == runtime.AnyOrNone {
// if pat is *runtime.String, Get(i) returns another *runtime.String
// whose Value array contains a single rune
if pat.Get(j) == runtime.AnyOrNone || pat.Get(j).Equal(runtime.NewString("*")) {
j++
back_j = j // Pattern Element after *
back_i = i // First Value Element which could be matched with that *
Expand Down Expand Up @@ -89,7 +102,7 @@ func matchRecordOf(val, pat sliceHolder) (bool, error) {
// reached if i == len(val) || j == len(pat)
if val.Len() == i {
for ; j < pat.Len(); j++ {
if pat.Get(j) != runtime.AnyOrNone {
if pat.Get(j) != runtime.AnyOrNone && !pat.Get(j).Equal(runtime.NewString("*")) {
return false, runtime.Errorf("First RecordOf is entirely matched, second isn't")
}
}
Expand Down
19 changes: 19 additions & 0 deletions builtins/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,25 @@ func TestMatch(t *testing.T) {
{List(runtime.SET_OF, 1, 2, 3), List(runtime.SUBSET, 1, 2, runtime.AnyOrNone), true},
{List(runtime.SET_OF, 1, 2, 3), List(runtime.SUBSET, runtime.AnyOrNone), true},
{List(runtime.SET_OF), List(runtime.SUBSET, runtime.AnyOrNone), true},

// Strings
{makeObj(""), makeObj(""), true},
{makeObj(""), makeObj("abc"), false},
{makeObj("abc"), makeObj(""), false},
{makeObj("abc"), makeObj("abc"), true},
{makeObj("abc"), makeObj("abd"), false},
{makeObj("abc"), makeObj("ab?"), true},
{makeObj("abc"), makeObj("a?c"), true},
{makeObj(""), makeObj("?"), false},
{makeObj("abc"), makeObj("abc*"), true},
{makeObj("abc"), makeObj("*abc"), true},
{makeObj("abc"), makeObj("a*c"), true},
{makeObj("abc"), makeObj("a*"), true},
{makeObj("abc"), makeObj("*"), true},
{makeObj(""), makeObj("*"), true},
{makeObj("abcdef"), makeObj("a*d*ef"), true},
{makeObj("abcdcdefaf"), makeObj("a*de*f"), true},
{makeObj("abcdcdefab"), makeObj("a*de*f"), false},
}

for _, test := range tests {
Expand Down
6 changes: 3 additions & 3 deletions interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func evalLiteral(n *ast.ValueLiteral, env runtime.Scope) runtime.Object {
if err != nil {
return runtime.Errorf("%s", err.Error())
}
return &runtime.String{Value: s}
return &runtime.String{Value: []rune(s)}
case token.BSTRING:
b, err := runtime.NewBitstring(n.Tok.Lit)
if err != nil {
Expand Down Expand Up @@ -482,7 +482,7 @@ func evalBinary(n *ast.BinaryExpr, env runtime.Scope) runtime.Object {
return evalBoolBinary(bool(x.(runtime.Bool)), bool(y.(runtime.Bool)), op, env)

case x.Type() == runtime.STRING:
return evalStringBinary(x.(*runtime.String).Value, y.(*runtime.String).Value, op, env)
return evalStringBinary(string(x.(*runtime.String).Value), string(y.(*runtime.String).Value), op, env)

case x.Type() == runtime.BITSTRING:
return evalBitstringBinary(x.(*runtime.Bitstring), y.(*runtime.Bitstring), op, env)
Expand Down Expand Up @@ -592,7 +592,7 @@ func evalBoolBinary(x bool, y bool, op token.Kind, env runtime.Scope) runtime.Ob

func evalStringBinary(x string, y string, op token.Kind, env runtime.Scope) runtime.Object {
if op == token.CONCAT {
return &runtime.String{Value: x + y}
return &runtime.String{Value: []rune(string(x) + string(y))}
}
return runtime.Errorf("unknown operator: charstring %s charstring", op)

Expand Down
8 changes: 4 additions & 4 deletions interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ func TestString(t *testing.T) {
t.Errorf("object is not runtime.String. got=%T (%+v)", val, val)
continue
}
if str.Value != tt.expected {
t.Errorf("object has wrong value. got=%s, want=%s", str.Value, tt.expected)
if string(str.Value) != tt.expected {
t.Errorf("object has wrong value. got=%s, want=%s", string(str.Value), tt.expected)
}
}
}
Expand Down Expand Up @@ -361,8 +361,8 @@ func TestMapExpr(t *testing.T) {
key runtime.Object
expected int64
}{
{&runtime.String{Value: "foo"}, 1},
{&runtime.String{Value: "bar"}, 2},
{&runtime.String{Value: []rune("foo")}, 1},
{&runtime.String{Value: []rune("bar")}, 2},
}
for _, tt := range tests {
val, ok := m.Get(tt.key)
Expand Down
30 changes: 23 additions & 7 deletions runtime/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,27 +182,43 @@ func NewInt(s string) Int {
}

type String struct {
Value string
Value []rune
}

func (s *String) Type() ObjectType { return STRING }
func (s *String) Inspect() string { return s.Value }
func (s *String) Inspect() string { return string(s.Value) }

func (s *String) Equal(obj Object) bool {
if other, ok := obj.(*String); ok {
return s.Value == other.Value
b, ok := obj.(*String)
if !ok || len(s.Value) != len(b.Value) {
return false
}
return false

for i, v := range s.Value {
if v != b.Value[i] {
return false
}
}

return true
}

func (s *String) hashKey() hashKey {
h := fnv.New64a()
h.Write([]byte(s.Value))
h.Write([]byte(string(s.Value)))
return hashKey{Type: s.Type(), Value: h.Sum64()}
}

func (s *String) Len() int {
return len(s.Value)
}

func (s *String) Get(index int) Object {
return NewString(string(s.Value[index]))
}

func NewString(s string) *String {
return &String{Value: s}
return &String{Value: []rune(s)}
}

type Bitstring struct {
Expand Down

0 comments on commit 1c391c8

Please sign in to comment.