http urls monitor.

parser.go 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package parser
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/hashicorp/hcl/hcl/ast"
  6. hcltoken "github.com/hashicorp/hcl/hcl/token"
  7. "github.com/hashicorp/hcl/json/scanner"
  8. "github.com/hashicorp/hcl/json/token"
  9. )
  10. type Parser struct {
  11. sc *scanner.Scanner
  12. // Last read token
  13. tok token.Token
  14. commaPrev token.Token
  15. enableTrace bool
  16. indent int
  17. n int // buffer size (max = 1)
  18. }
  19. func newParser(src []byte) *Parser {
  20. return &Parser{
  21. sc: scanner.New(src),
  22. }
  23. }
  24. // Parse returns the fully parsed source and returns the abstract syntax tree.
  25. func Parse(src []byte) (*ast.File, error) {
  26. p := newParser(src)
  27. return p.Parse()
  28. }
  29. var errEofToken = errors.New("EOF token found")
  30. // Parse returns the fully parsed source and returns the abstract syntax tree.
  31. func (p *Parser) Parse() (*ast.File, error) {
  32. f := &ast.File{}
  33. var err, scerr error
  34. p.sc.Error = func(pos token.Pos, msg string) {
  35. scerr = fmt.Errorf("%s: %s", pos, msg)
  36. }
  37. // The root must be an object in JSON
  38. object, err := p.object()
  39. if scerr != nil {
  40. return nil, scerr
  41. }
  42. if err != nil {
  43. return nil, err
  44. }
  45. // We make our final node an object list so it is more HCL compatible
  46. f.Node = object.List
  47. // Flatten it, which finds patterns and turns them into more HCL-like
  48. // AST trees.
  49. flattenObjects(f.Node)
  50. return f, nil
  51. }
  52. func (p *Parser) objectList() (*ast.ObjectList, error) {
  53. defer un(trace(p, "ParseObjectList"))
  54. node := &ast.ObjectList{}
  55. for {
  56. n, err := p.objectItem()
  57. if err == errEofToken {
  58. break // we are finished
  59. }
  60. // we don't return a nil node, because might want to use already
  61. // collected items.
  62. if err != nil {
  63. return node, err
  64. }
  65. node.Add(n)
  66. // Check for a followup comma. If it isn't a comma, then we're done
  67. if tok := p.scan(); tok.Type != token.COMMA {
  68. break
  69. }
  70. }
  71. return node, nil
  72. }
  73. // objectItem parses a single object item
  74. func (p *Parser) objectItem() (*ast.ObjectItem, error) {
  75. defer un(trace(p, "ParseObjectItem"))
  76. keys, err := p.objectKey()
  77. if err != nil {
  78. return nil, err
  79. }
  80. o := &ast.ObjectItem{
  81. Keys: keys,
  82. }
  83. switch p.tok.Type {
  84. case token.COLON:
  85. pos := p.tok.Pos
  86. o.Assign = hcltoken.Pos{
  87. Filename: pos.Filename,
  88. Offset: pos.Offset,
  89. Line: pos.Line,
  90. Column: pos.Column,
  91. }
  92. o.Val, err = p.objectValue()
  93. if err != nil {
  94. return nil, err
  95. }
  96. }
  97. return o, nil
  98. }
  99. // objectKey parses an object key and returns a ObjectKey AST
  100. func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
  101. keyCount := 0
  102. keys := make([]*ast.ObjectKey, 0)
  103. for {
  104. tok := p.scan()
  105. switch tok.Type {
  106. case token.EOF:
  107. return nil, errEofToken
  108. case token.STRING:
  109. keyCount++
  110. keys = append(keys, &ast.ObjectKey{
  111. Token: p.tok.HCLToken(),
  112. })
  113. case token.COLON:
  114. // If we have a zero keycount it means that we never got
  115. // an object key, i.e. `{ :`. This is a syntax error.
  116. if keyCount == 0 {
  117. return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
  118. }
  119. // Done
  120. return keys, nil
  121. case token.ILLEGAL:
  122. return nil, errors.New("illegal")
  123. default:
  124. return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
  125. }
  126. }
  127. }
  128. // object parses any type of object, such as number, bool, string, object or
  129. // list.
  130. func (p *Parser) objectValue() (ast.Node, error) {
  131. defer un(trace(p, "ParseObjectValue"))
  132. tok := p.scan()
  133. switch tok.Type {
  134. case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING:
  135. return p.literalType()
  136. case token.LBRACE:
  137. return p.objectType()
  138. case token.LBRACK:
  139. return p.listType()
  140. case token.EOF:
  141. return nil, errEofToken
  142. }
  143. return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok)
  144. }
  145. // object parses any type of object, such as number, bool, string, object or
  146. // list.
  147. func (p *Parser) object() (*ast.ObjectType, error) {
  148. defer un(trace(p, "ParseType"))
  149. tok := p.scan()
  150. switch tok.Type {
  151. case token.LBRACE:
  152. return p.objectType()
  153. case token.EOF:
  154. return nil, errEofToken
  155. }
  156. return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok)
  157. }
  158. // objectType parses an object type and returns a ObjectType AST
  159. func (p *Parser) objectType() (*ast.ObjectType, error) {
  160. defer un(trace(p, "ParseObjectType"))
  161. // we assume that the currently scanned token is a LBRACE
  162. o := &ast.ObjectType{}
  163. l, err := p.objectList()
  164. // if we hit RBRACE, we are good to go (means we parsed all Items), if it's
  165. // not a RBRACE, it's an syntax error and we just return it.
  166. if err != nil && p.tok.Type != token.RBRACE {
  167. return nil, err
  168. }
  169. o.List = l
  170. return o, nil
  171. }
  172. // listType parses a list type and returns a ListType AST
  173. func (p *Parser) listType() (*ast.ListType, error) {
  174. defer un(trace(p, "ParseListType"))
  175. // we assume that the currently scanned token is a LBRACK
  176. l := &ast.ListType{}
  177. for {
  178. tok := p.scan()
  179. switch tok.Type {
  180. case token.NUMBER, token.FLOAT, token.STRING:
  181. node, err := p.literalType()
  182. if err != nil {
  183. return nil, err
  184. }
  185. l.Add(node)
  186. case token.COMMA:
  187. continue
  188. case token.LBRACE:
  189. node, err := p.objectType()
  190. if err != nil {
  191. return nil, err
  192. }
  193. l.Add(node)
  194. case token.BOOL:
  195. // TODO(arslan) should we support? not supported by HCL yet
  196. case token.LBRACK:
  197. // TODO(arslan) should we support nested lists? Even though it's
  198. // written in README of HCL, it's not a part of the grammar
  199. // (not defined in parse.y)
  200. case token.RBRACK:
  201. // finished
  202. return l, nil
  203. default:
  204. return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type)
  205. }
  206. }
  207. }
  208. // literalType parses a literal type and returns a LiteralType AST
  209. func (p *Parser) literalType() (*ast.LiteralType, error) {
  210. defer un(trace(p, "ParseLiteral"))
  211. return &ast.LiteralType{
  212. Token: p.tok.HCLToken(),
  213. }, nil
  214. }
  215. // scan returns the next token from the underlying scanner. If a token has
  216. // been unscanned then read that instead.
  217. func (p *Parser) scan() token.Token {
  218. // If we have a token on the buffer, then return it.
  219. if p.n != 0 {
  220. p.n = 0
  221. return p.tok
  222. }
  223. p.tok = p.sc.Scan()
  224. return p.tok
  225. }
  226. // unscan pushes the previously read token back onto the buffer.
  227. func (p *Parser) unscan() {
  228. p.n = 1
  229. }
  230. // ----------------------------------------------------------------------------
  231. // Parsing support
  232. func (p *Parser) printTrace(a ...interface{}) {
  233. if !p.enableTrace {
  234. return
  235. }
  236. const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
  237. const n = len(dots)
  238. fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
  239. i := 2 * p.indent
  240. for i > n {
  241. fmt.Print(dots)
  242. i -= n
  243. }
  244. // i <= n
  245. fmt.Print(dots[0:i])
  246. fmt.Println(a...)
  247. }
  248. func trace(p *Parser, msg string) *Parser {
  249. p.printTrace(msg, "(")
  250. p.indent++
  251. return p
  252. }
  253. // Usage pattern: defer un(trace(p, "..."))
  254. func un(p *Parser) {
  255. p.indent--
  256. p.printTrace(")")
  257. }