parse.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. package toml
  2. import (
  3. "errors"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "github.com/naoina/toml/ast"
  8. )
  9. // The parser is generated by github.com/pointlander/peg. To regenerate it, do:
  10. //
  11. // go get -u github.com/pointlander/peg
  12. // go generate .
  13. //go:generate peg -switch -inline parse.peg
  14. var errParse = errors.New("invalid TOML syntax")
  15. // Parse returns an AST representation of TOML.
  16. // The toplevel is represented by a table.
  17. func Parse(data []byte) (*ast.Table, error) {
  18. d := &parseState{p: &tomlParser{Buffer: string(data)}}
  19. d.init()
  20. if err := d.parse(); err != nil {
  21. return nil, err
  22. }
  23. return d.p.toml.table, nil
  24. }
  25. type parseState struct {
  26. p *tomlParser
  27. }
  28. func (d *parseState) init() {
  29. d.p.Init()
  30. d.p.toml.init(d.p.buffer)
  31. }
  32. func (d *parseState) parse() error {
  33. if err := d.p.Parse(); err != nil {
  34. if err, ok := err.(*parseError); ok {
  35. return lineError(err.Line(), errParse)
  36. }
  37. return err
  38. }
  39. return d.execute()
  40. }
  41. func (d *parseState) execute() (err error) {
  42. defer func() {
  43. if e := recover(); e != nil {
  44. lerr, ok := e.(*LineError)
  45. if !ok {
  46. panic(e)
  47. }
  48. err = lerr
  49. }
  50. }()
  51. d.p.Execute()
  52. return nil
  53. }
  54. func (e *parseError) Line() int {
  55. tokens := []token32{e.max}
  56. positions, p := make([]int, 2*len(tokens)), 0
  57. for _, token := range tokens {
  58. positions[p], p = int(token.begin), p+1
  59. positions[p], p = int(token.end), p+1
  60. }
  61. for _, t := range translatePositions(e.p.buffer, positions) {
  62. if e.p.line < t.line {
  63. e.p.line = t.line
  64. }
  65. }
  66. return e.p.line
  67. }
  68. type stack struct {
  69. key string
  70. table *ast.Table
  71. }
  72. type array struct {
  73. parent *array
  74. child *array
  75. current *ast.Array
  76. line int
  77. }
  78. type toml struct {
  79. table *ast.Table
  80. line int
  81. currentTable *ast.Table
  82. s string
  83. key string
  84. val ast.Value
  85. arr *array
  86. stack []*stack
  87. skip bool
  88. }
  89. func (p *toml) init(data []rune) {
  90. p.line = 1
  91. p.table = p.newTable(ast.TableTypeNormal, "")
  92. p.table.Position.End = len(data) - 1
  93. p.table.Data = data[:len(data)-1] // truncate the end_symbol added by PEG parse generator.
  94. p.currentTable = p.table
  95. }
  96. func (p *toml) Error(err error) {
  97. panic(lineError(p.line, err))
  98. }
  99. func (p *tomlParser) SetTime(begin, end int) {
  100. p.val = &ast.Datetime{
  101. Position: ast.Position{Begin: begin, End: end},
  102. Data: p.buffer[begin:end],
  103. Value: string(p.buffer[begin:end]),
  104. }
  105. }
  106. func (p *tomlParser) SetFloat64(begin, end int) {
  107. p.val = &ast.Float{
  108. Position: ast.Position{Begin: begin, End: end},
  109. Data: p.buffer[begin:end],
  110. Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
  111. }
  112. }
  113. func (p *tomlParser) SetInt64(begin, end int) {
  114. p.val = &ast.Integer{
  115. Position: ast.Position{Begin: begin, End: end},
  116. Data: p.buffer[begin:end],
  117. Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
  118. }
  119. }
  120. func (p *tomlParser) SetString(begin, end int) {
  121. p.val = &ast.String{
  122. Position: ast.Position{Begin: begin, End: end},
  123. Data: p.buffer[begin:end],
  124. Value: p.s,
  125. }
  126. p.s = ""
  127. }
  128. func (p *tomlParser) SetBool(begin, end int) {
  129. p.val = &ast.Boolean{
  130. Position: ast.Position{Begin: begin, End: end},
  131. Data: p.buffer[begin:end],
  132. Value: string(p.buffer[begin:end]),
  133. }
  134. }
  135. func (p *tomlParser) StartArray() {
  136. if p.arr == nil {
  137. p.arr = &array{line: p.line, current: &ast.Array{}}
  138. return
  139. }
  140. p.arr.child = &array{parent: p.arr, line: p.line, current: &ast.Array{}}
  141. p.arr = p.arr.child
  142. }
  143. func (p *tomlParser) AddArrayVal() {
  144. if p.arr.current == nil {
  145. p.arr.current = &ast.Array{}
  146. }
  147. p.arr.current.Value = append(p.arr.current.Value, p.val)
  148. }
  149. func (p *tomlParser) SetArray(begin, end int) {
  150. p.arr.current.Position = ast.Position{Begin: begin, End: end}
  151. p.arr.current.Data = p.buffer[begin:end]
  152. p.val = p.arr.current
  153. p.arr = p.arr.parent
  154. }
  155. func (p *toml) SetTable(buf []rune, begin, end int) {
  156. p.setTable(p.table, buf, begin, end)
  157. }
  158. func (p *toml) setTable(parent *ast.Table, buf []rune, begin, end int) {
  159. name := string(buf[begin:end])
  160. names := splitTableKey(name)
  161. parent, err := p.lookupTable(parent, names[:len(names)-1])
  162. if err != nil {
  163. p.Error(err)
  164. }
  165. last := names[len(names)-1]
  166. tbl := p.newTable(ast.TableTypeNormal, last)
  167. switch v := parent.Fields[last].(type) {
  168. case nil:
  169. parent.Fields[last] = tbl
  170. case []*ast.Table:
  171. p.Error(fmt.Errorf("table `%s' is in conflict with array table in line %d", name, v[0].Line))
  172. case *ast.Table:
  173. if (v.Position == ast.Position{}) {
  174. // This table was created as an implicit parent.
  175. // Replace it with the real defined table.
  176. tbl.Fields = v.Fields
  177. parent.Fields[last] = tbl
  178. } else {
  179. p.Error(fmt.Errorf("table `%s' is in conflict with table in line %d", name, v.Line))
  180. }
  181. case *ast.KeyValue:
  182. p.Error(fmt.Errorf("table `%s' is in conflict with line %d", name, v.Line))
  183. default:
  184. p.Error(fmt.Errorf("BUG: table `%s' is in conflict but it's unknown type `%T'", last, v))
  185. }
  186. p.currentTable = tbl
  187. }
  188. func (p *toml) newTable(typ ast.TableType, name string) *ast.Table {
  189. return &ast.Table{
  190. Line: p.line,
  191. Name: name,
  192. Type: typ,
  193. Fields: make(map[string]interface{}),
  194. }
  195. }
  196. func (p *tomlParser) SetTableString(begin, end int) {
  197. p.currentTable.Data = p.buffer[begin:end]
  198. p.currentTable.Position.Begin = begin
  199. p.currentTable.Position.End = end
  200. }
  201. func (p *toml) SetArrayTable(buf []rune, begin, end int) {
  202. p.setArrayTable(p.table, buf, begin, end)
  203. }
  204. func (p *toml) setArrayTable(parent *ast.Table, buf []rune, begin, end int) {
  205. name := string(buf[begin:end])
  206. names := splitTableKey(name)
  207. parent, err := p.lookupTable(parent, names[:len(names)-1])
  208. if err != nil {
  209. p.Error(err)
  210. }
  211. last := names[len(names)-1]
  212. tbl := p.newTable(ast.TableTypeArray, last)
  213. switch v := parent.Fields[last].(type) {
  214. case nil:
  215. parent.Fields[last] = []*ast.Table{tbl}
  216. case []*ast.Table:
  217. parent.Fields[last] = append(v, tbl)
  218. case *ast.Table:
  219. p.Error(fmt.Errorf("array table `%s' is in conflict with table in line %d", name, v.Line))
  220. case *ast.KeyValue:
  221. p.Error(fmt.Errorf("array table `%s' is in conflict with line %d", name, v.Line))
  222. default:
  223. p.Error(fmt.Errorf("BUG: array table `%s' is in conflict but it's unknown type `%T'", name, v))
  224. }
  225. p.currentTable = tbl
  226. }
  227. func (p *toml) StartInlineTable() {
  228. p.skip = false
  229. p.stack = append(p.stack, &stack{p.key, p.currentTable})
  230. buf := []rune(p.key)
  231. if p.arr == nil {
  232. p.setTable(p.currentTable, buf, 0, len(buf))
  233. } else {
  234. p.setArrayTable(p.currentTable, buf, 0, len(buf))
  235. }
  236. }
  237. func (p *toml) EndInlineTable() {
  238. st := p.stack[len(p.stack)-1]
  239. p.key, p.currentTable = st.key, st.table
  240. p.stack[len(p.stack)-1] = nil
  241. p.stack = p.stack[:len(p.stack)-1]
  242. p.skip = true
  243. }
  244. func (p *toml) AddLineCount(i int) {
  245. p.line += i
  246. }
  247. func (p *toml) SetKey(buf []rune, begin, end int) {
  248. p.key = string(buf[begin:end])
  249. }
  250. func (p *toml) AddKeyValue() {
  251. if p.skip {
  252. p.skip = false
  253. return
  254. }
  255. if val, exists := p.currentTable.Fields[p.key]; exists {
  256. switch v := val.(type) {
  257. case *ast.Table:
  258. p.Error(fmt.Errorf("key `%s' is in conflict with table in line %d", p.key, v.Line))
  259. case *ast.KeyValue:
  260. p.Error(fmt.Errorf("key `%s' is in conflict with line %xd", p.key, v.Line))
  261. default:
  262. p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", p.key, v))
  263. }
  264. }
  265. p.currentTable.Fields[p.key] = &ast.KeyValue{Key: p.key, Value: p.val, Line: p.line}
  266. }
  267. func (p *toml) SetBasicString(buf []rune, begin, end int) {
  268. p.s = p.unquote(string(buf[begin:end]))
  269. }
  270. func (p *toml) SetMultilineString() {
  271. p.s = p.unquote(`"` + escapeReplacer.Replace(strings.TrimLeft(p.s, "\r\n")) + `"`)
  272. }
  273. func (p *toml) AddMultilineBasicBody(buf []rune, begin, end int) {
  274. p.s += string(buf[begin:end])
  275. }
  276. func (p *toml) SetLiteralString(buf []rune, begin, end int) {
  277. p.s = string(buf[begin:end])
  278. }
  279. func (p *toml) SetMultilineLiteralString(buf []rune, begin, end int) {
  280. p.s = strings.TrimLeft(string(buf[begin:end]), "\r\n")
  281. }
  282. func (p *toml) unquote(s string) string {
  283. s, err := strconv.Unquote(s)
  284. if err != nil {
  285. p.Error(err)
  286. }
  287. return s
  288. }
  289. func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) {
  290. for _, s := range keys {
  291. val, exists := t.Fields[s]
  292. if !exists {
  293. tbl := p.newTable(ast.TableTypeNormal, s)
  294. t.Fields[s] = tbl
  295. t = tbl
  296. continue
  297. }
  298. switch v := val.(type) {
  299. case *ast.Table:
  300. t = v
  301. case []*ast.Table:
  302. t = v[len(v)-1]
  303. case *ast.KeyValue:
  304. return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line)
  305. default:
  306. return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v)
  307. }
  308. }
  309. return t, nil
  310. }
  311. func splitTableKey(tk string) []string {
  312. key := make([]byte, 0, 1)
  313. keys := make([]string, 0, 1)
  314. inQuote := false
  315. for i := 0; i < len(tk); i++ {
  316. k := tk[i]
  317. switch {
  318. case k == tableSeparator && !inQuote:
  319. keys = append(keys, string(key))
  320. key = key[:0] // reuse buffer.
  321. case k == '"':
  322. inQuote = !inQuote
  323. case (k == ' ' || k == '\t') && !inQuote:
  324. // skip.
  325. default:
  326. key = append(key, k)
  327. }
  328. }
  329. keys = append(keys, string(key))
  330. return keys
  331. }