(:include js2-scope)
(:constructor nil)
(:constructor make-js2-script-node (&key (type js2-SCRIPT)
- (pos js2-token-beg)
+ (pos (js2-current-token-beg))
len
+ ;; FIXME: What are those?
var-decls
fun-decls)))
functions ; Lisp list of nested functions
(defun js2-skip-line ()
"Skip to end of line."
- (let (c)
- (while (not (memq (setq c (js2-get-char)) js2-eol-chars)))
- (js2-unget-char)
- (setf (js2-token-end (js2-current-token)) js2-ts-cursor)))
+ (while (not (memq (js2-get-char) js2-eol-chars)))
+ (js2-unget-char)
++ (setf (js2-token-end (js2-current-token)) js2-ts-cursor)
+ (setq js2-token-end js2-ts-cursor))
(defun js2-init-scanner (&optional buf line)
"Create token stream for BUF starting on LINE.
(logior c (lsh accumulator 4))))
(defun js2-get-token ()
- "Return next JavaScript token, an int such as js2-RETURN."
+ "If `js2-ti-lookahead' is zero, call scanner to get new token.
+ Otherwise, move `js2-ti-tokens-cursor' and return the type of
+ next saved token.
+
+ This function will not return a newline (js2-EOL) - instead, it
+ gobbles newlines until it finds a non-newline token. Call
+ `js2-peek-token-or-eol' when you care about newlines.
+
+ This function will also not return a js2-COMMENT. Instead, it
+ records comments found in `js2-scanned-comments'. If the token
+ returned by this function immediately follows a jsdoc comment,
+ the token is flagged as such."
+ (if (zerop js2-ti-lookahead)
+ (js2-get-token-internal)
+ (decf js2-ti-lookahead)
+ (setq js2-ti-tokens-cursor (mod (1+ js2-ti-tokens-cursor) js2-ti-ntokens))
+ (let ((tt (js2-current-token-type)))
+ (assert (not (= tt js2-EOL)))
+ tt)))
+
+ (defun js2-unget-token ()
+ (assert (< js2-ti-lookahead js2-ti-max-lookahead))
+ (incf js2-ti-lookahead)
+ (setq js2-ti-tokens-cursor (mod (1- js2-ti-tokens-cursor) js2-ti-ntokens)))
+
+ (defun js2-get-token-internal ()
+ (let* ((token (js2-get-token-internal-1)) ; call scanner
+ (tt (js2-token-type token))
+ saw-eol
+ face)
+ ;; process comments
+ (while (or (= tt js2-EOL) (= tt js2-COMMENT))
+ (if (= tt js2-EOL)
+ (setq saw-eol t)
+ (setq saw-eol nil)
+ (when js2-record-comments
+ (js2-record-comment token)))
+ (setq js2-ti-tokens-cursor (mod (1- js2-ti-tokens-cursor) js2-ti-ntokens))
+ (setq token (js2-get-token-internal-1) ; call scanner again
+ tt (js2-token-type token)))
+
+ (when saw-eol
+ (setf (js2-token-follows-eol-p token) t))
+
+ ;; perform lexical fontification as soon as token is scanned
+ (when js2-parse-ide-mode
+ (cond
+ ((minusp tt)
+ (js2-record-face 'js2-error token))
+ ((setq face (aref js2-kwd-tokens tt))
+ (js2-record-face face token))
+ ((and (= tt js2-NAME)
+ (equal (js2-token-string token) "undefined"))
+ (js2-record-face 'font-lock-constant-face token))))
+ tt))
+
+ (defun js2-get-token-internal-1 ()
+ "Return next JavaScript token type, an int such as js2-RETURN.
+ During operation, creates an instance of `js2-token' struct, sets
+ its relevant fields and puts it into `js2-ti-tokens'."
(let (c c1 identifier-start is-unicode-escape-start
- contains-escape escape-val escape-start str result base
+ contains-escape escape-val str result base
- is-integer quote-char val look-for-slash continue)
+ is-integer quote-char val look-for-slash continue tt
+ (token (js2-new-token 0)))
+ (setq
+ tt
(catch 'return
(while t
;; Eat whitespace, possibly sensitive to newlines.
(setq c val)))))
(js2-add-to-string c)
(setq c (js2-get-char)))))
- (setq js2-ts-string (js2-get-string-from-buffer))
+ (js2-set-string-from-buffer token)
(throw 'return js2-STRING))
- (js2-ts-return
- (case c
++ (js2-ts-return token
+ (case c
(?\;
(throw 'return js2-SEMI))
(?\[
(?=
(if (js2-match-char ?=)
(if (js2-match-char ?=)
- (js2-ts-return token js2-SHEQ)
+ js2-SHEQ
(throw 'return js2-EQ))
- (throw 'return js2-ASSIGN)))
+ (if (js2-match-char ?>)
+ (js2-ts-return token js2-ARROW)
+ (throw 'return js2-ASSIGN))))
(?!
(if (js2-match-char ?=)
(if (js2-match-char ?=)
(setq look-for-slash t))
((eq c ?/)
(if look-for-slash
- (js2-ts-return js2-COMMENT)))
+ (js2-ts-return token js2-COMMENT)))
(t
- (setq look-for-slash nil
- js2-token-end js2-ts-cursor)))))
+ (setf look-for-slash nil
+ (js2-token-end token) js2-ts-cursor)))))
(if (js2-match-char ?=)
- (js2-ts-return token js2-ASSIGN_DIV)
+ js2-ASSIGN_DIV
(throw 'return js2-DIV)))
(?#
- (when js2-skip-preprocessor-directives
- (js2-skip-line)
- (setq js2-ts-comment-type 'preprocessor
- js2-token-end js2-ts-cursor)
- (throw 'return js2-COMMENT))
- (throw 'return js2-ERROR))
+ (when js2-skip-preprocessor-directives
+ (js2-skip-line)
+ (setf (js2-token-comment-type token) 'preprocessor
+ (js2-token-end token) js2-ts-cursor)
+ (throw 'return js2-COMMENT))
+ (throw 'return js2-ERROR))
(?%
(if (js2-match-char ?=)
- (js2-ts-return token js2-ASSIGN_MOD)
+ js2-ASSIGN_MOD
(throw 'return js2-MOD)))
(?~
(throw 'return js2-BITNOT))
(t
(setq c js2-SUB)))
(setq js2-ts-dirty-line t)
- (js2-ts-return token c))
+ c)
(otherwise
- (js2-report-scan-error "msg.illegal.character"))))))))
- (js2-report-scan-error "msg.illegal.character"))))))
++ (js2-report-scan-error "msg.illegal.character")))))))
+ (setf (js2-token-type token) tt)
+ token))
- (defun js2-read-regexp (start-token)
+ (defun js2-read-regexp (start-tt)
"Called by parser when it gets / or /= in literal context."
(let (c err
in-class ; inside a '[' .. ']' character-class
(t (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
(js2-node-len node)))))
- (defun js2-parse-function-params (fn-node pos)
+ (defun js2-parse-function-params (function-type fn-node pos)
(if (js2-match-token js2-RP)
- (setf (js2-function-node-rp fn-node) (- js2-token-beg pos))
- (let (params param default-found rest-param-at)
+ (setf (js2-function-node-rp fn-node) (- (js2-current-token-beg) pos))
+ (let ((paren-free-arrow (and (eq function-type 'FUNCTION_ARROW)
+ (eq (js2-current-token-type) js2-NAME)))
- params len param default-found rest-param-at)
++ params param default-found rest-param-at)
+ (when paren-free-arrow
+ (js2-unget-token))
(loop for tt = (js2-peek-token)
do
(cond
(list js2-ERROR js2-EOF js2-RC))
(defun js2-statement-helper ()
- (let* ((tt (js2-peek-token))
+ (let* ((tt (js2-get-token))
(first-tt tt)
- (beg (js2-current-token-beg))
(parser (if (= tt js2-ERROR)
#'js2-parse-semi
(aref js2-parsers tt)))
pn))
(defun js2-parse-switch ()
- "Parser for if-statement. Last matched token must be js2-SWITCH."
+ "Parser for switch-statement. Last matched token must be js2-SWITCH."
- (let ((pos js2-token-beg)
+ (let ((pos (js2-current-token-beg))
tt pn discriminant has-default case-expr case-node
- case-pos cases stmt lp rp)
+ case-pos cases stmt lp)
- (js2-consume-token)
(if (js2-must-match js2-LP "msg.no.paren.switch")
- (setq lp js2-token-beg))
+ (setq lp (js2-current-token-beg)))
(setq discriminant (js2-parse-expr)
pn (make-js2-switch-node :discriminant discriminant
:pos pos
(defun js2-parse-default-xml-namespace ()
"Parse a `default xml namespace = <expr>' e4x statement."
- (let ((pos js2-token-beg)
+ (let ((pos (js2-current-token-beg))
- end len expr unary es)
+ end len expr unary)
- (js2-consume-token)
(js2-must-have-xml)
(js2-set-requires-activation)
(setq len (- js2-ts-cursor pos))
up any following labels and the next non-label statement into a
`js2-labeled-stmt-node' bundle and return that. Otherwise we parse an
expression and return it wrapped in a `js2-expr-stmt-node'."
- (let ((pos js2-token-beg)
+ (let ((pos (js2-current-token-beg))
- (end (js2-current-token-end))
expr stmt pn bundle
(continue t))
;; set check for label and call down to `js2-parse-primary-expr'
- (js2-set-check-for-label)
- (setq expr (js2-parse-expr))
- (if (/= (js2-node-type expr) js2-LABEL)
- ;; Parsed non-label expression - wrap with expression stmt.
- (setq pn (js2-wrap-with-expr-stmt pos expr t)) ;FIXME: `pn' is unused!
+ (setq expr (js2-maybe-parse-label))
+ (if (null expr)
+ ;; Parse the non-label expression and wrap with expression stmt.
- (setq pn (js2-wrap-with-expr-stmt pos (js2-parse-expr) t))
++ (setq pn (js2-wrap-with-expr-stmt pos (js2-parse-expr) t)) ;FIXME: `pn' is unused!
;; else parsed a label
(setq bundle (make-js2-labeled-stmt-node :pos pos))
(js2-record-label expr bundle)
result)))
(defun js2-parse-member-expr (&optional allow-call-syntax)
- (let ((tt (js2-peek-token))
+ (let ((tt (js2-current-token-type))
- pn pos target args beg end init tail)
+ pn pos target args beg end init)
(if (/= tt js2-NEW)
(setq pn (js2-parse-primary-expr))
;; parse a 'new' expression
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
+ (let (tt
(continue t))
(while continue
- (setq tt (js2-peek-token))
+ (setq tt (js2-get-token))
(cond
((or (= tt js2-DOT) (= tt js2-DOTDOT))
(setq pn (js2-parse-property-access tt pn)))
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))
+ (let ((pos (or at-pos (js2-current-token-beg)))
colon-pos
- (name (js2-create-name-node t js2-current-token))
+ (name (js2-create-name-node t (js2-current-token-type) s))
- ns tt ref pn)
+ ns tt pn)
(catch 'return
(when (js2-match-token js2-COLONCOLON)
(setq ns name
(js2-report-error "msg.syntax")
(make-js2-error-node)))))
- (defun js2-parse-name (tt-flagged _tt)
- (let ((name js2-ts-string)
- (name-pos js2-token-beg)
-(defun js2-parse-name (tt)
++(defun js2-parse-name (_tt)
+ (let ((name (js2-current-token-string))
node)
- (if (and (js2-flag-set-p tt-flagged js2-ti-check-label)
- (= (js2-peek-token) js2-COLON))
- (prog1
- ;; Do not consume colon, it is used as unwind indicator
- ;; to return to statementHelper.
- (make-js2-label-node :pos name-pos
- :len (- js2-token-end name-pos)
- :name name)
- (js2-set-face name-pos
- js2-token-end
- 'font-lock-variable-name-face 'record))
- ;; Otherwise not a label, just a name. Unfortunately peeking
- ;; the next token to check for a colon has biffed js2-token-beg
- ;; and js2-token-end. We store the name's bounds in buffer vars
- ;; and `js2-create-name-node' uses them.
- (js2-save-name-token-data name-pos name)
- (setq node (if js2-compiler-xml-available
- (js2-parse-property-name nil name 0)
- (js2-create-name-node 'check-activation)))
- (if js2-highlight-external-variables
- (js2-record-name-node node))
- node)))
+ (setq node (if js2-compiler-xml-available
+ (js2-parse-property-name nil name 0)
+ (js2-create-name-node 'check-activation nil name)))
+ (if js2-highlight-external-variables
+ (js2-record-name-node node))
+ node))
(defun js2-parse-warn-trailing-comma (msg pos elems comma-pos)
(js2-add-strict-warning
comma-pos))
(defun js2-parse-array-literal ()
- (let ((pos js2-token-beg)
+ (let ((pos (js2-current-token-beg))
- (end (js2-current-token-end))
(after-lb-or-comma t)
after-comma tt elems pn
(continue t))
((or (= tt js2-RB)
(= tt js2-EOF)) ; prevent infinite loop
(if (= tt js2-EOF)
- (js2-report-error "msg.no.bracket.arg" nil pos)
- (js2-consume-token))
+ (js2-report-error "msg.no.bracket.arg" nil pos))
(setq continue nil
- end (js2-current-token-end)
pn (make-js2-array-node :pos pos
:len (- js2-ts-cursor pos)
:elems (nreverse elems)))
EXPR is the first expression after the opening left-bracket.
POS is the beginning of the LB token preceding EXPR.
We should have just parsed the 'for' keyword before calling this function."
- (let (loops loop first prev filter if-pos result)
+ (let (loops loop first filter if-pos result)
- (while (= (js2-peek-token) js2-FOR)
+ (while (= (js2-get-token) js2-FOR)
(let ((prev (car loops))) ; rearrange scope chain
(push (setq loop (js2-parse-array-comp-loop)) loops)
(if prev ; each loop is parent scope to the next one