1// Copyright (c) 2020, Peter Ohler, All rights reserved. 2 3package gen 4 5import "fmt" 6 7// Builder is assists in build a more complex Node. 8type Builder struct { 9 stack []Node 10 starts []int 11} 12 13// Reset clears the the Builder of previous built nodes. 14func (b *Builder) Reset() { 15 if 0 < cap(b.stack) && 0 < len(b.stack) { 16 b.stack = b.stack[:0] 17 b.starts = b.starts[:0] 18 } else { 19 b.stack = make([]Node, 0, 64) 20 b.starts = make([]int, 0, 16) 21 } 22} 23 24// MustObject adds an object to the builder. A key is required if adding to a 25// parent object. 26func (b *Builder) MustObject(key ...string) { 27 if err := b.Object(key...); err != nil { 28 panic(err) 29 } 30} 31 32// Object adds an object to the builder. A key is required if adding to a 33// parent object. 34func (b *Builder) Object(key ...string) error { 35 newObj := Object{} 36 if 0 < len(key) { 37 if len(b.starts) == 0 || 0 <= b.starts[len(b.starts)-1] { 38 return fmt.Errorf("can not use a key when pushing to an array") 39 } 40 if obj, _ := b.stack[len(b.stack)-1].(Object); obj != nil { 41 obj[key[0]] = newObj 42 } 43 } else if 0 < len(b.starts) && b.starts[len(b.starts)-1] < 0 { 44 return fmt.Errorf("must have a key when pushing to an object") 45 } 46 b.starts = append(b.starts, -1) 47 b.stack = append(b.stack, newObj) 48 49 return nil 50} 51 52// MustArray adds an array to the builder. A key is required if adding to a 53// parent object. 54func (b *Builder) MustArray(key ...string) { 55 if err := b.Array(key...); err != nil { 56 panic(err) 57 } 58} 59 60// Array adds an array to the builder. A key is required if adding to a parent 61// object. 62func (b *Builder) Array(key ...string) error { 63 if 0 < len(key) { 64 if len(b.starts) == 0 || 0 <= b.starts[len(b.starts)-1] { 65 return fmt.Errorf("can not use a key when pushing to an array") 66 } 67 b.stack = append(b.stack, Key(key[0])) 68 } else if 0 < len(b.starts) && b.starts[len(b.starts)-1] < 0 { 69 return fmt.Errorf("must have a key when pushing to an object") 70 } 71 b.starts = append(b.starts, len(b.stack)) 72 b.stack = append(b.stack, EmptyArray) 73 74 return nil 75} 76 77// MustValue adds a Node to the builder. A key is required if adding to a 78// parent object. 79func (b *Builder) MustValue(value Node, key ...string) { 80 if err := b.Value(value, key...); err != nil { 81 panic(err) 82 } 83} 84 85// Value adds a Node to the builder. A key is required if adding to a parent 86// object. 87func (b *Builder) Value(value Node, key ...string) error { 88 if 0 < len(key) { 89 if len(b.starts) == 0 || 0 <= b.starts[len(b.starts)-1] { 90 return fmt.Errorf("can not use a key when pushing to an array") 91 } 92 if obj, _ := b.stack[len(b.stack)-1].(Object); obj != nil { 93 obj[key[0]] = value 94 } 95 } else if 0 < len(b.starts) && b.starts[len(b.starts)-1] < 0 { 96 return fmt.Errorf("must have a key when pushing to an object") 97 } else { 98 b.stack = append(b.stack, value) 99 } 100 return nil 101} 102 103// Pop close a parent Object or Array Node. 104func (b *Builder) Pop() { 105 if 0 < len(b.starts) { 106 start := b.starts[len(b.starts)-1] 107 if 0 <= start { // array 108 start++ 109 size := len(b.stack) - start 110 a := Array(make([]Node, size)) 111 copy(a, b.stack[start:len(b.stack)]) 112 b.stack = b.stack[:start] 113 b.stack[start-1] = a 114 if 2 < len(b.stack) { 115 if k, ok := b.stack[len(b.stack)-2].(Key); ok { 116 if obj, _ := b.stack[len(b.stack)-3].(Object); obj != nil { 117 obj[string(k)] = a 118 b.stack = b.stack[:len(b.stack)-2] 119 } 120 } 121 } 122 } 123 b.starts = b.starts[:len(b.starts)-1] 124 } 125} 126 127// PopAll close all parent Object or Array Nodes. 128func (b *Builder) PopAll() { 129 for 0 < len(b.starts) { 130 b.Pop() 131 } 132} 133 134// Result returns the current built Node. 135func (b *Builder) Result() (result Node) { 136 if 0 < len(b.stack) { 137 result = b.stack[0] 138 } 139 return 140} 141