1
0

node.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Package xpj reads and writes MPC Sample project files (.xpj).
  2. //
  3. // A project file is a gzip stream holding five header lines and one JSON
  4. // document. The JSON is held as an ordered tree: objects keep their key order
  5. // and numbers keep their original text, so a file that is read and written
  6. // back unchanged is byte-identical after decompression. The package knows
  7. // nothing about pads, samples or sequences.
  8. package xpj
  9. import (
  10. "errors"
  11. "fmt"
  12. "math"
  13. "strconv"
  14. "strings"
  15. )
  16. // Kind is the JSON type of a Node.
  17. type Kind int
  18. const (
  19. Null Kind = iota
  20. Bool
  21. Number
  22. String
  23. Array
  24. Object
  25. )
  26. func (k Kind) String() string {
  27. switch k {
  28. case Null:
  29. return "null"
  30. case Bool:
  31. return "bool"
  32. case Number:
  33. return "number"
  34. case String:
  35. return "string"
  36. case Array:
  37. return "array"
  38. case Object:
  39. return "object"
  40. }
  41. return fmt.Sprintf("Kind(%d)", int(k))
  42. }
  43. // Node is one JSON value.
  44. type Node struct {
  45. Kind Kind
  46. // Text is the decoded value of a String, or the literal text of a Number.
  47. Text string
  48. Bool bool
  49. Items []*Node // Array elements
  50. Members []Member // Object members, in file order
  51. }
  52. // Member is one key/value pair of an object.
  53. type Member struct {
  54. Key string
  55. Value *Node
  56. }
  57. // NewNull returns a null node.
  58. func NewNull() *Node { return &Node{Kind: Null} }
  59. // NewBool returns a boolean node.
  60. func NewBool(b bool) *Node { return &Node{Kind: Bool, Bool: b} }
  61. // NewString returns a string node.
  62. func NewString(s string) *Node { return &Node{Kind: String, Text: s} }
  63. // NewInt returns a number node written as an integer, e.g. 4.
  64. func NewInt(i int64) *Node { return &Node{Kind: Number, Text: strconv.FormatInt(i, 10)} }
  65. // NewFloat returns a number node for a float field. It is always written with
  66. // a decimal point or exponent (96.0, never 96), in the shortest form that
  67. // reads back as the same float64. It panics on NaN or infinity, which JSON
  68. // cannot hold.
  69. func NewFloat(f float64) *Node { return &Node{Kind: Number, Text: FormatFloat(f)} }
  70. // NewFloat32 is NewFloat for a field the device stores as a 32-bit float:
  71. // the value is rounded to float32 first, then printed as a float64
  72. // (12.4 is written as 12.399999618530273).
  73. func NewFloat32(f float64) *Node { return NewFloat(float64(float32(f))) }
  74. // NewArray returns an array node holding items.
  75. func NewArray(items ...*Node) *Node { return &Node{Kind: Array, Items: items} }
  76. // NewObject returns an empty object node.
  77. func NewObject() *Node { return &Node{Kind: Object} }
  78. // FormatFloat prints f the way the reference writer (Python's repr) does:
  79. // shortest round-trip digits, plain notation for exponents from -4 to 15
  80. // with at least one digit after the point, otherwise d.ddde±XX.
  81. func FormatFloat(f float64) string {
  82. if math.IsNaN(f) || math.IsInf(f, 0) {
  83. panic("xpj: cannot write NaN or infinity")
  84. }
  85. s := strconv.FormatFloat(f, 'e', -1, 64) // e.g. -1.2345e+01
  86. mant, expStr, _ := strings.Cut(s, "e")
  87. exp, _ := strconv.Atoi(expStr)
  88. neg := strings.HasPrefix(mant, "-")
  89. digits := strings.Replace(strings.TrimPrefix(mant, "-"), ".", "", 1)
  90. var out string
  91. if exp < -4 || exp >= 16 {
  92. out = digits[:1]
  93. if len(digits) > 1 {
  94. out += "." + digits[1:]
  95. }
  96. sign := "+"
  97. if exp < 0 {
  98. sign, exp = "-", -exp
  99. }
  100. out += fmt.Sprintf("e%s%02d", sign, exp)
  101. } else if exp < 0 {
  102. out = "0." + strings.Repeat("0", -exp-1) + digits
  103. } else if exp+1 >= len(digits) {
  104. out = digits + strings.Repeat("0", exp+1-len(digits)) + ".0"
  105. } else {
  106. out = digits[:exp+1] + "." + digits[exp+1:]
  107. }
  108. if neg {
  109. out = "-" + out
  110. }
  111. return out
  112. }
  113. // errMissing is returned by the value getters for a nil node.
  114. var errMissing = errors.New("xpj: value is missing")
  115. // Int returns the value of a Number node as an integer. A nil node, as
  116. // Lookup returns for a missing key, is an error.
  117. func (n *Node) Int() (int64, error) {
  118. if n == nil {
  119. return 0, errMissing
  120. }
  121. if n.Kind != Number {
  122. return 0, fmt.Errorf("xpj: %s is not a number", n.Kind)
  123. }
  124. if i, err := strconv.ParseInt(n.Text, 10, 64); err == nil {
  125. return i, nil
  126. }
  127. f, err := strconv.ParseFloat(n.Text, 64)
  128. if err != nil || f != math.Trunc(f) || math.Abs(f) > 1<<53 {
  129. return 0, fmt.Errorf("xpj: %s is not an integer", n.Text)
  130. }
  131. return int64(f), nil
  132. }
  133. // Float returns the value of a Number node. A nil node is an error.
  134. func (n *Node) Float() (float64, error) {
  135. if n == nil {
  136. return 0, errMissing
  137. }
  138. if n.Kind != Number {
  139. return 0, fmt.Errorf("xpj: %s is not a number", n.Kind)
  140. }
  141. return strconv.ParseFloat(n.Text, 64)
  142. }
  143. // Lookup returns the value of the first member called key, or nil if n is not
  144. // an object or has no such member.
  145. func (n *Node) Lookup(key string) *Node {
  146. if n == nil || n.Kind != Object {
  147. return nil
  148. }
  149. for _, m := range n.Members {
  150. if m.Key == key {
  151. return m.Value
  152. }
  153. }
  154. return nil
  155. }
  156. // SetKey replaces the value of the first member called key, keeping its
  157. // position, or appends a new member if there is none.
  158. func (n *Node) SetKey(key string, v *Node) error {
  159. if n.Kind != Object {
  160. return fmt.Errorf("xpj: cannot set key %q on %s", key, n.Kind)
  161. }
  162. for i := range n.Members {
  163. if n.Members[i].Key == key {
  164. n.Members[i].Value = v
  165. return nil
  166. }
  167. }
  168. n.Members = append(n.Members, Member{Key: key, Value: v})
  169. return nil
  170. }
  171. // DeleteKey removes the first member called key and reports whether it was there.
  172. func (n *Node) DeleteKey(key string) bool {
  173. if n.Kind != Object {
  174. return false
  175. }
  176. for i, m := range n.Members {
  177. if m.Key == key {
  178. n.Members = append(n.Members[:i], n.Members[i+1:]...)
  179. return true
  180. }
  181. }
  182. return false
  183. }
  184. // Insert puts v into an array at index i (0 <= i <= len), shifting later items.
  185. func (n *Node) Insert(i int, v *Node) error {
  186. if n.Kind != Array {
  187. return fmt.Errorf("xpj: cannot insert into %s", n.Kind)
  188. }
  189. if i < 0 || i > len(n.Items) {
  190. return fmt.Errorf("xpj: insert index %d out of range [0,%d]", i, len(n.Items))
  191. }
  192. n.Items = append(n.Items, nil)
  193. copy(n.Items[i+1:], n.Items[i:])
  194. n.Items[i] = v
  195. return nil
  196. }
  197. // Append adds v to the end of an array.
  198. func (n *Node) Append(v *Node) error { return n.Insert(len(n.Items), v) }
  199. // Remove deletes the array item at index i.
  200. func (n *Node) Remove(i int) error {
  201. if n.Kind != Array {
  202. return fmt.Errorf("xpj: cannot remove from %s", n.Kind)
  203. }
  204. if i < 0 || i >= len(n.Items) {
  205. return fmt.Errorf("xpj: remove index %d out of range [0,%d)", i, len(n.Items))
  206. }
  207. n.Items = append(n.Items[:i], n.Items[i+1:]...)
  208. return nil
  209. }
  210. // Clone returns a deep copy of n.
  211. func (n *Node) Clone() *Node {
  212. if n == nil {
  213. return nil
  214. }
  215. c := &Node{Kind: n.Kind, Text: n.Text, Bool: n.Bool}
  216. if n.Items != nil {
  217. c.Items = make([]*Node, len(n.Items))
  218. for i, it := range n.Items {
  219. c.Items[i] = it.Clone()
  220. }
  221. }
  222. if n.Members != nil {
  223. c.Members = make([]Member, len(n.Members))
  224. for i, m := range n.Members {
  225. c.Members[i] = Member{Key: m.Key, Value: m.Value.Clone()}
  226. }
  227. }
  228. return c
  229. }