From f6d651d2dbd231ebad9c7e84b021ea42d5109104 Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Thu, 24 Sep 2020 16:21:09 +0200 Subject: [PATCH] [EXT] pyjsdoc, pyjsparser --- _extensions/pyjsdoc/LICENSE | 174 ++ _extensions/pyjsdoc/__init__.py | 408 +++ _extensions/pyjsparser/LICENSE | 21 + _extensions/pyjsparser/README | 4 + _extensions/pyjsparser/__init__.py | 4 + _extensions/pyjsparser/parser.py | 2920 ++++++++++++++++++++++ _extensions/pyjsparser/pyjsparserdata.py | 297 +++ _extensions/pyjsparser/std_nodes.py | 470 ++++ 8 files changed, 4298 insertions(+) create mode 100644 _extensions/pyjsdoc/LICENSE create mode 100644 _extensions/pyjsdoc/__init__.py create mode 100644 _extensions/pyjsparser/LICENSE create mode 100644 _extensions/pyjsparser/README create mode 100644 _extensions/pyjsparser/__init__.py create mode 100644 _extensions/pyjsparser/parser.py create mode 100644 _extensions/pyjsparser/pyjsparserdata.py create mode 100644 _extensions/pyjsparser/std_nodes.py diff --git a/_extensions/pyjsdoc/LICENSE b/_extensions/pyjsdoc/LICENSE new file mode 100644 index 000000000..dd5b3a58a --- /dev/null +++ b/_extensions/pyjsdoc/LICENSE @@ -0,0 +1,174 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/_extensions/pyjsdoc/__init__.py b/_extensions/pyjsdoc/__init__.py new file mode 100644 index 000000000..8368f7308 --- /dev/null +++ b/_extensions/pyjsdoc/__init__.py @@ -0,0 +1,408 @@ +from __future__ import division +import re, json + +##### Parsing utilities ##### + +def split_delimited(delimiters, split_by, text): + """ + Generator that walks the ``text`` and splits it into an array on + ``split_by``, being careful not to break inside a delimiter pair. + ``delimiters`` should be an even-length string with each pair of matching + delimiters listed together, open first. + + + >>> list(split_delimited('{}[]', ',', '')) + [''] + >>> list(split_delimited('', ',', 'foo,bar')) + ['foo', 'bar'] + >>> list(split_delimited('[]', ',', 'foo,[bar, baz]')) + ['foo', '[bar, baz]'] + >>> list(split_delimited('{}', ' ', '{Type Name} name Desc')) + ['{Type Name}', 'name', 'Desc'] + >>> list(split_delimited('[]{}', ',', '[{foo,[bar, baz]}]')) + ['[{foo,[bar, baz]}]'] + + Two adjacent delimiters result in a zero-length string between them: + + >>> list(split_delimited('{}', ' ', '{Type Name} Desc')) + ['{Type Name}', '', 'Desc'] + + ``split_by`` may be a predicate function instead of a string, in which + case it should return true on a character to split. + + >>> list(split_delimited('', lambda c: c in '[]{}, ', '[{foo,[bar, baz]}]')) + ['', '', 'foo', '', 'bar', '', 'baz', '', '', ''] + + """ + delims = [0] * (len(delimiters) // 2) + actions = {} + for i in range(0, len(delimiters), 2): + actions[delimiters[i]] = (i // 2, 1) + actions[delimiters[i + 1]] = (i // 2, -1) + + if isinstance(split_by, str): + def split_fn(c): + return c == split_by + else: + split_fn = split_by + last = 0 + + for i in range(len(text)): + c = text[i] + if split_fn(c) and not any(delims): + yield text[last:i] + last = i + 1 + try: + which, dir = actions[c] + delims[which] = delims[which] + dir + except KeyError: + pass # Normal character + yield text[last:] + + +def strip_stars(doc_comment): + r""" + Strip leading stars from a doc comment. + + >>> strip_stars('/** This is a comment. */') + 'This is a comment.' + >>> strip_stars('/**\n * This is a\n * multiline comment. */') + 'This is a\n multiline comment.' + >>> strip_stars('/** \n\t * This is a\n\t * multiline comment. \n*/') + 'This is a\n multiline comment.' + + """ + return re.sub('\n\s*?\*\s*?', '\n', doc_comment[3:-2]).strip() + + +def split_tag(section): + """ + Split the JSDoc tag text (everything following the @) at the first + whitespace. Returns a tuple of (tagname, body). + """ + splitval = re.split('\s+', section, 1) + tag, body = len(splitval) > 1 and splitval or (splitval[0], '') + return tag.strip(), body.strip() + + +FUNCTION_REGEXPS = [ + 'function (\w+)', + '(\w+):\sfunction', + '\.(\w+)\s*=\s*function', +] + + +def guess_function_name(next_line, regexps=FUNCTION_REGEXPS): + """ + Attempt to determine the function name from the first code line + following the comment. The patterns recognized are described by + `regexps`, which defaults to FUNCTION_REGEXPS. If a match is successful, + returns the function name. Otherwise, returns None. + """ + for regexp in regexps: + match = re.search(regexp, next_line) + if match: + return match.group(1) + return None + + +def guess_parameters(next_line): + """ + Attempt to guess parameters based on the presence of a parenthesized + group of identifiers. If successful, returns a list of parameter names; + otherwise, returns None. + """ + match = re.search('\(([\w\s,]+)\)', next_line) + if match: + return [arg.strip() for arg in match.group(1).split(',')] + else: + return None + + +def parse_comment(doc_comment, next_line): + r""" + Split the raw comment text into a dictionary of tags. The main comment + body is included as 'doc'. + + >>> comment = get_doc_comments(read_file('examples/module.js'))[4][0] + >>> parse_comment(strip_stars(comment), '')['doc'] + 'This is the documentation for the fourth function.\n\n Since the function being documented is itself generated from another\n function, its name needs to be specified explicitly. using the @function tag' + >>> parse_comment(strip_stars(comment), '')['function'] + 'not_auto_discovered' + + If there are multiple tags with the same name, they're included as a list: + + >>> parse_comment(strip_stars(comment), '')['param'] + ['{String} arg1 The first argument.', '{Int} arg2 The second argument.'] + + """ + sections = re.split('\n\s*@', doc_comment) + tags = { + 'doc': sections[0].strip(), + 'guessed_function': guess_function_name(next_line), + 'guessed_params': guess_parameters(next_line) + } + for section in sections[1:]: + tag, body = split_tag(section) + if tag in tags: + existing = tags[tag] + try: + existing.append(body) + except AttributeError: + tags[tag] = [existing, body] + else: + tags[tag] = body + return tags + + +#### Classes ##### + +class CommentDoc(object): + """ + Base class for all classes that represent a parsed comment of some sort. + """ + + def __init__(self, parsed_comment): + self.parsed = parsed_comment + + def __str__(self): + return "Docs for " + self.name + + def __repr__(self): + return str(self) + + def __contains__(self, tag_name): + return tag_name in self.parsed + + def __getitem__(self, tag_name): + return self.get(tag_name) + + def get(self, tag_name, default=''): + """ + Return the value of a particular tag, or None if that tag doesn't + exist. Use 'doc' for the comment body itself. + """ + return self.parsed.get(tag_name, default) + + def get_as_list(self, tag_name): + """ + Return the value of a tag, making sure that it's a list. Absent + tags are returned as an empty-list; single tags are returned as a + one-element list. + + The returned list is a copy, and modifications do not affect the + original object. + """ + val = self.get(tag_name, []) + if isinstance(val, list): + return val[:] + else: + return [val] + + @property + def doc(self): + """ + Return the comment body. + """ + return self.get('doc') + + @property + def url(self): + """ + Return a URL for the comment, within the page. + """ + return '#' + self.name + + @property + def see(self): + """ + Return a list of all @see tags on the comment. + """ + return self.get_as_list('see') + + def to_json(self): + """ + Return a JSON representation of the CommentDoc. Keys are as per + to_dict. + """ + return json.dumps(self.to_dict()) + + def to_dict(self): + """ + Return a dictionary representation of the CommentDoc. The keys of + this correspond to the tags in the comment, with the comment body in + `doc`. + """ + return self.parsed.copy() + +class ParamDoc(object): + """ + Represents a parameter, option, or parameter-like object, basically + anything that has a name, a type, and a description, separated by spaces. + This is also used for return types and exceptions, which use an empty + string for the name. + + >>> param = ParamDoc('{Array} elems The elements to act upon') + >>> param.name + 'elems' + >>> param.doc + 'The elements to act upon' + >>> param.type + 'Array' + + You can also omit the type: if the first element is not surrounded by + curly braces, it's assumed to be the name instead: + + >>> param2 = ParamDoc('param1 The first param') + >>> param2.type + '' + >>> param2.name + 'param1' + >>> param2.doc + 'The first param' + + """ + + def __init__(self, text): + parsed = list(split_delimited('{}', ' ', text)) + if parsed[0].startswith('{') and parsed[0].endswith('}'): + self.type = parsed[0][1:-1] + self.name = parsed[1] + self.doc = ' '.join(parsed[2:]) + else: + self.type = '' + self.name = parsed[0] + self.doc = ' '.join(parsed[1:]) + + def to_dict(self): + """ + Convert this to a dict. Keys (all strings) are: + + - **name**: Parameter name + - **type**: Parameter type + - **doc**: Parameter description + """ + return { + 'name': self.name, + 'type': self.type, + 'doc': self.doc + } + + def to_html(self, css_class=''): + """ + Returns the parameter as a dt/dd pair. + """ + if self.name and self.type: + header_text = '%s (%s)' % (self.name, self.type) + elif self.type: + header_text = self.type + else: + header_text = self.name + return '
%s
%s
' % (header_text, self.doc) + + +##### DEPENDENCIES ##### + +class CyclicDependency(Exception): + """ + Exception raised if there is a cyclic dependency. + """ + + def __init__(self, remaining_dependencies): + self.values = remaining_dependencies + + def __str__(self): + return ('The following dependencies result in a cycle: ' + + ', '.join(self.values)) + + +class MissingDependency(Exception): + """ + Exception raised if a file references a dependency that doesn't exist. + """ + + def __init__(self, file, dependency): + self.file = file + self.dependency = dependency + + def __str__(self): + return "Couldn't find dependency %s when processing %s" % \ + (self.dependency, self.file) + + +def build_dependency_graph(start_nodes, js_doc): + """ + Build a graph where nodes are filenames and edges are reverse dependencies + (so an edge from jquery.js to jquery.dimensions.js indicates that jquery.js + must be included before jquery.dimensions.js). The graph is represented + as a dictionary from filename to (in-degree, edges) pair, for ease of + topological sorting. Also returns a list of nodes of degree zero. + """ + queue = [] + dependencies = {} + start_sort = [] + + def add_vertex(file): + in_degree = len(js_doc[file].module.dependencies) + dependencies[file] = [in_degree, []] + queue.append(file) + if in_degree == 0: + start_sort.append(file) + + def add_edge(from_file, to_file): + dependencies[from_file][1].append(to_file) + + def is_in_graph(file): + return file in dependencies + + for file in start_nodes: + add_vertex(file) + for file in queue: + for dependency in js_doc[file].module.dependencies: + if dependency not in js_doc: + raise MissingDependency(file, dependency) + if not is_in_graph(dependency): + add_vertex(dependency) + add_edge(dependency, file) + return dependencies, start_sort + + +def topological_sort(dependencies, start_nodes): + """ + Perform a topological sort on the dependency graph `dependencies`, starting + from list `start_nodes`. + """ + retval = [] + + def edges(node): + return dependencies[node][1] + + def in_degree(node): + return dependencies[node][0] + + def remove_incoming(node): + dependencies[node][0] = in_degree(node) - 1 + + while start_nodes: + node = start_nodes.pop() + retval.append(node) + for child in edges(node): + remove_incoming(child) + if not in_degree(child): + start_nodes.append(child) + leftover_nodes = [node for node in dependencies.keys() + if in_degree(node) > 0] + if leftover_nodes: + raise CyclicDependency(leftover_nodes) + else: + return retval + + +def find_dependencies(start_nodes, js_doc): + """ + Sort the dependency graph, taking in a list of starting module names and a + CodeBaseDoc (or equivalent dictionary). Returns an ordered list of + transitive dependencies such that no module appears before its + dependencies. + """ + return topological_sort(*build_dependency_graph(start_nodes, js_doc)) diff --git a/_extensions/pyjsparser/LICENSE b/_extensions/pyjsparser/LICENSE new file mode 100644 index 000000000..5f5aff9f6 --- /dev/null +++ b/_extensions/pyjsparser/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Piotr Dabkowski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/_extensions/pyjsparser/README b/_extensions/pyjsparser/README new file mode 100644 index 000000000..574593bbf --- /dev/null +++ b/_extensions/pyjsparser/README @@ -0,0 +1,4 @@ +Vendoring of pyjsparser to add comments support as we need them for autojsdoc. + +Alternative: use https://github.com/Kronuz/esprima-python instead, seems to +support comments though may be attaching them differently. diff --git a/_extensions/pyjsparser/__init__.py b/_extensions/pyjsparser/__init__.py new file mode 100644 index 000000000..19036bddb --- /dev/null +++ b/_extensions/pyjsparser/__init__.py @@ -0,0 +1,4 @@ +s__all__ = ['PyJsParser', 'parse', 'JsSyntaxError'] +__author__ = 'Piotr Dabkowski' +__version__ = '2.2.0' +from .parser import PyJsParser, parse, JsSyntaxError diff --git a/_extensions/pyjsparser/parser.py b/_extensions/pyjsparser/parser.py new file mode 100644 index 000000000..69729c448 --- /dev/null +++ b/_extensions/pyjsparser/parser.py @@ -0,0 +1,2920 @@ +# The MIT License +# +# Copyright 2014, 2015 Piotr Dabkowski +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the 'Software'), +# to deal in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +from __future__ import unicode_literals +from .pyjsparserdata import * +from .std_nodes import * +from pprint import pprint +import sys + +__all__ = ['PyJsParser', 'parse', 'ENABLE_JS2PY_ERRORS', 'ENABLE_PYIMPORT', 'JsSyntaxError'] +REGEXP_SPECIAL_SINGLE = ('\\', '^', '$', '*', '+', '?', '.', '[', ']', '(', ')', '{', '{', '|', '-') +ENABLE_PYIMPORT = False +ENABLE_JS2PY_ERRORS = False +ESPRIMA_VERSION = '2.2.0' + +DEBUG = False +# Small naming convention changes +# len -> leng +# id -> d +# type -> typ +# str -> st +true = True +false = False +null = None + + +class PyJsParser: + """ Usage: + parser = PyJsParser() + parser.parse('var JavaScriptCode = 5.1') + """ + + def __init__(self): + self.clean() + + def test(self, code): + pprint(self.parse(code)) + + def clean(self): + self.strict = None + self.sourceType = None + self.index = 0 + self.lineNumber = 1 + self.lineStart = 0 + self.hasLineTerminator = None + self.lastIndex = None + self.lastLineNumber = None + self.lastLineStart = None + self.startIndex = None + self.startLineNumber = None + self.startLineStart = None + self.scanning = None + self.lookahead = None + self.state = None + self.extra = None + self.isBindingElement = None + self.isAssignmentTarget = None + self.firstCoverInitializedNameError = None + + # 7.4 Comments + + def skipSingleLineComment(self, offset): + start = self.index - offset; + while self.index < self.length: + ch = self.source[self.index]; + self.index += 1 + if isLineTerminator(ch): + if (ord(ch) == 13 and ord(self.source[self.index]) == 10): + self.index += 1 + self.lineNumber += 1 + self.hasLineTerminator = True + self.lineStart = self.index + return { + 'type': 'Line', + 'value': self.source[start + offset:self.index-2], + 'leading': True, + 'trailing': False, + 'loc': None, + } + + def skipMultiLineComment(self): + start = self.index + while self.index < self.length: + ch = ord(self.source[self.index]) + if isLineTerminator(ch): + if (ch == 0x0D and ord(self.source[self.index + 1]) == 0x0A): + self.index += 1 + self.lineNumber += 1 + self.index += 1 + self.hasLineTerminator = True + self.lineStart = self.index + elif ch == 0x2A: + # Block comment ends with '*/'. + if ord(self.source[self.index + 1]) == 0x2F: + self.index += 2 + return { + 'type': 'Block', + 'value': self.source[start:self.index-2], + 'leading': True, + 'trailing': False, + 'loc': None, + } + self.index += 1 + else: + self.index += 1 + self.tolerateUnexpectedToken() + + def skipComment(self): + self.hasLineTerminator = False + startIndex = self.index + start = (self.index == 0) + comments = [] + while self.index < self.length: + ch = ord(self.source[self.index]) + if isWhiteSpace(ch): + self.index += 1 + elif isLineTerminator(ch): + self.hasLineTerminator = True + self.index += 1 + if (ch == 0x0D and ord(self.source[self.index]) == 0x0A): + self.index += 1 + self.lineNumber += 1 + self.lineStart = self.index + start = True + elif (ch == 0x2F): # U+002F is '/' + ch = ord(self.source[self.index + 1]) + if (ch == 0x2F): + self.index += 2 + comments.append(self.skipSingleLineComment(2)) + start = True + elif (ch == 0x2A): # U+002A is '*' + self.index += 2 + comments.append(self.skipMultiLineComment()) + else: + break + elif (start and ch == 0x2D): # U+002D is '-' + # U+003E is '>' + if (ord(self.source[self.index + 1]) == 0x2D) and (ord(self.source[self.index + 2]) == 0x3E): + # '-->' is a single-line comment + self.index += 3 + self.skipSingleLineComment(3) + else: + break + elif (ch == 0x3C): # U+003C is '<' + if self.source[self.index + 1: self.index + 4] == '!--': + #