Skip to content

Commit

Permalink
Fixed operation parser (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
spyzhov authored Jan 31, 2022
1 parent 0d5a0e9 commit cff065f
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func main() {
You can download `ajson` cli from the [release page](https://github.com/spyzhov/ajson/releases), or install from the source:

```shell script
go get github.com/spyzhov/ajson/cmd/[email protected].0
go get github.com/spyzhov/ajson/cmd/[email protected].1
```

Usage:
Expand Down
84 changes: 51 additions & 33 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ const (
asterisk byte = '*'
plus byte = '+'
minus byte = '-'
division byte = '/'
exclamation byte = '!'
caret byte = '^'
signL byte = '<'
signG byte = '>'
signE byte = '='
ampersand byte = '&'
pipe byte = '|'
question byte = '?'
//division byte = '/'
//exclamation byte = '!'
//caret byte = '^'
//signL byte = '<'
//signG byte = '>'
//signE byte = '='
//ampersand byte = '&'
//pipe byte = '|'
question byte = '?'
)

type (
Expand Down Expand Up @@ -88,6 +88,23 @@ func (b *buffer) next() (c byte, err error) {
return b.data[b.index], nil
}

func (b *buffer) slice(delta uint) ([]byte, error) {
if b.index+int(delta) > b.length {
return nil, io.EOF
}
return b.data[b.index : b.index+int(delta)], nil
}

func (b *buffer) move(delta int) error {
if b.index+delta >= b.length {
return io.EOF
}
if b.index+delta >= 0 {
b.index += delta
}
return nil
}

func (b *buffer) reset() {
b.last = GO
}
Expand Down Expand Up @@ -352,21 +369,13 @@ func (b *buffer) rpn() (result rpn, err error) {
break
}
switch true {
case c == asterisk || c == division || c == minus || c == plus || c == caret || c == ampersand || c == pipe || c == signL || c == signG || c == signE || c == exclamation: // operations
case priorityChar[c]: // operations
if variable {
variable = false
current = string(c)
current = b.operation()

c, err = b.next()
if err == nil {
temp = current + string(c)
if priority[temp] != 0 {
current = temp
} else {
b.index--
}
} else {
err = nil
if current == "" {
return nil, b.errorSymbol()
}

for len(stack) > 0 {
Expand Down Expand Up @@ -511,7 +520,6 @@ func (b *buffer) tokenize() (result tokens, err error) {
var (
c byte
start int
temp string
current string
variable bool
)
Expand All @@ -525,18 +533,10 @@ func (b *buffer) tokenize() (result tokens, err error) {
case priorityChar[c]: // operations
if variable || (c != minus && c != plus) {
variable = false
current = string(c)
current = b.operation()

c, err = b.next()
if err == nil {
temp = current + string(c)
if priority[temp] != 0 {
current = temp
} else {
b.index--
}
} else {
err = nil
if current == "" {
return nil, b.errorSymbol()
}

result = append(result, current)
Expand Down Expand Up @@ -637,6 +637,24 @@ func (b *buffer) tokenize() (result tokens, err error) {
return
}

func (b *buffer) operation() string {
current := ""

// Read the complete operation into the variable `current`: `+`, `!=`, `<=>`
// fixme: add additional order for comparison

for _, operation := range comparisonOperationsOrder() {
if bytes, ok := b.slice(uint(len(operation))); ok == nil {
if string(bytes) == operation {
current = operation
_ = b.move(len(operation) - 1) // error can't occupy here because of b.slice result
break
}
}
}
return current
}

func (b *buffer) errorEOF() error {
return errorEOF(b)
}
Expand Down
20 changes: 20 additions & 0 deletions buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,26 @@ func TestBuffer_Token(t *testing.T) {
}
}

func TestBuffer_RPN_long_operations_name(t *testing.T) {
jsonpath := `@.key !@#$%^&* 1`
_, err := newBuffer([]byte(jsonpath)).rpn()
if err == nil {
t.Errorf("Expected error, got nothing")
return
}

expected := []string{"@.key", "1", "!@#$%^&*"}
AddOperation(`!@#$%^&*`, 3, false, func(left *Node, right *Node) (result *Node, err error) {
return NullNode(""), nil
})
result, err := newBuffer([]byte(jsonpath)).rpn()
if err != nil {
t.Errorf("Unexpected error: %s", err.Error())
} else if !sliceEqual(expected, result) {
t.Errorf("Error on RPN(%s): result doesn't match\nExpected: %s\nActual: %s", jsonpath, sliceString(expected), sliceString(result))
}
}

func TestBuffer_RPN(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion cmd/ajson/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/spyzhov/ajson"
)

var version = "v0.7.0"
var version = "v0.7.1"

func usage() {
text := ``
Expand Down
13 changes: 13 additions & 0 deletions math.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math"
"math/rand"
"regexp"
"sort"
"strings"
)

Expand Down Expand Up @@ -479,3 +480,15 @@ func mathFactorial(x uint) uint {
}
return x * mathFactorial(x-1)
}

func comparisonOperationsOrder() []string {
result := make([]string, 0, len(operations))
for operation := range operations {
result = append(result, operation)
}

sort.Slice(result, func(i, j int) bool {
return len(result[i]) > len(result[j])
})
return result
}
14 changes: 13 additions & 1 deletion math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,27 @@ func TestAddConstant(t *testing.T) {
}

func TestAddOperation(t *testing.T) {
name := "new_operation_name"
name := "_one_to_rule_them_all_"
if _, ok := operations[name]; ok {
t.Error("test operation already exists")
return
}
AddOperation(name, 1, true, func(left *Node, right *Node) (result *Node, err error) {
return NumericNode("example", 1), nil
})
if _, ok := operations[name]; !ok {
t.Error("test operation was not added")
return
}
result, err := Eval(NullNode(""), `@ _one_to_rule_them_all_ 100500`)
if err != nil {
t.Errorf("Unexpected error: %s", err.Error())
return
}
if ok, err := result.Eq(NumericNode("", 1)); err != nil {
t.Errorf("Unexpected error: %s", err.Error())
} else if !ok {
t.Errorf("Should be one")
}
}

Expand Down

0 comments on commit cff065f

Please sign in to comment.