Bug 1633437 - Support for test metadata r=acreskey

This patch adds support for tests metadata. A test script parser is added as
well as a new "doc" flavor that can be used to display the script info in the
command line. This parser will be the basis for building automated docs and
scripts verifications if we want to do this.

Differential Revision: https://phabricator.services.mozilla.com/D72800
This commit is contained in:
Tarek Ziadé 2020-04-28 17:07:14 +00:00
Родитель dfbeca257b
Коммит 33f1eee4d5
42 изменённых файлов: 8037 добавлений и 41 удалений

Просмотреть файл

@ -23,6 +23,7 @@ mozilla.pth:third_party/python/distro
mozilla.pth:third_party/python/dlmanager mozilla.pth:third_party/python/dlmanager
mozilla.pth:third_party/python/ecdsa/src mozilla.pth:third_party/python/ecdsa/src
mozilla.pth:third_party/python/enum34 mozilla.pth:third_party/python/enum34
mozilla.pth:third_party/python/esprima
mozilla.pth:third_party/python/fluent.migrate mozilla.pth:third_party/python/fluent.migrate
mozilla.pth:third_party/python/fluent.syntax mozilla.pth:third_party/python/fluent.syntax
mozilla.pth:third_party/python/funcsigs mozilla.pth:third_party/python/funcsigs

Просмотреть файл

@ -19,10 +19,18 @@ from mozperftest.system import get_layers as system_layers
from mozperftest.browser import get_layers as browser_layers from mozperftest.browser import get_layers as browser_layers
from mozperftest.metrics import get_layers as metrics_layers from mozperftest.metrics import get_layers as metrics_layers
FLAVORS = ["script", "doc"]
class Options: class Options:
general_args = { general_args = {
"--flavor": {
"choices": FLAVORS,
"metavar": "{{{}}}".format(", ".join(FLAVORS)),
"default": None,
"help": "Only run tests of this flavor.",
},
"tests": { "tests": {
"nargs": "*", "nargs": "*",
"metavar": "TEST", "metavar": "TEST",

Просмотреть файл

@ -1,6 +1,8 @@
# This Source Code Form is subject to the terms of the Mozilla Public # This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this # License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import random
from functools import partial from functools import partial
from mach.decorators import CommandProvider, Command from mach.decorators import CommandProvider, Command
from mozbuild.base import MachCommandBase, MachCommandConditions as conditions from mozbuild.base import MachCommandBase, MachCommandConditions as conditions
@ -14,6 +16,25 @@ def get_perftest_parser():
@CommandProvider @CommandProvider
class Perftest(MachCommandBase): class Perftest(MachCommandBase):
def _build_test_list(self, tests, randomized=False):
res = []
for test in tests:
if os.path.isfile(test):
tests.append(test)
elif os.path.isdir(test):
for root, dirs, files in os.walk(test):
for file in files:
if not file.startswith("perftest"):
continue
res.append(os.path.join(root, file))
if not randomized:
res.sort()
else:
# random shuffling is used to make sure
# we don't always run tests in the same order
random.shuffle(res)
return res
@Command( @Command(
"perftest", "perftest",
category="testing", category="testing",
@ -24,6 +45,23 @@ class Perftest(MachCommandBase):
def run_perftest( def run_perftest(
self, flavor="script", test_objects=None, resolve_tests=True, **kwargs self, flavor="script", test_objects=None, resolve_tests=True, **kwargs
): ):
MachCommandBase._activate_virtualenv(self)
kwargs["tests"] = self._build_test_list(
kwargs["tests"], randomized=flavor != "doc"
)
if flavor == "doc":
from mozperftest.utils import install_package
install_package(self.virtualenv_manager, "esprima")
from mozperftest.scriptinfo import ScriptInfo
for test in kwargs["tests"]:
print(ScriptInfo(test))
return
from mozperftest import MachEnvironment, Metadata from mozperftest import MachEnvironment, Metadata
kwargs["test_objects"] = test_objects kwargs["test_objects"] = test_objects

Просмотреть файл

@ -0,0 +1,83 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from collections import defaultdict
import re
import os
import textwrap
# This import will fail if esprima is not installed.
# The package is vendored in python/third_party and also available at PyPI
# The mach perftest command will make sure it's installed when --flavor doc
# is being used.
import esprima
_INFO = """\
%(filename)s
%(filename_underline)s
%(description)s
Owner: %(owner)s
Usage:
%(usage)s
Description:
%(long_description)s
"""
class MetadataDict(defaultdict):
def __missing__(self, key):
return "N/A"
class ScriptInfo(MetadataDict):
def __init__(self, script):
super(ScriptInfo, self).__init__()
filename = os.path.basename(script)
self["filename"] = script, filename
self["filename_underline"] = None, "-" * len(filename)
self.script = script
with open(script) as f:
self.parsed = esprima.parseScript(f.read())
# looking for the exports statement
for stmt in self.parsed.body:
if (
stmt.type != "ExpressionStatement"
or stmt.expression.left is None
or stmt.expression.left.property.name != "exports"
or stmt.expression.right is None
or stmt.expression.right.properties is None
):
continue
# now scanning the properties
for prop in stmt.expression.right.properties:
if prop.value.type == "Identifier":
value = prop.value.name
elif prop.value.type == "Literal":
value = prop.value.value
elif prop.value.type == "TemplateLiteral":
# ugly
value = prop.value.quasis[0].value.cooked.replace("\n", " ")
value = re.sub("\s+", " ", value).strip()
elif prop.value.type == "ArrayExpression":
value = [e.value for e in prop.value.elements]
else:
raise ValueError(prop.value.type)
# line wrapping
if isinstance(value, str):
repr = "\n".join(textwrap.wrap(value, break_on_hyphens=False))
elif isinstance(value, list):
repr = ", ".join(value)
self[prop.key.name] = value, repr
def __str__(self):
reprs = dict((k, v[1]) for k, v in self.items())
d = MetadataDict()
d.update(reprs)
return _INFO % d

Просмотреть файл

@ -1,19 +0,0 @@
async function setUp(context) {
context.log.info("setUp example!");
}
async function test(context, commands) {
context.log.info("Test with setUp/tearDown example!");
await commands.measure.start("https://www.sitespeed.io/");
await commands.measure.start("https://www.mozilla.org/en-US/");
}
async function tearDown(context) {
context.log.info("tearDown example!");
}
module.exports = { // eslint-disable-line
setUp,
tearDown,
test,
};

Просмотреть файл

@ -0,0 +1,45 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/* eslint-env node */
"use strict";
var someVar;
async function setUp(context) {
context.log.info("setUp example!");
}
async function test(context, commands) {
context.log.info("Test with setUp/tearDown example!");
await commands.measure.start("https://www.sitespeed.io/");
await commands.measure.start("https://www.mozilla.org/en-US/");
}
async function tearDown(context) {
context.log.info("tearDown example!");
}
module.exports = {
setUp,
tearDown,
test,
owner: "Performance Team",
description: "Measures cold process applink time",
long_description: `
This test launches the appropriate android app, simulating an app link
workflow. The application is launched with the intent action
android.intent.action.VIEW loading a trivially simple website. The reported
metric is the time from process start to navigationStart, reported as processLaunchToNavStart
`,
usage: `
./mach perftest testing/performance/perftest_applink.js \
--android-install-apk ~/fenix.v2.fennec-nightly.2020.04.22-arm32.apk \
--hooks testing/performance/hooks_applink.py \
--android-app-name org.mozilla.fennec_aurora \
--perfherder-metrics processLaunchToNavStart
`,
supported_browser: ["Fenix nightly", "Geckoview_example", "Fennec"],
platform: ["Android"],
};

Просмотреть файл

@ -8,6 +8,11 @@ from mozperftest.metadata import Metadata
from mozperftest.environment import MachEnvironment from mozperftest.environment import MachEnvironment
HERE = os.path.dirname(__file__)
EXAMPLE_TESTS_DIR = os.path.join(HERE, "samples")
EXAMPLE_TEST = os.path.join(EXAMPLE_TESTS_DIR, "perftest_example.js")
@contextlib.contextmanager @contextlib.contextmanager
def temp_file(name="temp", content=None): def temp_file(name="temp", content=None):
tempdir = tempfile.mkdtemp() tempdir = tempfile.mkdtemp()

Просмотреть файл

@ -4,7 +4,7 @@ import mozunit
import mock import mock
import shutil import shutil
from mozperftest.tests.support import get_running_env from mozperftest.tests.support import get_running_env, EXAMPLE_TEST
from mozperftest.environment import BROWSER from mozperftest.environment import BROWSER
from mozperftest.browser.browsertime import add_options from mozperftest.browser.browsertime import add_options
from mozperftest.utils import silence from mozperftest.utils import silence
@ -28,7 +28,7 @@ def fetch(self, url):
def test_browser(): def test_browser():
mach_cmd, metadata, env = get_running_env() mach_cmd, metadata, env = get_running_env()
browser = env.layers[BROWSER] browser = env.layers[BROWSER]
env.set_arg("tests", [os.path.join(HERE, "example.js")]) env.set_arg("tests", [EXAMPLE_TEST])
try: try:
with browser as b, silence(): with browser as b, silence():
@ -38,7 +38,7 @@ def test_browser():
assert mach_cmd.run_process.call_count == 1 assert mach_cmd.run_process.call_count == 1
# XXX more checks # XXX more checks
assert mach_cmd.run_process.call_args[0][-1][-1] == os.path.join(HERE, "example.js") assert mach_cmd.run_process.call_args[0][-1][-1] == EXAMPLE_TEST
def test_add_options(): def test_add_options():

Просмотреть файл

@ -2,7 +2,7 @@
import os import os
import mozunit import mozunit
from mozperftest.tests.support import get_running_env, temp_dir from mozperftest.tests.support import EXAMPLE_TEST, get_running_env, temp_dir
from mozperftest.environment import METRICS from mozperftest.environment import METRICS
from mozperftest.utils import silence from mozperftest.utils import silence
@ -26,7 +26,7 @@ def test_console_output():
mach_cmd.run_process = _run_process mach_cmd.run_process = _run_process
metrics = env.layers[METRICS] metrics = env.layers[METRICS]
env.set_arg("tests", [os.path.join(HERE, "example.js")]) env.set_arg("tests", [EXAMPLE_TEST])
metadata.set_result(os.path.join(HERE, "browsertime-results")) metadata.set_result(os.path.join(HERE, "browsertime-results"))
with metrics as console, silence(): with metrics as console, silence():

Просмотреть файл

@ -7,6 +7,7 @@ import os
import mock import mock
import tempfile import tempfile
import shutil import shutil
from contextlib import contextmanager
from mach.registrar import Registrar from mach.registrar import Registrar
@ -16,6 +17,7 @@ Registrar.commands_by_category = {"testing": set()}
from mozperftest.environment import MachEnvironment from mozperftest.environment import MachEnvironment
from mozperftest.mach_commands import Perftest from mozperftest.mach_commands import Perftest
from mozperftest.tests.support import EXAMPLE_TESTS_DIR
class _TestMachEnvironment(MachEnvironment): class _TestMachEnvironment(MachEnvironment):
@ -29,8 +31,8 @@ class _TestMachEnvironment(MachEnvironment):
pass pass
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment) @contextmanager
def test_command(): def _get_perftest():
from mozbuild.base import MozbuildObject from mozbuild.base import MozbuildObject
config = MozbuildObject.from_environment() config = MozbuildObject.from_environment()
@ -43,11 +45,25 @@ def test_command():
state_dir = tempfile.mkdtemp() state_dir = tempfile.mkdtemp()
try: try:
test = Perftest(context()) yield Perftest(context())
test.run_perftest()
finally: finally:
shutil.rmtree(context.state_dir) shutil.rmtree(context.state_dir)
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
@mock.patch("mozperftest.mach_commands.MachCommandBase._activate_virtualenv")
def test_command(mocked_func):
with _get_perftest() as test:
test.run_perftest(tests=[EXAMPLE_TESTS_DIR])
# XXX add assertions
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
@mock.patch("mozperftest.mach_commands.MachCommandBase._activate_virtualenv")
def test_doc_flavor(mocked_func):
with _get_perftest() as test:
test.run_perftest(tests=[EXAMPLE_TESTS_DIR], flavor="doc")
if __name__ == "__main__": if __name__ == "__main__":
mozunit.main() mozunit.main()

Просмотреть файл

@ -3,7 +3,7 @@ import os
import mozunit import mozunit
import json import json
from mozperftest.tests.support import get_running_env, temp_file from mozperftest.tests.support import get_running_env, temp_file, EXAMPLE_TEST
from mozperftest.environment import METRICS from mozperftest.environment import METRICS
from mozperftest.utils import silence from mozperftest.utils import silence
@ -22,7 +22,7 @@ def test_metrics():
mach_cmd.run_process = _run_process mach_cmd.run_process = _run_process
metrics = env.layers[METRICS] metrics = env.layers[METRICS]
env.set_arg("tests", [os.path.join(HERE, "example.js")]) env.set_arg("tests", [EXAMPLE_TEST])
metadata.set_result(os.path.join(HERE, "browsertime-results")) metadata.set_result(os.path.join(HERE, "browsertime-results"))
with temp_file() as output: with temp_file() as output:

Просмотреть файл

@ -0,0 +1,20 @@
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import mozunit
from mozperftest.scriptinfo import ScriptInfo
from mozperftest.tests.support import EXAMPLE_TEST
def test_scriptinfo():
info = ScriptInfo(EXAMPLE_TEST)
assert info["author"] == "N/A"
display = str(info)
assert "appropriate android app" in display
if __name__ == "__main__":
mozunit.main()

Просмотреть файл

@ -4,6 +4,8 @@
import logging import logging
import contextlib import contextlib
import sys import sys
import os
from six import StringIO from six import StringIO
@ -54,3 +56,20 @@ class MachLogger:
def error(self, msg, name="mozperftest", **kwargs): def error(self, msg, name="mozperftest", **kwargs):
self._logger(logging.ERROR, name, kwargs, msg) self._logger(logging.ERROR, name, kwargs, msg)
def install_package(virtualenv_manager, package):
from pip._internal.req.constructors import install_req_from_line
req = install_req_from_line(package)
req.check_if_exists(use_user_site=False)
# already installed, check if it's in our venv
if req.satisfied_by is not None:
venv_site_lib = os.path.abspath(
os.path.join(virtualenv_manager.bin_path, "..", "lib")
)
site_packages = os.path.abspath(req.satisfied_by.location)
if site_packages.startswith(venv_site_lib):
# already installed in this venv, we can skip
return
virtualenv_manager._run_pip(["install", package])

Просмотреть файл

@ -5,23 +5,28 @@ from mozperftest.browser.browsertime import add_options
url = "'https://www.example.com'" url = "'https://www.example.com'"
common_options = [("processStartTime", "true"), common_options = [
("firefox.disableBrowsertimeExtension", "true"), ("processStartTime", "true"),
("firefox.android.intentArgument", "'-a'"), ("firefox.disableBrowsertimeExtension", "true"),
("firefox.android.intentArgument", "'android.intent.action.VIEW'"), ("firefox.android.intentArgument", "'-a'"),
("firefox.android.intentArgument", "'-d'"), ("firefox.android.intentArgument", "'android.intent.action.VIEW'"),
("firefox.android.intentArgument", url)] ("firefox.android.intentArgument", "'-d'"),
("firefox.android.intentArgument", url),
]
app_options = { app_options = {
"org.mozilla.geckoview_example": [ "org.mozilla.geckoview_example": [
("firefox.android.activity", "'org.mozilla.geckoview_example.GeckoViewActivity'") (
"firefox.android.activity",
"'org.mozilla.geckoview_example.GeckoViewActivity'",
)
], ],
"org.mozilla.fennec_aurora": [ "org.mozilla.fennec_aurora": [
("firefox.android.activity", "'org.mozilla.fenix.IntentReceiverActivity'") ("firefox.android.activity", "'org.mozilla.fenix.IntentReceiverActivity'")
], ],
"org.mozilla.firefox": [ "org.mozilla.firefox": [
("firefox.android.activity", "'org.mozilla.gecko.BrowserApp'") ("firefox.android.activity", "'org.mozilla.gecko.BrowserApp'")
] ],
} }

Просмотреть файл

@ -1,8 +1,10 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/* eslint-env node */ /* eslint-env node */
"use strict";
module.exports = async function(context, commands) { async function test(context, commands) {
"use strict";
// This violates all sorts of abstraction boundaries, but I don't see supported APIs for "just // This violates all sorts of abstraction boundaries, but I don't see supported APIs for "just
// waiting" nor for allowing navigation scripts to produce measurements. // waiting" nor for allowing navigation scripts to produce measurements.
await commands.measure.start(); await commands.measure.start();
@ -19,4 +21,25 @@ module.exports = async function(context, commands) {
console.log("processLaunchToNavStart: " + processLaunchToNavStart); console.log("processLaunchToNavStart: " + processLaunchToNavStart);
return true; return true;
}
module.exports = {
test,
owner: "Performance Team",
description: "Measures cold process applink time",
long_description: `
This test launches the appropriate android app, simulating an app link
workflow. The application is launched with the intent action
android.intent.action.VIEW loading a trivially simple website. The reported
metric is the time from process start to navigationStart, reported as processLaunchToNavStart
`,
usage: `
./mach perftest testing/performance/perftest_applink.js \
--android-install-apk ~/fenix.v2.fennec-nightly.2020.04.22-arm32.apk \
--hooks testing/performance/hooks_applink.py \
--android-app-name org.mozilla.fennec_aurora \
--perfherder-metrics processLaunchToNavStart
`,
supported_browser: ["Fenix nightly", "Geckoview_example", "Fennec"],
platform: ["Android"],
}; };

143
third_party/python/esprima/PKG-INFO поставляемый Normal file
Просмотреть файл

@ -0,0 +1,143 @@
Metadata-Version: 1.1
Name: esprima
Version: 4.0.1
Summary: ECMAScript parsing infrastructure for multipurpose analysis in Python
Home-page: https://github.com/Kronuz/esprima-python
Author: German M. Bravo (Kronuz)
Author-email: german.mb@gmail.com
License: BSD License
Description: |Donate| |PyPI Version| |PyPI License| |PyPI Format| |PyPI Status|
**Esprima** (`esprima.org <http://esprima.org>`__, BSD license) is a
high performance, standard-compliant
`ECMAScript <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`__
parser officially written in ECMAScript (also popularly known as
`JavaScript <https://en.wikipedia.org/wiki/JavaScript>`__) and ported to
Python. Esprima is created and maintained by `Ariya
Hidayat <https://twitter.com/ariyahidayat>`__, with the help of `many
contributors <https://github.com/jquery/esprima/contributors>`__.
Python port is a line-by-line manual translation and was created and is
maintained by `German Mendez Bravo
(Kronuz) <https://twitter.com/germbravo>`__.
Features
~~~~~~~~
- Full support for ECMAScript 2017 (`ECMA-262 8th
Edition <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`__)
- Sensible `syntax tree
format <https://github.com/estree/estree/blob/master/es5.md>`__ as
standardized by `ESTree project <https://github.com/estree/estree>`__
- Experimental support for `JSX <https://facebook.github.io/jsx/>`__, a
syntax extension for `React <https://facebook.github.io/react/>`__
- Optional tracking of syntax node location (index-based and
line-column)
- `Heavily tested <http://esprima.org/test/ci.html>`__ (~1500 `unit
tests <https://github.com/jquery/esprima/tree/master/test/fixtures>`__
with `full code
coverage <https://codecov.io/github/jquery/esprima>`__)
Installation
~~~~~~~~~~~~
.. code:: shell
pip install esprima
API
~~~
Esprima can be used to perform `lexical
analysis <https://en.wikipedia.org/wiki/Lexical_analysis>`__
(tokenization) or `syntactic
analysis <https://en.wikipedia.org/wiki/Parsing>`__ (parsing) of a
JavaScript program.
A simple example:
.. code:: javascript
>>> import esprima
>>> program = 'const answer = 42'
>>> esprima.tokenize(program)
[{
type: "Keyword",
value: "const"
}, {
type: "Identifier",
value: "answer"
}, {
type: "Punctuator",
value: "="
}, {
type: "Numeric",
value: "42"
}]
>>> esprima.parseScript(program)
{
body: [
{
kind: "const",
declarations: [
{
init: {
raw: "42",
type: "Literal",
value: 42
},
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "answer"
}
}
],
type: "VariableDeclaration"
}
],
type: "Program",
sourceType: "script"
}
For more information, please read the `complete
documentation <http://esprima.org/doc>`__.
.. |Donate| image:: https://img.shields.io/badge/Donate-PayPal-green.svg
:target: https://www.paypal.me/Kronuz/25
.. |PyPI Version| image:: https://img.shields.io/pypi/v/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI License| image:: https://img.shields.io/pypi/l/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Wheel| image:: https://img.shields.io/pypi/wheel/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Format| image:: https://img.shields.io/pypi/format/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Python Version| image:: https://img.shields.io/pypi/pyversions/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Implementation| image:: https://img.shields.io/pypi/implementation/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Status| image:: https://img.shields.io/pypi/status/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Downloads| image:: https://img.shields.io/pypi/dm/esprima.svg
:target: https://pypi.python.org/pypi/esprima
Keywords: esprima ecmascript javascript parser ast
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: General
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6

117
third_party/python/esprima/README поставляемый Normal file
Просмотреть файл

@ -0,0 +1,117 @@
|Donate| |PyPI Version| |PyPI License| |PyPI Format| |PyPI Status|
**Esprima** (`esprima.org <http://esprima.org>`__, BSD license) is a
high performance, standard-compliant
`ECMAScript <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`__
parser officially written in ECMAScript (also popularly known as
`JavaScript <https://en.wikipedia.org/wiki/JavaScript>`__) and ported to
Python. Esprima is created and maintained by `Ariya
Hidayat <https://twitter.com/ariyahidayat>`__, with the help of `many
contributors <https://github.com/jquery/esprima/contributors>`__.
Python port is a line-by-line manual translation and was created and is
maintained by `German Mendez Bravo
(Kronuz) <https://twitter.com/germbravo>`__.
Features
~~~~~~~~
- Full support for ECMAScript 2017 (`ECMA-262 8th
Edition <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`__)
- Sensible `syntax tree
format <https://github.com/estree/estree/blob/master/es5.md>`__ as
standardized by `ESTree project <https://github.com/estree/estree>`__
- Experimental support for `JSX <https://facebook.github.io/jsx/>`__, a
syntax extension for `React <https://facebook.github.io/react/>`__
- Optional tracking of syntax node location (index-based and
line-column)
- `Heavily tested <http://esprima.org/test/ci.html>`__ (~1500 `unit
tests <https://github.com/jquery/esprima/tree/master/test/fixtures>`__
with `full code
coverage <https://codecov.io/github/jquery/esprima>`__)
Installation
~~~~~~~~~~~~
.. code:: shell
pip install esprima
API
~~~
Esprima can be used to perform `lexical
analysis <https://en.wikipedia.org/wiki/Lexical_analysis>`__
(tokenization) or `syntactic
analysis <https://en.wikipedia.org/wiki/Parsing>`__ (parsing) of a
JavaScript program.
A simple example:
.. code:: javascript
>>> import esprima
>>> program = 'const answer = 42'
>>> esprima.tokenize(program)
[{
type: "Keyword",
value: "const"
}, {
type: "Identifier",
value: "answer"
}, {
type: "Punctuator",
value: "="
}, {
type: "Numeric",
value: "42"
}]
>>> esprima.parseScript(program)
{
body: [
{
kind: "const",
declarations: [
{
init: {
raw: "42",
type: "Literal",
value: 42
},
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "answer"
}
}
],
type: "VariableDeclaration"
}
],
type: "Program",
sourceType: "script"
}
For more information, please read the `complete
documentation <http://esprima.org/doc>`__.
.. |Donate| image:: https://img.shields.io/badge/Donate-PayPal-green.svg
:target: https://www.paypal.me/Kronuz/25
.. |PyPI Version| image:: https://img.shields.io/pypi/v/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI License| image:: https://img.shields.io/pypi/l/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Wheel| image:: https://img.shields.io/pypi/wheel/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Format| image:: https://img.shields.io/pypi/format/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Python Version| image:: https://img.shields.io/pypi/pyversions/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Implementation| image:: https://img.shields.io/pypi/implementation/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Status| image:: https://img.shields.io/pypi/status/esprima.svg
:target: https://pypi.python.org/pypi/esprima
.. |PyPI Downloads| image:: https://img.shields.io/pypi/dm/esprima.svg
:target: https://pypi.python.org/pypi/esprima

29
third_party/python/esprima/esprima/__init__.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import
version = '4.0.1'
__version__ = (4, 0, 1)
from .esprima import * # NOQA

105
third_party/python/esprima/esprima/__main__.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals, print_function, division
import sys
from .esprima import parse, tokenize, Error, toDict
from . import version
def main():
import json
import time
import optparse
usage = "usage: %prog [options] [file.js]"
parser = optparse.OptionParser(usage=usage, version=version)
parser.add_option("--comment", dest="comment",
action="store_true", default=False,
help="Gather all line and block comments in an array")
parser.add_option("--attachComment", dest="attachComment",
action="store_true", default=False,
help="Attach comments to nodes")
parser.add_option("--loc", dest="loc", default=False,
action="store_true",
help="Include line-column location info for each syntax node")
parser.add_option("--range", dest="range", default=False,
action="store_true",
help="Include index-based range for each syntax node")
parser.add_option("--raw", dest="raw", default=False,
action="store_true",
help="Display the raw value of literals")
parser.add_option("--tokens", dest="tokens", default=False,
action="store_true",
help="List all tokens in an array")
parser.add_option("--tolerant", dest="tolerant", default=False,
action="store_true",
help="Tolerate errors on a best-effort basis (experimental)")
parser.add_option("--tokenize", dest="tokenize", default=False,
action="store_true",
help="Only tokenize, do not parse.")
parser.add_option("--module", dest="sourceType", default='string',
action="store_const", const='module',
help="Tolerate errors on a best-effort basis (experimental)")
parser.set_defaults(jsx=True, classProperties=True)
opts, args = parser.parse_args()
if len(args) == 1:
with open(args[0], 'rb') as f:
code = f.read().decode('utf-8')
elif sys.stdin.isatty():
parser.print_help()
return 64
else:
code = sys.stdin.read().decode('utf-8')
options = opts.__dict__
do_tokenize = options.pop('tokenize')
t = time.time()
try:
if do_tokenize:
del options['sourceType']
del options['tokens']
del options['raw']
del options['jsx']
res = toDict(tokenize(code, options=options))
else:
res = toDict(parse(code, options=options))
except Error as e:
res = e.toDict()
dt = time.time() - t + 0.000000001
print(json.dumps(res, indent=4))
print()
print('Parsed everyting in', round(dt, 5), 'seconds.')
print('Thats %d characters per second' % (len(code) // dt))
return 0
if __name__ == '__main__':
retval = main()
sys.exit(retval)

125
third_party/python/esprima/esprima/character.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
import sys
import unicodedata
from collections import defaultdict
from .compat import uchr, xrange
# http://stackoverflow.com/questions/14245893/efficiently-list-all-characters-in-a-given-unicode-category
U_CATEGORIES = defaultdict(list)
for c in map(uchr, xrange(sys.maxunicode + 1)):
U_CATEGORIES[unicodedata.category(c)].append(c)
UNICODE_LETTER = set(
U_CATEGORIES['Lu'] + U_CATEGORIES['Ll'] +
U_CATEGORIES['Lt'] + U_CATEGORIES['Lm'] +
U_CATEGORIES['Lo'] + U_CATEGORIES['Nl']
)
UNICODE_OTHER_ID_START = set((
# Other_ID_Start
'\u1885', '\u1886', '\u2118', '\u212E', '\u309B', '\u309C',
# New in Unicode 8.0
'\u08B3', '\u0AF9', '\u13F8', '\u9FCD', '\uAB60', '\U00010CC0', '\U000108E0', '\U0002B820',
# New in Unicode 9.0
'\u1C80', '\U000104DB', '\U0001E922',
'\U0001EE00', '\U0001EE06', '\U0001EE0A',
))
UNICODE_OTHER_ID_CONTINUE = set((
# Other_ID_Continue
'\xB7', '\u0387', '\u1369', '\u136A', '\u136B', '\u136C',
'\u136D', '\u136E', '\u136F', '\u1370', '\u1371', '\u19DA',
# New in Unicode 8.0
'\u08E3', '\uA69E', '\U00011730',
# New in Unicode 9.0
'\u08D4', '\u1DFB', '\uA8C5', '\U00011450',
'\U0001EE03', '\U0001EE0B',
))
UNICODE_COMBINING_MARK = set(U_CATEGORIES['Mn'] + U_CATEGORIES['Mc'])
UNICODE_DIGIT = set(U_CATEGORIES['Nd'])
UNICODE_CONNECTOR_PUNCTUATION = set(U_CATEGORIES['Pc'])
IDENTIFIER_START = UNICODE_LETTER.union(UNICODE_OTHER_ID_START).union(set(('$', '_', '\\')))
IDENTIFIER_PART = IDENTIFIER_START.union(UNICODE_COMBINING_MARK).union(UNICODE_DIGIT).union(UNICODE_CONNECTOR_PUNCTUATION).union(set(('\u200D', '\u200C'))).union(UNICODE_OTHER_ID_CONTINUE)
WHITE_SPACE = set((
'\x09', '\x0B', '\x0C', '\x20', '\xA0',
'\u1680', '\u180E', '\u2000', '\u2001', '\u2002',
'\u2003', '\u2004', '\u2005', '\u2006', '\u2007',
'\u2008', '\u2009', '\u200A', '\u202F', '\u205F',
'\u3000', '\uFEFF',
))
LINE_TERMINATOR = set(('\x0A', '\x0D', '\u2028', '\u2029'))
DECIMAL_CONV = dict((c, n) for n, c in enumerate('0123456789'))
OCTAL_CONV = dict((c, n) for n, c in enumerate('01234567'))
HEX_CONV = dict((c, n) for n, c in enumerate('0123456789abcdef'))
for n, c in enumerate('ABCDEF', 10):
HEX_CONV[c] = n
DECIMAL_DIGIT = set(DECIMAL_CONV.keys())
OCTAL_DIGIT = set(OCTAL_CONV.keys())
HEX_DIGIT = set(HEX_CONV.keys())
class Character:
@staticmethod
def fromCodePoint(code):
return uchr(code)
# https://tc39.github.io/ecma262/#sec-white-space
@staticmethod
def isWhiteSpace(ch):
return ch in WHITE_SPACE
# https://tc39.github.io/ecma262/#sec-line-terminators
@staticmethod
def isLineTerminator(ch):
return ch in LINE_TERMINATOR
# https://tc39.github.io/ecma262/#sec-names-and-keywords
@staticmethod
def isIdentifierStart(ch):
return ch in IDENTIFIER_START
@staticmethod
def isIdentifierPart(ch):
return ch in IDENTIFIER_PART
# https://tc39.github.io/ecma262/#sec-literals-numeric-literals
@staticmethod
def isDecimalDigit(ch):
return ch in DECIMAL_DIGIT
@staticmethod
def isHexDigit(ch):
return ch in HEX_DIGIT
@staticmethod
def isOctalDigit(ch):
return ch in OCTAL_DIGIT

176
third_party/python/esprima/esprima/comment_handler.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,176 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, self.list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, self.list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# self.SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES
# LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# self.SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from .objects import Object
from .nodes import Node
from .syntax import Syntax
class Comment(Node):
def __init__(self, type, value, range=None, loc=None):
self.type = type
self.value = value
self.range = range
self.loc = loc
class Entry(Object):
def __init__(self, comment, start):
self.comment = comment
self.start = start
class NodeInfo(Object):
def __init__(self, node, start):
self.node = node
self.start = start
class CommentHandler(object):
def __init__(self):
self.attach = False
self.comments = []
self.stack = []
self.leading = []
self.trailing = []
def insertInnerComments(self, node, metadata):
# innnerComments for properties empty block
# `function a(:/** comments **\/}`
if node.type is Syntax.BlockStatement and not node.body:
innerComments = []
for i, entry in enumerate(self.leading):
if metadata.end.offset >= entry.start:
innerComments.append(entry.comment)
self.leading[i] = None
self.trailing[i] = None
if innerComments:
node.innerComments = innerComments
self.leading = [v for v in self.leading if v is not None]
self.trailing = [v for v in self.trailing if v is not None]
def findTrailingComments(self, metadata):
trailingComments = []
if self.trailing:
for i, entry in enumerate(self.trailing):
if entry.start >= metadata.end.offset:
trailingComments.append(entry.comment)
if trailingComments:
self.trailing = []
return trailingComments
last = self.stack and self.stack[-1]
if last and last.node.trailingComments:
firstComment = last.node.trailingComments[0]
if firstComment and firstComment.range[0] >= metadata.end.offset:
trailingComments = last.node.trailingComments
del last.node.trailingComments
return trailingComments
def findLeadingComments(self, metadata):
leadingComments = []
target = None
while self.stack:
entry = self.stack and self.stack[-1]
if entry and entry.start >= metadata.start.offset:
target = entry.node
self.stack.pop()
else:
break
if target:
if target.leadingComments:
for i, comment in enumerate(target.leadingComments):
if comment.range[1] <= metadata.start.offset:
leadingComments.append(comment)
target.leadingComments[i] = None
if leadingComments:
target.leadingComments = [v for v in target.leadingComments if v is not None]
if not target.leadingComments:
del target.leadingComments
return leadingComments
for i, entry in enumerate(self.leading):
if entry.start <= metadata.start.offset:
leadingComments.append(entry.comment)
self.leading[i] = None
if leadingComments:
self.leading = [v for v in self.leading if v is not None]
return leadingComments
def visitNode(self, node, metadata):
if node.type is Syntax.Program and node.body:
return
self.insertInnerComments(node, metadata)
trailingComments = self.findTrailingComments(metadata)
leadingComments = self.findLeadingComments(metadata)
if leadingComments:
node.leadingComments = leadingComments
if trailingComments:
node.trailingComments = trailingComments
self.stack.append(NodeInfo(
node=node,
start=metadata.start.offset
))
def visitComment(self, node, metadata):
type = 'Line' if node.type[0] == 'L' else 'Block'
comment = Comment(
type=type,
value=node.value
)
if node.range:
comment.range = node.range
if node.loc:
comment.loc = node.loc
self.comments.append(comment)
if self.attach:
entry = Entry(
comment=Comment(
type=type,
value=node.value,
range=[metadata.start.offset, metadata.end.offset]
),
start=metadata.start.offset
)
if node.loc:
entry.comment.loc = node.loc
node.type = type
self.leading.append(entry)
self.trailing.append(entry)
def visit(self, node, metadata):
if node.type == 'LineComment':
self.visitComment(node, metadata)
elif node.type == 'BlockComment':
self.visitComment(node, metadata)
elif self.attach:
self.visitNode(node, metadata)

72
third_party/python/esprima/esprima/compat.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
import sys
PY3 = sys.version_info >= (3, 0)
if PY3:
# Python 3:
basestring = str
long = int
xrange = range
unicode = str
uchr = chr
def uord(ch):
return ord(ch[0])
else:
basestring = basestring
long = long
xrange = xrange
unicode = unicode
try:
# Python 2 UCS4:
unichr(0x10000)
uchr = unichr
def uord(ch):
return ord(ch[0])
except ValueError:
# Python 2 UCS2:
def uchr(code):
# UTF-16 Encoding
if code <= 0xFFFF:
return unichr(code)
cu1 = ((code - 0x10000) >> 10) + 0xD800
cu2 = ((code - 0x10000) & 1023) + 0xDC00
return unichr(cu1) + unichr(cu2)
def uord(ch):
cp = ord(ch[0])
if cp >= 0xD800 and cp <= 0xDBFF:
second = ord(ch[1])
if second >= 0xDC00 and second <= 0xDFFF:
first = cp
cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000
return cp

74
third_party/python/esprima/esprima/error_handler.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
from .compat import unicode
class Error(Exception):
def __init__(self, message, name=None, index=None, lineNumber=None, column=None, description=None):
super(Error, self).__init__(message)
self.message = message
self.name = name
self.index = index
self.lineNumber = lineNumber
self.column = column
# self.description = description
def toString(self):
return '%s: %s' % (self.__class__.__name__, self)
def toDict(self):
d = dict((unicode(k), v) for k, v in self.__dict__.items() if v is not None)
d['message'] = self.toString()
return d
class ErrorHandler:
def __init__(self):
self.errors = []
self.tolerant = False
def recordError(self, error):
self.errors.append(error.toDict())
def tolerate(self, error):
if self.tolerant:
self.recordError(error)
else:
raise error
def createError(self, index, line, col, description):
msg = 'Line %s: %s' % (line, description)
return Error(msg, index=index, lineNumber=line, column=col, description=description)
def throwError(self, index, line, col, description):
raise self.createError(index, line, col, description)
def tolerateError(self, index, line, col, description):
error = self.createError(index, line, col, description)
if self.tolerant:
self.recordError(error)
else:
raise error

125
third_party/python/esprima/esprima/esprima.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from .comment_handler import CommentHandler
from .error_handler import Error
from .jsx_parser import JSXParser
from .jsx_syntax import JSXSyntax
from .objects import Array, toDict
from .parser import Parser
from .syntax import Syntax
from .tokenizer import Tokenizer
from .visitor import NodeVisitor
from . import nodes
from . import jsx_nodes
__all__ = ['Syntax', 'JSXSyntax', 'Error', 'NodeVisitor', 'nodes', 'jsx_nodes',
'parse', 'parseModule', 'parseScript', 'tokenize', 'toDict']
def parse(code, options=None, delegate=None, **kwargs):
options = {} if options is None else options.copy()
options.update(kwargs)
# ESNext presset:
if options.get('esnext', False):
options['jsx'] = True
options['classProperties'] = True
commentHandler = None
def proxyDelegate(node, metadata):
if delegate:
new_node = delegate(node, metadata)
if new_node is not None:
node = new_node
if commentHandler:
commentHandler.visit(node, metadata)
return node
parserDelegate = None if delegate is None else proxyDelegate
collectComment = options.get('comment', False)
attachComment = options.get('attachComment', False)
if collectComment or attachComment:
commentHandler = CommentHandler()
commentHandler.attach = attachComment
options['comment'] = True
parserDelegate = proxyDelegate
isModule = options.get('sourceType', 'script') == 'module'
if options.get('jsx', False):
parser = JSXParser(code, options=options, delegate=parserDelegate)
else:
parser = Parser(code, options=options, delegate=parserDelegate)
ast = parser.parseModule() if isModule else parser.parseScript()
if collectComment and commentHandler:
ast.comments = commentHandler.comments
if parser.config.tokens:
ast.tokens = parser.tokens
if parser.config.tolerant:
ast.errors = parser.errorHandler.errors
return ast
def parseModule(code, options=None, delegate=None, **kwargs):
kwargs['sourceType'] = 'module'
return parse(code, options, delegate, **kwargs)
def parseScript(code, options=None, delegate=None, **kwargs):
kwargs['sourceType'] = 'script'
return parse(code, options, delegate, **kwargs)
def tokenize(code, options=None, delegate=None, **kwargs):
options = {} if options is None else options.copy()
options.update(kwargs)
tokenizer = Tokenizer(code, options)
tokens = Array()
try:
while True:
token = tokenizer.getNextToken()
if not token:
break
if delegate:
token = delegate(token)
tokens.append(token)
except Error as e:
tokenizer.errorHandler.tolerate(e)
if tokenizer.errorHandler.tolerant:
tokens.errors = tokenizer.errors()
return tokens

100
third_party/python/esprima/esprima/jsx_nodes.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from .nodes import Node
from .jsx_syntax import JSXSyntax
class JSXClosingElement(Node):
def __init__(self, name):
self.type = JSXSyntax.JSXClosingElement
self.name = name
class JSXElement(Node):
def __init__(self, openingElement, children, closingElement):
self.type = JSXSyntax.JSXElement
self.openingElement = openingElement
self.children = children
self.closingElement = closingElement
class JSXEmptyExpression(Node):
def __init__(self):
self.type = JSXSyntax.JSXEmptyExpression
class JSXExpressionContainer(Node):
def __init__(self, expression):
self.type = JSXSyntax.JSXExpressionContainer
self.expression = expression
class JSXIdentifier(Node):
def __init__(self, name):
self.type = JSXSyntax.JSXIdentifier
self.name = name
class JSXMemberExpression(Node):
def __init__(self, object, property):
self.type = JSXSyntax.JSXMemberExpression
self.object = object
self.property = property
class JSXAttribute(Node):
def __init__(self, name, value):
self.type = JSXSyntax.JSXAttribute
self.name = name
self.value = value
class JSXNamespacedName(Node):
def __init__(self, namespace, name):
self.type = JSXSyntax.JSXNamespacedName
self.namespace = namespace
self.name = name
class JSXOpeningElement(Node):
def __init__(self, name, selfClosing, attributes):
self.type = JSXSyntax.JSXOpeningElement
self.name = name
self.selfClosing = selfClosing
self.attributes = attributes
class JSXSpreadAttribute(Node):
def __init__(self, argument):
self.type = JSXSyntax.JSXSpreadAttribute
self.argument = argument
class JSXText(Node):
def __init__(self, value, raw):
self.type = JSXSyntax.JSXText
self.value = value
self.raw = raw

584
third_party/python/esprima/esprima/jsx_parser.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,584 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from .compat import uchr
from .character import Character
from . import jsx_nodes as JSXNode
from .jsx_syntax import JSXSyntax
from . import nodes as Node
from .parser import Marker, Parser
from .token import Token, TokenName
from .xhtml_entities import XHTMLEntities
class MetaJSXElement(object):
def __init__(self, node=None, opening=None, closing=None, children=None):
self.node = node
self.opening = opening
self.closing = closing
self.children = children
class JSXToken(object):
Identifier = 100
Text = 101
class RawJSXToken(object):
def __init__(self, type=None, value=None, lineNumber=None, lineStart=None, start=None, end=None):
self.type = type
self.value = value
self.lineNumber = lineNumber
self.lineStart = lineStart
self.start = start
self.end = end
TokenName[JSXToken.Identifier] = "JSXIdentifier"
TokenName[JSXToken.Text] = "JSXText"
# Fully qualified element name, e.g. <svg:path> returns "svg:path"
def getQualifiedElementName(elementName):
typ = elementName.type
if typ is JSXSyntax.JSXIdentifier:
id = elementName
qualifiedName = id.name
elif typ is JSXSyntax.JSXNamespacedName:
ns = elementName
qualifiedName = getQualifiedElementName(ns.namespace) + ':' + getQualifiedElementName(ns.name)
elif typ is JSXSyntax.JSXMemberExpression:
expr = elementName
qualifiedName = getQualifiedElementName(expr.object) + '.' + getQualifiedElementName(expr.property)
return qualifiedName
class JSXParser(Parser):
def __init__(self, code, options, delegate):
super(JSXParser, self).__init__(code, options, delegate)
def parsePrimaryExpression(self):
return self.parseJSXRoot() if self.match('<') else super(JSXParser, self).parsePrimaryExpression()
def startJSX(self):
# Unwind the scanner before the lookahead token.
self.scanner.index = self.startMarker.index
self.scanner.lineNumber = self.startMarker.line
self.scanner.lineStart = self.startMarker.index - self.startMarker.column
def finishJSX(self):
# Prime the next lookahead.
self.nextToken()
def reenterJSX(self):
self.startJSX()
self.expectJSX('}')
# Pop the closing '}' added from the lookahead.
if self.config.tokens:
self.tokens.pop()
def createJSXNode(self):
self.collectComments()
return Marker(
index=self.scanner.index,
line=self.scanner.lineNumber,
column=self.scanner.index - self.scanner.lineStart
)
def createJSXChildNode(self):
return Marker(
index=self.scanner.index,
line=self.scanner.lineNumber,
column=self.scanner.index - self.scanner.lineStart
)
def scanXHTMLEntity(self, quote):
result = '&'
valid = True
terminated = False
numeric = False
hex = False
while not self.scanner.eof() and valid and not terminated:
ch = self.scanner.source[self.scanner.index]
if ch == quote:
break
terminated = (ch == ';')
result += ch
self.scanner.index += 1
if not terminated:
length = len(result)
if length == 2:
# e.g. '&#123;'
numeric = (ch == '#')
elif length == 3:
if numeric:
# e.g. '&#x41;'
hex = ch == 'x'
valid = hex or Character.isDecimalDigit(ch)
numeric = numeric and not hex
else:
valid = valid and not (numeric and not Character.isDecimalDigit(ch))
valid = valid and not (hex and not Character.isHexDigit(ch))
if valid and terminated and len(result) > 2:
# e.g. '&#x41;' becomes just '#x41'
st = result[1:-1]
if numeric and len(st) > 1:
result = uchr(int(st[1:], 10))
elif hex and len(st) > 2:
result = uchr(int(st[2:], 16))
elif not numeric and not hex and st in XHTMLEntities:
result = XHTMLEntities[st]
return result
# Scan the next JSX token. This replaces Scanner#lex when in JSX mode.
def lexJSX(self):
ch = self.scanner.source[self.scanner.index]
# < > / : = { }
if ch in ('<', '>', '/', ':', '=', '{', '}'):
value = self.scanner.source[self.scanner.index]
self.scanner.index += 1
return RawJSXToken(
type=Token.Punctuator,
value=value,
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=self.scanner.index - 1,
end=self.scanner.index
)
# " '
if ch in ('\'', '"'):
start = self.scanner.index
quote = self.scanner.source[self.scanner.index]
self.scanner.index += 1
str = ''
while not self.scanner.eof():
ch = self.scanner.source[self.scanner.index]
self.scanner.index += 1
if ch == quote:
break
elif ch == '&':
str += self.scanXHTMLEntity(quote)
else:
str += ch
return RawJSXToken(
type=Token.StringLiteral,
value=str,
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=start,
end=self.scanner.index
)
# ... or .
if ch == '.':
start = self.scanner.index
if self.scanner.source[start + 1:start + 3] == '..':
value = '...'
self.scanner.index += 3
else:
value = '.'
self.scanner.index += 1
return RawJSXToken(
type=Token.Punctuator,
value=value,
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=start,
end=self.scanner.index
)
# `
if ch == '`':
# Only placeholder, since it will be rescanned as a real assignment expression.
return RawJSXToken(
type=Token.Template,
value='',
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=self.scanner.index,
end=self.scanner.index
)
# Identifer can not contain backslash (char code 92).
if Character.isIdentifierStart(ch) and ch != '\\':
start = self.scanner.index
self.scanner.index += 1
while not self.scanner.eof():
ch = self.scanner.source[self.scanner.index]
if Character.isIdentifierPart(ch) and ch != '\\':
self.scanner.index += 1
elif ch == '-':
# Hyphen (char code 45) can be part of an identifier.
self.scanner.index += 1
else:
break
id = self.scanner.source[start:self.scanner.index]
return RawJSXToken(
type=JSXToken.Identifier,
value=id,
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=start,
end=self.scanner.index
)
return self.scanner.lex()
def nextJSXToken(self):
self.collectComments()
self.startMarker.index = self.scanner.index
self.startMarker.line = self.scanner.lineNumber
self.startMarker.column = self.scanner.index - self.scanner.lineStart
token = self.lexJSX()
self.lastMarker.index = self.scanner.index
self.lastMarker.line = self.scanner.lineNumber
self.lastMarker.column = self.scanner.index - self.scanner.lineStart
if self.config.tokens:
self.tokens.append(self.convertToken(token))
return token
def nextJSXText(self):
self.startMarker.index = self.scanner.index
self.startMarker.line = self.scanner.lineNumber
self.startMarker.column = self.scanner.index - self.scanner.lineStart
start = self.scanner.index
text = ''
while not self.scanner.eof():
ch = self.scanner.source[self.scanner.index]
if ch in ('{', '<'):
break
self.scanner.index += 1
text += ch
if Character.isLineTerminator(ch):
self.scanner.lineNumber += 1
if ch == '\r' and self.scanner.source[self.scanner.index] == '\n':
self.scanner.index += 1
self.scanner.lineStart = self.scanner.index
self.lastMarker.index = self.scanner.index
self.lastMarker.line = self.scanner.lineNumber
self.lastMarker.column = self.scanner.index - self.scanner.lineStart
token = RawJSXToken(
type=JSXToken.Text,
value=text,
lineNumber=self.scanner.lineNumber,
lineStart=self.scanner.lineStart,
start=start,
end=self.scanner.index
)
if text and self.config.tokens:
self.tokens.append(self.convertToken(token))
return token
def peekJSXToken(self):
state = self.scanner.saveState()
self.scanner.scanComments()
next = self.lexJSX()
self.scanner.restoreState(state)
return next
# Expect the next JSX token to match the specified punctuator.
# If not, an exception will be thrown.
def expectJSX(self, value):
token = self.nextJSXToken()
if token.type is not Token.Punctuator or token.value != value:
self.throwUnexpectedToken(token)
# Return True if the next JSX token matches the specified punctuator.
def matchJSX(self, *value):
next = self.peekJSXToken()
return next.type is Token.Punctuator and next.value in value
def parseJSXIdentifier(self):
node = self.createJSXNode()
token = self.nextJSXToken()
if token.type is not JSXToken.Identifier:
self.throwUnexpectedToken(token)
return self.finalize(node, JSXNode.JSXIdentifier(token.value))
def parseJSXElementName(self):
node = self.createJSXNode()
elementName = self.parseJSXIdentifier()
if self.matchJSX(':'):
namespace = elementName
self.expectJSX(':')
name = self.parseJSXIdentifier()
elementName = self.finalize(node, JSXNode.JSXNamespacedName(namespace, name))
elif self.matchJSX('.'):
while self.matchJSX('.'):
object = elementName
self.expectJSX('.')
property = self.parseJSXIdentifier()
elementName = self.finalize(node, JSXNode.JSXMemberExpression(object, property))
return elementName
def parseJSXAttributeName(self):
node = self.createJSXNode()
identifier = self.parseJSXIdentifier()
if self.matchJSX(':'):
namespace = identifier
self.expectJSX(':')
name = self.parseJSXIdentifier()
attributeName = self.finalize(node, JSXNode.JSXNamespacedName(namespace, name))
else:
attributeName = identifier
return attributeName
def parseJSXStringLiteralAttribute(self):
node = self.createJSXNode()
token = self.nextJSXToken()
if token.type is not Token.StringLiteral:
self.throwUnexpectedToken(token)
raw = self.getTokenRaw(token)
return self.finalize(node, Node.Literal(token.value, raw))
def parseJSXExpressionAttribute(self):
node = self.createJSXNode()
self.expectJSX('{')
self.finishJSX()
if self.match('}'):
self.tolerateError('JSX attributes must only be assigned a non-empty expression')
expression = self.parseAssignmentExpression()
self.reenterJSX()
return self.finalize(node, JSXNode.JSXExpressionContainer(expression))
def parseJSXAttributeValue(self):
if self.matchJSX('{'):
return self.parseJSXExpressionAttribute()
if self.matchJSX('<'):
return self.parseJSXElement()
return self.parseJSXStringLiteralAttribute()
def parseJSXNameValueAttribute(self):
node = self.createJSXNode()
name = self.parseJSXAttributeName()
value = None
if self.matchJSX('='):
self.expectJSX('=')
value = self.parseJSXAttributeValue()
return self.finalize(node, JSXNode.JSXAttribute(name, value))
def parseJSXSpreadAttribute(self):
node = self.createJSXNode()
self.expectJSX('{')
self.expectJSX('...')
self.finishJSX()
argument = self.parseAssignmentExpression()
self.reenterJSX()
return self.finalize(node, JSXNode.JSXSpreadAttribute(argument))
def parseJSXAttributes(self):
attributes = []
while not self.matchJSX('/', '>'):
attribute = self.parseJSXSpreadAttribute() if self.matchJSX('{') else self.parseJSXNameValueAttribute()
attributes.append(attribute)
return attributes
def parseJSXOpeningElement(self):
node = self.createJSXNode()
self.expectJSX('<')
name = self.parseJSXElementName()
attributes = self.parseJSXAttributes()
selfClosing = self.matchJSX('/')
if selfClosing:
self.expectJSX('/')
self.expectJSX('>')
return self.finalize(node, JSXNode.JSXOpeningElement(name, selfClosing, attributes))
def parseJSXBoundaryElement(self):
node = self.createJSXNode()
self.expectJSX('<')
if self.matchJSX('/'):
self.expectJSX('/')
elementName = self.parseJSXElementName()
self.expectJSX('>')
return self.finalize(node, JSXNode.JSXClosingElement(elementName))
name = self.parseJSXElementName()
attributes = self.parseJSXAttributes()
selfClosing = self.matchJSX('/')
if selfClosing:
self.expectJSX('/')
self.expectJSX('>')
return self.finalize(node, JSXNode.JSXOpeningElement(name, selfClosing, attributes))
def parseJSXEmptyExpression(self):
node = self.createJSXChildNode()
self.collectComments()
self.lastMarker.index = self.scanner.index
self.lastMarker.line = self.scanner.lineNumber
self.lastMarker.column = self.scanner.index - self.scanner.lineStart
return self.finalize(node, JSXNode.JSXEmptyExpression())
def parseJSXExpressionContainer(self):
node = self.createJSXNode()
self.expectJSX('{')
if self.matchJSX('}'):
expression = self.parseJSXEmptyExpression()
self.expectJSX('}')
else:
self.finishJSX()
expression = self.parseAssignmentExpression()
self.reenterJSX()
return self.finalize(node, JSXNode.JSXExpressionContainer(expression))
def parseJSXChildren(self):
children = []
while not self.scanner.eof():
node = self.createJSXChildNode()
token = self.nextJSXText()
if token.start < token.end:
raw = self.getTokenRaw(token)
child = self.finalize(node, JSXNode.JSXText(token.value, raw))
children.append(child)
if self.scanner.source[self.scanner.index] == '{':
container = self.parseJSXExpressionContainer()
children.append(container)
else:
break
return children
def parseComplexJSXElement(self, el):
stack = []
while not self.scanner.eof():
el.children.extend(self.parseJSXChildren())
node = self.createJSXChildNode()
element = self.parseJSXBoundaryElement()
if element.type is JSXSyntax.JSXOpeningElement:
opening = element
if opening.selfClosing:
child = self.finalize(node, JSXNode.JSXElement(opening, [], None))
el.children.append(child)
else:
stack.append(el)
el = MetaJSXElement(
node=node,
opening=opening,
closing=None,
children=[],
)
if element.type is JSXSyntax.JSXClosingElement:
el.closing = element
open = getQualifiedElementName(el.opening.name)
close = getQualifiedElementName(el.closing.name)
if open != close:
self.tolerateError('Expected corresponding JSX closing tag for %0', open)
if stack:
child = self.finalize(el.node, JSXNode.JSXElement(el.opening, el.children, el.closing))
el = stack[-1]
el.children.append(child)
stack.pop()
else:
break
return el
def parseJSXElement(self):
node = self.createJSXNode()
opening = self.parseJSXOpeningElement()
children = []
closing = None
if not opening.selfClosing:
el = self.parseComplexJSXElement(MetaJSXElement(
node=node,
opening=opening,
closing=closing,
children=children
))
children = el.children
closing = el.closing
return self.finalize(node, JSXNode.JSXElement(opening, children, closing))
def parseJSXRoot(self):
# Pop the opening '<' added from the lookahead.
if self.config.tokens:
self.tokens.pop()
self.startJSX()
element = self.parseJSXElement()
self.finishJSX()
return element
def isStartOfExpression(self):
return super(JSXParser, self).isStartOfExpression() or self.match('<')

38
third_party/python/esprima/esprima/jsx_syntax.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
class JSXSyntax:
JSXAttribute = "JSXAttribute"
JSXClosingElement = "JSXClosingElement"
JSXElement = "JSXElement"
JSXEmptyExpression = "JSXEmptyExpression"
JSXExpressionContainer = "JSXExpressionContainer"
JSXIdentifier = "JSXIdentifier"
JSXMemberExpression = "JSXMemberExpression"
JSXNamespacedName = "JSXNamespacedName"
JSXOpeningElement = "JSXOpeningElement"
JSXSpreadAttribute = "JSXSpreadAttribute"
JSXText = "JSXText"

90
third_party/python/esprima/esprima/messages.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
# Error messages should be identical to V8.
class Messages:
ObjectPatternAsRestParameter = "Unexpected token {"
BadImportCallArity = "Unexpected token"
BadGetterArity = "Getter must not have any formal parameters"
BadSetterArity = "Setter must have exactly one formal parameter"
BadSetterRestParameter = "Setter function argument must not be a rest parameter"
ConstructorIsAsync = "Class constructor may not be an async method"
ConstructorSpecialMethod = "Class constructor may not be an accessor"
DeclarationMissingInitializer = "Missing initializer in %0 declaration"
DefaultRestParameter = "Unexpected token ="
DefaultRestProperty = "Unexpected token ="
DuplicateBinding = "Duplicate binding %0"
DuplicateConstructor = "A class may only have one constructor"
DuplicateProtoProperty = "Duplicate __proto__ fields are not allowed in object literals"
ForInOfLoopInitializer = "%0 loop variable declaration may not have an initializer"
GeneratorInLegacyContext = "Generator declarations are not allowed in legacy contexts"
IllegalBreak = "Illegal break statement"
IllegalContinue = "Illegal continue statement"
IllegalExportDeclaration = "Unexpected token"
IllegalImportDeclaration = "Unexpected token"
IllegalLanguageModeDirective = "Illegal 'use strict' directive in function with non-simple parameter list"
IllegalReturn = "Illegal return statement"
InvalidEscapedReservedWord = "Keyword must not contain escaped characters"
InvalidHexEscapeSequence = "Invalid hexadecimal escape sequence"
InvalidLHSInAssignment = "Invalid left-hand side in assignment"
InvalidLHSInForIn = "Invalid left-hand side in for-in"
InvalidLHSInForLoop = "Invalid left-hand side in for-loop"
InvalidModuleSpecifier = "Unexpected token"
InvalidRegExp = "Invalid regular expression"
LetInLexicalBinding = "let is disallowed as a lexically bound name"
MissingFromClause = "Unexpected token"
MultipleDefaultsInSwitch = "More than one default clause in switch statement"
NewlineAfterThrow = "Illegal newline after throw"
NoAsAfterImportNamespace = "Unexpected token"
NoCatchOrFinally = "Missing catch or finally after try"
ParameterAfterRestParameter = "Rest parameter must be last formal parameter"
PropertyAfterRestProperty = "Unexpected token"
Redeclaration = "%0 '%1' has already been declared"
StaticPrototype = "Classes may not have static property named prototype"
StrictCatchVariable = "Catch variable may not be eval or arguments in strict mode"
StrictDelete = "Delete of an unqualified identifier in strict mode."
StrictFunction = "In strict mode code, functions can only be declared at top level or inside a block"
StrictFunctionName = "Function name may not be eval or arguments in strict mode"
StrictLHSAssignment = "Assignment to eval or arguments is not allowed in strict mode"
StrictLHSPostfix = "Postfix increment/decrement may not have eval or arguments operand in strict mode"
StrictLHSPrefix = "Prefix increment/decrement may not have eval or arguments operand in strict mode"
StrictModeWith = "Strict mode code may not include a with statement"
StrictOctalLiteral = "Octal literals are not allowed in strict mode."
StrictParamDupe = "Strict mode function may not have duplicate parameter names"
StrictParamName = "Parameter name eval or arguments is not allowed in strict mode"
StrictReservedWord = "Use of future reserved word in strict mode"
StrictVarName = "Variable name may not be eval or arguments in strict mode"
TemplateOctalLiteral = "Octal literals are not allowed in template strings."
UnexpectedEOS = "Unexpected end of input"
UnexpectedIdentifier = "Unexpected identifier"
UnexpectedNumber = "Unexpected number"
UnexpectedReserved = "Unexpected reserved word"
UnexpectedString = "Unexpected string"
UnexpectedTemplate = "Unexpected quasi %0"
UnexpectedToken = "Unexpected token %0"
UnexpectedTokenIllegal = "Unexpected token ILLEGAL"
UnknownLabel = "Undefined label '%0'"
UnterminatedRegExp = "Invalid regular expression: missing /"

620
third_party/python/esprima/esprima/nodes.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,620 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from .objects import Object
from .syntax import Syntax
from .scanner import RegExp
class Node(Object):
def __dir__(self):
return list(self.__dict__.keys())
def __iter__(self):
return self.__iter__
def keys(self):
return self.__dict__.keys()
def items(self):
return self.__dict__.items()
class ArrayExpression(Node):
def __init__(self, elements):
self.type = Syntax.ArrayExpression
self.elements = elements
class ArrayPattern(Node):
def __init__(self, elements):
self.type = Syntax.ArrayPattern
self.elements = elements
class ArrowFunctionExpression(Node):
def __init__(self, params, body, expression):
self.type = Syntax.ArrowFunctionExpression
self.generator = False
self.isAsync = False
self.params = params
self.body = body
self.expression = expression
class AssignmentExpression(Node):
def __init__(self, operator, left, right):
self.type = Syntax.AssignmentExpression
self.operator = operator
self.left = left
self.right = right
class AssignmentPattern(Node):
def __init__(self, left, right):
self.type = Syntax.AssignmentPattern
self.left = left
self.right = right
class AsyncArrowFunctionExpression(Node):
def __init__(self, params, body, expression):
self.type = Syntax.ArrowFunctionExpression
self.generator = False
self.isAsync = True
self.params = params
self.body = body
self.expression = expression
class AsyncFunctionDeclaration(Node):
def __init__(self, id, params, body):
self.type = Syntax.FunctionDeclaration
self.generator = False
self.expression = False
self.isAsync = True
self.id = id
self.params = params
self.body = body
class AsyncFunctionExpression(Node):
def __init__(self, id, params, body):
self.type = Syntax.FunctionExpression
self.generator = False
self.expression = False
self.isAsync = True
self.id = id
self.params = params
self.body = body
class AwaitExpression(Node):
def __init__(self, argument):
self.type = Syntax.AwaitExpression
self.argument = argument
class BinaryExpression(Node):
def __init__(self, operator, left, right):
self.type = Syntax.LogicalExpression if operator in ('||', '&&') else Syntax.BinaryExpression
self.operator = operator
self.left = left
self.right = right
class BlockStatement(Node):
def __init__(self, body):
self.type = Syntax.BlockStatement
self.body = body
class BreakStatement(Node):
def __init__(self, label):
self.type = Syntax.BreakStatement
self.label = label
class CallExpression(Node):
def __init__(self, callee, args):
self.type = Syntax.CallExpression
self.callee = callee
self.arguments = args
class CatchClause(Node):
def __init__(self, param, body):
self.type = Syntax.CatchClause
self.param = param
self.body = body
class ClassBody(Node):
def __init__(self, body):
self.type = Syntax.ClassBody
self.body = body
class ClassDeclaration(Node):
def __init__(self, id, superClass, body):
self.type = Syntax.ClassDeclaration
self.id = id
self.superClass = superClass
self.body = body
class ClassExpression(Node):
def __init__(self, id, superClass, body):
self.type = Syntax.ClassExpression
self.id = id
self.superClass = superClass
self.body = body
class ComputedMemberExpression(Node):
def __init__(self, object, property):
self.type = Syntax.MemberExpression
self.computed = True
self.object = object
self.property = property
class ConditionalExpression(Node):
def __init__(self, test, consequent, alternate):
self.type = Syntax.ConditionalExpression
self.test = test
self.consequent = consequent
self.alternate = alternate
class ContinueStatement(Node):
def __init__(self, label):
self.type = Syntax.ContinueStatement
self.label = label
class DebuggerStatement(Node):
def __init__(self):
self.type = Syntax.DebuggerStatement
class Directive(Node):
def __init__(self, expression, directive):
self.type = Syntax.ExpressionStatement
self.expression = expression
self.directive = directive
class DoWhileStatement(Node):
def __init__(self, body, test):
self.type = Syntax.DoWhileStatement
self.body = body
self.test = test
class EmptyStatement(Node):
def __init__(self):
self.type = Syntax.EmptyStatement
class ExportAllDeclaration(Node):
def __init__(self, source):
self.type = Syntax.ExportAllDeclaration
self.source = source
class ExportDefaultDeclaration(Node):
def __init__(self, declaration):
self.type = Syntax.ExportDefaultDeclaration
self.declaration = declaration
class ExportNamedDeclaration(Node):
def __init__(self, declaration, specifiers, source):
self.type = Syntax.ExportNamedDeclaration
self.declaration = declaration
self.specifiers = specifiers
self.source = source
class ExportSpecifier(Node):
def __init__(self, local, exported):
self.type = Syntax.ExportSpecifier
self.exported = exported
self.local = local
class ExportDefaultSpecifier(Node):
def __init__(self, local):
self.type = Syntax.ExportDefaultSpecifier
self.local = local
class ExpressionStatement(Node):
def __init__(self, expression):
self.type = Syntax.ExpressionStatement
self.expression = expression
class ForInStatement(Node):
def __init__(self, left, right, body):
self.type = Syntax.ForInStatement
self.each = False
self.left = left
self.right = right
self.body = body
class ForOfStatement(Node):
def __init__(self, left, right, body):
self.type = Syntax.ForOfStatement
self.left = left
self.right = right
self.body = body
class ForStatement(Node):
def __init__(self, init, test, update, body):
self.type = Syntax.ForStatement
self.init = init
self.test = test
self.update = update
self.body = body
class FunctionDeclaration(Node):
def __init__(self, id, params, body, generator):
self.type = Syntax.FunctionDeclaration
self.expression = False
self.isAsync = False
self.id = id
self.params = params
self.body = body
self.generator = generator
class FunctionExpression(Node):
def __init__(self, id, params, body, generator):
self.type = Syntax.FunctionExpression
self.expression = False
self.isAsync = False
self.id = id
self.params = params
self.body = body
self.generator = generator
class Identifier(Node):
def __init__(self, name):
self.type = Syntax.Identifier
self.name = name
class IfStatement(Node):
def __init__(self, test, consequent, alternate):
self.type = Syntax.IfStatement
self.test = test
self.consequent = consequent
self.alternate = alternate
class Import(Node):
def __init__(self):
self.type = Syntax.Import
class ImportDeclaration(Node):
def __init__(self, specifiers, source):
self.type = Syntax.ImportDeclaration
self.specifiers = specifiers
self.source = source
class ImportDefaultSpecifier(Node):
def __init__(self, local):
self.type = Syntax.ImportDefaultSpecifier
self.local = local
class ImportNamespaceSpecifier(Node):
def __init__(self, local):
self.type = Syntax.ImportNamespaceSpecifier
self.local = local
class ImportSpecifier(Node):
def __init__(self, local, imported):
self.type = Syntax.ImportSpecifier
self.local = local
self.imported = imported
class LabeledStatement(Node):
def __init__(self, label, body):
self.type = Syntax.LabeledStatement
self.label = label
self.body = body
class Literal(Node):
def __init__(self, value, raw):
self.type = Syntax.Literal
self.value = value
self.raw = raw
class MetaProperty(Node):
def __init__(self, meta, property):
self.type = Syntax.MetaProperty
self.meta = meta
self.property = property
class MethodDefinition(Node):
def __init__(self, key, computed, value, kind, isStatic):
self.type = Syntax.MethodDefinition
self.key = key
self.computed = computed
self.value = value
self.kind = kind
self.static = isStatic
class FieldDefinition(Node):
def __init__(self, key, computed, value, kind, isStatic):
self.type = Syntax.FieldDefinition
self.key = key
self.computed = computed
self.value = value
self.kind = kind
self.static = isStatic
class Module(Node):
def __init__(self, body):
self.type = Syntax.Program
self.sourceType = 'module'
self.body = body
class NewExpression(Node):
def __init__(self, callee, args):
self.type = Syntax.NewExpression
self.callee = callee
self.arguments = args
class ObjectExpression(Node):
def __init__(self, properties):
self.type = Syntax.ObjectExpression
self.properties = properties
class ObjectPattern(Node):
def __init__(self, properties):
self.type = Syntax.ObjectPattern
self.properties = properties
class Property(Node):
def __init__(self, kind, key, computed, value, method, shorthand):
self.type = Syntax.Property
self.key = key
self.computed = computed
self.value = value
self.kind = kind
self.method = method
self.shorthand = shorthand
class RegexLiteral(Node):
def __init__(self, value, raw, pattern, flags):
self.type = Syntax.Literal
self.value = value
self.raw = raw
self.regex = RegExp(
pattern=pattern,
flags=flags,
)
class RestElement(Node):
def __init__(self, argument):
self.type = Syntax.RestElement
self.argument = argument
class ReturnStatement(Node):
def __init__(self, argument):
self.type = Syntax.ReturnStatement
self.argument = argument
class Script(Node):
def __init__(self, body):
self.type = Syntax.Program
self.sourceType = 'script'
self.body = body
class SequenceExpression(Node):
def __init__(self, expressions):
self.type = Syntax.SequenceExpression
self.expressions = expressions
class SpreadElement(Node):
def __init__(self, argument):
self.type = Syntax.SpreadElement
self.argument = argument
class StaticMemberExpression(Node):
def __init__(self, object, property):
self.type = Syntax.MemberExpression
self.computed = False
self.object = object
self.property = property
class Super(Node):
def __init__(self):
self.type = Syntax.Super
class SwitchCase(Node):
def __init__(self, test, consequent):
self.type = Syntax.SwitchCase
self.test = test
self.consequent = consequent
class SwitchStatement(Node):
def __init__(self, discriminant, cases):
self.type = Syntax.SwitchStatement
self.discriminant = discriminant
self.cases = cases
class TaggedTemplateExpression(Node):
def __init__(self, tag, quasi):
self.type = Syntax.TaggedTemplateExpression
self.tag = tag
self.quasi = quasi
class TemplateElement(Node):
class Value(Object):
def __init__(self, raw, cooked):
self.raw = raw
self.cooked = cooked
def __init__(self, raw, cooked, tail):
self.type = Syntax.TemplateElement
self.value = TemplateElement.Value(raw, cooked)
self.tail = tail
class TemplateLiteral(Node):
def __init__(self, quasis, expressions):
self.type = Syntax.TemplateLiteral
self.quasis = quasis
self.expressions = expressions
class ThisExpression(Node):
def __init__(self):
self.type = Syntax.ThisExpression
class ThrowStatement(Node):
def __init__(self, argument):
self.type = Syntax.ThrowStatement
self.argument = argument
class TryStatement(Node):
def __init__(self, block, handler, finalizer):
self.type = Syntax.TryStatement
self.block = block
self.handler = handler
self.finalizer = finalizer
class UnaryExpression(Node):
def __init__(self, operator, argument):
self.type = Syntax.UnaryExpression
self.prefix = True
self.operator = operator
self.argument = argument
class UpdateExpression(Node):
def __init__(self, operator, argument, prefix):
self.type = Syntax.UpdateExpression
self.operator = operator
self.argument = argument
self.prefix = prefix
class VariableDeclaration(Node):
def __init__(self, declarations, kind):
self.type = Syntax.VariableDeclaration
self.declarations = declarations
self.kind = kind
class VariableDeclarator(Node):
def __init__(self, id, init):
self.type = Syntax.VariableDeclarator
self.id = id
self.init = init
class WhileStatement(Node):
def __init__(self, test, body):
self.type = Syntax.WhileStatement
self.test = test
self.body = body
class WithStatement(Node):
def __init__(self, object, body):
self.type = Syntax.WithStatement
self.object = object
self.body = body
class YieldExpression(Node):
def __init__(self, argument, delegate):
self.type = Syntax.YieldExpression
self.argument = argument
self.delegate = delegate
class ArrowParameterPlaceHolder(Node):
def __init__(self, params):
self.type = Syntax.ArrowParameterPlaceHolder
self.params = params
self.isAsync = False
class AsyncArrowParameterPlaceHolder(Node):
def __init__(self, params):
self.type = Syntax.ArrowParameterPlaceHolder
self.params = params
self.isAsync = True
class BlockComment(Node):
def __init__(self, value):
self.type = Syntax.BlockComment
self.value = value
class LineComment(Node):
def __init__(self, value):
self.type = Syntax.LineComment
self.value = value

46
third_party/python/esprima/esprima/objects.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
def toDict(value):
from .visitor import ToDictVisitor
return ToDictVisitor().visit(value)
class Array(list):
pass
class Object(object):
def toDict(self):
from .visitor import ToDictVisitor
return ToDictVisitor().visit(self)
def __repr__(self):
from .visitor import ReprVisitor
return ReprVisitor().visit(self)
def __getattr__(self, name):
return None

3104
third_party/python/esprima/esprima/parser.py поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1189
third_party/python/esprima/esprima/scanner.py поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

100
third_party/python/esprima/esprima/syntax.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
class Syntax:
AssignmentExpression = "AssignmentExpression"
AssignmentPattern = "AssignmentPattern"
ArrayExpression = "ArrayExpression"
ArrayPattern = "ArrayPattern"
ArrowFunctionExpression = "ArrowFunctionExpression"
AwaitExpression = "AwaitExpression"
BlockStatement = "BlockStatement"
BinaryExpression = "BinaryExpression"
BreakStatement = "BreakStatement"
CallExpression = "CallExpression"
CatchClause = "CatchClause"
ClassBody = "ClassBody"
ClassDeclaration = "ClassDeclaration"
ClassExpression = "ClassExpression"
ConditionalExpression = "ConditionalExpression"
ContinueStatement = "ContinueStatement"
DoWhileStatement = "DoWhileStatement"
DebuggerStatement = "DebuggerStatement"
EmptyStatement = "EmptyStatement"
ExportAllDeclaration = "ExportAllDeclaration"
ExportDefaultDeclaration = "ExportDefaultDeclaration"
ExportNamedDeclaration = "ExportNamedDeclaration"
ExportSpecifier = "ExportSpecifier"
ExportDefaultSpecifier = "ExportDefaultSpecifier"
ExpressionStatement = "ExpressionStatement"
ForStatement = "ForStatement"
ForOfStatement = "ForOfStatement"
ForInStatement = "ForInStatement"
FunctionDeclaration = "FunctionDeclaration"
FunctionExpression = "FunctionExpression"
Identifier = "Identifier"
IfStatement = "IfStatement"
Import = "Import"
ImportDeclaration = "ImportDeclaration"
ImportDefaultSpecifier = "ImportDefaultSpecifier"
ImportNamespaceSpecifier = "ImportNamespaceSpecifier"
ImportSpecifier = "ImportSpecifier"
Literal = "Literal"
LabeledStatement = "LabeledStatement"
LogicalExpression = "LogicalExpression"
MemberExpression = "MemberExpression"
MetaProperty = "MetaProperty"
MethodDefinition = "MethodDefinition"
FieldDefinition = "FieldDefinition"
NewExpression = "NewExpression"
ObjectExpression = "ObjectExpression"
ObjectPattern = "ObjectPattern"
Program = "Program"
Property = "Property"
RestElement = "RestElement"
ReturnStatement = "ReturnStatement"
SequenceExpression = "SequenceExpression"
SpreadElement = "SpreadElement"
Super = "Super"
SwitchCase = "SwitchCase"
SwitchStatement = "SwitchStatement"
TaggedTemplateExpression = "TaggedTemplateExpression"
TemplateElement = "TemplateElement"
TemplateLiteral = "TemplateLiteral"
ThisExpression = "ThisExpression"
ThrowStatement = "ThrowStatement"
TryStatement = "TryStatement"
UnaryExpression = "UnaryExpression"
UpdateExpression = "UpdateExpression"
VariableDeclaration = "VariableDeclaration"
VariableDeclarator = "VariableDeclarator"
WhileStatement = "WhileStatement"
WithStatement = "WithStatement"
YieldExpression = "YieldExpression"
ArrowParameterPlaceHolder = "ArrowParameterPlaceHolder"
BlockComment = "BlockComment"
LineComment = "LineComment"

50
third_party/python/esprima/esprima/token.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
class Token:
BooleanLiteral = 1
EOF = 2
Identifier = 3
Keyword = 4
NullLiteral = 5
NumericLiteral = 6
Punctuator = 7
StringLiteral = 8
RegularExpression = 9
Template = 10
TokenName = {}
TokenName[Token.BooleanLiteral] = "Boolean"
TokenName[Token.EOF] = "<end>"
TokenName[Token.Identifier] = "Identifier"
TokenName[Token.Keyword] = "Keyword"
TokenName[Token.NullLiteral] = "Null"
TokenName[Token.NumericLiteral] = "Numeric"
TokenName[Token.Punctuator] = "Punctuator"
TokenName[Token.StringLiteral] = "String"
TokenName[Token.RegularExpression] = "RegularExpression"
TokenName[Token.Template] = "Template"

193
third_party/python/esprima/esprima/tokenizer.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES
# LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
from collections import deque
from .objects import Object
from .error_handler import ErrorHandler
from .scanner import Scanner, SourceLocation, Position, RegExp
from .token import Token, TokenName
class BufferEntry(Object):
def __init__(self, type, value, regex=None, range=None, loc=None):
self.type = type
self.value = value
self.regex = regex
self.range = range
self.loc = loc
class Reader(object):
def __init__(self):
self.values = []
self.curly = self.paren = -1
# A function following one of those tokens is an expression.
def beforeFunctionExpression(self, t):
return t in (
'(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
'return', 'case', 'delete', 'throw', 'void',
# assignment operators
'=', '+=', '-=', '*=', '**=', '/=', '%=', '<<=', '>>=', '>>>=',
'&=', '|=', '^=', ',',
# binary/unary operators
'+', '-', '*', '**', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
'|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
'<=', '<', '>', '!=', '!=='
)
# Determine if forward slash (/) is an operator or part of a regular expression
# https://github.com/mozilla/sweet.js/wiki/design
def isRegexStart(self):
if not self.values:
return True
previous = self.values[-1]
regex = previous is not None
if previous in (
'this',
']',
):
regex = False
elif previous == ')':
keyword = self.values[self.paren - 1]
regex = keyword in ('if', 'while', 'for', 'with')
elif previous == '}':
# Dividing a function by anything makes little sense,
# but we have to check for that.
regex = True
if len(self.values) >= 3 and self.values[self.curly - 3] == 'function':
# Anonymous function, e.g. function(){} /42
check = self.values[self.curly - 4]
regex = not self.beforeFunctionExpression(check) if check else False
elif len(self.values) >= 4 and self.values[self.curly - 4] == 'function':
# Named function, e.g. function f(){} /42/
check = self.values[self.curly - 5]
regex = not self.beforeFunctionExpression(check) if check else True
return regex
def append(self, token):
if token.type in (Token.Punctuator, Token.Keyword):
if token.value == '{':
self.curly = len(self.values)
elif token.value == '(':
self.paren = len(self.values)
self.values.append(token.value)
else:
self.values.append(None)
class Config(Object):
def __init__(self, tolerant=None, comment=None, range=None, loc=None, **options):
self.tolerant = tolerant
self.comment = comment
self.range = range
self.loc = loc
for k, v in options.items():
setattr(self, k, v)
class Tokenizer(object):
def __init__(self, code, options):
self.config = Config(**options)
self.errorHandler = ErrorHandler()
self.errorHandler.tolerant = self.config.tolerant
self.scanner = Scanner(code, self.errorHandler)
self.scanner.trackComment = self.config.comment
self.trackRange = self.config.range
self.trackLoc = self.config.loc
self.buffer = deque()
self.reader = Reader()
def errors(self):
return self.errorHandler.errors
def getNextToken(self):
if not self.buffer:
comments = self.scanner.scanComments()
if self.scanner.trackComment:
for e in comments:
value = self.scanner.source[e.slice[0]:e.slice[1]]
comment = BufferEntry(
type='BlockComment' if e.multiLine else 'LineComment',
value=value
)
if self.trackRange:
comment.range = e.range
if self.trackLoc:
comment.loc = e.loc
self.buffer.append(comment)
if not self.scanner.eof():
if self.trackLoc:
loc = SourceLocation(
start=Position(
line=self.scanner.lineNumber,
column=self.scanner.index - self.scanner.lineStart
),
end=Position(),
)
maybeRegex = self.scanner.source[self.scanner.index] == '/' and self.reader.isRegexStart()
if maybeRegex:
state = self.scanner.saveState()
try:
token = self.scanner.scanRegExp()
except Exception:
self.scanner.restoreState(state)
token = self.scanner.lex()
else:
token = self.scanner.lex()
self.reader.append(token)
entry = BufferEntry(
type=TokenName[token.type],
value=self.scanner.source[token.start:token.end]
)
if self.trackRange:
entry.range = [token.start, token.end]
if self.trackLoc:
loc.end = Position(
line=self.scanner.lineNumber,
column=self.scanner.index - self.scanner.lineStart
)
entry.loc = loc
if token.type is Token.RegularExpression:
entry.regex = RegExp(
pattern=token.pattern,
flags=token.flags,
)
self.buffer.append(entry)
return self.buffer.popleft() if self.buffer else None

40
third_party/python/esprima/esprima/utils.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, unicode_literals
import re
from .compat import unicode
def format(messageFormat, *args):
def formatter(m):
formatter.idx += 1
assert formatter.idx < len(args), 'Message reference must be in range'
return unicode(args[formatter.idx])
formatter.idx = -1
return format.re.sub(formatter, messageFormat)
format.re = re.compile(r'%(\d)')

288
third_party/python/esprima/esprima/visitor.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
import json
import types
from collections import deque
from .objects import Object
from .compat import PY3, unicode
class VisitRecursionError(Exception):
pass
class Visited(object):
def __init__(self, result):
if isinstance(result, Visited):
result = result.result
self.result = result
class Visitor(object):
"""
An Object visitor base class that walks the abstract syntax tree and calls a
visitor function for every Object found. This function may return a value
which is forwarded by the `visit` method.
This class is meant to be subclassed, with the subclass adding visitor
methods.
Per default the visitor functions for the nodes are ``'visit_'`` +
class name of the Object. So a `Module` Object visit function would
be `visit_Module`. This behavior can be changed by overriding
the `visit` method. If no visitor function exists for a Object
(return value `None`) the `generic_visit` visitor is used instead.
"""
def __call__(self, obj, metadata):
return self.transform(obj, metadata)
def transform(self, obj, metadata):
"""Transform an Object."""
if isinstance(obj, Object):
method = 'transform_' + obj.__class__.__name__
transformer = getattr(self, method, self.transform_Object)
new_obj = transformer(obj, metadata)
if new_obj is not None and obj is not new_obj:
obj = new_obj
return obj
def transform_Object(self, obj, metadata):
"""Called if no explicit transform function exists for an Object."""
return obj
def generic_visit(self, obj):
return self.visit(self.visit_Object(obj))
def visit(self, obj):
"""Visit a Object."""
if not hasattr(self, 'visitors'):
self._visit_context = {}
self._visit_count = 0
try:
self._visit_count += 1
stack = deque()
stack.append((obj, None))
last_result = None
while stack:
try:
last, visited = stack[-1]
if isinstance(last, types.GeneratorType):
stack.append((last.send(last_result), None))
last_result = None
elif isinstance(last, Visited):
stack.pop()
last_result = last.result
elif isinstance(last, Object):
if last in self._visit_context:
if self._visit_context[last] == self.visit_Object:
visitor = self.visit_RecursionError
else:
visitor = self.visit_Object
else:
method = 'visit_' + last.__class__.__name__
visitor = getattr(self, method, self.visit_Object)
self._visit_context[last] = visitor
stack.pop()
stack.append((visitor(last), last))
else:
method = 'visit_' + last.__class__.__name__
visitor = getattr(self, method, self.visit_Generic)
stack.pop()
stack.append((visitor(last), None))
except StopIteration:
stack.pop()
if visited and visited in self._visit_context:
del self._visit_context[visited]
return last_result
finally:
self._visit_count -= 1
if self._visit_count <= 0:
self._visit_context = {}
def visit_RecursionError(self, obj):
raise VisitRecursionError
def visit_Object(self, obj):
"""Called if no explicit visitor function exists for an Object."""
yield obj.__dict__
yield Visited(obj)
def visit_Generic(self, obj):
"""Called if no explicit visitor function exists for an object."""
yield Visited(obj)
def visit_list(self, obj):
for item in obj:
yield item
yield Visited(obj)
visit_Array = visit_list
def visit_dict(self, obj):
for field, value in list(obj.items()):
if not field.startswith('_'):
yield value
yield Visited(obj)
class NodeVisitor(Visitor):
pass
class ReprVisitor(Visitor):
def visit(self, obj, indent=4, nl="\n", sp="", skip=()):
self.level = 0
if isinstance(indent, int):
indent = " " * indent
self.indent = indent
self.nl = nl
self.sp = sp
self.skip = skip
return super(ReprVisitor, self).visit(obj)
def visit_RecursionError(self, obj):
yield Visited("...")
def visit_Object(self, obj):
value_repr = yield obj.__dict__
yield Visited(value_repr)
def visit_Generic(self, obj):
yield Visited(repr(obj))
def visit_list(self, obj):
indent1 = self.indent * self.level
indent2 = indent1 + self.indent
self.level += 1
try:
items = []
for item in obj:
v = yield item
items.append(v)
if items:
value_repr = "[%s%s%s%s%s%s%s]" % (
self.sp,
self.nl,
indent2,
(",%s%s%s" % (self.nl, self.sp, indent2)).join(items),
self.nl,
indent1,
self.sp,
)
else:
value_repr = "[]"
finally:
self.level -= 1
yield Visited(value_repr)
visit_Array = visit_list
def visit_dict(self, obj):
indent1 = self.indent * self.level
indent2 = indent1 + self.indent
self.level += 1
try:
items = []
for k, item in obj.items():
if item is not None and not k.startswith('_') and k not in self.skip:
v = yield item
items.append("%s: %s" % (k, v))
if items:
value_repr = "{%s%s%s%s%s%s%s}" % (
self.sp,
self.nl,
indent2,
(",%s%s%s" % (self.nl, self.sp, indent2)).join(items),
self.nl,
indent1,
self.sp,
)
else:
value_repr = "{}"
finally:
self.level -= 1
yield Visited(value_repr)
if PY3:
def visit_str(self, obj):
value_repr = json.dumps(obj)
yield Visited(value_repr)
else:
def visit_unicode(self, obj):
value_repr = json.dumps(obj)
yield Visited(value_repr)
def visit_SourceLocation(self, obj):
old_indent, self.indent = self.indent, ""
old_nl, self.nl = self.nl, ""
old_sp, self.sp = self.sp, ""
try:
yield obj
finally:
self.indent = old_indent
self.nl = old_nl
self.sp = old_sp
class ToDictVisitor(Visitor):
map = {
'isAsync': 'async',
'allowAwait': 'await',
}
def visit_RecursionError(self, obj):
yield Visited({
'error': "Infinite recursion detected...",
})
def visit_Object(self, obj):
obj = yield obj.__dict__
yield Visited(obj)
def visit_list(self, obj):
items = []
for item in obj:
v = yield item
items.append(v)
yield Visited(items)
visit_Array = visit_list
def visit_dict(self, obj):
items = []
for k, item in obj.items():
if item is not None and not k.startswith('_'):
v = yield item
k = unicode(k)
items.append((self.map.get(k, k), v))
yield Visited(dict(items))
def visit_SRE_Pattern(self, obj):
yield Visited({})

281
third_party/python/esprima/esprima/xhtml_entities.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,281 @@
# -*- coding: utf-8 -*-
# Copyright JS Foundation and other contributors, https://js.foundation/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import unicode_literals
# Generated by generate-xhtml-entities.js. DO NOT MODIFY!
XHTMLEntities = {
'quot': "\u0022",
'amp': "\u0026",
'apos': "\u0027",
'gt': "\u003E",
'nbsp': "\u00A0",
'iexcl': "\u00A1",
'cent': "\u00A2",
'pound': "\u00A3",
'curren': "\u00A4",
'yen': "\u00A5",
'brvbar': "\u00A6",
'sect': "\u00A7",
'uml': "\u00A8",
'copy': "\u00A9",
'ordf': "\u00AA",
'laquo': "\u00AB",
'not': "\u00AC",
'shy': "\u00AD",
'reg': "\u00AE",
'macr': "\u00AF",
'deg': "\u00B0",
'plusmn': "\u00B1",
'sup2': "\u00B2",
'sup3': "\u00B3",
'acute': "\u00B4",
'micro': "\u00B5",
'para': "\u00B6",
'middot': "\u00B7",
'cedil': "\u00B8",
'sup1': "\u00B9",
'ordm': "\u00BA",
'raquo': "\u00BB",
'frac14': "\u00BC",
'frac12': "\u00BD",
'frac34': "\u00BE",
'iquest': "\u00BF",
'Agrave': "\u00C0",
'Aacute': "\u00C1",
'Acirc': "\u00C2",
'Atilde': "\u00C3",
'Auml': "\u00C4",
'Aring': "\u00C5",
'AElig': "\u00C6",
'Ccedil': "\u00C7",
'Egrave': "\u00C8",
'Eacute': "\u00C9",
'Ecirc': "\u00CA",
'Euml': "\u00CB",
'Igrave': "\u00CC",
'Iacute': "\u00CD",
'Icirc': "\u00CE",
'Iuml': "\u00CF",
'ETH': "\u00D0",
'Ntilde': "\u00D1",
'Ograve': "\u00D2",
'Oacute': "\u00D3",
'Ocirc': "\u00D4",
'Otilde': "\u00D5",
'Ouml': "\u00D6",
'times': "\u00D7",
'Oslash': "\u00D8",
'Ugrave': "\u00D9",
'Uacute': "\u00DA",
'Ucirc': "\u00DB",
'Uuml': "\u00DC",
'Yacute': "\u00DD",
'THORN': "\u00DE",
'szlig': "\u00DF",
'agrave': "\u00E0",
'aacute': "\u00E1",
'acirc': "\u00E2",
'atilde': "\u00E3",
'auml': "\u00E4",
'aring': "\u00E5",
'aelig': "\u00E6",
'ccedil': "\u00E7",
'egrave': "\u00E8",
'eacute': "\u00E9",
'ecirc': "\u00EA",
'euml': "\u00EB",
'igrave': "\u00EC",
'iacute': "\u00ED",
'icirc': "\u00EE",
'iuml': "\u00EF",
'eth': "\u00F0",
'ntilde': "\u00F1",
'ograve': "\u00F2",
'oacute': "\u00F3",
'ocirc': "\u00F4",
'otilde': "\u00F5",
'ouml': "\u00F6",
'divide': "\u00F7",
'oslash': "\u00F8",
'ugrave': "\u00F9",
'uacute': "\u00FA",
'ucirc': "\u00FB",
'uuml': "\u00FC",
'yacute': "\u00FD",
'thorn': "\u00FE",
'yuml': "\u00FF",
'OElig': "\u0152",
'oelig': "\u0153",
'Scaron': "\u0160",
'scaron': "\u0161",
'Yuml': "\u0178",
'fnof': "\u0192",
'circ': "\u02C6",
'tilde': "\u02DC",
'Alpha': "\u0391",
'Beta': "\u0392",
'Gamma': "\u0393",
'Delta': "\u0394",
'Epsilon': "\u0395",
'Zeta': "\u0396",
'Eta': "\u0397",
'Theta': "\u0398",
'Iota': "\u0399",
'Kappa': "\u039A",
'Lambda': "\u039B",
'Mu': "\u039C",
'Nu': "\u039D",
'Xi': "\u039E",
'Omicron': "\u039F",
'Pi': "\u03A0",
'Rho': "\u03A1",
'Sigma': "\u03A3",
'Tau': "\u03A4",
'Upsilon': "\u03A5",
'Phi': "\u03A6",
'Chi': "\u03A7",
'Psi': "\u03A8",
'Omega': "\u03A9",
'alpha': "\u03B1",
'beta': "\u03B2",
'gamma': "\u03B3",
'delta': "\u03B4",
'epsilon': "\u03B5",
'zeta': "\u03B6",
'eta': "\u03B7",
'theta': "\u03B8",
'iota': "\u03B9",
'kappa': "\u03BA",
'lambda': "\u03BB",
'mu': "\u03BC",
'nu': "\u03BD",
'xi': "\u03BE",
'omicron': "\u03BF",
'pi': "\u03C0",
'rho': "\u03C1",
'sigmaf': "\u03C2",
'sigma': "\u03C3",
'tau': "\u03C4",
'upsilon': "\u03C5",
'phi': "\u03C6",
'chi': "\u03C7",
'psi': "\u03C8",
'omega': "\u03C9",
'thetasym': "\u03D1",
'upsih': "\u03D2",
'piv': "\u03D6",
'ensp': "\u2002",
'emsp': "\u2003",
'thinsp': "\u2009",
'zwnj': "\u200C",
'zwj': "\u200D",
'lrm': "\u200E",
'rlm': "\u200F",
'ndash': "\u2013",
'mdash': "\u2014",
'lsquo': "\u2018",
'rsquo': "\u2019",
'sbquo': "\u201A",
'ldquo': "\u201C",
'rdquo': "\u201D",
'bdquo': "\u201E",
'dagger': "\u2020",
'Dagger': "\u2021",
'bull': "\u2022",
'hellip': "\u2026",
'permil': "\u2030",
'prime': "\u2032",
'Prime': "\u2033",
'lsaquo': "\u2039",
'rsaquo': "\u203A",
'oline': "\u203E",
'frasl': "\u2044",
'euro': "\u20AC",
'image': "\u2111",
'weierp': "\u2118",
'real': "\u211C",
'trade': "\u2122",
'alefsym': "\u2135",
'larr': "\u2190",
'uarr': "\u2191",
'rarr': "\u2192",
'darr': "\u2193",
'harr': "\u2194",
'crarr': "\u21B5",
'lArr': "\u21D0",
'uArr': "\u21D1",
'rArr': "\u21D2",
'dArr': "\u21D3",
'hArr': "\u21D4",
'forall': "\u2200",
'part': "\u2202",
'exist': "\u2203",
'empty': "\u2205",
'nabla': "\u2207",
'isin': "\u2208",
'notin': "\u2209",
'ni': "\u220B",
'prod': "\u220F",
'sum': "\u2211",
'minus': "\u2212",
'lowast': "\u2217",
'radic': "\u221A",
'prop': "\u221D",
'infin': "\u221E",
'ang': "\u2220",
'and': "\u2227",
'or': "\u2228",
'cap': "\u2229",
'cup': "\u222A",
'int': "\u222B",
'there4': "\u2234",
'sim': "\u223C",
'cong': "\u2245",
'asymp': "\u2248",
'ne': "\u2260",
'equiv': "\u2261",
'le': "\u2264",
'ge': "\u2265",
'sub': "\u2282",
'sup': "\u2283",
'nsub': "\u2284",
'sube': "\u2286",
'supe': "\u2287",
'oplus': "\u2295",
'otimes': "\u2297",
'perp': "\u22A5",
'sdot': "\u22C5",
'lceil': "\u2308",
'rceil': "\u2309",
'lfloor': "\u230A",
'rfloor': "\u230B",
'loz': "\u25CA",
'spades': "\u2660",
'clubs': "\u2663",
'hearts': "\u2665",
'diams': "\u2666",
'lang': "\u27E8",
'rang': "\u27E9",
}

4
third_party/python/esprima/setup.cfg поставляемый Normal file
Просмотреть файл

@ -0,0 +1,4 @@
[egg_info]
tag_build =
tag_date = 0

55
third_party/python/esprima/setup.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
import os
from esprima import version
def read(fname):
try:
with open(os.path.join(os.path.dirname(__file__), fname), "r") as fp:
return fp.read().strip()
except IOError:
return ''
setup(
name="esprima",
version=version,
author="German M. Bravo (Kronuz)",
author_email="german.mb@gmail.com",
url="https://github.com/Kronuz/esprima-python",
license="BSD License",
keywords="esprima ecmascript javascript parser ast",
description="ECMAScript parsing infrastructure for multipurpose analysis in Python",
long_description=read("README.rst"),
packages=["esprima"],
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Topic :: Software Development :: Code Generators",
"Topic :: Software Development :: Compilers",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing :: General",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
],
entry_points={
'console_scripts': [
'esprima = esprima.__main__:main',
]
},
)

1
third_party/python/requirements.in поставляемый
Просмотреть файл

@ -23,6 +23,7 @@ compare-locales==7.2.5
cookies==2.2.1 cookies==2.2.1
distro==1.4.0 distro==1.4.0
ecdsa==0.15 ecdsa==0.15
esprima==4.0.1
jsmin==2.1.0 jsmin==2.1.0
json-e==2.7.0 json-e==2.7.0
mozilla-version==0.3.0 mozilla-version==0.3.0

3
third_party/python/requirements.txt поставляемый
Просмотреть файл

@ -38,6 +38,9 @@ ecdsa==0.15 \
--hash=sha256:867ec9cf6df0b03addc8ef66b56359643cb5d0c1dc329df76ba7ecfe256c8061 \ --hash=sha256:867ec9cf6df0b03addc8ef66b56359643cb5d0c1dc329df76ba7ecfe256c8061 \
--hash=sha256:8f12ac317f8a1318efa75757ef0a651abe12e51fc1af8838fb91079445227277 \ --hash=sha256:8f12ac317f8a1318efa75757ef0a651abe12e51fc1af8838fb91079445227277 \
# via -r requirements-mach-vendor-python.in # via -r requirements-mach-vendor-python.in
esprima==4.0.1 \
--hash=sha256:08db1a876d3c2910db9cfaeb83108193af5411fc3a3a66ebefacd390d21323ee \
# via -r requirements-mach-vendor-python.in
fluent.syntax==0.15.1 \ fluent.syntax==0.15.1 \
--hash=sha256:3d3c95b9de82df498172d9447576e787e809b753c6f7f5acf64a9ef8d7782c81 \ --hash=sha256:3d3c95b9de82df498172d9447576e787e809b753c6f7f5acf64a9ef8d7782c81 \
--hash=sha256:e95bb3abfe7cf51b2c6d1e92d57335f07c737ba57bbbba18e57618bd15f78d4b \ --hash=sha256:e95bb3abfe7cf51b2c6d1e92d57335f07c737ba57bbbba18e57618bd15f78d4b \