You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
1.9 KiB

  1. // Copyright 2018 Frank Schroeder. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package properties
  5. import (
  6. "fmt"
  7. "runtime"
  8. )
  9. type parser struct {
  10. lex *lexer
  11. }
  12. func parse(input string) (properties *Properties, err error) {
  13. p := &parser{lex: lex(input)}
  14. defer p.recover(&err)
  15. properties = NewProperties()
  16. key := ""
  17. comments := []string{}
  18. for {
  19. token := p.expectOneOf(itemComment, itemKey, itemEOF)
  20. switch token.typ {
  21. case itemEOF:
  22. goto done
  23. case itemComment:
  24. comments = append(comments, token.val)
  25. continue
  26. case itemKey:
  27. key = token.val
  28. if _, ok := properties.m[key]; !ok {
  29. properties.k = append(properties.k, key)
  30. }
  31. }
  32. token = p.expectOneOf(itemValue, itemEOF)
  33. if len(comments) > 0 {
  34. properties.c[key] = comments
  35. comments = []string{}
  36. }
  37. switch token.typ {
  38. case itemEOF:
  39. properties.m[key] = ""
  40. goto done
  41. case itemValue:
  42. properties.m[key] = token.val
  43. }
  44. }
  45. done:
  46. return properties, nil
  47. }
  48. func (p *parser) errorf(format string, args ...interface{}) {
  49. format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format)
  50. panic(fmt.Errorf(format, args...))
  51. }
  52. func (p *parser) expect(expected itemType) (token item) {
  53. token = p.lex.nextItem()
  54. if token.typ != expected {
  55. p.unexpected(token)
  56. }
  57. return token
  58. }
  59. func (p *parser) expectOneOf(expected ...itemType) (token item) {
  60. token = p.lex.nextItem()
  61. for _, v := range expected {
  62. if token.typ == v {
  63. return token
  64. }
  65. }
  66. p.unexpected(token)
  67. panic("unexpected token")
  68. }
  69. func (p *parser) unexpected(token item) {
  70. p.errorf(token.String())
  71. }
  72. // recover is the handler that turns panics into returns from the top level of Parse.
  73. func (p *parser) recover(errp *error) {
  74. e := recover()
  75. if e != nil {
  76. if _, ok := e.(runtime.Error); ok {
  77. panic(e)
  78. }
  79. *errp = e.(error)
  80. }
  81. return
  82. }