1#!/usr/bin/env python
2#
3# Copyright 2008 The Closure Linter Authors. All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS-IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Parser for JavaScript files."""
18
19
20
21from closure_linter import javascripttokens
22from closure_linter import statetracker
23from closure_linter import tokenutil
24
25# Shorthand
26Type = javascripttokens.JavaScriptTokenType
27
28
29class JsDocFlag(statetracker.DocFlag):
30  """Javascript doc flag object.
31
32  Attribute:
33    flag_type: param, return, define, type, etc.
34    flag_token: The flag token.
35    type_start_token: The first token specifying the flag JS type,
36      including braces.
37    type_end_token: The last token specifying the flag JS type,
38      including braces.
39    type: The JavaScript type spec.
40    name_token: The token specifying the flag name.
41    name: The flag name
42    description_start_token: The first token in the description.
43    description_end_token: The end token in the description.
44    description: The description.
45  """
46
47  # Please keep these lists alphabetized.
48
49  # Some projects use the following extensions to JsDoc.
50  # TODO(robbyw): determine which of these, if any, should be illegal.
51  EXTENDED_DOC = frozenset([
52      'class', 'code', 'desc', 'final', 'hidden', 'inheritDoc', 'link',
53      'meaning', 'protected', 'notypecheck', 'throws'])
54
55  LEGAL_DOC = EXTENDED_DOC | statetracker.DocFlag.LEGAL_DOC
56
57  def __init__(self, flag_token):
58    """Creates the JsDocFlag object and attaches it to the given start token.
59
60    Args:
61      flag_token: The starting token of the flag.
62    """
63    statetracker.DocFlag.__init__(self, flag_token)
64
65
66class JavaScriptStateTracker(statetracker.StateTracker):
67  """JavaScript state tracker.
68
69  Inherits from the core EcmaScript StateTracker adding extra state tracking
70  functionality needed for JavaScript.
71  """
72
73  def __init__(self):
74    """Initializes a JavaScript token stream state tracker."""
75    statetracker.StateTracker.__init__(self, JsDocFlag)
76
77  def InTopLevel(self):
78    """Compute whether we are at the top level in the class.
79
80    This function call is language specific.  In some languages like
81    JavaScript, a function is top level if it is not inside any parenthesis.
82    In languages such as ActionScript, a function is top level if it is directly
83    within a class.
84
85    Returns:
86      Whether we are at the top level in the class.
87    """
88    return not self.InParentheses()
89
90  def GetBlockType(self, token):
91    """Determine the block type given a START_BLOCK token.
92
93    Code blocks come after parameters, keywords  like else, and closing parens.
94
95    Args:
96      token: The current token. Can be assumed to be type START_BLOCK
97    Returns:
98      Code block type for current token.
99    """
100    last_code = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES, None,
101                                       True)
102    if last_code.type in (Type.END_PARAMETERS, Type.END_PAREN,
103                          Type.KEYWORD) and not last_code.IsKeyword('return'):
104      return self.CODE
105    else:
106      return self.OBJECT_LITERAL
107
108  def HandleToken(self, token, last_non_space_token):
109    """Handles the given token and updates state.
110
111    Args:
112      token: The token to handle.
113      last_non_space_token:
114    """
115    super(JavaScriptStateTracker, self).HandleToken(token,
116                                                    last_non_space_token)
117