parser.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Copyright 2013 Google, Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package yaml
  15. import (
  16. "bufio"
  17. "bytes"
  18. "errors"
  19. "fmt"
  20. "io"
  21. "strings"
  22. )
  23. // Parse returns a root-level Node parsed from the lines read from r. In
  24. // general, this will be done for you by one of the File constructors.
  25. func Parse(r io.Reader) (node Node, err error) {
  26. lb := &lineBuffer{
  27. Reader: bufio.NewReader(r),
  28. }
  29. defer func() {
  30. if r := recover(); r != nil {
  31. switch r := r.(type) {
  32. case error:
  33. err = r
  34. case string:
  35. err = errors.New(r)
  36. default:
  37. err = fmt.Errorf("%v", r)
  38. }
  39. }
  40. }()
  41. node = parseNode(lb, 0, nil)
  42. return
  43. }
  44. // Supporting types and constants
  45. const (
  46. typUnknown = iota
  47. typSequence
  48. typMapping
  49. typScalar
  50. )
  51. var typNames = []string{
  52. "Unknown", "Sequence", "Mapping", "Scalar",
  53. }
  54. type lineReader interface {
  55. Next(minIndent int) *indentedLine
  56. }
  57. type indentedLine struct {
  58. lineno int
  59. indent int
  60. line []byte
  61. }
  62. func (line *indentedLine) String() string {
  63. return fmt.Sprintf("%2d: %s%s", line.indent,
  64. strings.Repeat(" ", 0*line.indent), string(line.line))
  65. }
  66. func parseNode(r lineReader, ind int, initial Node) (node Node) {
  67. first := true
  68. node = initial
  69. // read lines
  70. for {
  71. line := r.Next(ind)
  72. if line == nil {
  73. break
  74. }
  75. if len(line.line) == 0 {
  76. continue
  77. }
  78. if first {
  79. ind = line.indent
  80. first = false
  81. }
  82. types := []int{}
  83. pieces := []string{}
  84. var inlineValue func([]byte)
  85. inlineValue = func(partial []byte) {
  86. // TODO(kevlar): This can be a for loop now
  87. vtyp, brk := getType(partial)
  88. begin, end := partial[:brk], partial[brk:]
  89. if vtyp == typMapping {
  90. end = end[1:]
  91. }
  92. end = bytes.TrimLeft(end, " ")
  93. switch vtyp {
  94. case typScalar:
  95. types = append(types, typScalar)
  96. pieces = append(pieces, string(end))
  97. return
  98. case typMapping:
  99. types = append(types, typMapping)
  100. pieces = append(pieces, strings.TrimSpace(string(begin)))
  101. trimmed := bytes.TrimSpace(end)
  102. if len(trimmed) == 1 && trimmed[0] == '|' {
  103. text := ""
  104. for {
  105. l := r.Next(1)
  106. if l == nil {
  107. break
  108. }
  109. s := string(l.line)
  110. s = strings.TrimSpace(s)
  111. if len(s) == 0 {
  112. break
  113. }
  114. text = text + "\n" + s
  115. }
  116. types = append(types, typScalar)
  117. pieces = append(pieces, string(text))
  118. return
  119. }
  120. inlineValue(end)
  121. case typSequence:
  122. types = append(types, typSequence)
  123. pieces = append(pieces, "-")
  124. inlineValue(end)
  125. }
  126. }
  127. inlineValue(line.line)
  128. var prev Node
  129. // Nest inlines
  130. for len(types) > 0 {
  131. last := len(types) - 1
  132. typ, piece := types[last], pieces[last]
  133. var current Node
  134. if last == 0 {
  135. current = node
  136. }
  137. //child := parseNode(r, line.indent+1, typUnknown) // TODO allow scalar only
  138. // Add to current node
  139. switch typ {
  140. case typScalar: // last will be == nil
  141. if _, ok := current.(Scalar); current != nil && !ok {
  142. panic("cannot append scalar to non-scalar node")
  143. }
  144. if current != nil {
  145. current = Scalar(piece) + " " + current.(Scalar)
  146. break
  147. }
  148. current = Scalar(piece)
  149. case typMapping:
  150. var mapNode Map
  151. var ok bool
  152. var child Node
  153. // Get the current map, if there is one
  154. if mapNode, ok = current.(Map); current != nil && !ok {
  155. _ = current.(Map) // panic
  156. } else if current == nil {
  157. mapNode = make(Map)
  158. }
  159. if _, inlineMap := prev.(Scalar); inlineMap && last > 0 {
  160. current = Map{
  161. piece: prev,
  162. }
  163. break
  164. }
  165. child = parseNode(r, line.indent+1, prev)
  166. mapNode[piece] = child
  167. current = mapNode
  168. case typSequence:
  169. var listNode List
  170. var ok bool
  171. var child Node
  172. // Get the current list, if there is one
  173. if listNode, ok = current.(List); current != nil && !ok {
  174. _ = current.(List) // panic
  175. } else if current == nil {
  176. listNode = make(List, 0)
  177. }
  178. if _, inlineList := prev.(Scalar); inlineList && last > 0 {
  179. current = List{
  180. prev,
  181. }
  182. break
  183. }
  184. child = parseNode(r, line.indent+1, prev)
  185. listNode = append(listNode, child)
  186. current = listNode
  187. }
  188. if last < 0 {
  189. last = 0
  190. }
  191. types = types[:last]
  192. pieces = pieces[:last]
  193. prev = current
  194. }
  195. node = prev
  196. }
  197. return
  198. }
  199. func getType(line []byte) (typ, split int) {
  200. if len(line) == 0 {
  201. return
  202. }
  203. if line[0] == '-' {
  204. typ = typSequence
  205. split = 1
  206. return
  207. }
  208. typ = typScalar
  209. if line[0] == ' ' || line[0] == '"' {
  210. return
  211. }
  212. // the first character is real
  213. // need to iterate past the first word
  214. // things like "foo:" and "foo :" are mappings
  215. // everything else is a scalar
  216. idx := bytes.IndexAny(line, " \":")
  217. if idx < 0 {
  218. return
  219. }
  220. if line[idx] == '"' {
  221. return
  222. }
  223. if line[idx] == ':' {
  224. typ = typMapping
  225. split = idx
  226. } else if line[idx] == ' ' {
  227. // we have a space
  228. // need to see if its all spaces until a :
  229. for i := idx; i < len(line); i++ {
  230. switch ch := line[i]; ch {
  231. case ' ':
  232. continue
  233. case ':':
  234. // only split on colons followed by a space
  235. if i+1 < len(line) && line[i+1] != ' ' {
  236. continue
  237. }
  238. typ = typMapping
  239. split = i
  240. break
  241. default:
  242. break
  243. }
  244. }
  245. }
  246. if typ == typMapping && split+1 < len(line) && line[split+1] != ' ' {
  247. typ = typScalar
  248. split = 0
  249. }
  250. return
  251. }
  252. // lineReader implementations
  253. type lineBuffer struct {
  254. *bufio.Reader
  255. readLines int
  256. pending *indentedLine
  257. }
  258. func (lb *lineBuffer) Next(min int) (next *indentedLine) {
  259. if lb.pending == nil {
  260. var (
  261. read []byte
  262. more bool
  263. err error
  264. )
  265. l := new(indentedLine)
  266. l.lineno = lb.readLines
  267. more = true
  268. for more {
  269. read, more, err = lb.ReadLine()
  270. if err != nil {
  271. if err == io.EOF {
  272. return nil
  273. }
  274. panic(err)
  275. }
  276. l.line = append(l.line, read...)
  277. }
  278. lb.readLines++
  279. for _, ch := range l.line {
  280. switch ch {
  281. case ' ':
  282. l.indent += 1
  283. continue
  284. default:
  285. }
  286. break
  287. }
  288. l.line = l.line[l.indent:]
  289. // Ignore blank lines and comments.
  290. if len(l.line) == 0 || l.line[0] == '#' {
  291. return lb.Next(min)
  292. }
  293. lb.pending = l
  294. }
  295. next = lb.pending
  296. if next.indent < min {
  297. return nil
  298. }
  299. lb.pending = nil
  300. return
  301. }
  302. type lineSlice []*indentedLine
  303. func (ls *lineSlice) Next(min int) (next *indentedLine) {
  304. if len(*ls) == 0 {
  305. return nil
  306. }
  307. next = (*ls)[0]
  308. if next.indent < min {
  309. return nil
  310. }
  311. *ls = (*ls)[1:]
  312. return
  313. }
  314. func (ls *lineSlice) Push(line *indentedLine) {
  315. *ls = append(*ls, line)
  316. }