Skip to content

Commit

Permalink
Add supporting of nested placeholders
Browse files Browse the repository at this point in the history
  • Loading branch information
judimator committed Jul 23, 2024
1 parent 7795594 commit 0e1ca73
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [v1.4.0](https://github.com/judimator/augurken/tree/v1.4.0)

**Enhancements:**
- Add support of nested placeholders in JSON like `{"x":<p1:<p2>:v>}`

## [v1.3.2](https://github.com/judimator/augurken/tree/v1.3.2)

**Enhancements:**
Expand Down
56 changes: 48 additions & 8 deletions json/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ type SyntaxError struct {
func (e *SyntaxError) Error() string { return e.msg }

type scanner struct {
step func(*scanner, byte) int
endTop bool
parseState []int
err error
bytes int64
step func(*scanner, byte) int
endTop bool
parseState []int
err error
bytes int64
placeholderStack placeholderStack
}

var scannerPool = sync.Pool{
Expand All @@ -51,10 +52,30 @@ var scannerPool = sync.Pool{
},
}

type placeholderStack struct {
chars []byte
length int
}

func (s *placeholderStack) push(char byte) {
s.chars = append(s.chars, char)
s.length++
}

func (s *placeholderStack) pop() byte {
char := s.chars[len(s.chars)-1]

s.chars = s.chars[0 : len(s.chars)-1]
s.length--

return char
}

func newScanner() *scanner {
scan := scannerPool.Get().(*scanner)
// scan.reset by design doesn't set bytes to zero
scan.bytes = 0
scan.placeholderStack = placeholderStack{}
scan.reset()

return scan
Expand Down Expand Up @@ -109,6 +130,7 @@ const maxNestingDepth = 10000
func (s *scanner) reset() {
s.step = stateBeginValue
s.parseState = s.parseState[0:0]
s.placeholderStack.chars = s.placeholderStack.chars[0:0]
s.err = nil
s.endTop = false
}
Expand Down Expand Up @@ -220,6 +242,7 @@ func stateBeginValue(s *scanner, c byte) int {
return scanBeginLiteral
case '<':
s.step = stateInPlaceholder
s.placeholderStack.push(c)

return scanBeginPlaceholder
}
Expand Down Expand Up @@ -251,7 +274,18 @@ func stateBeginStringOrEmpty(s *scanner, c byte) int {

// stateInPlaceholder is the state after reading <placeholder>
func stateInPlaceholder(s *scanner, c byte) int {
if c == '>' {
switch c {
case '>':
if s.placeholderStack.length == 0 {
return s.error(c, "Invalid placeholder given")
}

s.placeholderStack.pop()

if s.placeholderStack.length >= 1 {
return scanContinue
}

n := len(s.parseState)
if n == 0 {
// Completed top-level before the current byte.
Expand All @@ -268,9 +302,13 @@ func stateInPlaceholder(s *scanner, c byte) int {
s.step = stateEndValue

return scanEndPlaceholder
}
case '<':
s.placeholderStack.push(c)

return scanContinue
return scanContinue
default:
return scanContinue
}
}

// stateBeginStringOrPlaceHolder is the state after reading `{"key": value,`.
Expand All @@ -287,6 +325,7 @@ func stateBeginStringOrPlaceHolder(s *scanner, c byte) int {

if c == '<' {
s.step = stateInPlaceholder
s.placeholderStack.push(c)

return scanBeginPlaceholder
}
Expand Down Expand Up @@ -410,6 +449,7 @@ func stateInStringAfterMissingComma(s *scanner, c byte) int {

if c == '<' {
s.step = stateInPlaceholder
s.placeholderStack.push(c)

return scanContinueAfterMissingComma
}
Expand Down
3 changes: 3 additions & 0 deletions json/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func TestIndent(t *testing.T) {
}
}`},
{Name(""), "{\"\":\"<>&\u2028\u2029\"}", "{\n \"\": \"<>&\u2028\u2029\"\n}"}, // See golang.org/issue/34070
{Name(""), `{"x":<p1:<p2>:v>}`, `{
"x": <p1:<p2>:v>
}`},
}

var buf bytes.Buffer
Expand Down

0 comments on commit 0e1ca73

Please sign in to comment.