                                                         (pos js2-ts-cursor)
                                                         len
                                                         content)))
-  "AST node for a CDATA escape section."
+  "AST node for a CDATA escape section.  Not currently used."
   content)  ; a `js2-string-node' with node-property 'quote-type 'cdata
 
 (put 'cl-struct-js2-xml-cdata-node 'js2-visitor 'js2-visit-xml-cdata-node)

        expr
        pn)
    (js2-consume-token)
    (setq expr (js2-parse-variables tt)
          pn (make-js2-expr-stmt-node :pos pos
                                      :len (- (js2-node-end expr) pos)
                                      :expr expr))
    (js2-node-add-children pn expr)
    pn))

(defun js2-parse-let ()
  "Parser for let-statement.  Last matched token must be js2-LET."
  (js2-consume-token)
  (let ((let-pos js2-token-beg)
        (tt (js2-peek-token))
        expr
        pn)
    (if (eq tt js2-LP)
        (js2-parse-let-stmt t let-pos)  ; return value
      ;; Else we're looking at a statement like let x = 6, y = 7;
      ;; Rhino just returns a variables Node of type Token.LET,
      ;; but we'll wrap it in a let-stmt without a block.
      (setq expr (js2-parse-variables js2-LET)
            pn (make-js2-let-stmt-node :pos let-pos
                                       :len (- (js2-node-end expr) let-pos)
                                       :vars expr))
      (js2-node-add-children pn expr)
      pn)))

(defun js2-parse-ret-yield ()
  (js2-parse-return-or-yield (js2-peek-token) nil))

        beg
        end
        init
        tail)
    (if (/= tt js2-NEW)
        (setq pn (js2-parse-primary-expr))
      ;; parse a 'new' expression
      (js2-consume-token)
      (setq pos js2-token-beg
            beg pos
            target (js2-parse-member-expr)
            end (js2-node-end target)
            pn (make-js2-new-node :pos pos
                                  :target target
                                  :len (- end pos)))
      (js2-node-add-children pn target)
      (when (js2-match-token js2-LP)
        ;; Add the arguments to pn, if any are supplied.
        (setf beg pos  ; start of "new" keyword
              pos js2-token-beg
              args (nreverse (js2-parse-argument-list))
              (js2-new-node-args pn) args
              end js2-token-end
              (js2-new-node-lp pn) (- pos beg)
              (js2-new-node-rp pn) (- end 1 beg))
        (apply #'js2-node-add-children pn args))

      (when (and js2-allow-rhino-new-expr-initializer
                 (js2-match-token js2-LC))
        (setf init (js2-parse-object-literal)
              end (js2-node-end init)
              (js2-new-node-initializer pn) init)
        (js2-node-add-children pn init))

        (setf (js2-node-len pn) (- beg pos)))  ; end outer if

    (js2-parse-member-expr-tail allow-call-syntax pn)))

(defun js2-parse-member-expr-tail (allow-call-syntax pn)
  "Parse a chain of property/array accesses or function calls.
Includes parsing for E4X operators like `..' and `.@'.
If ALLOW-CALL-SYNTAX is nil, stops when we encounter a left-paren.
Returns an expression tree that includes PN, the parent node."
  (let ((beg (js2-node-pos pn))
        tt
        (continue t))
    (while continue
      (setq tt (js2-peek-token))
      (cond
       ((or (= tt js2-DOT) (= tt js2-DOTDOT))
        (setq pn (js2-parse-property-access tt pn)))

       ((= tt js2-DOTQUERY)
        (setq pn (js2-parse-dot-query pn)))

       ((= tt js2-LB)
        (setq pn (js2-parse-element-get pn)))

       ((= tt js2-LP)
        (if allow-call-syntax
            (setq pn (js2-parse-function-call pn))
          (setq continue nil)))
       (t
        (setq continue nil))))
    (if (>= js2-highlight-level 2)
        (js2-parse-highlight-member-expr-node pn))
    pn))

(defun js2-parse-dot-query (pn)
  "Parse a dot-query expression, e.g. foo.bar.(@name == 2)
Last token parsed must be `js2-DOTQUERY'."
  (let ((pos (js2-node-pos pn))
        op-pos
        expr
        end)
    (js2-consume-token)
    (js2-must-have-xml)
    (js2-set-requires-activation)
    (setq op-pos js2-token-beg
          expr (js2-parse-expr)
          end (js2-node-end expr)
          pn (make-js2-xml-dot-query-node :left pn
                                          :pos pos
                                          :op-pos op-pos
                                          :right expr))
    (js2-node-add-children pn
                           (js2-xml-dot-query-node-left pn)
                           (js2-xml-dot-query-node-right pn))
    (if (js2-must-match js2-RP "msg.no.paren")
        (setf (js2-xml-dot-query-node-rp pn) js2-token-beg
              end js2-token-end))
    (setf (js2-node-len pn) (- end pos))
    pn))

(defun js2-parse-element-get (pn)
  "Parse an element-get expression, e.g. foo[bar].
Last token parsed must be `js2-RB'."
  (let ((lb js2-token-beg)
        (pos (js2-node-pos pn))
        rb
        expr)
    (js2-consume-token)
    (setq expr (js2-parse-expr))
    (if (js2-must-match js2-RB "msg.no.bracket.index")
        (setq rb js2-token-beg))
    (setq pn (make-js2-elem-get-node :target pn
                                     :pos pos
                                     :element expr
                                     :lb (js2-relpos lb pos)
                                     :rb (js2-relpos rb pos)
                                     :len (- js2-token-end pos)))
    (js2-node-add-children pn
                           (js2-elem-get-node-target pn)
                           (js2-elem-get-node-element pn))
    pn))

(defun js2-parse-function-call (pn)
  (let (args
        (pos (js2-node-pos pn)))
    (js2-consume-token)
    (setq pn (make-js2-call-node :pos pos
                                 :target pn
                                 :lp (- js2-token-beg pos)))
    (js2-node-add-children pn (js2-call-node-target pn))

    ;; Add the arguments to pn, if any are supplied.
    (setf args (nreverse (js2-parse-argument-list))
          (js2-call-node-rp pn) (- js2-token-beg pos)
          (js2-call-node-args pn) args)
    (apply #'js2-node-add-children pn args)

    (setf (js2-node-len pn) (- js2-ts-cursor pos))
    pn))

(defun js2-parse-property-access (tt pn)
  "Parse a property access, XML descendants access, or XML attr access."
  (let ((member-type-flags 0)
        (dot-pos js2-token-beg)
        (dot-len (if (= tt js2-DOTDOT) 2 1))
        name
        ref  ; right side of . or .. operator
        result)
    (js2-consume-token)
    (when (= tt js2-DOTDOT)
      (js2-must-have-xml)
      (setq member-type-flags js2-descendants-flag))
    (if (not js2-compiler-xml-available)
        (progn
          (js2-must-match-prop-name "msg.no.name.after.dot")
          (setq name (js2-create-name-node t js2-GETPROP)
                result (make-js2-prop-get-node :left pn
                                               :pos js2-token-beg
                                               :right name
                                               :len (- js2-token-end
                                                       js2-token-beg)))
          (js2-node-add-children result pn name)
          result)
      ;; otherwise look for XML operators
      (setf result (if (= tt js2-DOT)
                       (make-js2-prop-get-node)
                     (make-js2-infix-node :type js2-DOTDOT))
            (js2-node-pos result) (js2-node-pos pn)
            (js2-infix-node-op-pos result) dot-pos
            (js2-infix-node-left result) pn  ; do this after setting position
            tt (js2-next-token))
      (cond
       ;; needed for generator.throw()
       ((= tt js2-THROW)
        (js2-save-name-token-data js2-token-beg "throw")
        (setq ref (js2-parse-property-name nil js2-ts-string member-type-flags)))

       ;; handles: name, ns::name, ns::*, ns::[expr]
       ((js2-valid-prop-name-token tt)
        (setq ref (js2-parse-property-name -1 js2-ts-string member-type-flags)))

       ;; handles: *, *::name, *::*, *::[expr]
       ((= tt js2-MUL)
        (js2-save-name-token-data js2-token-beg "*")
        (setq ref (js2-parse-property-name nil "*" member-type-flags)))

       ;; handles: '@attr', '@ns::attr', '@ns::*', '@ns::[expr]', etc.
       ((= tt js2-XMLATTR)
        (setq result (js2-parse-attribute-access)))

       (t
        (js2-report-error "msg.no.name.after.dot" nil dot-pos dot-len)))

      (if ref
          (setf (js2-node-len result) (- (js2-node-end ref)
                                         (js2-node-pos result))
                (js2-infix-node-right result) ref))
      (if (js2-infix-node-p result)
          (js2-node-add-children result
                                 (js2-infix-node-left result)
                                 (js2-infix-node-right result)))
      result)))

(defun js2-parse-attribute-access ()
  "Parse an E4X XML attribute expression.
This includes expressions of the forms:

  @attr      @ns::attr     @ns::*
  @*         @*::attr      @*::*
  @[expr]    @*::[expr]    @ns::[expr]

Called if we peeked an '@' token."
  (let ((tt (js2-next-token))
        (at-pos js2-token-beg))
    (cond
     ;; handles: @name, @ns::name, @ns::*, @ns::[expr]
     ((js2-valid-prop-name-token tt)
      (js2-parse-property-name at-pos js2-ts-string 0))

     ;; handles: @*, @*::name, @*::*, @*::[expr]
     ((= tt js2-MUL)
      (js2-save-name-token-data js2-token-beg "*")
      (js2-parse-property-name js2-token-beg "*" 0))

     ;; handles @[expr]
     ((= tt js2-LB)
      (js2-parse-xml-elem-ref at-pos))

     (t
      (js2-report-error "msg.no.name.after.xmlAttr")
      ;; Avoid cascaded errors that happen if we make an error node here.
      (js2-save-name-token-data js2-token-beg "")
      (js2-parse-property-name js2-token-beg "" 0)))))

(defun js2-parse-property-name (at-pos s member-type-flags)
  "Check if :: follows name in which case it becomes qualified name.

AT-POS is a natural number if we just read an '@' token, else nil.
S is the name or string that was matched:  an identifier, 'throw' or '*'.
MEMBER-TYPE-FLAGS is a bit set tracking whether we're a '.' or '..' child.

Returns a `js2-xml-ref-node' if it's an attribute access, a child of a '..'
operator, or the name is followed by ::.  For a plain name, returns a
`js2-name-node'.  Returns a `js2-error-node' for malformed XML expressions."
  (let ((pos (or at-pos js2-token-beg))
        colon-pos
        (name (js2-create-name-node t js2-current-token))
        ns
        tt
        ref
        pn)
    (catch 'return
      (when (js2-match-token js2-COLONCOLON)
        (setq ns name
              colon-pos js2-token-beg
              tt (js2-next-token))
        (cond
         ;; handles name::name
         ((js2-valid-prop-name-token tt)
          (setq name (js2-create-name-node)))

         ;; handles name::*
         ((= tt js2-MUL)
          (js2-save-name-token-data js2-token-beg "*")
          (setq name (js2-create-name-node)))

         ;; handles name::[expr]
         ((= tt js2-LB)
          (throw 'return (js2-parse-xml-elem-ref at-pos ns colon-pos)))

         (t
          (js2-report-error "msg.no.name.after.coloncolon"))))

      (if (and (null ns) (zerop member-type-flags))
          name
        (prog1
            (setq pn
                  (make-js2-xml-prop-ref-node :pos pos
                                              :len (- (js2-node-end name) pos)
                                              :at-pos at-pos
                                              :colon-pos colon-pos
                                              :propname name))
          (js2-node-add-children pn name))))))

(defun js2-parse-xml-elem-ref (at-pos &optional namespace colon-pos)
  "Parse the [expr] portion of an xml element reference.
For instance, @[expr], @*::[expr], or ns::[expr]."
  (let* ((lb js2-token-beg)
         (pos (or at-pos lb))
         rb
         (expr (js2-parse-expr))
         (end (js2-node-end expr))
         pn)
    (if (js2-must-match js2-RB "msg.no.bracket.index")
        (setq rb js2-token-beg
              end js2-token-end))
    (prog1
        (setq pn
              (make-js2-xml-elem-ref-node :pos pos
                                          :len (- end pos)
                                          :namespace namespace
                                          :colon-pos colon-pos
                                          :at-pos at-pos
                                          :expr expr
                                          :lb (js2-relpos lb pos)
                                          :rb (js2-relpos rb pos)))
      (js2-node-add-children pn namespace expr))))

(defun js2-parse-primary-expr ()
  "Parses a literal (leaf) expression of some sort.
Includes complex literals such as functions, object-literals,
array-literals, array comprehensions and regular expressions."
  (let ((tt-flagged (js2-next-flagged-token))
        pn      ; parent node  (usually return value)
        tt
        px-pos  ; paren-expr pos
        len
        flags   ; regexp flags
        expr)
    (setq tt js2-current-token)
    (cond
     ((= tt js2-FUNCTION)
      (js2-parse-function 'FUNCTION_EXPRESSION))

     ((= tt js2-LB)
      (js2-parse-array-literal))

     ((= tt js2-LC)
      (js2-parse-object-literal))

     ((= tt js2-LET)
      (js2-parse-let js2-token-beg))

     ((= tt js2-LP)
      (setq px-pos js2-token-beg
            expr (js2-parse-expr))
      (js2-must-match js2-RP "msg.no.paren")
