~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/lib2to3/pgen2/driver.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
 
2
# Licensed to PSF under a Contributor Agreement.
 
3
 
 
4
# Modifications:
 
5
# Copyright 2006 Google, Inc. All Rights Reserved.
 
6
# Licensed to PSF under a Contributor Agreement.
 
7
 
 
8
"""Parser driver.
 
9
 
 
10
This provides a high-level interface to parse a file into a syntax tree.
 
11
 
 
12
"""
 
13
 
 
14
__author__ = "Guido van Rossum <guido@python.org>"
 
15
 
 
16
__all__ = ["Driver", "load_grammar"]
 
17
 
 
18
# Python imports
 
19
import os
 
20
import logging
 
21
import sys
 
22
 
 
23
# Pgen imports
 
24
from . import grammar, parse, token, tokenize, pgen
 
25
 
 
26
 
 
27
class Driver(object):
 
28
 
 
29
    def __init__(self, grammar, convert=None, logger=None):
 
30
        self.grammar = grammar
 
31
        if logger is None:
 
32
            logger = logging.getLogger()
 
33
        self.logger = logger
 
34
        self.convert = convert
 
35
 
 
36
    def parse_tokens(self, tokens, debug=False):
 
37
        """Parse a series of tokens and return the syntax tree."""
 
38
        # XXX Move the prefix computation into a wrapper around tokenize.
 
39
        p = parse.Parser(self.grammar, self.convert)
 
40
        p.setup()
 
41
        lineno = 1
 
42
        column = 0
 
43
        type = value = start = end = line_text = None
 
44
        prefix = ""
 
45
        for quintuple in tokens:
 
46
            type, value, start, end, line_text = quintuple
 
47
            if start != (lineno, column):
 
48
                assert (lineno, column) <= start, ((lineno, column), start)
 
49
                s_lineno, s_column = start
 
50
                if lineno < s_lineno:
 
51
                    prefix += "\n" * (s_lineno - lineno)
 
52
                    lineno = s_lineno
 
53
                    column = 0
 
54
                if column < s_column:
 
55
                    prefix += line_text[column:s_column]
 
56
                    column = s_column
 
57
            if type in (tokenize.COMMENT, tokenize.NL):
 
58
                prefix += value
 
59
                lineno, column = end
 
60
                if value.endswith("\n"):
 
61
                    lineno += 1
 
62
                    column = 0
 
63
                continue
 
64
            if type == token.OP:
 
65
                type = grammar.opmap[value]
 
66
            if debug:
 
67
                self.logger.debug("%s %r (prefix=%r)",
 
68
                                  token.tok_name[type], value, prefix)
 
69
            if p.addtoken(type, value, (prefix, start)):
 
70
                if debug:
 
71
                    self.logger.debug("Stop.")
 
72
                break
 
73
            prefix = ""
 
74
            lineno, column = end
 
75
            if value.endswith("\n"):
 
76
                lineno += 1
 
77
                column = 0
 
78
        else:
 
79
            # We never broke out -- EOF is too soon (how can this happen???)
 
80
            raise parse.ParseError("incomplete input",
 
81
                                   type, value, (prefix, start))
 
82
        return p.rootnode
 
83
 
 
84
    def parse_stream_raw(self, stream, debug=False):
 
85
        """Parse a stream and return the syntax tree."""
 
86
        tokens = tokenize.generate_tokens(stream.readline)
 
87
        return self.parse_tokens(tokens, debug)
 
88
 
 
89
    def parse_stream(self, stream, debug=False):
 
90
        """Parse a stream and return the syntax tree."""
 
91
        return self.parse_stream_raw(stream, debug)
 
92
 
 
93
    def parse_file(self, filename, debug=False):
 
94
        """Parse a file and return the syntax tree."""
 
95
        stream = open(filename)
 
96
        try:
 
97
            return self.parse_stream(stream, debug)
 
98
        finally:
 
99
            stream.close()
 
100
 
 
101
    def parse_string(self, text, debug=False):
 
102
        """Parse a string and return the syntax tree."""
 
103
        tokens = tokenize.generate_tokens(generate_lines(text).__next__)
 
104
        return self.parse_tokens(tokens, debug)
 
105
 
 
106
 
 
107
def generate_lines(text):
 
108
    """Generator that behaves like readline without using StringIO."""
 
109
    for line in text.splitlines(True):
 
110
        yield line
 
111
    while True:
 
112
        yield ""
 
113
 
 
114
 
 
115
def load_grammar(gt="Grammar.txt", gp=None,
 
116
                 save=True, force=False, logger=None):
 
117
    """Load the grammar (maybe from a pickle)."""
 
118
    if logger is None:
 
119
        logger = logging.getLogger()
 
120
    if gp is None:
 
121
        head, tail = os.path.splitext(gt)
 
122
        if tail == ".txt":
 
123
            tail = ""
 
124
        gp = head + tail + ".".join(map(str, sys.version_info)) + ".pickle"
 
125
    if force or not _newer(gp, gt):
 
126
        logger.info("Generating grammar tables from %s", gt)
 
127
        g = pgen.generate_grammar(gt)
 
128
        if save:
 
129
            logger.info("Writing grammar tables to %s", gp)
 
130
            try:
 
131
                g.dump(gp)
 
132
            except IOError as e:
 
133
                logger.info("Writing failed:"+str(e))
 
134
    else:
 
135
        g = grammar.Grammar()
 
136
        g.load(gp)
 
137
    return g
 
138
 
 
139
 
 
140
def _newer(a, b):
 
141
    """Inquire whether file a was written since file b."""
 
142
    if not os.path.exists(a):
 
143
        return False
 
144
    if not os.path.exists(b):
 
145
        return True
 
146
    return os.path.getmtime(a) >= os.path.getmtime(b)