summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus/js_parser/parser.py
blob: f67708a9cce9f84181ee1bd54040feea6624ec58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env python

"""parser.py - A JavaScript parser, currently with many bugs.

See README.md for instructions.
"""

from . import parser_tables
from .lexer import JSLexer


# "type: ignore" because mypy can't see inside js_parser.parser_tables.
class JSParser(parser_tables.Parser):  # type: ignore
    def __init__(self, goal='Script', builder=None):
        super().__init__(goal, builder)
        self._goal = goal

    def clone(self):
        return JSParser(self._goal, self.methods)

    def on_recover(self, error_code, lexer, stv):
        """Check that ASI error recovery is really acceptable."""
        if error_code == 'asi':
            # ASI is allowed in three places:
            # - at the end of the source text
            # - before a close brace `}`
            # - after a LineTerminator
            # Hence the three-part if-condition below.
            #
            # The other quirks of ASI are implemented by massaging the syntax,
            # in parse_esgrammar.py.
            if not self.closed and stv.term != '}' and not lexer.saw_line_terminator():
                lexer.throw("missing semicolon")
        else:
            # ASI is always allowed in this one state.
            assert error_code == 'do_while_asi'


def parse_Script(text):
    lexer = JSLexer(JSParser('Script'))
    lexer.write(text)
    return lexer.close()